diff --git a/lib/sassc/functions_handler.rb b/lib/sassc/functions_handler.rb index c2237794..97a10973 100644 --- a/lib/sassc/functions_handler.rb +++ b/lib/sassc/functions_handler.rb @@ -12,7 +12,11 @@ def setup(native_options) list = Native.make_function_list(Script.custom_functions.count) - functions = FunctionWrapper.extend(Script::Functions) + # use an anonymous class wrapper to avoid mutations in a threaded environment + functions = Class.new do + attr_accessor :options + include Script::Functions + end.new functions.options = @options Script.custom_functions.each_with_index do |custom_function, i| @@ -65,11 +69,5 @@ def error(message) $stderr.puts "[SassC::FunctionsHandler] #{message}" Native.make_error(message) end - - class FunctionWrapper - class << self - attr_accessor :options - end - end end end diff --git a/test/functions_test.rb b/test/functions_test.rb index 71fc0fa8..5cf7aeca 100644 --- a/test/functions_test.rb +++ b/test/functions_test.rb @@ -185,6 +185,22 @@ def test_function_that_takes_a_sass_list CSS end + def test_concurrency + 10.times do + threads = [] + 10.times do |i| + threads << Thread.new(i) do |id| + out = Engine.new("div { url: inspect_options(); }", {test_key1: 'test_value', test_key2: id}).render + assert_match /test_key1/, out + assert_match /test_key2/, out + assert_match /test_value/, out + assert_match /#{id}/, out + end + end + threads.each(&:join) + end + end + private def assert_sass(sass, expected_css) @@ -279,6 +295,10 @@ def inspect_list(argument) return argument end + def inspect_options + SassC::Script::Value::String.new(self.options.inspect, :string) + end + def returns_sass_value return SassC::Script::Value::Color.new(red: 0, green: 0, blue: 0) end