Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add DumpWrapper to avoid hashes as api.

* DumpWrapper decorator is configured while adding mappings
* Integrate shared behaviours from veritas
* Deduplicate Transformator::{Loader,Dumper} as far as possible
* Yeah there is a design error in Transformator#transformation(name)
* This will be addressed by defiving operations from AttributeSet
  • Loading branch information...
commit 699274de5e8d30b87de1678bb18cc83e9946facb 1 parent d3e6a48
Markus Schirp authored
Showing with 555 additions and 292 deletions.
  1. +4 −6 TODO
  2. +1 −1  config/flog.yml
  3. +5 −3 config/site.reek
  4. +1 −0  lib/mapper.rb
  5. +1 −1  lib/mapper/attribute.rb
  6. +19 −41 lib/mapper/attribute/object.rb
  7. +22 −1 lib/mapper/attribute_set.rb
  8. +6 −24 lib/mapper/class_methods.rb
  9. +69 −6 lib/mapper/transformer.rb
  10. +40 −0 lib/mapper/transformer/dump_wrapper.rb
  11. +10 −36 lib/mapper/transformer/dumper.rb
  12. +4 −37 lib/mapper/transformer/loader.rb
  13. +4 −4 spec/integration/spike_spec.rb
  14. +7 −0 spec/shared/command_method_behavior.rb
  15. +15 −0 spec/shared/each_method_behaviour.rb
  16. +17 −0 spec/shared/hash_method_behavior.rb
  17. +7 −0 spec/shared/idempotent_method_behavior.rb
  18. +9 −0 spec/shared/invertible_method_behaviour.rb
  19. +13 −4 spec/spec_helper.rb
  20. +3 −0  spec/unit/mapper/attribute/class_methods/const_name_spec.rb
  21. +4 −0 spec/unit/mapper/attribute/class_methods/determine_type_spec.rb
  22. +3 −1 spec/unit/mapper/attribute/class_methods/handles_spec.rb
  23. +4 −2 spec/unit/mapper/attribute/custom/define_dumper_spec.rb
  24. +4 −2 spec/unit/mapper/attribute/custom/define_loader_spec.rb
  25. +1 −1  spec/unit/mapper/attribute/embedded_collection/load_spec.rb
  26. +1 −1  spec/unit/mapper/attribute/embedded_document/load_spec.rb
  27. +41 −0 spec/unit/mapper/attribute/object/define_dump_reader_spec.rb
  28. +22 −7 spec/unit/mapper/attribute/object/define_dumper_spec.rb
  29. +6 −6 spec/unit/mapper/attribute/object/define_loader_spec.rb
  30. +0 −31 spec/unit/mapper/attribute/object/dumper_method_source_spec.rb
  31. +7 −0 spec/unit/mapper/attribute/object/key_ques_spec.rb
  32. +2 −2 spec/unit/mapper/attribute/object/load_spec.rb
  33. +0 −31 spec/unit/mapper/attribute/object/loader_method_source_spec.rb
  34. +4 −0 spec/unit/mapper/attribute_set/add_spec.rb
  35. +44 −0 spec/unit/mapper/attribute_set/dump_key_names_spec.rb
  36. +2 −0  spec/unit/mapper/attribute_set/empty_ques_spec.rb
  37. +2 −0  spec/unit/mapper/attribute_set/fetch_dump_name_spec.rb
  38. +2 −0  spec/unit/mapper/attribute_set/fetch_load_name_spec.rb
  39. +2 −0  spec/unit/mapper/class_methods/attributes_spec.rb
  40. +3 −0  spec/unit/mapper/class_methods/const_missing_spec.rb
  41. +1 −5 spec/unit/mapper/class_methods/dump_spec.rb
  42. +1 −1  spec/unit/mapper/class_methods/dumper_spec.rb
  43. +1 −1  spec/unit/mapper/class_methods/loader_spec.rb
  44. +57 −0 spec/unit/mapper/transformer/class_methods/define_reader_spec.rb
  45. +3 −0  spec/unit/mapper/transformer/class_methods/mapper_spec.rb
  46. +1 −1  spec/unit/mapper/transformer/class_methods/reader_method_source_spec.rb
  47. +26 −0 spec/unit/mapper/transformer/dump_wrapper/read_spec.rb
  48. +5 −10 spec/unit/mapper/transformer/dumper/dump_spec.rb
  49. +25 −0 spec/unit/mapper/transformer/dumper/key_spec.rb
  50. +0 −12 spec/unit/mapper/transformer/dumper/object_spec.rb
  51. +2 −0  spec/unit/mapper/transformer/loader/attributes_spec.rb
  52. +0 −12 spec/unit/mapper/transformer/loader/dump_spec.rb
  53. +2 −0  spec/unit/mapper/transformer/loader/object_spec.rb
  54. +6 −2 spec/unit/mapper/transformer/mapper_spec.rb
  55. +14 −0 spec/unit/mapper/transformer/source_spec.rb
