decorum 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
 - data/Gemfile +4 -0
 - data/LICENSE.txt +22 -0
 - data/README.md +356 -0
 - data/Rakefile +1 -0
 - data/decorum.gemspec +24 -0
 - data/examples/coffee.rb +7 -0
 - data/examples/fibonacci_decorator.rb +24 -0
 - data/examples/milk_decorator.rb +29 -0
 - data/examples/sugar_decorator.rb +12 -0
 - data/lib/decorum.rb +14 -0
 - data/lib/decorum/bare_particular.rb +5 -0
 - data/lib/decorum/chain_stop.rb +7 -0
 - data/lib/decorum/decorated_state.rb +29 -0
 - data/lib/decorum/decorations.rb +101 -0
 - data/lib/decorum/decorator.rb +85 -0
 - data/lib/decorum/version.rb +3 -0
 - data/spec/integration/coffee_spec.rb +41 -0
 - data/spec/integration/fibonacci_spec.rb +20 -0
 - data/spec/spec_helper.rb +4 -0
 - data/spec/support/decorated_state/shared_state_stub.rb +15 -0
 - data/spec/support/decorations/decorated_object_stub.rb +17 -0
 - data/spec/support/decorations/first_decorator.rb +20 -0
 - data/spec/support/decorations/second_decorator.rb +20 -0
 - data/spec/support/decorations/third_decorator.rb +20 -0
 - data/spec/support/decorator/basic_decorator.rb +20 -0
 - data/spec/support/decorator/decorated_object_stub.rb +17 -0
 - data/spec/support/decorator/decorated_state_stub.rb +11 -0
 - data/spec/support/decorator/decorator_stub.rb +11 -0
 - data/spec/unit/bare_particular_spec.rb +13 -0
 - data/spec/unit/chain_stop_spec.rb +12 -0
 - data/spec/unit/decorated_state_spec.rb +31 -0
 - data/spec/unit/decorations_spec.rb +233 -0
 - data/spec/unit/decorator_spec.rb +166 -0
 - metadata +146 -0
 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Decorum
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Spec
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Decorations
         
     | 
| 
      
 4 
     | 
    
         
            +
                  class ThirdDecorator < Decorum::Decorator
         
     | 
| 
      
 5 
     | 
    
         
            +
                    share :shared_attribute
         
     | 
| 
      
 6 
     | 
    
         
            +
                    attr_accessor :local_attribute
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                    def third_decorator_method
         
     | 
| 
      
 9 
     | 
    
         
            +
                      "third"
         
     | 
| 
      
 10 
     | 
    
         
            +
                    end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    alias_method :current_decorator_method, :third_decorator_method
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    def respect_previously_defined_methods?
         
     | 
| 
      
 15 
     | 
    
         
            +
                      false
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Decorum
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Spec
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Decorator
         
     | 
| 
      
 4 
     | 
    
         
            +
                  class BasicDecorator < Decorum::Decorator
         
     | 
| 
      
 5 
     | 
    
         
            +
                    default_attributes first_default: "default value", overridden_default: false
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                    share :shared_attribute, :unused_shared_attribute
         
     | 
| 
      
 8 
     | 
    
         
            +
                    attr_accessor :name, :unused_personal_attribute
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                    def basic_decorator_method
         
     | 
| 
      
 11 
     | 
    
         
            +
                      true
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    def respect_previously_defined_methods?
         
     | 
| 
      
 15 
     | 
    
         
            +
                      false
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Decorum
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Spec
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Decorator
         
     | 
| 
      
 4 
     | 
    
         
            +
                  class DecoratedObjectStub
         
     | 
| 
      
 5 
     | 
    
         
            +
                    include Decorum::Decorations
         
     | 
| 
      
 6 
     | 
    
         
            +
                    
         
     | 
| 
      
 7 
     | 
    
         
            +
                    def respect_previously_defined_methods?
         
     | 
| 
      
 8 
     | 
    
         
            +
                      true
         
     | 
| 
      
 9 
     | 
    
         
            +
                    end
         
     | 
| 
      
 10 
     | 
    
         
            +
                    
         
     | 
