From cf574f7888055b59510efb300e6bcffd948aef5c Mon Sep 17 00:00:00 2001 From: Ryan Boland Date: Mar 03 2020 14:56:23 +0000 Subject: Merge pull request #162 from ahorek/custom_functions allow passing functions directly --- diff --git a/lib/sassc/engine.rb b/lib/sassc/engine.rb index aa43bf7..cb47f33 100644 --- a/lib/sassc/engine.rb +++ b/lib/sassc/engine.rb @@ -16,6 +16,7 @@ module SassC def initialize(template, options = {}) @template = template @options = options + @functions = options.fetch(:functions, Script::Functions) end def render @@ -37,7 +38,7 @@ module SassC Native.option_set_omit_source_map_url(native_options, true) if omit_source_map_url? import_handler.setup(native_options) - functions_handler.setup(native_options) + functions_handler.setup(native_options, functions: @functions) status = Native.compile_data_context(data_context) diff --git a/lib/sassc/functions_handler.rb b/lib/sassc/functions_handler.rb index 97a1097..8a3c349 100644 --- a/lib/sassc/functions_handler.rb +++ b/lib/sassc/functions_handler.rb @@ -6,24 +6,24 @@ module SassC @options = options end - def setup(native_options) + def setup(native_options, functions: Script::Functions) @callbacks = {} @function_names = {} - list = Native.make_function_list(Script.custom_functions.count) + list = Native.make_function_list(Script.custom_functions(functions: functions).count) # use an anonymous class wrapper to avoid mutations in a threaded environment - functions = Class.new do + functions_wrapper = Class.new do attr_accessor :options - include Script::Functions + include functions end.new - functions.options = @options + functions_wrapper.options = @options - Script.custom_functions.each_with_index do |custom_function, i| + Script.custom_functions(functions: functions).each_with_index do |custom_function, i| @callbacks[custom_function] = FFI::Function.new(:pointer, [:pointer, :pointer]) do |native_argument_list, cookie| begin function_arguments = arguments_from_native_list(native_argument_list) - result = functions.send(custom_function, *function_arguments) + result = functions_wrapper.send(custom_function, *function_arguments) to_native_value(result) rescue StandardError => exception # This rescues any exceptions that occur either in value conversion @@ -32,7 +32,7 @@ module SassC end end - @function_names[custom_function] = Script.formatted_function_name(custom_function) + @function_names[custom_function] = Script.formatted_function_name(custom_function, functions: functions) callback = Native.make_function( @function_names[custom_function], diff --git a/lib/sassc/script.rb b/lib/sassc/script.rb index aecb987..0eed756 100644 --- a/lib/sassc/script.rb +++ b/lib/sassc/script.rb @@ -3,12 +3,12 @@ module SassC module Script - def self.custom_functions - Functions.public_instance_methods + def self.custom_functions(functions: Functions) + functions.public_instance_methods end - def self.formatted_function_name(function_name) - params = Functions.instance_method(function_name).parameters + def self.formatted_function_name(function_name, functions: Functions) + params = functions.instance_method(function_name).parameters params = params.map { |param_type, name| "$#{name}#{': null' if param_type == :opt}" }.join(", ") return "#{function_name}(#{params})" end diff --git a/test/functions_test.rb b/test/functions_test.rb index 5cf7aec..4b25c4b 100644 --- a/test/functions_test.rb +++ b/test/functions_test.rb @@ -201,6 +201,17 @@ module SassC end end + def test_pass_custom_functions_as_a_parameter + out = Engine.new("div { url: test-function(); }", {functions: ExternalFunctions}).render + assert_match /custom_function/, out + end + + def test_pass_incompatible_type_to_custom_functions + assert_raises(TypeError) do + Engine.new("div { url: test-function(); }", {functions: Class.new}).render + end + end + private def assert_sass(sass, expected_css) @@ -319,5 +330,11 @@ module SassC end + module ExternalFunctions + def test_function + SassC::Script::Value::String.new("custom_function", :string) + end + end + end end