Class: Sass::Script::Funcall

Inherits:
Node
  • Object
show all
Defined in:
lib/sass/script/funcall.rb

Overview

A SassScript parse node representing a function call.

A function call either calls one of the functions in Functions, or if no function with the given name exists it returns a string representation of the function call.

Instance Attribute Summary collapse

Attributes inherited from Node

#line, #options

Instance Method Summary collapse

Methods inherited from Node

#dasherize, #opts, #perform

Constructor Details

#initialize(name, args, keywords, splat) ⇒ Funcall

Returns a new instance of Funcall.

Parameters:



35
36
37
38
39
40
41
# File 'lib/sass/script/funcall.rb', line 35

def initialize(name, args, keywords, splat)
  @name = name
  @args = args
  @keywords = keywords
  @splat = splat
  super()
end

Instance Attribute Details

#argsArray<Script::Node> (readonly)

The arguments to the function.

Returns:



19
20
21
# File 'lib/sass/script/funcall.rb', line 19

def args
  @args
end

#keywords{String => Script::Node} (readonly)

The keyword arguments to the function.

Returns:



24
25
26
# File 'lib/sass/script/funcall.rb', line 24

def keywords
  @keywords
end

#nameString (readonly)

The name of the function.

Returns:



14
15
16
# File 'lib/sass/script/funcall.rb', line 14

def name
  @name
end

#splatScript::Node?

The splat argument for this function, if one exists.

Returns:



29
30
31
# File 'lib/sass/script/funcall.rb', line 29

def splat
  @splat
end

Instance Method Details

#_perform(environment) ⇒ Literal (protected)

Evaluates the function call.

Parameters:

  • environment (Sass::Environment)

    The environment in which to evaluate the SassScript

Returns:

  • (Literal)

    The SassScript object that is the value of the function call

Raises:



98
99
100
101
102
103
104
105
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/sass/script/funcall.rb', line 98

def _perform(environment)
  args = @args.map {|a| a.perform(environment)}
  splat = @splat.perform(environment) if @splat
  if fn = environment.function(@name)
    keywords = Sass::Util.map_hash(@keywords) {|k, v| [k, v.perform(environment)]}
    return perform_sass_fn(fn, args, keywords, splat)
  end

  ruby_name = @name.tr('-', '_')
  args = construct_ruby_args(ruby_name, args, splat, environment)

  unless Functions.callable?(ruby_name)
    opts(to_literal(args))
  else
    opts(Functions::EvaluationContext.new(environment.options).send(ruby_name, *args))
  end
rescue ArgumentError => e
  message = e.message

  # If this is a legitimate Ruby-raised argument error, re-raise it.
  # Otherwise, it's an error in the user's stylesheet, so wrap it.
  if Sass::Util.rbx?
    # Rubinius has a different error report string than vanilla Ruby. It
    # also doesn't put the actual method for which the argument error was
    # thrown in the backtrace, nor does it include `send`, so we look for
    # `_perform`.
    if e.message =~ /^method '([^']+)': given (\d+), expected (\d+)/
      error_name, given, expected = $1, $2, $3
      raise e if error_name != ruby_name || e.backtrace[0] !~ /:in `_perform'$/
      message = "wrong number of arguments (#{given} for #{expected})"
    end
  elsif Sass::Util.jruby?
    if Sass::Util.jruby1_6?
      should_maybe_raise = e.message =~ /^wrong number of arguments \((\d+) for (\d+)\)/ &&
        # The one case where JRuby does include the Ruby name of the function
        # is manually-thrown ArgumentErrors, which are indistinguishable from
        # legitimate ArgumentErrors. We treat both of these as
        # Sass::SyntaxErrors even though it can hide Ruby errors.
        e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
    else
      should_maybe_raise = e.message =~ /^wrong number of arguments calling `[^`]+` \((\d+) for (\d+)\)/
      given, expected = $1, $2
    end

    if should_maybe_raise
      # JRuby 1.7 includes __send__ before send and _perform.
      trace = e.backtrace.dup
      raise e if !Sass::Util.jruby1_6? && trace.shift !~ /:in `__send__'$/

      # JRuby (as of 1.7.2) doesn't put the actual method
      # for which the argument error was thrown in the backtrace, so we
      # detect whether our send threw an argument error.
      if !(trace[0] =~ /:in `send'$/ && trace[1] =~ /:in `_perform'$/)
        raise e
      elsif !Sass::Util.jruby1_6?
        # JRuby 1.7 doesn't use standard formatting for its ArgumentErrors.
        message = "wrong number of arguments (#{given} for #{expected})"
      end
    end
  elsif e.message =~ /^wrong number of arguments \(\d+ for \d+\)/ &&
      e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
    raise e
  end
  raise Sass::SyntaxError.new("#{message} for `#{name}'")
end

#childrenArray<Node>

Returns the arguments to the function.

Returns:

See Also:



77
78
79
80
81
# File 'lib/sass/script/funcall.rb', line 77

def children
  res = @args + @keywords.values
  res << @splat if @splat
  res
end

#deep_copy

See Also:



84
85
86
87
88
89
# File 'lib/sass/script/funcall.rb', line 84

def deep_copy
  node = dup
  node.instance_variable_set('@args', args.map {|a| a.deep_copy})
  node.instance_variable_set('@keywords', Hash[keywords.map {|k, v| [k, v.deep_copy]}])
  node
end

#inspectString

Returns A string representation of the function call.

Returns:

  • (String)

    A string representation of the function call



44
45
46
47
48
49
50
51
52
53
# File 'lib/sass/script/funcall.rb', line 44

def inspect
  args = @args.map {|a| a.inspect}.join(', ')
  keywords = Sass::Util.hash_to_a(@keywords).
      map {|k, v| "$#{k}: #{v.inspect}"}.join(', ')
  if self.splat
    splat = (args.empty? && keywords.empty?) ? "" : ", "
    splat = "#{splat}#{self.splat.inspect}..."
  end
  "#{name}(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords}#{splat})"
end

#to_literal(args) (protected)

This method is factored out from _perform so that compass can override it with a cross-browser implementation for functions that require vendor prefixes in the generated css.



167
168
169
# File 'lib/sass/script/funcall.rb', line 167

def to_literal(args)
  Script::String.new("#{name}(#{args.join(', ')})")
end

#to_sass(opts = {})

See Also:



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/sass/script/funcall.rb', line 56

def to_sass(opts = {})
  arg_to_sass = lambda do |arg|
    sass = arg.to_sass(opts)
    sass = "(#{sass})" if arg.is_a?(Sass::Script::List) && arg.separator == :comma
    sass
  end

  args = @args.map(&arg_to_sass).join(', ')
  keywords = Sass::Util.hash_to_a(@keywords).
    map {|k, v| "$#{dasherize(k, opts)}: #{arg_to_sass[v]}"}.join(', ')
  if self.splat
    splat = (args.empty? && keywords.empty?) ? "" : ", "
    splat = "#{splat}#{arg_to_sass[self.splat]}..."
  end
  "#{dasherize(name, opts)}(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords}#{splat})"
end