class Sass::Script::Tree::Funcall

returns a string representation of the function call.
{Sass::Script::Functions}, or if no function with the given name exists it
A function call either calls one of the functions in
A SassScript parse node representing a function call.

def _perform(environment)

Raises:
  • (Sass::SyntaxError) - if the function call raises an ArgumentError

Returns:
  • (Sass::Script::Value) - The SassScript object that is the value of the function call

Parameters:
  • environment (Sass::Environment) -- The environment in which to evaluate the SassScript
def _perform(environment)
  args = @args.each_with_index.
    map {|a, i| perform_arg(a, environment, signature && signature.args[i])}
  keywords = Sass::Util.map_hash(@keywords) do |k, v|
    [k, perform_arg(v, environment, k.tr('-', '_'))]
  end
  splat = Sass::Tree::Visitors::Perform.perform_splat(
    @splat, keywords, @kwarg_splat, environment)
  fn = @callable || environment.function(@name)
  if fn && fn.origin == :stylesheet
    environment.stack.with_function(filename, line, name) do
      return without_original(perform_sass_fn(fn, args, splat, environment))
    end
  end
  args = construct_ruby_args(ruby_name, args, splat, environment)
  if Sass::Script::Functions.callable?(ruby_name) && (!fn || fn.origin == :builtin)
    local_environment = Sass::Environment.new(environment.global_env, environment.options)
    local_environment.caller = Sass::ReadOnlyEnvironment.new(environment, environment.options)
    result = local_environment.stack.with_function(filename, line, name) do
      opts(Sass::Script::Functions::EvaluationContext.new(
        local_environment).send(ruby_name, *args))
    end
    without_original(result)
  else
    opts(to_literal(args))
  end
rescue ArgumentError => e
  reformat_argument_error(e)
end

def children

Other tags:
    See: Node#children -

Returns:
  • (Array) -
def children
  res = @args + @keywords.values
  res << @splat if @splat
  res << @kwarg_splat if @kwarg_splat
  res
end

def construct_ruby_args(name, args, splat, environment)

def construct_ruby_args(name, args, splat, environment)
  args += splat.to_a if splat
  # 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
  unless (signature = Sass::Script::Functions.signature(name.to_sym, args.size, keywords.size))
    return args if keywords.empty?
    raise Sass::SyntaxError.new("Function #{name} doesn't support keyword arguments")
  end
  # If the user passes more non-keyword args than the function expects,
  # but it does expect keyword args, Ruby's arg handling won't raise an error.
  # Since we don't want to make functions think about this,
  # we'll handle it for them here.
  if signature.var_kwargs && !signature.var_args && args.size > signature.args.size
    raise Sass::SyntaxError.new(
      "#{args[signature.args.size].inspect} is not a keyword argument for `#{name}'")
  elsif keywords.empty?
    args << {} if signature.var_kwargs
    return args
  end
  argnames = signature.args[args.size..-1] || []
  deprecated_argnames = (signature.deprecated && signature.deprecated[args.size..-1]) || []
  args += argnames.zip(deprecated_argnames).map do |(argname, deprecated_argname)|
    if keywords.has_key?(argname)
      keywords.delete(argname)
    elsif deprecated_argname && keywords.has_key?(deprecated_argname)
      deprecated_argname = keywords.denormalize(deprecated_argname)
      Sass::Util.sass_warn("DEPRECATION WARNING: The `$#{deprecated_argname}' argument for " +
        "`#{@name}()' has been renamed to `$#{argname}'.")
      keywords.delete(deprecated_argname)
    else
      raise Sass::SyntaxError.new("Function #{name} requires an argument named $#{argname}")
    end
  end
  if keywords.size > 0
    if signature.var_kwargs
      # Don't pass a NormalizedMap to a Ruby function.
      args << keywords.to_hash
    else
      argname = keywords.keys.sort.first
      if signature.args.include?(argname)
        raise Sass::SyntaxError.new(
          "Function #{name} was passed argument $#{argname} both by position and by name")
      else
        raise Sass::SyntaxError.new(
          "Function #{name} doesn't have an argument named $#{argname}")
      end
    end
  end
  args
end

def deep_copy

Other tags:
    See: Node#deep_copy -
def deep_copy
  node = dup
  node.instance_variable_set('@args', args.map {|a| a.deep_copy})
  copied_keywords = Sass::Util::NormalizedMap.new
  @keywords.as_stored.each {|k, v| copied_keywords[k] = v.deep_copy}
  node.instance_variable_set('@keywords', copied_keywords)
  node
end

def initialize(name_or_callable, args, keywords, splat, kwarg_splat)

