From f2806d786b8a116f70440aaba80a200c6ec9d4d7 Mon Sep 17 00:00:00 2001 From: Marc Siegel Date: Sun, 28 Jul 2013 18:20:59 -0400 Subject: [PATCH] Begin to bring specs in line with betterspecs.org standards --- spec/docile_spec.rb | 327 +++++++++++++++++++++++++------------------- 1 file changed, 188 insertions(+), 139 deletions(-) diff --git a/spec/docile_spec.rb b/spec/docile_spec.rb index 0ad2c21..c83e006 100644 --- a/spec/docile_spec.rb +++ b/spec/docile_spec.rb @@ -2,24 +2,36 @@ require "spec_helper" describe Docile do - context :dsl_eval do + describe "#dsl_eval" do - it "should return the DSL object" do - Docile.dsl_eval([]) do - push 1 - push 2 - pop - push 3 - end.should == [1, 3] - end + context "when DSL context object is an Array" do + let(:array) { [] } + let!(:result) { execute_dsl_against_array } - it "should use the __id__ method of the proxy object" do - arr = [] - Docile.dsl_eval(arr) { __id__.should_not == arr.__id__ } - end + def execute_dsl_against_array + Docile.dsl_eval(array) do + push 1 + push 2 + pop + push 3 + end + end - it "should raise NoMethodError if the DSL object doesn't implement the method" do - expect { Docile.dsl_eval([]) { no_such_method } }.to raise_error(NoMethodError) + it "executes the block against the DSL context object" do + array.should == [1, 3] + end + + it "returns the DSL object after executing block against it" do + result.should == array + end + + it "doesn't proxy #__id__" do + Docile.dsl_eval(array) { __id__.should_not == array.__id__ } + end + + it "raises NoMethodError if the DSL object doesn't implement the method" do + expect { Docile.dsl_eval(array) { no_such_method } }.to raise_error(NoMethodError) + end end Pizza = Struct.new(:cheese, :pepperoni, :bacon, :sauce) @@ -34,13 +46,22 @@ describe Docile do end end - it "should handle a Builder pattern" do - @sauce = :extra - Docile.dsl_eval(PizzaBuilder.new) do - bacon - cheese - sauce @sauce - end.build.should == Pizza.new(true, false, true, :extra) + context "when DSL context object is a Builder pattern" do + let(:builder) { PizzaBuilder.new } + let(:result) { execute_dsl_against_builder_and_call_build } + + def execute_dsl_against_builder_and_call_build + @sauce = :extra + Docile.dsl_eval(builder) do + bacon + cheese + sauce @sauce + end.build + end + + it "returns correctly built object" do + result.should == Pizza.new(true, false, true, :extra) + end end class InnerDSL @@ -65,12 +86,12 @@ describe Docile do Docile.dsl_eval(OuterDSL.new, &block) end - def parameterized(*args, &block) - Docile.dsl_eval(OuterDSL.new, *args, &block) - end + context "when given parameters for the DSL block" do + def parameterized(*args, &block) + Docile.dsl_eval(OuterDSL.new, *args, &block) + end - context "parameters" do - it "should pass parameters to the block" do + it "passes parameters to the block" do parameterized(1,2,3) do |x,y,z| x.should == 1 y.should == 2 @@ -78,11 +99,11 @@ describe Docile do end end - it "should find parameters before methods" do + it "finds parameters before methods" do parameterized(1) { |a| a.should == 1 } end - it "should find outer parameters in inner dsl scope" do + it "find outer dsl parameters in inner dsl scope" do parameterized(1,2,3) do |a,b,c| inner_with_params(c) do |d,e| a.should == 1 @@ -95,140 +116,168 @@ describe Docile do end end - context "methods" do - it "should find method of outer dsl in outer dsl scope" do - outer { a.should == 'a' } + context "when DSL blocks are nested" do + + context "method lookup" do + it "finds method of outer dsl in outer dsl scope" do + outer { a.should == 'a' } + end + + it "finds method of inner dsl in inner dsl scope" do + outer { inner { b.should == 'b' } } + end + + it "finds method of outer dsl in inner dsl scope" do + outer { inner { a.should == 'a' } } + end + + it "finds method of block's context in outer dsl scope" do + def c; 'c'; end + outer { c.should == 'c' } + end + + it "finds method of block's context in inner dsl scope" do + def c; 'c'; end + outer { inner { c.should == 'c' } } + end + + it "finds method of outer dsl in preference to block context" do + def a; 'not a'; end + outer { a.should == 'a' } + outer { inner { a.should == 'a' } } + end end - it "should find method of inner dsl in inner dsl scope" do - outer { inner { b.should == 'b' } } + context "local variable lookup" do + it "finds local variable from block context in outer dsl scope" do + foo = 'foo' + outer { foo.should == 'foo' } + end + + it "finds local variable from block definition in inner dsl scope" do + bar = 'bar' + outer { inner { bar.should == 'bar' } } + end end - it "should find method of outer dsl in inner dsl scope" do - outer { inner { a.should == 'a' } } + context "instance variable lookup" do + it "finds instance variable from block definition in outer dsl scope" do + @iv1 = 'iv1'; outer { @iv1.should == 'iv1' } + end + + it "proxies instance variable assignments in block in outer dsl scope back into block's context" do + @iv1 = 'foo'; outer { @iv1 = 'bar' }; @iv1.should == 'bar' + end + + it "finds instance variable from block definition in inner dsl scope" do + @iv2 = 'iv2'; outer { inner { @iv2.should == 'iv2' } } + end + + it "proxies instance variable assignments in block in inner dsl scope back into block's context" do + @iv2 = 'foo'; outer { inner { @iv2 = 'bar' } }; @iv2.should == 'bar' + end end - it "should find method of block's context in outer dsl scope" do - def c; 'c'; end - outer { c.should == 'c' } - end - - it "should find method of block's context in inner dsl scope" do - def c; 'c'; end - outer { inner { c.should == 'c' } } - end - - it "should find method of outer dsl in preference to block context" do - def a; 'not a'; end - outer { a.should == 'a' } - outer { inner { a.should == 'a' } } - end end - context "local variables" do - it "should find local variable from block context in outer dsl scope" do - foo = 'foo' - outer { foo.should == 'foo' } + context "when DSL context object is a Dispatch pattern" do + class DispatchScope + def params + { :a => 1, :b => 2, :c => 3 } + end end - it "should find local variable from block definition in inner dsl scope" do - bar = 'bar' - outer { inner { bar.should == 'bar' } } - end - end + class MessageDispatch + include Singleton - context "instance variables" do - it "should find instance variable from block definition in outer dsl scope" do - @iv1 = 'iv1'; outer { @iv1.should == 'iv1' } + def initialize + @responders = {} + end + + def add_responder path, &block + @responders[path] = block + end + + def dispatch path, request + Docile.dsl_eval(DispatchScope.new, request, &@responders[path]) + end end - it "should proxy instance variable assignments in block in outer dsl scope back into block's context" do - @iv1 = 'foo'; outer { @iv1 = 'bar' }; @iv1.should == 'bar' + def respond(path, &block) + MessageDispatch.instance.add_responder(path, &block) end - it "should find instance variable from block definition in inner dsl scope" do - @iv2 = 'iv2'; outer { inner { @iv2.should == 'iv2' } } + def send_request(path, request) + MessageDispatch.instance.dispatch(path, request) end - it "should proxy instance variable assignments in block in inner dsl scope back into block's context" do - @iv2 = 'foo'; outer { inner { @iv2 = 'bar' } }; @iv2.should == 'bar' - end - end + it "dispatches correctly" do + @first = @second = nil - class DispatchScope - def params - { :a => 1, :b => 2, :c => 3 } - end - end + respond '/path' do |request| + @first = request + end - class MessageDispatch - include Singleton + respond '/new_bike' do |bike| + @second = "Got a new #{bike}" + end - def initialize - @responders = {} + def x(y) ; "Got a #{y}"; end + respond '/third' do |third| + x(third).should == 'Got a third thing' + end + + fourth = nil + respond '/params' do |arg| + fourth = params[arg] + end + + send_request '/path', 1 + send_request '/new_bike', 'ten speed' + send_request '/third', 'third thing' + send_request '/params', :b + + @first.should == 1 + @second.should == 'Got a new ten speed' + fourth.should == 2 end - def add_responder path, &block - @responders[path] = block - end - - def dispatch path, request - Docile.dsl_eval(DispatchScope.new, request, &@responders[path]) - end - end - - def respond path, &block - MessageDispatch.instance.add_responder path, &block - end - - def send_request path, request - MessageDispatch.instance.dispatch path, request - end - - it "should handle the dispatch pattern" do - @first = @second = nil - respond '/path' do |request| - @first = request - end - - respond '/new_bike' do |bike| - @second = "Got a new #{bike}" - end - - def x(y) ; "Got a #{y}"; end - respond '/third' do |third| - x(third).should == 'Got a third thing' - end - - fourth = nil - respond '/params' do |arg| - fourth = params[arg] - end - - send_request '/path', 1 - send_request '/new_bike', 'ten speed' - send_request '/third', 'third thing' - send_request '/params', :b - - @first.should == 1 - @second.should == 'Got a new ten speed' - fourth.should == 2 - end - - end - - context "FallbackContextProxy#instance_variables" do - - it "should preserve the class (String or Symbol) normally returned by current ruby version" do - @a = 1 - expected_type = instance_variables.first.class - - fcp = Docile::FallbackContextProxy.new(nil, nil) - fcp.instance_variable_set(:@foo, "foo") - - fcp.instance_variables.first.class.should == expected_type end end end + +describe Docile::FallbackContextProxy do + + describe "#instance_variables" do + subject { create_fcp_and_set_one_instance_variable.instance_variables } + let(:expected_type_of_names) { type_of_ivar_names_on_this_ruby } + let(:actual_type_of_names) { subject.first.class } + let(:excluded) { Docile::FallbackContextProxy::NON_PROXIED_INSTANCE_VARIABLES } + + def create_fcp_and_set_one_instance_variable + fcp = Docile::FallbackContextProxy.new(nil, nil) + fcp.instance_variable_set(:@foo, "foo") + fcp + end + + def type_of_ivar_names_on_this_ruby + @a = 1 + instance_variables.first.class + end + + it "returns proxied instance variables" do + subject.map(&:to_sym).should include(:@foo) + end + + it "doesn't return non-proxied instance variables" do + subject.map(&:to_sym).should_not include(*excluded) + end + + it "preserves the type (String or Symbol) of names on this ruby version" do + actual_type_of_names.should == expected_type_of_names + end + end + +end