| 
      
 11 
     | 
    
         
            +
                    def decorated_state(*args)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      @decorated_state ||= Decorum::Spec::Decorator::DecoratedStateStub.new
         
     | 
| 
      
 13 
     | 
    
         
            +
                    end
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Decorum::BareParticular do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let(:bp) { Decorum::BareParticular.new }
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              it 'is decoratable' do
         
     | 
| 
      
 7 
     | 
    
         
            +
                expect(bp).to be_a(Decorum::Decorations)
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              it 'black holes undefined methods' do
         
     | 
| 
      
 11 
     | 
    
         
            +
                expect(bp.nonexistent_method).to be_nil
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Decorum::ChainStop do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let(:chainstop) { Decorum::ChainStop.new }
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              it 'throws self via :chain_stop on undefined method' do
         
     | 
| 
      
 7 
     | 
    
         
            +
                response = catch :chain_stop do 
         
     | 
| 
      
 8 
     | 
    
         
            +
                  chainstop.nonexistent_method
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
                expect(response).to be_equal(chainstop)
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Decorum::DecoratedState do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let(:ds) { Decorum::DecoratedState.new(foo: "bar") }
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              it 'assigns initialized options' do
         
     | 
| 
      
 7 
     | 
    
         
            +
                expect(ds.foo).to eq("bar")
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              context 'when forwarding messages' do
         
     | 
| 
      
 11 
     | 
    
         
            +
                before(:each) do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # need to pop it open first...
         
     | 
| 
      
 13 
     | 
    
         
            +
                  fake_shared_state = Decorum::Spec::DecoratedState::SharedStateStub.new
         
     | 
| 
      
 14 
     | 
    
         
            +
                  ds.instance_variable_set(:@shared_state, fake_shared_state)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                it 'forwards getter methods' do
         
     | 
| 
      
 18 
     | 
    
         
            +
                  expect(ds.marker).to eq("retrieved")
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                it 'forwards setter methods' do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  expect(ds.send(:"marker=", 'foo')).to eq('assigned')
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                describe '#respond_to?' do
         
     | 
| 
      
 26 
     | 
    
         
            +
                  it 'is false for forwarded messages' do
         
     | 
| 
      
 27 
     | 
    
         
            +
                    expect(ds.respond_to?(:marker)).to be_false
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end 
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,233 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Decorum::Decorations do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let(:decorated) { Decorum::Spec::Decorations::DecoratedObjectStub.new }
         
     | 
| 
      
 5 
     | 
    
         
            +
              let(:deco_class_1) { Decorum::Spec::Decorations::FirstDecorator }
         
     | 
| 
      
 6 
     | 
    
         
            +
              let(:deco_class_2) { Decorum::Spec::Decorations::SecondDecorator }
         
     | 
| 
      
 7 
     | 
    
         
            +
              let(:deco_class_3) { Decorum::Spec::Decorations::ThirdDecorator }
         
     | 
| 
      
 8 
     | 
    
         
            +
               
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              context 'as-yet-undecorated' do 
         
     | 
| 
      
 11 
     | 
    
         
            +
                # assert some basic assumptions
         
     | 
| 
      
 12 
     | 
    
         
            +
                it 'is decoratable' do
         
     | 
| 
      
 13 
     | 
    
         
            +
                  expect(decorated.is_a?(Decorum::Decorations)).to be_true
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                it 'does not respond to first decorator test method' do
         
     | 
| 
      
 17 
     | 
    
         
            +
                  expect(decorated.respond_to?(:first_decorator_method)).to be_false
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                it 'responds to its own methods' do 
         
     | 
| 
      
 21 
     | 
    
         
            +
                  expect(decorated.undecorated_method).to be_true
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                describe '#decorated_state' do
         
     | 
| 
      
 25 
     | 
    
         
            +
                  it 'returns a hash' do
         
     | 
| 
      
 26 
     | 
    
         
            +
                    blank_state = decorated.decorated_state
         
     | 
| 
      
 27 
     | 
    
         
            +
                    expect(blank_state.is_a?(Hash)).to be_true
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  it 'returns an empty hash' do
         
     | 
| 
      
 31 
     | 
    
         
            +
                    blank_state = decorated.decorated_state
         
     | 
