flat_map 0.0.3
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.
- checksums.yaml +15 -0
- data/.gitignore +31 -0
- data/.metrics +17 -0
- data/.rspec +4 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +20 -0
- data/LICENSE +20 -0
- data/README.markdown +211 -0
- data/Rakefile +15 -0
- data/flat_map.gemspec +30 -0
- data/lib/flat_map.rb +9 -0
- data/lib/flat_map/base_mapper.rb +95 -0
- data/lib/flat_map/base_mapper/attribute_methods.rb +54 -0
- data/lib/flat_map/base_mapper/factory.rb +238 -0
- data/lib/flat_map/base_mapper/mapping.rb +123 -0
- data/lib/flat_map/base_mapper/mounting.rb +168 -0
- data/lib/flat_map/base_mapper/persistence.rb +145 -0
- data/lib/flat_map/base_mapper/skipping.rb +62 -0
- data/lib/flat_map/base_mapper/traits.rb +94 -0
- data/lib/flat_map/empty_mapper.rb +29 -0
- data/lib/flat_map/errors.rb +57 -0
- data/lib/flat_map/mapper.rb +213 -0
- data/lib/flat_map/mapper/skipping.rb +45 -0
- data/lib/flat_map/mapper/targeting.rb +130 -0
- data/lib/flat_map/mapping.rb +124 -0
- data/lib/flat_map/mapping/factory.rb +21 -0
- data/lib/flat_map/mapping/reader.rb +12 -0
- data/lib/flat_map/mapping/reader/basic.rb +28 -0
- data/lib/flat_map/mapping/reader/formatted.rb +45 -0
- data/lib/flat_map/mapping/reader/formatted/formats.rb +28 -0
- data/lib/flat_map/mapping/reader/method.rb +25 -0
- data/lib/flat_map/mapping/reader/proc.rb +15 -0
- data/lib/flat_map/mapping/writer.rb +11 -0
- data/lib/flat_map/mapping/writer/basic.rb +25 -0
- data/lib/flat_map/mapping/writer/method.rb +28 -0
- data/lib/flat_map/mapping/writer/proc.rb +18 -0
- data/lib/flat_map/version.rb +3 -0
- data/spec/flat_map/empty_mapper_spec.rb +36 -0
- data/spec/flat_map/errors_spec.rb +23 -0
- data/spec/flat_map/mapper/attribute_methods_spec.rb +36 -0
- data/spec/flat_map/mapper/callbacks_spec.rb +76 -0
- data/spec/flat_map/mapper/factory_spec.rb +258 -0
- data/spec/flat_map/mapper/mapping_spec.rb +98 -0
- data/spec/flat_map/mapper/mounting_spec.rb +142 -0
- data/spec/flat_map/mapper/skipping_spec.rb +91 -0
- data/spec/flat_map/mapper/targeting_spec.rb +156 -0
- data/spec/flat_map/mapper/traits_spec.rb +172 -0
- data/spec/flat_map/mapper/validations_spec.rb +72 -0
- data/spec/flat_map/mapper_spec.rb +9 -0
- data/spec/flat_map/mapping/factory_spec.rb +12 -0
- data/spec/flat_map/mapping/reader/basic_spec.rb +15 -0
- data/spec/flat_map/mapping/reader/formatted_spec.rb +62 -0
- data/spec/flat_map/mapping/reader/method_spec.rb +13 -0
- data/spec/flat_map/mapping/reader/proc_spec.rb +13 -0
- data/spec/flat_map/mapping/writer/basic_spec.rb +15 -0
- data/spec/flat_map/mapping/writer/method_spec.rb +13 -0
- data/spec/flat_map/mapping/writer/proc_spec.rb +13 -0
- data/spec/flat_map/mapping_spec.rb +123 -0
- data/spec/spec_helper.rb +7 -0
- data/tmp/metric_fu/_data/20131218.yml +6902 -0
- data/tmp/metric_fu/_data/20131219.yml +6726 -0
- metadata +184 -0
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            module FlatMap
         | 
| 2 | 
            +
              module Mapping::Reader
         | 
| 3 | 
            +
                # Proc reader accepts a lambda and calls it with the target
         | 
| 4 | 
            +
                # as an argument for reading.
         | 
| 5 | 
            +
                class Proc < Method
         | 
