diff --git a/lib/docile/fallback_context_proxy.rb b/lib/docile/fallback_context_proxy.rb index 95a4b24..14561fb 100644 --- a/lib/docile/fallback_context_proxy.rb +++ b/lib/docile/fallback_context_proxy.rb @@ -21,6 +21,10 @@ module Docile :instance_variable_get, :instance_variable_set, :remove_instance_variable] + # The set of methods which will **not** fallback from the block's context + # to the dsl object. + NON_FALLBACK_METHODS = Set[:class, :self, :respond_to?, :instance_of?] + # The set of instance variables which are local to this object and hidden. # All other instance variables will be copied in and out of this object # from the scope in which this proxy was created. @@ -49,7 +53,8 @@ module Docile # contain calls to methods on the DSL object. singleton_class. send(:define_method, :method_missing) do |method, *args, &block| - if receiver.respond_to?(method.to_sym) + m = method.to_sym + if !NON_FALLBACK_METHODS.include?(m) && receiver.respond_to?(m) receiver.__send__(method.to_sym, *args, &block) else super(method, *args, &block) diff --git a/spec/docile_spec.rb b/spec/docile_spec.rb index 9d8d10f..25be0a7 100644 --- a/spec/docile_spec.rb +++ b/spec/docile_spec.rb @@ -283,6 +283,37 @@ describe Docile do end end + context "identity of 'self' inside nested dsl blocks" do + # see https://github.com/ms-ati/docile/issues/31 + subject do + identified_selves = {} + + outer do + identified_selves[:a] = self + + inner do + identified_selves[:b] = self + end + + identified_selves[:c] = self + end + + identified_selves + end + + it "identifies self inside outer dsl block" do + expect(subject[:a]).to be_instance_of(OuterDSL) + end + + it "replaces self inside inner dsl block" do + expect(subject[:b]).to be_instance_of(InnerDSL) + end + + it "restores self to the outer dsl object after the inner dsl block" do + expect(subject[:c]).to be_instance_of(OuterDSL) + expect(subject[:c]).to be(subject[:a]) + end + end end context "when DSL context object is a Dispatch pattern" do