| 
      
 32 
     | 
    
         
            +
                    expect(blank_state.empty?).to be_true
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  it 'returns nil given an argument' do
         
     | 
| 
      
 36 
     | 
    
         
            +
                    expect(decorated.decorated_state(:not_gonna_work)).to be_nil
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
                
         
     | 
| 
      
 40 
     | 
    
         
            +
                describe 'undecorate' do
         
     | 
| 
      
 41 
     | 
    
         
            +
                  it 'returns self on symbol' do
         
     | 
| 
      
 42 
     | 
    
         
            +
                    expect(decorated.undecorate(:symbol_arg)).to be_equal(decorated)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  it 'returns self on spurious Decorator' do
         
     | 
| 
      
 46 
     | 
    
         
            +
                    expect(decorated.undecorate(deco_class_1)).to be_equal(decorated)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              context 'decorated' do
         
     | 
| 
      
 52 
     | 
    
         
            +
                describe '#decorate' do
         
     | 
| 
      
 53 
     | 
    
         
            +
                  it 'returns self on decoration' do
         
     | 
| 
      
 54 
     | 
    
         
            +
                    real_decorated = decorated
         
     | 
| 
      
 55 
     | 
    
         
            +
                    expect(decorated.decorate(deco_class_1)).to be_equal(real_decorated)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
                  
         
     | 
| 
      
 58 
     | 
    
         
            +
                  it 'yields decorator if block_given?' do
         
     | 
| 
      
 59 
     | 
    
         
            +
                    decorator = nil
         
     | 
| 
      
 60 
     | 
    
         
            +
                    decorated.decorate(deco_class_1) { |dec| decorator = dec }
         
     | 
| 
      
 61 
     | 
    
         
            +
                    actual_decorator = decorated.instance_variable_get(:@_decorator_chain)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    expect(decorator).to be(actual_decorator)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                   
         
     | 
| 
      
 65 
     | 
    
         
            +
                  context 'success' do 
         
     | 
| 
      
 66 
     | 
    
         
            +
                    before(:each) do
         
     | 
| 
      
 67 
     | 
    
         
            +
                      decorator_options = { decorator_handle: "first", shared_attribute: "shared 1", local_attribute: "local 1" }
         
     | 
| 
      
 68 
     | 
    
         
            +
                      decorated.decorate(deco_class_1, decorator_options)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    it 'installs intercept' do
         
     | 
| 
      
 72 
     | 
    
         
            +
                      expect(decorated.is_a?(Decorum::Decorations::Intercept)).to be_true
         
     | 
| 
      
 73 
     | 
    
         
            +
                    end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    it 'sets internal state' do
         
     | 
| 
      
 76 
     | 
    
         
            +
                      internal_state = decorated.instance_variable_get(:@_decorator_chain)
         
     | 
| 
      
 77 
     | 
    
         
            +
                      expect(internal_state.is_a?(deco_class_1)).to be_true
         
     | 
| 
      
 78 
     | 
    
         
            +
                    end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    it 'does not lose its own methods' do
         
     | 
| 
      
 81 
     | 
    
         
            +
                      expect(decorated.respect_previously_defined_methods?).to be_true
         
     | 
| 
      
 82 
     | 
    
         
            +
                    end
         
     | 
| 
      
 83 
     | 
    
         
            +
                    
         
     | 
| 
      
 84 
     | 
    
         
            +
                    it 'gains the methods of the decorator' do
         
     | 
| 
      
 85 
     | 
    
         
            +
                      expect(decorated.first_decorator_method).to eq('first')
         
     | 
| 
      
 86 
     | 
    
         
            +
                    end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                    it 'raises NoMethodError on nonexistent method' do
         
     | 
| 
      
 89 
     | 
    
         
            +
                      expect { decorated.nonexistent_method }.to raise_error(NoMethodError)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
                    
         
     | 
| 
      
 92 
     | 
    
         
            +
                    it 'is decorated by local attributes' do
         
     | 
| 
      
 93 
     | 
    
         
            +
                      expect(decorated.local_attribute).to eq("local 1")
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                    it 'is decorated by shared attributes' do
         
     | 