| 6 | 
            +
                  # Call a <tt>@method</tt>, which is a {Proc} object,
         | 
| 7 | 
            +
                  # passing the +target+ object to it.
         | 
| 8 | 
            +
                  #
         | 
| 9 | 
            +
                  # @return [Object] value returned by reader's lambda
         | 
| 10 | 
            +
                  def read
         | 
| 11 | 
            +
                    @method.call(target)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            module FlatMap
         | 
| 2 | 
            +
              # Writer module hosts various writer classes that are used
         | 
| 3 | 
            +
              # by mappings to assign values to the target of an associated mapper.
         | 
| 4 | 
            +
              module Mapping::Writer
         | 
| 5 | 
            +
                extend ActiveSupport::Autoload
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                autoload :Basic
         | 
| 8 | 
            +
                autoload :Method
         | 
| 9 | 
            +
                autoload :Proc
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module FlatMap
         | 
| 2 | 
            +
              module Mapping::Writer
         | 
| 3 | 
            +
                # Basic writer simply calls the target's attribute assignment method
         | 
| 4 | 
            +
                # passing to it the value being written.
         | 
| 5 | 
            +
                class Basic
         | 
| 6 | 
            +
                  attr_reader :mapping
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  delegate :target, :target_attribute, :to => :mapping
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  # Initialize writer by passing +mapping+ to it.
         | 
| 11 | 
            +
                  def initialize(mapping)
         | 
| 12 | 
            +
                    @mapping = mapping
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  # Call the assignment method of the target, passing
         | 
| 16 | 
            +
                  # the +value+ to it.
         | 
| 17 | 
            +
                  #
         | 
| 18 | 
            +
                  # @param [Object] value
         | 
| 19 | 
            +
                  # @return [Object] result of assignment
         | 
| 20 | 
            +
                  def write(value)
         | 
| 21 | 
            +
                    target.send("#{target_attribute}=", value)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            module FlatMap
         | 
| 2 | 
            +
              module Mapping::Writer
         | 
| 3 | 
            +
                # Method writer calls a method defined by mapper and sends mapping
         | 
| 4 | 
            +
                # and value to it as arguments.
         | 
| 5 | 
            +
                #
         | 
| 6 | 
            +
                # Note that this doesn't set anything on the target itself.
         | 
| 7 | 
            +
                class Method < Basic
         | 
| 8 | 
            +
                  delegate :mapper, :to => :mapping
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  # Initialize the writer with a +mapping+ and +method+ name
         | 
| 11 | 
            +
                  # that should be called on the mapping's mapper.
         | 
| 12 | 
            +
                  #
         | 
| 13 | 
            +
                  # @param [FlatMap::Mapping] mapping
         | 
| 14 | 
            +
                  # @param [Symbol] method
         | 
| 15 | 
            +
                  def initialize(mapping, method)
         | 
| 16 | 
            +
                    @mapping, @method = mapping, method
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  # Write a +value+ by sending it, along with the mapping itself.
         | 
| 20 | 
            +
                  #
         | 
| 21 | 
            +
                  # @param [Object] value
         | 
| 22 | 
            +
                  # @return [Object] result of writing
         | 
| 23 | 
            +
                  def write(value)
         | 
| 24 | 
            +
                    mapper.send(@method, mapping, value)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            module FlatMap
         | 
| 2 | 
            +
              module Mapping::Writer
         | 
| 3 | 
            +
                # Proc writer calls a lambda passed on the mapping definition and
         | 
| 4 | 
            +
                # sends the mapper's target and value to it.
         | 
| 5 | 
            +
                #
         | 
| 6 | 
            +
                # Note that this doesn't set anything on the target itself.
         | 
| 7 | 
            +
                class Proc < Method
         | 
| 8 | 
            +
                  # Call a <tt>@method</tt>, which is a +Proc+ object,
         | 
| 9 | 
            +
                  # passing it the mapping's +target+ and +value+.
         | 
| 10 | 
            +
                  #
         | 
| 11 | 
            +
                  # @param [Object] value
         | 
| 12 | 
            +
                  # @return [Object] result of writing
         | 
| 13 | 
            +
                  def write(value)
         | 
| 14 | 
            +
                    @method.call(target, value)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module EmptyMapperSpec
         | 
| 4 | 
            +
              class MountedMapper < ::FlatMap::Mapper
         | 
