Class: Sass::Tree::Visitors::Perform

Inherits:
Base
  • Object
show all
Defined in:
.ruby-sass/lib/sass/tree/visitors/perform.rb

Overview

A visitor for converting a dynamic Sass tree into a static Sass tree.

Constant Summary

@@function_name_deprecation =
Sass::Deprecation.new

Class Method Summary (collapse)

Class Method Details

.perform_arguments(callable, args, splat, environment) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File '.ruby-sass/lib/sass/tree/visitors/perform.rb', line 14

def perform_arguments(callable, args, splat, environment)
  desc = "#{callable.type.capitalize} #{callable.name}"
  downcase_desc = "#{callable.type} #{callable.name}"

  # All keywords are contained in splat.keywords for consistency,
  # even if there were no splats passed in.
  old_keywords_accessed = splat.keywords_accessed
  keywords = splat.keywords
  splat.keywords_accessed = old_keywords_accessed

  begin
    unless keywords.empty?
      unknown_args = Sass::Util.array_minus(keywords.keys,
        callable.args.map {|var| var.first.underscored_name})
      if callable.splat && unknown_args.include?(callable.splat.underscored_name)
        raise Sass::SyntaxError.new("Argument $#{callable.splat.name} of #{downcase_desc} " +
                                    "cannot be used as a named argument.")
      elsif unknown_args.any?
        description = unknown_args.length > 1 ? 'the following arguments:' : 'an argument named'
        raise Sass::SyntaxError.new("#{desc} doesn't have #{description} " +
                                    "#{unknown_args.map {|name| "$#{name}"}.join ', '}.")
      end
    end
  rescue Sass::SyntaxError => keyword_exception
  end

  # If there's no splat, raise the keyword exception immediately. The actual
  # raising happens in the ensure clause at the end of this function.
  return if keyword_exception && !callable.splat

  splat_sep = :comma
  if splat
    args += splat.to_a
    splat_sep = splat.separator
  end

  if args.size > callable.args.size && !callable.splat
    extra_args_because_of_splat = splat && args.size - splat.to_a.size <= callable.args.size

    takes = callable.args.size
    passed = args.size
    message = "#{desc} takes #{takes} argument#{'s' unless takes == 1} " +
      "but #{passed} #{passed == 1 ? 'was' : 'were'} passed."
    raise Sass::SyntaxError.new(message) unless extra_args_because_of_splat
    # TODO: when the deprecation period is over, make this an error.
    Sass::Util.sass_warn("WARNING: #{message}\n" +
      environment.stack.to_s.gsub(/^/m, " " * 8) + "\n" +
      "This will be an error in future versions of Sass.")
  end

  env = Sass::Environment.new(callable.environment)
  callable.args.zip(args[0...callable.args.length]) do |(var, default), value|
    if value && keywords.has_key?(var.name)
      raise Sass::SyntaxError.new("#{desc} was passed argument $#{var.name} " +
                                  "both by position and by name.")
    end

    value ||= keywords.delete(var.name)
    value ||= default && default.perform(env)
    raise Sass::SyntaxError.new("#{desc} is missing argument #{var.inspect}.") unless value
    env.set_local_var(var.name, value)
  end

  if callable.splat
    rest = args[callable.args.length..-1] || []
    arg_list = Sass::Script::Value::ArgList.new(rest, keywords, splat_sep)
    arg_list.options = env.options
    env.set_local_var(callable.splat.name, arg_list)
  end

  yield env
rescue StandardError => e
ensure
  # If there's a keyword exception, we don't want to throw it immediately,
  # because the invalid keywords may be part of a glob argument that should be
  # passed on to another function. So we only raise it if we reach the end of
  # this function *and* the keywords attached to the argument list glob object
  # haven't been accessed.
  #
  # The keyword exception takes precedence over any Sass errors, but not over
  # non-Sass exceptions.
  if keyword_exception &&
      !(arg_list && arg_list.keywords_accessed) &&
      (e.nil? || e.is_a?(Sass::SyntaxError))
    raise keyword_exception
  elsif e
    raise e
  end
end

.perform_splat(splat, performed_keywords, kwarg_splat, environment) ⇒ Sass::Script::Value::ArgList

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File '.ruby-sass/lib/sass/tree/visitors/perform.rb', line 106

def perform_splat(splat, performed_keywords, kwarg_splat, environment)
  args, kwargs, separator = [], nil, :comma

  if splat
    splat = splat.perform(environment)
    separator = splat.separator || separator
    if splat.is_a?(Sass::Script::Value::ArgList)
      args = splat.to_a
      kwargs = splat.keywords
    elsif splat.is_a?(Sass::Script::Value::Map)
      kwargs = arg_hash(splat)
    else
      args = splat.to_a
    end
  end
  kwargs ||= Sass::Util::NormalizedMap.new
  kwargs.update(performed_keywords)

  if kwarg_splat
    kwarg_splat = kwarg_splat.perform(environment)
    unless kwarg_splat.is_a?(Sass::Script::Value::Map)
      raise Sass::SyntaxError.new("Variable keyword arguments must be a map " +
                                  "(was #{kwarg_splat.inspect}).")
    end
    kwargs.update(arg_hash(kwarg_splat))
  end

  Sass::Script::Value::ArgList.new(args, kwargs, separator)
end

.visit(root, environment = nil) ⇒ Tree::Node

Returns The resulting tree of static nodes.

Parameters:

  • root (Tree::Node)

    The root node of the tree to visit.

  • environment (Sass::Environment) (defaults to: nil)

    The lexical environment.

Returns:

  • (Tree::Node)

    The resulting tree of static nodes.



9
10
11
# File '.ruby-sass/lib/sass/tree/visitors/perform.rb', line 9

def visit(root, environment = nil)
  new(environment).send(:visit, root)
end