| 
      
 97 
     | 
    
         
            +
                      expect(decorated.shared_attribute).to eq("shared 1")
         
     | 
| 
      
 98 
     | 
    
         
            +
                    end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                    it 'creates decorated state for decorator class' do
         
     | 
| 
      
 101 
     | 
    
         
            +
                      expect(decorated.decorated_state(deco_class_1).shared_attribute).to eq('shared 1')
         
     | 
| 
      
 102 
     | 
    
         
            +
                    end
         
     | 
| 
      
 103 
     | 
    
         
            +
                  
         
     | 
| 
      
 104 
     | 
    
         
            +
                    context 'with multiple decorators' do
         
     | 
| 
      
 105 
     | 
    
         
            +
                      before(:each) do
         
     | 
| 
      
 106 
     | 
    
         
            +
                        3.times do |i|
         
     | 
| 
      
 107 
     | 
    
         
            +
                          klass = send(:"deco_class_#{i + 1}")
         
     | 
| 
      
 108 
     | 
    
         
            +
                          decorated.decorate(klass)
         
     | 
| 
      
 109 
     | 
    
         
            +
                        end
         
     | 
| 
      
 110 
     | 
    
         
            +
                      end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                      it 'retains decorated methods' do
         
     | 
| 
      
 113 
     | 
    
         
            +
                        responses = [:first, :second, :third].map do |prefix|
         
     | 
| 
      
 114 
     | 
    
         
            +
                          decorated.send(:"#{prefix}_decorator_method") 
         
     | 
| 
      
 115 
     | 
    
         
            +
                        end
         
     | 
| 
      
 116 
     | 
    
         
            +
                        expect(responses).to eq(["first", "second", "third"])
         
     | 
| 
      
 117 
     | 
    
         
            +
                      end
         
     | 
| 
      
 118 
     | 
    
         
            +
                      
         
     | 
| 
      
 119 
     | 
    
         
            +
                      it 'prefers the most recent decorator' do
         
     | 
| 
      
 120 
     | 
    
         
            +
                        expect(decorated.current_decorator_method).to eq("third")
         
     | 
| 
      
 121 
     | 
    
         
            +
                      end
         
     | 
| 
      
 122 
     | 
    
         
            +
                    end
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                  context 'failure' do
         
     | 
| 
      
 126 
     | 
    
         
            +
                    it 'rejects classes that are not Decorators' do
         
     | 
| 
      
 127 
     | 
    
         
            +
                      expect { decorated.decorate(Class,{}) }.to raise_error(RuntimeError)
         
     | 
| 
      
 128 
     | 
    
         
            +
                    end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                    it 'rejects non unique decorator handles' do
         
     | 
| 
      
 131 
     | 
    
         
            +
                      3.times do |i|
         
     | 
| 
      
 132 
     | 
    
         
            +
                        klass = send(:"deco_class_#{i + 1}")
         
     | 
| 
      
 133 
     | 
    
         
            +
                        decorated.decorate(klass, decorator_handle: "deco-#{i + 1}")
         
     | 
| 
      
 134 
     | 
    
         
            +
                      end
         
     | 
| 
      
 135 
     | 
    
         
            +
                      expect { decorated.decorate(deco_class_1, decorator_handle: "deco-2") }.to raise_error(RuntimeError)
         
     | 
| 
      
 136 
     | 
    
         
            +
                    end
         
     | 
| 
      
 137 
     | 
    
         
            +
                  end
         
     | 
| 
      
 138 
     | 
    
         
            +
                end
         
     | 
| 
      
 139 
     | 
    
         
            +
                
         
     | 
| 
      
 140 
     | 
    
         
            +
                describe '#respond_to?' do
         
     | 
| 
      
 141 
     | 
    
         
            +
                  before(:each) { decorated.decorate(deco_class_1) }
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                  it 'returns true for decorated methods' do  
         
     | 
| 
      
 144 
     | 
    
         
            +
                    expect(decorated.respond_to?(:first_decorator_method)).to be_true
         
     | 
| 
      
 145 
     | 
    
         
            +
                  end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                  it 'returns true for undecorated methods' do
         
     | 
