Exclude certain methods from falling back from block context to dsl object

This appears to address the case where the identity of 'self' within the
outer block of a nested DSL is appearing to be overwritten with the identity
of inner DSL objects, as reported by @robkinyon.

Fixes #31
This commit is contained in:
Marc Siegel 2018-08-19 17:02:41 -04:00
parent 0b355504e9
commit 67517e7573
2 changed files with 37 additions and 1 deletions

View File

@ -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)

View File

@ -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