From 5001479f54347f713e8150acef6d971dd86aea35 Mon Sep 17 00:00:00 2001 From: Jochen Seeber Date: Mon, 11 Jan 2021 23:03:24 +0100 Subject: [PATCH] Add ruby2_keywords to delegating methods (#62) * Add ruby2_keywords to delegating methods * Fix unit tests for Ruby 1.9 --- lib/docile.rb | 6 +++ lib/docile/chaining_fallback_context_proxy.rb | 2 + lib/docile/execution.rb | 2 + lib/docile/fallback_context_proxy.rb | 3 ++ spec/docile_spec.rb | 41 +++++++++++++++++++ 5 files changed, 54 insertions(+) diff --git a/lib/docile.rb b/lib/docile.rb index 85e348d..9bc5308 100644 --- a/lib/docile.rb +++ b/lib/docile.rb @@ -44,6 +44,8 @@ def dsl_eval(dsl, *args, &block) exec_in_proxy_context(dsl, FallbackContextProxy, *args, &block) dsl end + + ruby2_keywords :dsl_eval if respond_to?(:ruby2_keywords, true) module_function :dsl_eval # Execute a block in the context of an object whose methods represent the @@ -83,6 +85,8 @@ def dsl_eval(dsl, *args, &block) def dsl_eval_with_block_return(dsl, *args, &block) exec_in_proxy_context(dsl, FallbackContextProxy, *args, &block) end + + ruby2_keywords :dsl_eval_with_block_return if respond_to?(:ruby2_keywords, true) module_function :dsl_eval_with_block_return # Execute a block in the context of an immutable object whose methods, @@ -120,5 +124,7 @@ def dsl_eval_with_block_return(dsl, *args, &block) def dsl_eval_immutable(dsl, *args, &block) exec_in_proxy_context(dsl, ChainingFallbackContextProxy, *args, &block) end + + ruby2_keywords :dsl_eval_immutable if respond_to?(:ruby2_keywords, true) module_function :dsl_eval_immutable end diff --git a/lib/docile/chaining_fallback_context_proxy.rb b/lib/docile/chaining_fallback_context_proxy.rb index 58539a7..3f7875a 100644 --- a/lib/docile/chaining_fallback_context_proxy.rb +++ b/lib/docile/chaining_fallback_context_proxy.rb @@ -16,5 +16,7 @@ class ChainingFallbackContextProxy < FallbackContextProxy def method_missing(method, *args, &block) @__receiver__ = super(method, *args, &block) end + + ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true) end end diff --git a/lib/docile/execution.rb b/lib/docile/execution.rb index a9326f7..38cdb2c 100644 --- a/lib/docile/execution.rb +++ b/lib/docile/execution.rb @@ -36,6 +36,8 @@ def exec_in_proxy_context(dsl, proxy_type, *args, &block) end end end + + ruby2_keywords :exec_in_proxy_context if respond_to?(:ruby2_keywords, true) module_function :exec_in_proxy_context end end diff --git a/lib/docile/fallback_context_proxy.rb b/lib/docile/fallback_context_proxy.rb index 4ea64c0..64637d5 100644 --- a/lib/docile/fallback_context_proxy.rb +++ b/lib/docile/fallback_context_proxy.rb @@ -61,6 +61,8 @@ def initialize(receiver, fallback) end end + singleton_class.send(:ruby2_keywords, :method_missing) if singleton_class.respond_to?(:ruby2_keywords, true) + # instrument a helper method to remove the above instrumentation singleton_class. send(:define_method, :__docile_undo_fallback__) do @@ -94,6 +96,7 @@ def method_missing(method, *args, &block) end end end + ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true) end end diff --git a/spec/docile_spec.rb b/spec/docile_spec.rb index 095c8bb..dd26d08 100644 --- a/spec/docile_spec.rb +++ b/spec/docile_spec.rb @@ -465,6 +465,47 @@ def set(v0, v1:, v2:) end end end + + if RUBY_VERSION >= "2.0.0" + context "when a DSL method has a double splat" do + class DSLMethodWithDoubleSplat + attr_reader :arguments, :options + + # Use class_eval because Ruby 1.x does not support double splat + class_eval <<-METHOD, __FILE__, __LINE__ + 1 + def configure(*arguments, **options) + @arguments = arguments.dup + @options = options.dup + end + METHOD + end + + let(:dsl) { DSLMethodWithDoubleSplat.new } + + it "correctly passes keyword arguments" do + Docile.dsl_eval(dsl) { configure(1, a: 1) } + + expect(dsl.arguments).to eq [1] + expect(dsl.options).to eq({ a: 1 }) + end + + if RUBY_VERSION >= "3.0.0" + it "correctly passes hash arguments on Ruby 3+" do + Docile.dsl_eval(dsl) { configure(1, { a: 1 }) } + + expect(dsl.arguments).to eq [1, { a: 1 }] + expect(dsl.options).to eq({}) + end + elsif RUBY_VERSION >= "2.0.0" + it "correctly passes hash arguments on Ruby 2" do + Docile.dsl_eval(dsl) { configure(1, { a: 1 }) } + + expect(dsl.arguments).to eq [1] + expect(dsl.options).to eq({ a: 1 }) + end + end + end + end end describe ".dsl_eval_with_block_return" do