| 
      
 148 
     | 
    
         
            +
                    expect(decorated.respond_to?(:undecorated_method)).to be_true
         
     | 
| 
      
 149 
     | 
    
         
            +
                  end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
                  it 'returns false for undefined method' do
         
     | 
| 
      
 152 
     | 
    
         
            +
                    expect(decorated.respond_to?(:nonexistent_method)).to be_false
         
     | 
| 
      
 153 
     | 
    
         
            +
                  end
         
     | 
| 
      
 154 
     | 
    
         
            +
                end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                context 'monitoring and unloading' do
         
     | 
| 
      
 157 
     | 
    
         
            +
                  before(:each) do
         
     | 
| 
      
 158 
     | 
    
         
            +
                    3.times do |x|
         
     | 
| 
      
 159 
     | 
    
         
            +
                      klass = send(:"deco_class_#{x + 1}")
         
     | 
| 
      
 160 
     | 
    
         
            +
                      decorated.decorate(klass, decorator_handle: "deco-#{x + 1}")
         
     | 
| 
      
 161 
     | 
    
         
            +
                    end
         
     | 
| 
      
 162 
     | 
    
         
            +
                  end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                  describe '#decorators' do
         
     | 
| 
      
 165 
     | 
    
         
            +
                    it 'accurately reflects loaded decorators and in order' do
         
     | 
| 
      
 166 
     | 
    
         
            +
                      expected_map = ["deco-3", "deco-2", "deco-1"]
         
     | 
| 
      
 167 
     | 
    
         
            +
                      expect(decorated.decorators.map { |d| d.decorator_handle }).to eq(expected_map)
         
     | 
| 
      
 168 
     | 
    
         
            +
                    end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                    it 'memoizes decorators' do
         
     | 
| 
      
 171 
     | 
    
         
            +
                      decorated.decorators[0].next_link = decorated.decorators[2]
         
     | 
| 
      
 172 
     | 
    
         
            +
                      expect(decorated.decorators.length).to be(3)
         
     | 
| 
      
 173 
     | 
    
         
            +
                    end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                    it 'refreshes via #decorators!' do
         
     | 
| 
      
 176 
     | 
    
         
            +
                      decorated.decorators[0].next_link = decorated.decorators[2]
         
     | 
| 
      
 177 
     | 
    
         
            +
                      decorated.send(:decorators!)
         
     | 
| 
      
 178 
     | 
    
         
            +
                      expect(decorated.decorators.length).to be(2)
         
     | 
| 
      
 179 
     | 
    
         
            +
                    end
         
     | 
| 
      
 180 
     | 
    
         
            +
                  end
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                  describe '#undecorate' do 
         
     | 
| 
      
 183 
     | 
    
         
            +
                    before(:each) do
         
     | 
| 
      
 184 
     | 
    
         
            +
                      @undec = decorated.decorators.detect { |d| d.decorator_handle == "deco-2" }
         
     | 
| 
      
 185 
     | 
    
         
            +
                      # just to make sure...
         
     | 
| 
      
 186 
     | 
    
         
            +
                      unless @undec.is_a?(Decorum::Decorator)
         
     | 
| 
      
 187 
     | 
    
         
            +
                        raise "broken test---no such decorator deco-2; undec was #{@undec.inspect}"
         
     | 
| 
      
 188 
     | 
    
         
            +
                      end
         
     | 
| 
      
 189 
     | 
    
         
            +
                    end
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
                    it 'undecorates' do
         
     | 
| 
      
 192 
     | 
    
         
            +
                      decorated.undecorate(@undec)
         
     | 
| 
      
 193 
     | 
    
         
            +
                      expect(decorated.decorators.length).to be(2)
         
     | 
| 
      
 194 
     | 
    
         
            +
                    end
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
                    it 'undecorates the right one' do
         
     | 
| 
      
 197 
     | 
    
         
            +
                      decorated.undecorate(@undec)
         
     | 
| 
      
 198 
     | 
    
         
            +
                      expected_map = ["deco-3", "deco-1"]
         
     | 
| 
      
 199 
     | 
    
         
            +
                      expect(decorated.decorators.map { |d| d.decorator_handle }).to eq(expected_map)
         
     | 