| 5 | 
            +
              end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              class Mapper < ::FlatMap::EmptyMapper
         | 
| 8 | 
            +
                mount :mounted,
         | 
| 9 | 
            +
                  :mapper_class_name => 'EmptyMapperSpec::MountedMapper',
         | 
| 10 | 
            +
                  :target => Object.new
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                trait :some_trait do
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            module FlatMap
         | 
| 18 | 
            +
              describe EmptyMapper do
         | 
| 19 | 
            +
                let(:mapper){ EmptyMapperSpec::Mapper.new(:some_trait){} }
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                it 'should be normally initialized' do
         | 
| 22 | 
            +
                  mapper.mounting(:mounted).should be_present
         | 
| 23 | 
            +
                  mapper.trait(:some_trait).should be_present
         | 
| 24 | 
            +
                  mapper.extension.should be_present
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                it 'should raise error for malounted mapper when target is not specified' do
         | 
| 28 | 
            +
                  mapper_class = Class.new(::FlatMap::EmptyMapper) do
         | 
| 29 | 
            +
                    mount :mounted, :mapper_class_name => 'EmptyMapperSpec::MountedMapper'
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  expect{ mapper_class.new.mounting(:mounted) }.
         | 
| 33 | 
            +
                    to raise_error(::FlatMap::Mapper::Targeting::NoTargetError)
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe FlatMap::Errors do
         | 
| 4 | 
            +
              let(:errors) {
         | 
| 5 | 
            +
                described_class.new(
         | 
| 6 | 
            +
                  double( 'mapper', :suffixed? => true,
         | 
| 7 | 
            +
                                    :suffix    => 'foo',
         | 
| 8 | 
            +
                                    'attr_foo' => 2)
         | 
| 9 | 
            +
                )
         | 
| 10 | 
            +
              }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              it "preserved errors should appear on #empty? call exactly once" do
         | 
| 13 | 
            +
                errors.preserve :base, 'an error'
         | 
| 14 | 
            +
                errors.should_not be_empty
         | 
| 15 | 
            +
                errors[:base].should == ['an error']
         | 
| 16 | 
            +
                expect{ errors.empty? }.not_to change{ errors[:base].length }
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              it "should add error to mapper with suffix" do
         | 
| 20 | 
            +
                errors.add(:attr, 'an error')
         | 
| 21 | 
            +
                errors[:attr_foo].should == ['an error']
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FlatMap
         | 
| 4 | 
            +
              module AttributeMethodsSpec
         | 
| 5 | 
            +
                class SpecMapper < Mapper
         | 
| 6 | 
            +
                  map :attr_a, :attr_b
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              describe 'Attribute Methods' do
         | 
| 11 | 
            +
                let(:target){ OpenStruct.new }
         | 
| 12 | 
            +
                let(:mapper){ AttributeMethodsSpec::SpecMapper.new(target) }
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                before do
         | 
| 15 | 
            +
                  target.attr_a = 'a'
         | 
| 16 | 
            +
                  target.attr_b = 'b'
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                it 'should be able to read values via method calls' do
         | 
| 20 | 
            +
                  mapper.attr_a.should == 'a'
         | 
| 21 | 
            +
                  mapper.attr_b.should == 'b'
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                it 'should be able to write values via method calls' do
         | 
| 25 | 
            +
                  mapper.attr_a = 'A'
         | 
| 26 | 
            +
                  mapper.attr_b = 'B'
         | 
| 27 | 
            +
                  target.attr_a.should == 'A'
         | 
| 28 | 
            +
                  target.attr_b.should == 'B'
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                it 'should still raise for unknown or private method calls' do
         | 
| 32 | 
            +
                  expect{ mapper.undefined_method }.to raise_error(NoMethodError)
         | 
| 33 | 
            +
                  expect{ mapper.attribute_methods }.to raise_error(NoMethodError)
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
            end
         | 
| @@ -0,0 +1,76 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FlatMap
         | 
| 4 | 
            +
              module CallbacksSpec
         | 
| 5 | 
            +
                class MountMapper < Mapper
         | 
| 6 | 
            +
                  map :attr_c
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  set_callback :validate, :before, :set_c
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def set_c
         | 
| 11 | 
            +
                    self.attr_c = 'mounted before validate'
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                class SpecMapper < Mapper
         | 
