diff --git a/HISTORY.md b/HISTORY.md index 0491618..28819bc 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,7 +2,9 @@ ## [Unreleased changes](http://github.com/ms-ati/docile/compare/v1.3.5...master) - ... + - Short-circuit to calling #instance_exec directly on the DSL object (prior to + constructing a proxy object) when the DSL object and block context object are + identical ## [v1.3.5 (Jan 13, 2021)](http://github.com/ms-ati/docile/compare/v1.3.4...v1.3.5) diff --git a/lib/docile/execution.rb b/lib/docile/execution.rb index 38cdb2c..253227c 100644 --- a/lib/docile/execution.rb +++ b/lib/docile/execution.rb @@ -16,6 +16,13 @@ module Execution # @return [Object] the return value of the block def exec_in_proxy_context(dsl, proxy_type, *args, &block) block_context = eval("self", block.binding) + + # Use #equal? to test strict object identity (assuming that this dictum + # from the Ruby docs holds: "[u]nlike ==, the equal? method should never + # be overridden by subclasses as it is used to determine object + # identity") + return dsl.instance_exec(*args, &block) if dsl.equal?(block_context) + proxy_context = proxy_type.new(dsl, block_context) begin block_context.instance_variables.each do |ivar| diff --git a/spec/docile_spec.rb b/spec/docile_spec.rb index dd26d08..d118426 100644 --- a/spec/docile_spec.rb +++ b/spec/docile_spec.rb @@ -414,6 +414,12 @@ def dsl_eval_string(string) expect(dsl.foo).to eq(0) expect(dsl.bar).to eq(1) end + + context "when the DSL object is frozen" do + it "can call non-mutative code without raising an exception" do + expect { dsl.freeze.dsl_eval_string('1 + 2') }.not_to raise_error + end + end end context "when NoMethodError is raised" do