| 
      
 200 
     | 
    
         
            +
                    end
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                    it 'returns self on success' do
         
     | 
| 
      
 203 
     | 
    
         
            +
                      real_decorated = decorated
         
     | 
| 
      
 204 
     | 
    
         
            +
                      expect(decorated.undecorate(@undec)).to be_equal(real_decorated)
         
     | 
| 
      
 205 
     | 
    
         
            +
                    end
         
     | 
| 
      
 206 
     | 
    
         
            +
                    
         
     | 
| 
      
 207 
     | 
    
         
            +
                    context 'once undecorated' do
         
     | 
| 
      
 208 
     | 
    
         
            +
                      before(:each) { decorated.undecorate(@undec) }
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
                      it 'no longer responds to removed decorated method' do
         
     | 
| 
      
 211 
     | 
    
         
            +
                        expect(decorated.respond_to?(:second_decorator_method)).to be_false
         
     | 
| 
      
 212 
     | 
    
         
            +
                      end
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
                      it 'still responds to other decorated methods' do 
         
     | 
| 
      
 215 
     | 
    
         
            +
                        expect(decorated.respond_to?(:third_decorator_method)).to be_true
         
     | 
| 
      
 216 
     | 
    
         
            +
                      end
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
                      it 'doesn\'t mind if we check one just to be sure' do
         
     | 
| 
      
 219 
     | 
    
         
            +
                        expect(decorated.first_decorator_method).to eq('first')
         
     | 
| 
      
 220 
     | 
    
         
            +
                      end
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
                      it 'destroys shared state when last class member is gone' do
         
     | 
| 
      
 223 
     | 
    
         
            +
                        expect(decorated.decorated_state(deco_class_2)).to be_nil
         
     | 
| 
      
 224 
     | 
    
         
            +
                      end
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                      it 'does not destroy other shared state' do
         
     | 
| 
      
 227 
     | 
    
         
            +
                        expect(decorated.decorated_state(deco_class_1)).to be_a(Decorum::DecoratedState)
         
     | 
| 
      
 228 
     | 
    
         
            +
                      end
         
     | 
| 
      
 229 
     | 
    
         
            +
                    end 
         
     | 
| 
      
 230 
     | 
    
         
            +
                  end
         
     | 
| 
      
 231 
     | 
    
         
            +
                end
         
     | 
| 
      
 232 
     | 
    
         
            +
              end
         
     | 
| 
      
 233 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,166 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Decorum::Decorator do
         
     | 
| 
      
 4 
     | 
    
         
            +
              let(:decorator) do 
         
     | 
| 
      
 5 
     | 
    
         
            +
                @next_link = Decorum::ChainStop.new
         
     | 
| 
      
 6 
     | 
    
         
            +
                @root = Decorum::Spec::Decorator::DecoratedObjectStub.new
         
     | 
| 
      
 7 
     | 
    
         
            +
                @options_for_decorator = { name: 'bob', shared_attribute: 'shared', overridden_default: true }
         
     | 
| 
      
 8 
     | 
    
         
            +
                Decorum::Spec::Decorator::BasicDecorator.new(@next_link, @root, @options_for_decorator)
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              it 'responds to .share' do
         
     | 
| 
      
 12 
     | 
    
         
            +
                expect(Decorum::Decorator.respond_to?(:share)).to be_true
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              it 'responds to .accumulator' do
         
     | 
| 
      
 16 
     | 
    
         
            +
                expect(Decorum::Decorator.respond_to?(:accumulator)).to be_true
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              describe '#decorated_state' do
         
     | 
| 
      
 20 
     | 
    
         
            +
                it 'defers to the root object' do
         
     | 
| 
      
 21 
     | 
    
         
            +
                  expect(decorator.decorated_state.reaching_its_destination?).to be_true  
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              describe '#next_link' do  
         
     | 
| 
      
 26 
     | 
    
         
            +
                it 'returns the next decorator' do
         
     | 
| 
      
 27 
     | 
    
         
            +
                  expect(decorator.next_link).to be_equal(@next_link)
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              describe '#next_link=' do
         
     | 