| 16 | 
            +
                  map :attr_a
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  set_callback :save, :before, :set_a
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  trait :with_b do
         | 
| 21 | 
            +
                    map :attr_b
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    set_callback :validate, :before, :set_b
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    def set_b
         | 
| 26 | 
            +
                      self.attr_b = 'before validate'
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def set_a
         | 
| 31 | 
            +
                    self.attr_a = 'before save'
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  mount :mount,
         | 
| 35 | 
            +
                    :mapper_class_name => 'FlatMap::CallbacksSpec::MountMapper',
         | 
| 36 | 
            +
                    :target            => lambda{ |_| OpenStruct.new }
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              describe 'Callbacks' do
         | 
| 41 | 
            +
                let(:mapper) do
         | 
| 42 | 
            +
                  CallbacksSpec::SpecMapper.new(OpenStruct.new, :with_b) do
         | 
| 43 | 
            +
                    set_callback :validate, :before, :extension_set_b
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                    def extension_set_b
         | 
| 46 | 
            +
                      self.attr_b = 'extension value'
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                it 'should call callbacks once' do
         | 
| 52 | 
            +
                  mapper.should_receive(:set_a).once
         | 
| 53 | 
            +
                  mapper.save
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                specify 'validation callbacks' do
         | 
| 57 | 
            +
                  mapper.valid?
         | 
| 58 | 
            +
                  mapper.attr_a.should be_nil
         | 
| 59 | 
            +
                  mapper.attr_b.should == 'before validate'
         | 
| 60 | 
            +
                  mapper.attr_c.should == 'mounted before validate'
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                specify 'save callbacks' do
         | 
| 64 | 
            +
                  mapper.save
         | 
| 65 | 
            +
                  mapper.attr_a.should == 'before save'
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                context 'extension trait and named traits' do
         | 
| 69 | 
            +
                  it 'should process extension first' do
         | 
| 70 | 
            +
                    mapper.extension.should_receive(:extension_set_b).once.and_call_original
         | 
| 71 | 
            +
                    mapper.valid?
         | 
| 72 | 
            +
                    mapper.attr_b.should == 'before validate'
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
            end
         | 
| @@ -0,0 +1,258 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FlatMap
         | 
| 4 | 
            +
              describe BaseMapper::Factory do
         | 
| 5 | 
            +
                let(:trait_class){ Class.new(Mapper) }
         | 
| 6 | 
            +
                let(:target){ Object.new }
         | 
| 7 | 
            +
                let(:other_target){ Object.new }
         | 
| 8 | 
            +
                let(:mapper){ Class.new(Mapper).new(target) }
         | 
| 9 | 
            +
                let(:mount_factory){ BaseMapper::Factory.new(:spec_mount, :traits => :used_traits) }
         | 
| 10 | 
            +
                let(:trait_factory){ BaseMapper::Factory.new(trait_class, :trait_name => :a_trait) }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                context 'when used for a trait' do
         | 
| 13 | 
            +
                  subject{ trait_factory }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  it{ should be_traited }
         | 
| 16 | 
            +
                  its(:name){ should be_nil }
         | 
| 17 | 
            +
                  its(:trait_name){ should == :a_trait }
         | 
| 18 | 
            +
                  its(:mapper_class){ should == trait_class }
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                context 'when used for a mounted mapper' do
         | 
| 22 | 
            +
                  subject{ mount_factory }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  it{ should_not be_traited }
         | 
| 25 | 
            +
                  its(:name){ should == :spec_mount }
         | 
| 26 | 
            +
                  its(:trait_name){ should be_nil }
         | 
| 27 | 
            +
                  its(:traits){ should == [:used_traits] }
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                describe 'behavior' do
         | 
| 31 | 
            +
                  describe '#mapper_class for mounted mappers' do
         | 
| 32 | 
            +
                    class ::SpecMountMapper < Mapper; end
         | 
| 33 | 
            +
                    class BaseMapper::Factory::SpecMountMapper; end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    it "should be able to fetch class name from name" do
         | 
| 36 | 
            +
                      mount_factory.mapper_class.should == ::SpecMountMapper
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    it "should use options if specified" do
         | 
| 40 | 
            +
                      factory = BaseMapper::Factory.new(
         | 
| 41 | 
            +
                                  :spec_mount,
         | 
| 42 | 
            +
                                  :mapper_class_name => 'FlatMap::BaseMapper::Factory::SpecMountMapper'
         | 
| 43 | 
            +
                                )
         | 
