class Sass::Tree::Visitors::Perform
def perform_arguments(callable, args, splat, environment)
- Api: - private
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