mirror of
https://github.com/haml/haml.git
synced 2022-11-09 12:33:31 -05:00
[Sass] Pass the options into literals returned by functions and operations.
This commit is contained in:
parent
e9fa71cf38
commit
6c718b21a8
8 changed files with 79 additions and 10 deletions
|
@ -41,7 +41,9 @@ module Sass
|
|||
return Script::String.new("#{name}(#{args.map {|a| a.perform(environment)}.join(', ')})")
|
||||
end
|
||||
|
||||
return Functions::EvaluationContext.new(environment.options).send(ruby_name, *args)
|
||||
result = Functions::EvaluationContext.new(environment.options).send(ruby_name, *args)
|
||||
result.options = environment.options
|
||||
return result
|
||||
rescue ArgumentError => e
|
||||
raise e unless e.backtrace.any? {|t| t =~ /:in `(block in )?(#{name}|perform)'$/}
|
||||
raise Sass::SyntaxError.new("#{e.message} for `#{name}'")
|
||||
|
|
|
@ -87,6 +87,13 @@ module Sass::Script
|
|||
#
|
||||
# Within one of the functions in this module,
|
||||
# methods of {EvaluationContext} can be used.
|
||||
#
|
||||
# ### Caveats
|
||||
#
|
||||
# When creating new {Literal} objects within functions,
|
||||
# be aware that it's not safe to call {Literal#to_s #to_s}
|
||||
# (or other methods that use the string representation)
|
||||
# on those objects without first setting {Node#options= the #options attribute}.
|
||||
module Functions
|
||||
# The context in which methods in {Script::Functions} are evaluated.
|
||||
# That means that all instance methods of {EvaluationContext}
|
||||
|
|
|
@ -39,6 +39,23 @@ module Sass::Script
|
|||
[]
|
||||
end
|
||||
|
||||
# Returns the options hash for this node.
|
||||
#
|
||||
# @return [{Symbol => Object}]
|
||||
# @raise [Sass::SyntaxError] if the options hash hasn't been set.
|
||||
# This should only happen when the literal was created
|
||||
# outside of the parser and \{#to\_s} was called on it
|
||||
def options
|
||||
opts = super
|
||||
return opts if opts
|
||||
raise Sass::SyntaxError.new(<<MSG)
|
||||
The #options attribute is not set on this #{self.class}.
|
||||
This error is probably occurring because #to_s was called
|
||||
on this literal within a custom Sass function without first
|
||||
setting the #option attribute.
|
||||
MSG
|
||||
end
|
||||
|
||||
# The SassScript `and` operation.
|
||||
#
|
||||
# @param other [Literal] The right-hand side of the operator
|
||||
|
@ -181,5 +198,13 @@ module Sass::Script
|
|||
|
||||
# @raise [Sass::SyntaxError] if this literal isn't an integer
|
||||
def assert_int!; to_i; end
|
||||
|
||||
# Returns the string representation of this literal
|
||||
# as it would be output to the CSS document.
|
||||
#
|
||||
# @return [String]
|
||||
def to_s
|
||||
raise Sass::SyntaxError.new("[BUG] All subclasses of Sass::Literal must implement #to_s.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -35,7 +35,9 @@ module Sass::Script
|
|||
literal1 = @operand1.perform(environment)
|
||||
literal2 = @operand2.perform(environment)
|
||||
begin
|
||||
literal1.send(@operator, literal2)
|
||||
res = literal1.send(@operator, literal2)
|
||||
res.options = environment.options
|
||||
res
|
||||
rescue NoMethodError => e
|
||||
raise e unless e.name.to_s == @operator.to_s
|
||||
raise Sass::SyntaxError.new("Undefined operation: \"#{literal1} #{@operator} #{literal2}\".")
|
||||
|
|
|
@ -3,6 +3,12 @@ require File.dirname(__FILE__) + '/../test_helper'
|
|||
require 'sass/engine'
|
||||
require 'stringio'
|
||||
|
||||
module Sass::Script::Functions::UserFunctions
|
||||
def option(name)
|
||||
Sass::Script::String.new(@options[name.value.to_sym].to_s)
|
||||
end
|
||||
end
|
||||
|
||||
class SassEngineTest < Test::Unit::TestCase
|
||||
# A map of erroneous Sass documents to the error messages they should produce.
|
||||
# The error messages may be arrays;
|
||||
|
|
|
@ -2,16 +2,18 @@ require 'test/unit'
|
|||
require File.dirname(__FILE__) + '/../../lib/sass'
|
||||
require 'sass/script'
|
||||
|
||||
module UserFunctions
|
||||
module Sass::Script::Functions::UserFunctions
|
||||
def call_options_on_new_literal
|
||||
str = Sass::Script::String.new("foo")
|
||||
str.options[:foo]
|
||||
str
|
||||
end
|
||||
|
||||
def user_defined
|
||||
Sass::Script::String.new("I'm a user-defined string!")
|
||||
end
|
||||
end
|
||||
|
||||
module Sass::Script::Functions
|
||||
include UserFunctions
|
||||
end
|
||||
|
||||
class SassFunctionTest < Test::Unit::TestCase
|
||||
# Tests taken from:
|
||||
# http://www.w3.org/Style/CSS/Test/CSS3/Color/20070927/html4/t040204-hsl-h-rotating-b.htm
|
||||
|
@ -251,6 +253,15 @@ class SassFunctionTest < Test::Unit::TestCase
|
|||
assert_equal("I'm a user-defined string!", evaluate("user_defined()"))
|
||||
end
|
||||
|
||||
def test_options_on_new_literals_fails
|
||||
assert_error_message(<<MSG, "call-options-on-new-literal()")
|
||||
The #options attribute is not set on this Sass::Script::String.
|
||||
This error is probably occurring because #to_s was called
|
||||
on this literal within a custom Sass function without first
|
||||
setting the #option attribute.
|
||||
MSG
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def evaluate(value)
|
||||
|
|
|
@ -2,6 +2,13 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
require 'sass/engine'
|
||||
|
||||
module Sass::Script::Functions::UserFunctions
|
||||
def assert_options(val)
|
||||
val.options[:foo]
|
||||
Sass::Script::String.new("Options defined!")
|
||||
end
|
||||
end
|
||||
|
||||
class SassScriptTest < Test::Unit::TestCase
|
||||
include Sass::Script
|
||||
|
||||
|
@ -157,6 +164,11 @@ WARN
|
|||
assert_equal 'blam(foo)', resolve('blam("foo")')
|
||||
end
|
||||
|
||||
def test_function_results_have_options
|
||||
assert_equal "Options defined!", resolve("assert_options(abs(1))")
|
||||
assert_equal "Options defined!", resolve("assert_options(round(1.2))")
|
||||
end
|
||||
|
||||
def test_hyphenated_variables
|
||||
assert_equal("a-b", resolve("!a-b", {}, env("a-b" => Sass::Script::String.new("a-b"))))
|
||||
end
|
||||
|
@ -266,6 +278,11 @@ WARN
|
|||
assert_equal "true", resolve("1.1cm == 11mm")
|
||||
end
|
||||
|
||||
def test_operations_have_options
|
||||
assert_equal "Options defined!", resolve("assert_options(1 + 1)")
|
||||
assert_equal "Options defined!", resolve("assert_options('bar' + 'baz')")
|
||||
end
|
||||
|
||||
# Regression Tests
|
||||
|
||||
def test_funcall_has_higher_precedence_than_color_name
|
||||
|
|
|
@ -10,9 +10,8 @@ require 'sass'
|
|||
Sass::RAILS_LOADED = true unless defined?(Sass::RAILS_LOADED)
|
||||
|
||||
module Sass::Script::Functions
|
||||
def option(name)
|
||||
Sass::Script::String.new(@options[name.value.to_sym].to_s)
|
||||
end
|
||||
module UserFunctions; end
|
||||
include UserFunctions
|
||||
end
|
||||
|
||||
class Test::Unit::TestCase
|
||||
|
|
Loading…
Reference in a new issue