| 44 | 
            +
                      factory.mapper_class.should == ::FlatMap::BaseMapper::Factory::SpecMountMapper
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  describe '#fetch_target_from' do
         | 
| 49 | 
            +
                    it "should return owner's target for traited factory" do
         | 
| 50 | 
            +
                      trait_factory.fetch_target_from(mapper).should == target
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                    context 'explicit target' do
         | 
| 54 | 
            +
                      it "should use explicitly specified if applicable" do
         | 
| 55 | 
            +
                        factory = BaseMapper::Factory.new(:mount, :target => other_target)
         | 
| 56 | 
            +
                        factory.fetch_target_from(mapper).should == other_target
         | 
| 57 | 
            +
                      end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                      it "should call Proc and pass owner target to it if Proc is specified as :target" do
         | 
| 60 | 
            +
                        factory = BaseMapper::Factory.new(:mount, :target => lambda{ |obj| obj.foo })
         | 
| 61 | 
            +
                        target.should_receive(:foo).and_return(other_target)
         | 
| 62 | 
            +
                        factory.fetch_target_from(mapper).should == other_target
         | 
| 63 | 
            +
                      end
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                    context 'target from association' do
         | 
| 67 | 
            +
                      before{ target.stub(:kind_of?).with(ActiveRecord::Base).and_return(true) }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                      let(:has_one_current_reflection) {
         | 
| 70 | 
            +
                        double('reflection', :macro => :has_one, :options => {:is_current => true})
         | 
| 71 | 
            +
                      }
         | 
| 72 | 
            +
                      let(:has_one_reflection) {
         | 
| 73 | 
            +
                        double('reflection', :macro => :has_one, :options => {})
         | 
| 74 | 
            +
                      }
         | 
| 75 | 
            +
                      let(:belongs_to_reflection) {
         | 
| 76 | 
            +
                        double('reflection', :macro => :belongs_to)
         | 
| 77 | 
            +
                      }
         | 
| 78 | 
            +
                      let(:has_many_reflection) {
         | 
| 79 | 
            +
                        double('reflection', :macro => :has_many, :name => :spec_mounts)
         | 
| 80 | 
            +
                      }
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                      it "should refer to effective name for has_one_current association" do
         | 
| 83 | 
            +
                        # Note: has_one_current is not part of Rails
         | 
| 84 | 
            +
                        mount_factory.should_receive(:reflection_from_target).
         | 
| 85 | 
            +
                                      with(target).
         | 
| 86 | 
            +
                                      and_return(has_one_current_reflection)
         | 
| 87 | 
            +
                        target.should_receive(:effective_spec_mount).and_return(other_target)
         | 
| 88 | 
            +
                        mount_factory.fetch_target_from(mapper).should == other_target
         | 
| 89 | 
            +
                      end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                      it "should refer to existing association object if possible, " \
         | 
| 92 | 
            +
                         "and build it if it is absent for :has_one" do
         | 
| 93 | 
            +
                        mount_factory.should_receive(:reflection_from_target).
         | 
| 94 | 
            +
                                      with(target).
         | 
| 95 | 
            +
                                      and_return(has_one_reflection)
         | 
| 96 | 
            +
                        target.should_receive(:spec_mount).and_return(nil)
         | 
| 97 | 
            +
                        target.should_receive(:build_spec_mount).and_return(other_target)
         | 
| 98 | 
            +
                        mount_factory.fetch_target_from(mapper).should == other_target
         | 
| 99 | 
            +
                      end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                      it "should refer to existing association object if possible, " \
         | 
| 102 | 
            +
                         "and build it if it is absent for :belongs_to" do
         | 
| 103 | 
            +
                        mount_factory.should_receive(:reflection_from_target).
         | 
| 104 | 
            +
                                      with(target).
         | 
| 105 | 
            +
                                      and_return(belongs_to_reflection)
         | 
| 106 | 
            +
                        target.should_receive(:spec_mount).and_return(nil)
         | 
| 107 | 
            +
                        target.should_receive(:build_spec_mount).and_return(other_target)
         | 
| 108 | 
            +
                        mount_factory.fetch_target_from(mapper).should == other_target
         | 
| 109 | 
            +
                      end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                      it "should always build a new record for :has_many association" do
         | 