| 
      
 32 
     | 
    
         
            +
                it 'sets the next decorator' do
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @new_next_link = Decorum::Spec::Decorator::DecoratorStub.new
         
     | 
| 
      
 34 
     | 
    
         
            +
                  decorator.next_link = @new_next_link
         
     | 
| 
      
 35 
     | 
    
         
            +
                  response = catch :deferred do 
         
     | 
| 
      
 36 
     | 
    
         
            +
                    decorator.send(:nonexistent_method)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  expect(response).to be_equal(@new_next_link)
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              describe '#root' do
         
     | 
| 
      
 43 
     | 
    
         
            +
                it 'returns the root object' do
         
     | 
| 
      
 44 
     | 
    
         
            +
                  expect(decorator.root).to be_equal(@root)
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                it 'is aliased as #object' do
         
     | 
| 
      
 48 
     | 
    
         
            +
                  expect(decorator.object).to be_equal(@root)
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              describe '#
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              describe '#decorated_tail' do
         
     | 
| 
      
 55 
     | 
    
         
            +
                let(:value) { "howdy" } 
         
     | 
| 
      
 56 
     | 
    
         
            +
                
         
     | 
| 
      
 57 
     | 
    
         
            +
                it 'catches :chain_stop' do
         
     | 
| 
      
 58 
     | 
    
         
            +
                  response = decorator.decorated_tail(value) { throw :chain_stop, "caught" }
         
     | 
| 
      
 59 
     | 
    
         
            +
                  expect(response).to eq("caught")
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                it 'preserves return value' do 
         
     | 
| 
      
 63 
     | 
    
         
            +
                  response = decorator.decorated_tail(value) { decorator.send(:nonexistent_method) }
         
     | 
| 
      
 64 
     | 
    
         
            +
                  expect(response).to eq(value)
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
              
         
     | 
| 
      
 68 
     | 
    
         
            +
              context 'when attributes are declared default' do
         
     | 
| 
      
 69 
     | 
    
         
            +
                describe '#getter' do
         
     | 
| 
      
 70 
     | 
    
         
            +
                  it 'gets default value' do
         
     | 
| 
      
 71 
     | 
    
         
            +
                    expect(decorator.first_default).to eq("default value")
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  
         
     | 
| 
      
 74 
     | 
    
         
            +
                  it 'is overridden by options passed to initialize' do
         
     | 
| 
      
 75 
     | 
    
         
            +
                    expect(decorator.overridden_default).to equal(true)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
                
         
     | 
| 
      
 79 
     | 
    
         
            +
                describe '#setter' do 
         
     | 
| 
      
 80 
     | 
    
         
            +
                  it 'gets defined' do
         
     | 
| 
      
 81 
     | 
    
         
            +
                    decorator.first_default = "new value"
         
     | 
| 
      
 82 
     | 
    
         
            +
                    expect(decorator.first_default).to eq("new value")
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
              end
         
     | 
| 
      
 86 
     | 
    
         
            +
                    
         
     | 
| 
      
 87 
     | 
    
         
            +
              context 'when attributes are declared via share' do
         
     | 
| 
      
 88 
     | 
    
         
            +
                describe '#setter' do
         
     | 
| 
      
 89 
     | 
    
         
            +
                  it 'does not set attribute locally' do
         
     | 
| 
      
 90 
     | 
    
         
            +
                    expect(decorator.instance_variable_get(:@shared_attribute)).to be_nil
         
     | 
| 
      
 91 
     | 
    
         
            +
                  end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                  it 'sets attribute in shared state' do 
         
     | 
| 
      
 94 
     | 
    
         
            +
                    expect(decorator.decorated_state.shared_attribute).to eq('shared')
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                describe '#getter' do
         
     | 
| 
      
 99 
     | 
    
         
            +
                  it 'sets attribute' do
         
     | 
| 
      
 100 
     | 
    
         
            +
                    expect(decorator.shared_attribute).to eq('shared')
         
     | 
| 
      
 101 
     | 
    
         
            +
                  end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                  it 'gets nil for unused attribute' do
         
     | 
| 
      
 104 
     | 
    
         
            +
                    expect(decorator.unused_shared_attribute).to be_nil
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                describe '#boolean' do
         
     | 
