Skip to content

Commit

Permalink
Exclude certain methods from falling back from block context to dsl o…
Browse files Browse the repository at this point in the history
…bject

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
  • Loading branch information
ms-ati committed Aug 19, 2018
1 parent 0b35550 commit 67517e7
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 1 deletion.
7 changes: 6 additions & 1 deletion lib/docile/fallback_context_proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class FallbackContextProxy
: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.
Expand Down Expand Up @@ -49,7 +53,8 @@ def initialize(receiver, fallback)
# 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)
Expand Down
31 changes: 31 additions & 0 deletions spec/docile_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,37 @@ def a; "not a"; end
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
Expand Down

0 comments on commit 67517e7

Please sign in to comment.