| 112 | 
            +
                        mount_factory.should_receive(:reflection_from_target).
         | 
| 113 | 
            +
                                      with(target).
         | 
| 114 | 
            +
                                      and_return(has_many_reflection)
         | 
| 115 | 
            +
                        target.should_receive(:association).with(:spec_mounts)
         | 
| 116 | 
            +
                        target.stub_chain(:association, :build).and_return(other_target)
         | 
| 117 | 
            +
                        mount_factory.fetch_target_from(mapper).should == other_target
         | 
| 118 | 
            +
                      end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                      describe 'reflection_from_target' do
         | 
| 121 | 
            +
                        before{ target.stub(:is_a?).with(ActiveRecord::Base).and_return(true) }
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                        it 'should first refer to singular association' do
         | 
| 124 | 
            +
                          target.stub_chain(:class, :reflect_on_association).
         | 
| 125 | 
            +
                                 with(:spec_mount).
         | 
| 126 | 
            +
                                 and_return(has_one_reflection)
         | 
| 127 | 
            +
                          mount_factory.reflection_from_target(target).should == has_one_reflection
         | 
| 128 | 
            +
                        end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                        it 'should use collection association if singular does not exist' do
         | 
| 131 | 
            +
                          target.stub_chain(:class, :reflect_on_association).
         | 
| 132 | 
            +
                                 with(:spec_mount).
         | 
| 133 | 
            +
                                 and_return(nil)
         | 
| 134 | 
            +
                          target.stub_chain(:class, :reflect_on_association).
         | 
| 135 | 
            +
                                 with(:spec_mounts).
         | 
| 136 | 
            +
                                 and_return(has_many_reflection)
         | 
| 137 | 
            +
                          mount_factory.reflection_from_target(target).should == has_many_reflection
         | 
| 138 | 
            +
                        end
         | 
| 139 | 
            +
                      end
         | 
| 140 | 
            +
                    end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                    context 'target from name' do
         | 
| 143 | 
            +
                      it 'should simply send method to owner target' do
         | 
| 144 | 
            +
                        target.should_receive(:spec_mount).and_return(other_target)
         | 
| 145 | 
            +
                        mount_factory.fetch_target_from(mapper).should == other_target
         | 
| 146 | 
            +
                      end
         | 
| 147 | 
            +
                    end
         | 
| 148 | 
            +
                  end
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                  describe '#create' do
         | 
| 151 | 
            +
                    specify 'traited factory should create an owned mapper' do
         | 
| 152 | 
            +
                      new_one = trait_factory.create(mapper)
         | 
| 153 | 
            +
                      new_one.owner.should == mapper
         | 
| 154 | 
            +
                    end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                    context 'mounted empty mapper' do
         | 
| 157 | 
            +
                      class ::SpecEmptyMountMapper < EmptyMapper; end
         | 
| 158 | 
            +
                      let(:factory){ BaseMapper::Factory.new(:spec_empty_mount) }
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                      it 'should not call fetch_target_from' do
         | 
| 161 | 
            +
                        factory.should_not_receive(:fetch_target_from)
         | 
| 162 | 
            +
                        factory.create(mapper)
         | 
| 163 | 
            +
                      end
         | 
| 164 | 
            +
                    end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                    context 'mounted mapper' do
         | 
| 167 | 
            +
                      let(:mount_class){ Class.new(Mapper) }
         | 
| 168 | 
            +
                      let(:factory){ mount_factory }
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                      before do
         | 
| 171 | 
            +
                        factory.stub(:mapper_class).and_return(mount_class)
         | 
| 172 | 
            +
                        factory.stub(:fetch_target_from).and_return(other_target)
         | 
| 173 | 
            +
                      end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                      it 'should combine traits' do
         | 
| 176 | 
            +
                        mount_class.should_receive(:new).
         | 
| 177 | 
            +
                                    with(other_target, :used_traits, :another_trait).
         | 
| 178 | 
            +
                                    and_call_original
         | 
| 179 | 
            +
                        factory.create(mapper, :another_trait)
         | 
| 180 | 
            +
                      end
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                      it 'should properly set properties' do
         | 
| 183 | 
            +
                        new_one = factory.create(mapper)
         | 
| 184 | 
            +
                        new_one.host      .should == mapper
         | 
| 185 | 
            +
                        new_one.name      .should == :spec_mount
         | 