| 
      
 109 
     | 
    
         
            +
                  it 'returns true on set attribute' do
         
     | 
| 
      
 110 
     | 
    
         
            +
                    expect(decorator.shared_attribute?).to equal(true)
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  it 'returns false on unset attribute' do
         
     | 
| 
      
 114 
     | 
    
         
            +
                    expect(decorator.unused_shared_attribute?).to equal(false)
         
     | 
| 
      
 115 
     | 
    
         
            +
                  end
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                describe '#resetter' do
         
     | 
| 
      
 119 
     | 
    
         
            +
                  before(:each) { decorator.reset_shared_attribute }
         
     | 
| 
      
 120 
     | 
    
         
            +
                 
         
     | 
| 
      
 121 
     | 
    
         
            +
                  it 'sets attribute to nil' do
         
     | 
| 
      
 122 
     | 
    
         
            +
                    expect(decorator.shared_attribute).to be_nil
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                  it 'sets attribute to nil in shared state' do
         
     | 
| 
      
 126 
     | 
    
         
            +
                    decorator.instance_variable_set(:@shared_attribute, "for real not nil")
         
     | 
| 
      
 127 
     | 
    
         
            +
                    expect(decorator.shared_attribute).to be_nil
         
     | 
| 
      
 128 
     | 
    
         
            +
                  end
         
     | 
| 
      
 129 
     | 
    
         
            +
                end 
         
     | 
| 
      
 130 
     | 
    
         
            +
              end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
              context 'when attributes via declared personally' do
         
     | 
| 
      
 133 
     | 
    
         
            +
                describe '#setter' do
         
     | 
| 
      
 134 
     | 
    
         
            +
                  it 'sets local attribute via initialize' do
         
     | 
| 
      
 135 
     | 
    
         
            +
                    expect(decorator.name).to eq('bob')
         
     | 
| 
      
 136 
     | 
    
         
            +
                  end
         
     | 
| 
      
 137 
     | 
    
         
            +
                
         
     | 
| 
      
 138 
     | 
    
         
            +
                  it 'sets local attribute locally by initialize' do
         
     | 
| 
      
 139 
     | 
    
         
            +
                    expect(decorator.instance_variable_get(:@name)).to eq('bob')
         
     | 
| 
      
 140 
     | 
    
         
            +
                  end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                  it 'does not set local attribute in shared state via initialize' do
         
     | 
| 
      
 143 
     | 
    
         
            +
                    expect(decorator.decorated_state.name).to be_nil
         
     | 
| 
      
 144 
     | 
    
         
            +
                  end
         
     | 
| 
      
 145 
     | 
    
         
            +
                end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                describe '#getter' do
         
     | 
| 
      
 148 
     | 
    
         
            +
                  it 'gets nil for unused attribute' do
         
     | 
| 
      
 149 
     | 
    
         
            +
                    expect(decorator.unused_personal_attribute).to be_nil
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
                end
         
     | 
| 
      
 152 
     | 
    
         
            +
              end
         
     | 
| 
      
 153 
     | 
    
         
            +
              
         
     | 
| 
      
 154 
     | 
    
         
            +
              context 'when calling decorator methods' do
         
     | 
| 
      
 155 
     | 
    
         
            +
                it 'picks up methods it has' do
         
     | 
| 
      
 156 
     | 
    
         
            +
                  expect(decorator.basic_decorator_method).to be_true
         
     | 
| 
      
 157 
     | 
    
         
            +
                end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                it 'defers methods it doesn\'t have' do
         
     | 
| 
      
 160 
     | 
    
         
            +
                  response = catch :chain_stop do 
         
     | 
| 
      
 161 
     | 
    
         
            +
                    decorator.send(:nonexistent_method) 
         
     | 
| 
      
 162 
     | 
    
         
            +
                  end
         
     | 
| 
      
 163 
     | 
    
         
            +
                  expect(response).to be_a(Decorum::ChainStop)
         
     | 
| 
      
 164 
     | 
    
         
            +
                end
         
     | 
| 
      
 165 
     | 
    
         
            +
              end
         
     | 
| 
      
 166 
     | 
    
         
            +
            end
         
     |