Parameters:
  • kwarg_splat (Node) -- See \{#kwarg_splat}
  • splat (Node) -- See \{#splat}
  • keywords (Sass::Util::NormalizedMap) -- See \{#keywords}
  • args (Array) -- See \{#args}
  • name_or_callable (String, Sass::Callable) -- See \{#name}
def initialize(name_or_callable, args, keywords, splat, kwarg_splat)
  if name_or_callable.is_a?(Sass::Callable)
    @callable = name_or_callable
    @name = name_or_callable.name
  else
    @callable = nil
    @name = name_or_callable
  end
  @args = args
  @keywords = keywords
  @splat = splat
  @kwarg_splat = kwarg_splat
  super()
end

def inspect

Returns:
  • (String) - A string representation of the function call
def inspect
  args = @args.map {|a| a.inspect}.join(', ')
  keywords = @keywords.as_stored.to_a.map {|k, v| "$#{k}: #{v.inspect}"}.join(', ')
  if self.splat
    splat = args.empty? && keywords.empty? ? "" : ", "
    splat = "#{splat}#{self.splat.inspect}..."
    splat = "#{splat}, #{kwarg_splat.inspect}..." if kwarg_splat
  end
  "#{name}(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords}#{splat})"
end

def perform_arg(argument, environment, name)

def perform_arg(argument, environment, name)
  return argument if signature && signature.delayed_args.include?(name)
  argument.perform(environment)
end

def perform_sass_fn(function, args, splat, environment)

def perform_sass_fn(function, args, splat, environment)
  Sass::Tree::Visitors::Perform.perform_arguments(function, args, splat, environment) do |env|
    env.caller = Sass::Environment.new(environment)
    val = catch :_sass_return do
      function.tree.each {|c| Sass::Tree::Visitors::Perform.visit(c, env)}
      raise Sass::SyntaxError.new("Function #{@name} finished without @return")
    end
    val
  end
end

def reformat_argument_error(e)

def reformat_argument_error(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?
    should_maybe_raise =
      e.message =~ /^wrong number of arguments calling `[^`]+` \((\d+) for (\d+)\)/
    given, expected = $1, $2
    if should_maybe_raise
      # JRuby 1.7 includes __send__ before send and _perform.
      trace = e.backtrace.dup
      raise e if 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
      else
        # JRuby 1.7 doesn't use standard formatting for its ArgumentErrors.
        message = "wrong number of arguments (#{given} for #{expected})"
      end
    end
  elsif (md = /^wrong number of arguments \(given (\d+), expected (\d+)\)/.match(e.message)) &&
        e.backtrace[0] =~ /:in `#{ruby_name}'$/
    # Handle ruby 2.3 error formatting
    message = "wrong number of arguments (#{md[1]} for #{md[2]})"
  elsif e.message =~ /^wrong number of arguments/ &&
        e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
    raise e
  end
  raise Sass::SyntaxError.new("#{message} for `#{name}'")
end

def ruby_name

def ruby_name
  @ruby_name ||= @name.tr('-', '_')
end

def signature

def signature
  @signature ||= Sass::Script::Functions.signature(name.to_sym, @args.size, @keywords.size)
end

def to_literal(args)

We should get rid of it in the future.
Compass historically overrode this before it changed name to {Funcall#to_value}.
def to_literal(args)
  to_value(args)
end

def to_sass(opts = {})

Other tags:
    See: Node#to_sass -
def to_sass(opts = {})
  arg_to_sass = lambda do |arg|
    sass = arg.to_sass(opts)
    sass = "(#{sass})" if arg.is_a?(Sass::Script::Tree::ListLiteral) && arg.separator == :comma
    sass
  end
  args = @args.map(&arg_to_sass)
  keywords = @keywords.as_stored.to_a.map {|k, v| "$#{dasherize(k, opts)}: #{arg_to_sass[v]}"}
  if self.splat
    splat = "#{arg_to_sass[self.splat]}..."
    kwarg_splat = "#{arg_to_sass[self.kwarg_splat]}..." if self.kwarg_splat
  end
  arglist = [args, splat, keywords, kwarg_splat].flatten.compact.join(', ')
  "#{dasherize(name, opts)}(#{arglist})"
end

def to_value(args)

in the generated css.
it with a cross-browser implementation for functions that require vendor prefixes
This method is factored out from `_perform` so that compass can override
def to_value(args)
  Sass::Script::Value::String.new("#{name}(#{args.join(', ')})")
end

def without_original(value)

def without_original(value)
  return value unless value.is_a?(Sass::Script::Value::Number)
  value = value.dup
  value.original = nil
  value
end