| 186 | 
            +
                        new_one.save_order.should == :after
         | 
| 187 | 
            +
                        new_one.suffix.should be_nil
         | 
| 188 | 
            +
                      end
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                      context 'when suffix is defined' do
         | 
| 191 | 
            +
                        let(:factory){ BaseMapper::Factory.new(:spec_mount, :suffix => :foo) }
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                        it "should adjust properties with suffix" do
         | 
| 194 | 
            +
                          new_one = factory.create(mapper)
         | 
| 195 | 
            +
                          new_one.name  .should == :spec_mount_foo
         | 
| 196 | 
            +
                          new_one.suffix.should == :foo
         | 
| 197 | 
            +
                        end
         | 
| 198 | 
            +
                      end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                      context 'when extension is present' do
         | 
| 201 | 
            +
                        let(:extension){ Proc.new{} }
         | 
| 202 | 
            +
                        let(:factory){ BaseMapper::Factory.new(:spec_mount, &extension) }
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                        it "should pass it to mapper initialization" do
         | 
| 205 | 
            +
                          mount_class.should_receive(:new).
         | 
| 206 | 
            +
                                      with(other_target, &extension).
         | 
| 207 | 
            +
                                      and_call_original
         | 
| 208 | 
            +
                          new_one = factory.create(mapper)
         | 
| 209 | 
            +
                        end
         | 
| 210 | 
            +
                      end
         | 
| 211 | 
            +
             | 
| 212 | 
            +
                      describe 'save order' do
         | 
| 213 | 
            +
                        context 'when explicitly set' do
         | 
| 214 | 
            +
                          let(:factory){ BaseMapper::Factory.new(:spec_mount, :save => :before) }
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                          it 'should fetch from options, if possible' do
         | 
| 217 | 
            +
                            new_one = factory.create(mapper)
         | 
| 218 | 
            +
                            new_one.save_order.should == :before
         | 
| 219 | 
            +
                          end
         | 
| 220 | 
            +
                        end
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                        it 'should be :before for belongs_to association' do
         | 
| 223 | 
            +
                          mount_factory.stub(:reflection_from_target).
         | 
| 224 | 
            +
                                        and_return(double('reflection', :macro => :belongs_to))
         | 
| 225 | 
            +
                          factory.fetch_save_order(mapper).should == :before
         | 
| 226 | 
            +
                        end
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                        it 'should be :after for other cases' do
         | 
| 229 | 
            +
                          mount_factory.stub(:reflection_from_target).
         | 
| 230 | 
            +
                                        and_return(double('reflection', :macro => :has_one))
         | 
| 231 | 
            +
                          factory.fetch_save_order(mapper).should == :after
         | 
| 232 | 
            +
                        end
         | 
| 233 | 
            +
                      end
         | 
| 234 | 
            +
                    end
         | 
| 235 | 
            +
                  end
         | 
| 236 | 
            +
             | 
| 237 | 
            +
                  describe '#required_for_any_trait?' do
         | 
| 238 | 
            +
                    let(:mapper_class) do
         | 
| 239 | 
            +
                      Class.new(FlatMap::Mapper) do
         | 
| 240 | 
            +
                        trait(:trait_a) {
         | 
| 241 | 
            +
                          trait(:trait_b) {
         | 
| 242 | 
            +
                            trait(:trait_c) {
         | 
| 243 | 
            +
                        } } }
         | 
| 244 | 
            +
                      end
         | 
| 245 | 
            +
                    end
         | 
| 246 | 
            +
                    let(:factory_for_b){ mapper_class.mountings.first.mapper_class.mountings.first }
         | 
| 247 | 
            +
             | 
| 248 | 
            +
                    it "should be required for nested trait" do
         | 
| 249 | 
            +
                      factory_for_b.required_for_any_trait?([:trait_c]).should be_true
         | 
| 250 | 
            +
                    end
         | 
| 251 | 
            +
             | 
| 252 | 
            +
                    it "should not be required for top trait" do
         | 
| 253 | 
            +
                      factory_for_b.required_for_any_trait?([:trait_a]).should be_false
         | 
| 254 | 
            +
                    end
         | 
| 255 | 
            +
                  end
         | 
| 256 | 
            +
                end
         | 
| 257 | 
            +
              end
         | 
| 258 | 
            +
            end
         |