View
10 TODO
@@ -1,6 +1,4 @@
-* Remove ::Mapper::Mapper namespacing uglyness
-* Assert database root documents have a key
-* Add specs for load_key and dump_key
-* Create a mapper level identity map to allow
- loading an object tree where an object appears twice.
-* Create Loader and Dumper classes, to allow mapper level identity map.
+* Prevent Transformer::Loader#{key,attributes,object} to be overriden by mapping definitions
+* Prevent Transformer::Dumper#{key,dump} to be overriden by mapping definitions
+* Expose Transformations generated from AttributeSet to Transformator
+* Finalize the state of DumpWrapper in inheritance tree
View
2  config/flog.yml
@@ -1,2 +1,2 @@
---
-threshold: 9.0
+threshold: 13.9
View
8 config/site.reek
@@ -7,10 +7,12 @@ UncommunicativeParameterName:
- !ruby/regexp /[0-9]$/
- !ruby/regexp /[A-Z]/
LargeClass:
- max_methods: 13
+# AttributeSet will be broken than this can be lowered
+ max_methods: 15
enabled: true
exclude: []
- max_instance_variables: 3
+# AttributeSet will be broken than this can be lowered
+ max_instance_variables: 5
UncommunicativeMethodName:
accept: []
exclude: []
@@ -51,7 +53,7 @@ NestedIterators:
enabled: true
max_allowed_nesting: 1
LongMethod:
- max_statements: 4
+ max_statements: 5
exclude: []
enabled: true
Duplication:
View
1  lib/mapper.rb
@@ -46,6 +46,7 @@ def self.new_mapper
require 'mapper/transformer'
require 'mapper/transformer/loader'
require 'mapper/transformer/dumper'
+require 'mapper/transformer/dump_wrapper'
require 'mapper/attribute'
require 'mapper/attribute/object'
require 'mapper/attribute/embedded'
View
2  lib/mapper/attribute.rb
@@ -73,7 +73,7 @@ def self.handle?(class_or_name)
# @api private
#
def self.handles
- [self,const_name]
+ @handles ||= [self,const_name]
end
end
end
View
60 lib/mapper/attribute/object.rb
@@ -16,24 +16,6 @@ def initialize(load_name,options={})
@key = !!options.fetch(:key,false)
end
- # Define reader on transformer
- #
- # @param [Class] klass
- # the loader or dumper class to define the reader on
- #
- # @param [String] source
- # the source of the method to define
- #
- # @api private
- #
- # @return [self]
- #
- def define_reader(klass,source)
- klass.class_eval(source,__FILE__,__LINE__+1)
-
- self
- end
-
public
# Return wheather this attribute is a key
@@ -46,25 +28,6 @@ def key?
@key
end
- # Return loader method source
- #
- # @return [String]
- #
- # @api private
- #
- def loader_method_source
- Transformer.reader_method_source(@load_name)
- end
-
- # Return dumper method source
- #
- # @return [String]
- #
- # @api private
- def dumper_method_source
- Transformer.reader_method_source(@dump_name)
- end
-
# Return names of domain object attributes this attribute loads
#
# @return [Array<Symbol>]
@@ -94,7 +57,7 @@ def dump_names
# @api private
#
def define_loader(klass)
- define_reader(klass,loader_method_source)
+ klass.define_reader(@load_name)
self
end
@@ -108,7 +71,23 @@ def define_loader(klass)
# @api private
#
def define_dumper(klass)
- define_reader(klass,dumper_method_source)
+ klass.define_reader(@dump_name)
+
+ self
+ end
+
+ # Define reader method on dump wrapper class
+ #
+ # @param [Class] klass
+ #
+ # @return [self]
+ #
+ # @api private
+ #
+ def define_dump_reader(klass)
+ dump_names.each do |name|
+ klass.define_reader(name)
+ end
self
end
@@ -133,9 +112,8 @@ def dump(object)
#
# @api private
#
- # TODO: Introduce dump accessor object.
def load(dump)
- dump.fetch(@dump_name)
+ dump.send(@dump_name)
end
end
end
View
23 lib/mapper/attribute_set.rb
@@ -36,6 +36,16 @@ def dump_names
dump_map.keys
end
+ # Return all dump names of attributes that are keys
+ #
+ # @return [Array<Symbol>]
+ #
+ # @api private
+ #
+ def dump_key_names
+ @dump_key_names ||= key_attributes.map(&:dump_names).flatten
+ end
+
# Return all names of domain object attributes in set
#
# @return [Array<Symbol>]
@@ -88,6 +98,17 @@ def initialize()
@set = Set.new
end
+ # Return all attributes that hold part of key
+ #
+ # @return [Enumerable]
+ #
+ # @api private
+ #
+ def key_attributes
+ @set.select(&:key?)
+ end
+
+
# Return map of load names to attribute
#
# @return [Hash<Symbol,Attribute>]
@@ -167,7 +188,7 @@ def map_entries(method)
# @api private
#
def reset
- @dump_map = @load_map = nil
+ @dump_map = @load_map = @dump_key_names = nil
self
end
end
View
30 lib/mapper/class_methods.rb
@@ -33,7 +33,7 @@ def load(dump)
#
# @api private
def loader(dump)
- loader_klass.new(dump)
+ self::Loader.new(dump)
end
# Transform domain object into dump
@@ -59,7 +59,7 @@ def dump(object)
# @api private
#
def dumper(object)
- dumper_klass.new(object)
+ self::Dumper.new(object)
end
# Return attributes mapper is handling
@@ -160,32 +160,13 @@ def const_missing(name)
#
def add_attribute(attribute)
attributes.add(attribute)
- attribute.define_loader(loader_klass)
- attribute.define_dumper(dumper_klass)
+ attribute.define_loader(self::Loader)
+ attribute.define_dumper(self::Dumper)
+ attribute.define_dump_reader(self::DumpWrapper)
self
end
- # Return mappers dumper class
- #
- # @return [Class<Dumper>]
- #
- # @api private
- #
- def dumper_klass
- const_get(:Dumper)
- end
-
- # Return mappers dumper class
- #
- # @return [Class<Loader>]
- #
- # @api private
- #
- def loader_klass
- const_get(:Loader)
- end
-
# Read mappers model or raise
#
# @return [Model]
@@ -205,6 +186,7 @@ def read_model
def setup
create(Transformer::Dumper,:Dumper)
create(Transformer::Loader,:Loader)
+ create(Transformer::DumpWrapper,:DumpWrapper)
self
end
View
75 lib/mapper/transformer.rb
@@ -1,6 +1,14 @@
module Mapper
# Base class for loader and dumper classes
class Transformer
+ # Return source of transformation
+ #
+ # @return [Object]
+ #
+ # @api private
+ #
+ attr_reader :source
+
# Access transformers class mapper
#
# @raise [RuntimeError]
@@ -25,14 +33,30 @@ def self.mapper
# @api private
#
def self.reader_method_source(name)
- # comment to keep vim syntax happy
+ # comment to keep vim ruby syntax happy
<<-RUBY
def #{name}
- memonized(:#{name})
+ read(:#{name})
end
RUBY
end
+ # Define reader on class
+ #
+ # @param [Symbol] name
+ # the name of the reader to define
+ #
+ # @return [self]
+ #
+ # @api private
+ #
+ def self.define_reader(name)
+ source = reader_method_source(name)
+ class_eval(source,__FILE__,__LINE__)
+
+ self
+ end
+
# Access transformers mapper
#
# @return [Mapper]
@@ -43,8 +67,21 @@ def mapper
self.class.mapper
end
+
private
+ # Initialize transformer with source
+ #
+ # @param [Object] source
+ #
+ # @return [undefined]
+ #
+ # @api private
+ #
+ def initialize(source,operation)
+ @source,@operation = source,operation
+ end
+
# Access mappers attribute set
#
# @return [Mapper::AttributeSet]
@@ -70,19 +107,45 @@ def map(names)
end
end
- # Access transformer value via memonization guard
+ # Return transformed value via memonization guard
#
- # @param [Symbol] name of value to access
+ # @param [Symbol] name of value to return
#
# @return [Object]
#
# @api private
#
- def memonized(name)
+ def read(name)
@memonized ||= {}
@memonized.fetch(name) do
- @memonized[name]=access(name)
+ @memonized[name]=read_nocache(name)
end
end
+
+ # Return transformed value
+ #
+ # @param [Symbol] name of value to return
+ #
+ # @return [Object]
+ #
+ # @api private
+ #
+ def read_nocache(name)
+ transformation(name).send(@operation,@source)
+ end
+
+ # Return transformation
+ #
+ # (Currently an Attribute)
+ #
+ # @return [Transformation]
+ #
+ # @api private
+ #
+ # TODO: Will be replaced by real transformation
+ #
+ def transformation(name)
+ attribute_set.send("fetch_#{@operation}_name",name)
+ end
end
end
View
40 lib/mapper/transformer/dump_wrapper.rb
@@ -0,0 +1,40 @@
+module Mapper
+ class Transformer
+ # Wraps a raw dump to abstract away hash
+ # Not naturally a subclass of transformer, hence the undefs.
+ # But I'd like to use the Transformer.define_reader.
+ #
+ class DumpWrapper < Transformer
+
+ undef :transformation
+ undef :read
+ undef :read_nocache
+
+ private
+
+ # Initialize dump wrapper
+ #
+ # @param [Hash] dump
+ #
+ # @return [undefined]
+ #
+ # @api private
+ #
+ def initialize(dump)
+ @dump = dump
+ end
+
+ # Read a dump value
+ #
+ # @param [Symbol] name
+ #
+ # @return [Object]
+ #
+ # @api private
+ #
+ def read(name)
+ @dump.fetch(name)
+ end
+ end
+ end
+end
View
46 lib/mapper/transformer/dumper.rb
@@ -2,22 +2,24 @@ module Mapper
class Transformer
# Dumper base class
class Dumper < Transformer
- # Return domain object to dump
+ # Return dumped representation of domain object
#
- # @return [Object]
+ # @return [Hash]
#
# @api private
#
- attr_reader :object
+ def dump
+ @dump ||= map(attribute_set.dump_names)
+ end
- # Return dumped representation of domain object
+ # Return key
#
- # @return [Hash]
+ # @return [Object]
#
# @api private
#
- def dump
- map(attribute_set.dump_names)
+ def key
+ @key ||= map(attribute_set.dump_key_names)
end
private
@@ -32,35 +34,7 @@ def dump
# @return [undefined]
#
def initialize(object)
- @object = object
- end
-
- # Access dumped representation of domain object attribute with name
- #
- # This method takes aliasing into account.
- #
- # @param [Symbol] name
- # the name of the attribute
- #
- # @return [Object]
- # the transformed object
- #
- # @api private
- #
- def access(name)
- attribute(name).dump(@object)
- end
-
- # Resolve attribute via dump name
- #
- # @param [Symbol] name
- #
- # @return [Attribute]
- #
- # @api private
- #
- def attribute(name)
- attribute_set.fetch_dump_name(name)
+ super(object,:dump)
end
end
end
View
41 lib/mapper/transformer/loader.rb
@@ -2,14 +2,6 @@ module Mapper
class Transformer
# Loader base class
class Loader < Transformer
- # Return input dump
- #
- # @return [Object]
- #
- # @api private
- #
- attr_reader :dump
-
# Return loaded domain object
#
# @return [Object]
@@ -17,7 +9,7 @@ class Loader < Transformer
# @api private
#
def object
- mapper.instanciate_model(attributes)
+ @object ||= mapper.instanciate_model(attributes)
end
# Return loaded attributes
@@ -27,44 +19,19 @@ def object
# @api private
#
def attributes
- map(attribute_set.load_names)
+ @attributes ||= map(attribute_set.load_names)
end
private
- # Initialize loader with dumped representation
+ # Initalize Loader
#
# @param [Object] dump
- #
# @return [undefined]
- #
# @api private
#
def initialize(dump)
- @dump = dump
- end
-
- # Access domain object attribute with name
- #
- # @param [Symbol] name
- #
- # @return [Object]
- #
- # @api private
- #
- def access(name)
- attribute(name).load(@dump)
- end
-
- # Resolve attribute via load name
- #
- # @param [Symbol] name
- #
- # @return [Attribute]
- #
- # @api private
- def attribute(name)
- attribute_set.fetch_load_name(name)
+ super(mapper::DumpWrapper.new(dump),:load)
end
end
end
View
8 spec/integration/spike_spec.rb
@@ -94,7 +94,7 @@ class Mapper
class Dumper
def preferred_phone_idx
- object.phones.index(object.preferred_phone)
+ source.phones.index(source.preferred_phone)
end
def vat_rate_numerator
@@ -110,18 +110,18 @@ def vat_rate
end
def with_vat_rate
- vat_rate = object.vat_rate
+ vat_rate = source.vat_rate
yield vat_rate if vat_rate
end
end
class Loader
def vat_rate
- Rational(@dump[:vat_rate_numerator],@dump[:vat_rate_denominator])
+ Rational(source.vat_rate_numerator,source.vat_rate_denominator)
end
def preferred_phone
- prefered_phone_idx = @dump[:preferred_phone_idx]
+ prefered_phone_idx = source.preferred_phone_idx
if prefered_phone_idx
phones.fetch(prefered_phone_idx)
end
View
7 spec/shared/command_method_behavior.rb
@@ -0,0 +1,7 @@
+# encoding: utf-8
+
+shared_examples_for 'a command method' do
+ it 'returns self' do
+ should equal(object)
+ end
+end
View
15 spec/shared/each_method_behaviour.rb
@@ -0,0 +1,15 @@
+# encoding: utf-8
+
+shared_examples_for 'an #each method' do
+ it_should_behave_like 'a command method'
+
+ context 'with no block' do
+ subject { object.each }
+
+ it { should be_instance_of(to_enum.class) }
+
+ it 'yields the expected values' do
+ subject.to_a.should eql(object.to_a)
+ end
+ end
+end
View
17 spec/shared/hash_method_behavior.rb
@@ -0,0 +1,17 @@
+# encoding: utf-8
+
+shared_examples_for 'a hash method' do
+ it_should_behave_like 'an idempotent method'
+
+ specification = proc do
+ should be_instance_of(Fixnum)
+ end
+
+ it 'is a fixnum' do
+ instance_eval(&specification)
+ end
+
+ it 'memoizes the hash code' do
+ subject.should eql(object.memoized(:hash))
+ end
+end
View
7 spec/shared/idempotent_method_behavior.rb
@@ -0,0 +1,7 @@
+# encoding: utf-8
+
+shared_examples_for 'an idempotent method' do
+ it 'is idempotent' do
+ should equal(instance_eval(&self.class.subject))
+ end
+end
View
9 spec/shared/invertible_method_behaviour.rb
@@ -0,0 +1,9 @@
+# encoding: utf-8
+
+shared_examples_for 'an invertible method' do
+ it_should_behave_like 'an idempotent method'
+
+ it 'is invertible' do
+ subject.inverse.should equal(object)
+ end
+end
View
17 spec/spec_helper.rb
@@ -7,16 +7,25 @@
$LOAD_PATH << File.expand_path('../lib', __FILE__)
-Dir.glob('spec/**/*_shared.rb').each { |file| require File.expand_path(file) }
+Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each { |f| require f }
# simple domain object used in specs
class DomainObject
- attr_reader :foo
- def initialize(attributes)
- @foo = attributes.fetch(:foo)
+ attr_reader :foo,:id
+ def initialize(attributes={})
+ @id = attributes.fetch(:id,1)
+ @foo = attributes.fetch(:foo,:bar)
end
end
+require 'mapper'
+
+module DomainObjectMapper
+ include ::Mapper
+ map :id, Object, :key => true
+ map :foo, Object
+end
+
module SpecHelper
def compress_prefix(lines)
View
3  spec/unit/mapper/attribute/class_methods/const_name_spec.rb
@@ -3,6 +3,9 @@
describe Mapper::Attribute,'.const_name' do
let(:object) { described_class }
subject { object.const_name }
+
+ it_should_behave_like 'an idempotent method'
+
it 'should return classes const name' do
should == :Attribute
end
View
4 spec/unit/mapper/attribute/class_methods/determine_type_spec.rb
@@ -9,6 +9,8 @@
let(:class_or_name) { ::Object }
it { should be(Mapper::Attribute::Object) }
+
+ it_should_behave_like 'an idempotent method'
end
context 'with undeterminable type' do
@@ -22,6 +24,8 @@
context 'with :EmbeddedCollection' do
let(:class_or_name) { :EmbeddedCollection }
+ it_should_behave_like 'an idempotent method'
+
it { should be(Mapper::Attribute::EmbeddedCollection) }
end
end
View
4 spec/unit/mapper/attribute/class_methods/handles_spec.rb
@@ -1,10 +1,12 @@
require 'spec_helper'
describe Mapper::Attribute,'.handles' do
- let(:object) { described_class }
+ let(:object) { Class.new(described_class) }
subject { object.handles }
+ it_should_behave_like 'an idempotent method'
+
it 'should return class and const name' do
should == [object,object.const_name]
end
View
6 spec/unit/mapper/attribute/custom/define_dumper_spec.rb
@@ -2,9 +2,11 @@
describe Mapper::Attribute::Custom,'#define_dumper' do
let(:object) { described_class.new(:name) }
- let(:dumper_klass) { Class.new.freeze }
+ let(:dumper_class) { Class.new.freeze }
- subject { object.define_dumper(dumper_klass) }
+ subject { object.define_dumper(dumper_class) }
+
+ it_should_behave_like 'a command method'
it 'should not modify dumper klass' do
subject
View
6 spec/unit/mapper/attribute/custom/define_loader_spec.rb
@@ -2,9 +2,11 @@
describe Mapper::Attribute::Custom,'#define_loader' do
let(:object) { described_class.new(:name) }
- let(:loader_klass) { Class.new.freeze }
+ let(:loader_class) { Class.new.freeze }
- subject { object.define_loader(loader_klass) }
+ subject { object.define_loader(loader_class) }
+
+ it_should_behave_like 'a command method'
it 'should not modify loader klass' do
subject
View
2  spec/unit/mapper/attribute/embedded_collection/load_spec.rb
@@ -6,7 +6,7 @@
let(:item) { mock }
let(:coerced) { mock }
let(:value) { [item] }
- let(:dump) { { :name => value } }
+ let(:dump) { mock(:name => value) }
subject { object.load(dump) }
View
2  spec/unit/mapper/attribute/embedded_document/load_spec.rb
@@ -7,7 +7,7 @@
subject { object.load(dump) }
let(:coerced) { mock }
- let(:dump) { { :name => value } }
+ let(:dump) { mock(:name => value) }
context 'when value is NOT nil' do
let(:value) { mock }
View
41 spec/unit/mapper/attribute/object/define_dump_reader_spec.rb
@@ -0,0 +1,41 @@
+require 'spec_helper'
+
+describe Mapper::Attribute::Object,'#define_dump_reader' do
+ let(:object) { described_class.new(name,options) }
+
+ let(:name) { :name }
+ let(:options) { {} }
+
+ let(:dumper_class) { mock }
+
+ subject { object.define_dump_reader(dumper_class) }
+
+ context 'when dump name is NOT changed' do
+
+ before do
+ dumper_class.should_receive(:define_reader).with(:name)
+ end
+
+ it 'should define method on dump name' do
+
+ subject
+ end
+
+ it_should_behave_like 'a command method'
+ end
+
+ context 'when dump name is changed' do
+ let(:options) { { :to => :other } }
+
+ before do
+ dumper_class.should_receive(:define_reader).with(:other)
+ end
+
+ it 'should define method on dump name' do
+
+ subject
+ end
+
+ it_should_behave_like 'a command method'
+ end
+end
View
29 spec/unit/mapper/attribute/object/define_dumper_spec.rb
@@ -6,15 +6,30 @@
let(:name) { :name }
let(:options) { {} }
- let(:dumper_klass) { mock }
+ let(:dumper_class) { Mapper::Transformer }
- subject { object.define_dumper(dumper_klass) }
- it 'should define method on dumper klass with correct ruby' do
- dumper_klass.
- should_receive(:class_eval).
- with(object.dumper_method_source,"/home/mbj/devel/mapper/lib/mapper/attribute/object.rb",33)
+ subject { object.define_dumper(dumper_class) }
- subject
+ context 'when dump name is NOT changed' do
+ it 'should define method on dump name' do
+ dumper_class.should_receive(:define_reader).with(:name)
+
+ subject
+ end
+
+ it_should_behave_like 'a command method'
+ end
+
+ context 'when dump name is changed' do
+ let(:options) { { :to => :other } }
+
+ it 'should define method on dump name' do
+ dumper_class.should_receive(:define_reader).with(:other)
+
+ subject
+ end
+
+ it_should_behave_like 'a command method'
end
end
View
12 spec/unit/mapper/attribute/object/define_loader_spec.rb
@@ -6,15 +6,15 @@
let(:name) { :name }
let(:options) { {} }
- let(:dumper_klass) { mock }
+ let(:dumper_class) { Mapper::Transformer }
- subject { object.define_loader(dumper_klass) }
+ subject { object.define_loader(dumper_class) }
- it 'should define method on dumper klass with correct ruby' do
- dumper_klass.
- should_receive(:class_eval).
- with(object.loader_method_source,"/home/mbj/devel/mapper/lib/mapper/attribute/object.rb",33)
+ it 'should define reader method on name' do
+ dumper_class.should_receive(:define_reader).with(:name)
subject
end
+
+ it_should_behave_like 'a command method'
end
View
31 spec/unit/mapper/attribute/object/dumper_method_source_spec.rb
@@ -1,31 +0,0 @@
-require 'spec_helper'
-
-describe Mapper::Attribute::Object,'#dumper_method_source' do
- let(:object) { described_class.new(name,options) }
-
- let(:name) { :name }
- let(:options) { {} }
-
- subject { object.dumper_method_source }
-
- context 'with defaults' do
- it 'should create correct ruby' do
- compress_prefix(subject).should == compress_prefix(<<-RUBY)
- def name
- memonized(:name)
- end
- RUBY
- end
- end
-
- context 'with aliased dump name' do
- let(:options) { { :to => :other } }
- it 'should create correct ruby' do
- compress_prefix(subject).should == compress_prefix(<<-RUBY)
- def other
- memonized(:other)
- end
- RUBY
- end
- end
-end
View
7 spec/unit/mapper/attribute/object/key_ques_spec.rb
@@ -5,28 +5,35 @@
subject { object.key? }
+
context 'when options are empty' do
let(:options) { {} }
it { should be_false }
+
+ it_should_behave_like 'an idempotent method'
end
context 'when option :key contains false' do
let(:options) { {:key => false } }
it { should be_false }
+ it_should_behave_like 'an idempotent method'
end
context 'when option :key contains a falsy value' do
let(:options) { {:key => nil } }
it { should be_false }
+ it_should_behave_like 'an idempotent method'
end
context 'when option :key contains a truly value' do
let(:options) { {:key => "foo" } }
it { should be_true }
+ it_should_behave_like 'an idempotent method'
end
context 'when option :key contains true' do
let(:options) { {:key => true } }
it { should be_true }
+ it_should_behave_like 'an idempotent method'
end
end
View
4 spec/unit/mapper/attribute/object/load_spec.rb
@@ -7,7 +7,7 @@
let(:options) { {} }
let(:value) { mock }
- let(:dump) { { :name => value } }
+ let(:dump) { mock(:name => value) }
subject { object.load(dump) }
@@ -19,7 +19,7 @@
context 'with aliased dump name' do
let(:options) { { :to => :other } }
- let(:dump) { { :other => value } }
+ let(:dump) { mock(:other => value) }
it 'should load value' do
should be(value)
end
View
31 spec/unit/mapper/attribute/object/loader_method_source_spec.rb
@@ -1,31 +0,0 @@
-require 'spec_helper'
-
-describe Mapper::Attribute::Object,'#loader_method_source' do
- let(:object) { described_class.new(name,options) }
-
- let(:name) { :name }
- let(:options) { {} }
-
- subject { object.loader_method_source }
-
- context 'with defaults' do
- it 'should create correct ruby' do
- compress_prefix(subject).should == compress_prefix(<<-RUBY)
- def name
- memonized(:name)
- end
- RUBY
- end
- end
-
- context 'with aliased dump name' do
- let(:options) { { :to => :other } }
- it 'should create correct ruby' do
- compress_prefix(subject).should == compress_prefix(<<-RUBY)
- def name
- memonized(:name)
- end
- RUBY
- end
- end
-end
View
4 spec/unit/mapper/attribute_set/add_spec.rb
@@ -6,6 +6,8 @@
subject { object.add(attribute) }
+ it_should_behave_like 'a command method'
+
it 'should add attribute to load names' do
subject
object.load_names.should == [:load_name]
@@ -24,6 +26,8 @@
object.dump_names
end
+ it_should_behave_like 'a command method'
+
it 'should add attribute to load names' do
subject
object.load_names.to_set.should == [:something,:load_name].to_set
View
44 spec/unit/mapper/attribute_set/dump_key_names_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe Mapper::AttributeSet,'#dump_key_names' do
+ let(:object) { described_class.new }
+ let(:key_attribute) { Mapper::Attribute::Object.new(:key,:key => true) }
+ let(:other_attribute) { Mapper::Attribute::Object.new(:foo) }
+
+ subject { object.dump_key_names }
+
+ context 'when set is empty' do
+ it { should be_empty }
+ end
+
+ context 'when set only contains non key attributes' do
+ before do
+ object.add(other_attribute)
+ end
+
+ it { should be_empty }
+ end
+
+ context 'when set contains key attribute' do
+ before do
+ object.add(other_attribute)
+ object.add(key_attribute)
+ end
+
+ it 'return key attribute dump name' do
+ should == [:key]
+ end
+ end
+
+ context 'when we accessed dump_key names before adding new attribute' do
+ before do
+ object.add(other_attribute)
+ object.dump_key_names
+ object.add(key_attribute)
+ end
+
+ it 'return key attribute dump name' do
+ should == [:key]
+ end
+ end
+end
View
2  spec/unit/mapper/attribute_set/empty_ques_spec.rb
@@ -7,6 +7,7 @@
context 'when empty' do
it { should be_true }
+ it_should_behave_like 'an idempotent method'
end
context 'when not empty' do
@@ -14,6 +15,7 @@
object.add(Mapper::Attribute::Object.new(:foo))
end
+ it_should_behave_like 'an idempotent method'
it { should be_false }
end
end
View
2  spec/unit/mapper/attribute_set/fetch_dump_name_spec.rb
@@ -19,6 +19,8 @@
it 'should return attribute' do
should be(attribute)
end
+
+ it_should_behave_like 'an idempotent method'
end
context 'when dump name does NOT exist' do
View
2  spec/unit/mapper/attribute_set/fetch_load_name_spec.rb
@@ -19,6 +19,8 @@
it 'should return attribute' do
should be(attribute)
end
+
+ it_should_behave_like 'an idempotent method'
end
context 'when load name does NOT exist' do
View
2  spec/unit/mapper/class_methods/attributes_spec.rb
@@ -9,6 +9,8 @@
Mapper.new
end
+ it_should_behave_like 'an idempotent method'
+
it { should be_kind_of(Mapper::AttributeSet) }
it { should be_empty }
end
View
3  spec/unit/mapper/class_methods/const_missing_spec.rb
@@ -8,16 +8,19 @@
context 'when :Object is passed' do
let(:value) { :Object }
it { should be(Mapper::Attribute::Object) }
+ it_should_behave_like 'an idempotent method'
end
context 'when :EmbeddedCollection is passed' do
let(:value) { :EmbeddedCollection }
it { should be(Mapper::Attribute::EmbeddedCollection) }
+ it_should_behave_like 'an idempotent method'
end
context 'when :EmbeddedDocument is passed' do
let(:value) { :EmbeddedDocument }
it { should be(Mapper::Attribute::EmbeddedDocument) }
+ it_should_behave_like 'an idempotent method'
end
context 'when :UnkownMapping is passed' do
View
6 spec/unit/mapper/class_methods/dump_spec.rb
@@ -2,11 +2,7 @@
describe Mapper::ClassMethods,'#dump' do
let(:domain_object) do
- Object.new.extend(Module.new do
- def foo
- :bar
- end
- end)
+ DomainObject.new(:foo => :bar)
end
let(:described_class) do
View
2  spec/unit/mapper/class_methods/dumper_spec.rb
@@ -14,5 +14,5 @@
subject { object.dumper(domain_object) }
its(:class) { should == described_class::Dumper }
- its(:object) { should == domain_object }
+ its(:source) { should == domain_object }
end
View
2  spec/unit/mapper/class_methods/loader_spec.rb
@@ -14,5 +14,5 @@
subject { object.loader(dump) }
its(:class) { should == described_class::Loader }
- its(:dump) { should == dump }
+ its(:source) { should be_kind_of(described_class::DumpWrapper) }
end
View
57 spec/unit/mapper/transformer/class_methods/define_reader_spec.rb
@@ -0,0 +1,57 @@
+# encoding: utf-8
+
+require 'spec_helper'
+
+describe Mapper::Transformer, '#define_reader' do
+ let(:object) do
+ Class.new(described_class) do
+ def read(name)
+ name
+ end
+ end
+ end
+
+ let(:instance) do
+ object.new(mock,mock)
+ end
+
+ let(:name) { :foo }
+
+ subject { object.define_reader(name) }
+
+ it_should_behave_like 'a command method'
+
+ it 'creates a method #foo' do
+ expect { subject }.to change { instance.respond_to?(:foo) }.
+ from(false).
+ to(true)
+ end
+
+ it 'defines #foo as #read(:foo)' do
+ subject
+ instance.foo.should == :foo
+ end
+
+ specification = proc do
+ object.class_eval do
+ def read(name)
+ caller
+ end
+ end
+
+ subject
+
+ file, line = instance.foo.first.split(':')[0, 2]
+
+ File.expand_path(file).should eql(File.expand_path('../../../../../../lib/mapper/transformer.rb', __FILE__))
+ line.to_i.should eql(56)
+ end
+
+ it 'sets the file and line number properly' do
+ if RUBY_PLATFORM.include?('java')
+ pending('Kernel#caller returns the incorrect line number in JRuby', &specification)
+ else
+ instance_eval(&specification)
+ end
+ end
+end
View
3  spec/unit/mapper/transformer/class_methods/mapper_spec.rb
@@ -9,6 +9,7 @@
subject { object.mapper }
+
context 'when mapper setup was done' do
before do
object.instance_variable_set(:@mapper,mapper)
@@ -17,6 +18,8 @@
it 'should return mapper' do
should be(mapper)
end
+
+ it_should_behave_like 'an idempotent method'
end
context 'when mapper setup was NOT done' do
View
2  spec/unit/mapper/transformer/class_methods/reader_method_source_spec.rb
@@ -10,7 +10,7 @@
it 'should return correct ruby' do
compress_prefix(subject).should == compress_prefix(<<-RUBY)
def foo
- memonized(:foo)
+ read(:foo)
end
RUBY
end
View
26 spec/unit/mapper/transformer/dump_wrapper/read_spec.rb
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+describe Mapper::Transformer::DumpWrapper,'#read' do
+ let(:object) { described_class.new(data) }
+ subject { object.send(:read,name) }
+
+ let(:data) { { :foo => :bar } }
+
+ context 'when name does exist' do
+ let(:name) { :foo }
+
+ it 'should return value' do
+ should == :bar
+ end
+
+ it_should_behave_like 'an idempotent method'
+ end
+
+ context 'when name does NOT exist' do
+ let(:name) { :unexistend }
+
+ it 'should raise error' do
+ expect { subject }.to raise_error(IndexError)
+ end
+ end
+end
View
15 spec/unit/mapper/transformer/dumper/dump_spec.rb
@@ -1,15 +1,8 @@
require 'spec_helper'
describe Mapper::Transformer::Dumper,'#dump' do
- let(:domain_object) do
- mock(:foo => :bar)
- end
-
- let(:mapper) do
- ::Mapper.new do
- map :foo, Object
- end
- end
+ let(:domain_object) { DomainObject.new }
+ let(:mapper) { DomainObjectMapper }
let(:described_class) { mapper::Dumper }
let(:object) { described_class.new(domain_object) }
@@ -20,7 +13,9 @@
object.stub(:mapper => mapper)
end
+ it_should_behave_like 'an idempotent method'
+
it 'should return dumped object' do
- should == { :foo => :bar }
+ should == { :foo => :bar, :id => 1 }
end
end
View
25 spec/unit/mapper/transformer/dumper/key_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe Mapper::Transformer::Dumper,'#key' do
+ let(:mapper) do
+ Mapper.new do
+ map :id, Object, :key => true
+ map :foo, Object
+ end
+ end
+
+ let(:domain_object) do
+ DomainObject.new(:id => :some_key,:foo => :bar)
+ end
+
+ let(:described_class) { mapper::Dumper }
+ let(:object) { described_class.new(domain_object) }
+
+ subject { object.key }
+
+ it_should_behave_like 'an idempotent method'
+
+ it 'should return domain objects key' do
+ should == { :id => :some_key }
+ end
+end
View
12 spec/unit/mapper/transformer/dumper/object_spec.rb
@@ -1,12 +0,0 @@
-require 'spec_helper'
-
-describe Mapper::Transformer::Dumper,'#object' do
- let(:object) { described_class.new(domain_object) }
- let(:domain_object) { mock }
-
- subject { object.object }
-
- it 'should return wrapped object' do
- should be(domain_object)
- end
-end
View
2  spec/unit/mapper/transformer/loader/attributes_spec.rb
@@ -19,4 +19,6 @@
end
it { should == { :foo => :bar } }
+
+ it_should_behave_like 'an idempotent method'
end
View
12 spec/unit/mapper/transformer/loader/dump_spec.rb
@@ -1,12 +0,0 @@
-require 'spec_helper'
-
-describe Mapper::Transformer::Loader,'#dump' do
- let(:object) { described_class.new(dump) }
- let(:dump) { mock }
-
- subject { object.dump }
-
- it 'should return wrapped dump' do
- should be(dump)
- end
-end
View
2  spec/unit/mapper/transformer/loader/object_spec.rb
@@ -21,4 +21,6 @@
its(:class) { should == DomainObject }
its(:foo) { should == :bar }
+
+ it_should_behave_like 'an idempotent method'
end
View
8 spec/unit/mapper/transformer/mapper_spec.rb
@@ -7,13 +7,17 @@
end
end
- let(:mapper) { mock }
+ let(:source) { mock }
+ let(:operation) { mock }
+ let(:mapper) { mock }
- let(:object) { described_class.new }
+ let(:object) { described_class.new(source,operation) }
subject { object.mapper }
it 'should return class mapper' do
should be(mapper)
end
+
+ it_should_behave_like 'an idempotent method'
end
View
14 spec/unit/mapper/transformer/source_spec.rb
@@ -0,0 +1,14 @@
+require 'spec_helper'
+
+describe Mapper::Transformer,'#source' do
+ let(:object) { described_class.new(source,:operation) }
+ let(:source) { mock }
+
+ subject { object.source }
+
+ it 'should return source' do
+ should be(source)
+ end
+
+ it_should_behave_like 'an idempotent method'
+end
Please sign in to comment.
Something went wrong with that request. Please try again.