rom 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -3
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +13 -14
  5. data/{Changelog.md → CHANGELOG.md} +12 -3
  6. data/Gemfile +14 -10
  7. data/Gemfile.devtools +16 -16
  8. data/Guardfile +2 -5
  9. data/README.md +68 -56
  10. data/Rakefile +3 -3
  11. data/config/flay.yml +2 -2
  12. data/config/mutant.yml +2 -4
  13. data/config/rubocop.yml +30 -0
  14. data/lib/rom.rb +47 -9
  15. data/lib/rom/adapter.rb +52 -0
  16. data/lib/rom/adapter/memory.rb +70 -0
  17. data/lib/rom/boot.rb +158 -0
  18. data/lib/rom/boot/base_relation_dsl.rb +43 -0
  19. data/lib/rom/boot/dsl.rb +30 -0
  20. data/lib/rom/boot/mapper_dsl.rb +23 -0
  21. data/lib/rom/boot/relation_dsl.rb +23 -0
  22. data/lib/rom/boot/schema_dsl.rb +27 -0
  23. data/lib/rom/env.rb +48 -0
  24. data/lib/rom/header.rb +123 -0
  25. data/lib/rom/mapper.rb +38 -153
  26. data/lib/rom/mapper_builder.rb +85 -0
  27. data/lib/rom/model_builder.rb +58 -0
  28. data/lib/rom/ra.rb +196 -0
  29. data/lib/rom/ra/operation/group.rb +49 -0
  30. data/lib/rom/ra/operation/join.rb +41 -0
  31. data/lib/rom/ra/operation/wrap.rb +45 -0
  32. data/lib/rom/reader.rb +62 -0
  33. data/lib/rom/reader_builder.rb +28 -0
  34. data/lib/rom/relation.rb +41 -350
  35. data/lib/rom/relation_builder.rb +48 -0
  36. data/lib/rom/repository.rb +28 -53
  37. data/lib/rom/support/registry.rb +34 -0
  38. data/lib/rom/version.rb +3 -0
  39. data/rom.gemspec +12 -10
  40. data/spec/integration/adapters/extending_relations_spec.rb +43 -0
  41. data/spec/integration/mappers/definition_dsl_spec.rb +82 -0
  42. data/spec/integration/mappers/prefixing_attributes_spec.rb +42 -0
  43. data/spec/integration/mappers/renaming_attributes_spec.rb +138 -0
  44. data/spec/integration/ra/group_spec.rb +47 -0
  45. data/spec/integration/ra/join_spec.rb +24 -0
  46. data/spec/integration/ra/wrap_spec.rb +37 -0
  47. data/spec/integration/relations/reading_spec.rb +116 -0
  48. data/spec/integration/relations/registry_dsl_spec.rb +44 -0
  49. data/spec/integration/schema_spec.rb +29 -0
  50. data/spec/integration/setup_spec.rb +18 -0
  51. data/spec/shared/users_and_tasks.rb +34 -0
  52. data/spec/spec_helper.rb +14 -36
  53. data/spec/unit/rom/adapter_spec.rb +59 -0
  54. data/spec/unit/rom/header_spec.rb +58 -0
  55. data/spec/unit/rom/mapper_spec.rb +27 -0
  56. data/spec/unit/rom/ra/operation/group_spec.rb +55 -0
  57. data/spec/unit/rom/ra/operation/wrap_spec.rb +29 -0
  58. data/spec/unit/rom/relation_spec.rb +34 -0
  59. metadata +122 -190
  60. data/lib/rom/constants.rb +0 -16
  61. data/lib/rom/environment.rb +0 -105
  62. data/lib/rom/environment/builder.rb +0 -71
  63. data/lib/rom/mapper/attribute.rb +0 -108
  64. data/lib/rom/mapper/builder.rb +0 -58
  65. data/lib/rom/mapper/builder/definition.rb +0 -162
  66. data/lib/rom/mapper/header.rb +0 -103
  67. data/lib/rom/mapper/loader_builder.rb +0 -26
  68. data/lib/rom/schema.rb +0 -21
  69. data/lib/rom/schema/builder.rb +0 -59
  70. data/lib/rom/schema/definition.rb +0 -84
  71. data/lib/rom/schema/definition/relation.rb +0 -80
  72. data/lib/rom/schema/definition/relation/base.rb +0 -27
  73. data/lib/rom/session.rb +0 -111
  74. data/lib/rom/session/environment.rb +0 -67
  75. data/lib/rom/session/identity_map.rb +0 -43
  76. data/lib/rom/session/mapper.rb +0 -62
  77. data/lib/rom/session/relation.rb +0 -140
  78. data/lib/rom/session/state.rb +0 -59
  79. data/lib/rom/session/state/created.rb +0 -22
  80. data/lib/rom/session/state/deleted.rb +0 -25
  81. data/lib/rom/session/state/persisted.rb +0 -34
  82. data/lib/rom/session/state/transient.rb +0 -20
  83. data/lib/rom/session/state/updated.rb +0 -29
  84. data/lib/rom/session/tracker.rb +0 -62
  85. data/lib/rom/support/axiom/adapter.rb +0 -111
  86. data/lib/rom/support/axiom/adapter/data_objects.rb +0 -38
  87. data/lib/rom/support/axiom/adapter/memory.rb +0 -25
  88. data/lib/rom/support/axiom/adapter/postgres.rb +0 -19
  89. data/lib/rom/support/axiom/adapter/sqlite3.rb +0 -20
  90. data/lib/version.rb +0 -3
  91. data/spec/integration/environment_setup_spec.rb +0 -24
  92. data/spec/integration/grouped_mappers_spec.rb +0 -87
  93. data/spec/integration/join_and_group_spec.rb +0 -76
  94. data/spec/integration/join_and_wrap_spec.rb +0 -68
  95. data/spec/integration/mapping_embedded_relations_spec.rb +0 -73
  96. data/spec/integration/mapping_relations_spec.rb +0 -120
  97. data/spec/integration/schema_definition_spec.rb +0 -152
  98. data/spec/integration/session_spec.rb +0 -87
  99. data/spec/integration/wrapped_mappers_spec.rb +0 -73
  100. data/spec/shared/unit/environment_context.rb +0 -6
  101. data/spec/shared/unit/loader.rb +0 -11
  102. data/spec/shared/unit/loader_identity.rb +0 -13
  103. data/spec/shared/unit/mapper_context.rb +0 -11
  104. data/spec/shared/unit/relation_context.rb +0 -82
  105. data/spec/shared/unit/session_environment_context.rb +0 -11
  106. data/spec/shared/unit/session_relation_context.rb +0 -18
  107. data/spec/support/helper.rb +0 -34
  108. data/spec/support/ice_nine_config.rb +0 -10
  109. data/spec/support/test_mapper.rb +0 -110
  110. data/spec/unit/rom/environment/builder/mapping_spec.rb +0 -24
  111. data/spec/unit/rom/environment/builder/schema_spec.rb +0 -33
  112. data/spec/unit/rom/environment/class_methods/setup_spec.rb +0 -18
  113. data/spec/unit/rom/environment/repository_spec.rb +0 -21
  114. data/spec/unit/rom/mapper/attribute/embedded_collection/to_ast_spec.rb +0 -18
  115. data/spec/unit/rom/mapper/attribute/embedded_value/to_ast_spec.rb +0 -16
  116. data/spec/unit/rom/mapper/attribute/rename_spec.rb +0 -9
  117. data/spec/unit/rom/mapper/attribute/to_ast_spec.rb +0 -9
  118. data/spec/unit/rom/mapper/builder/class_methods/call_spec.rb +0 -61
  119. data/spec/unit/rom/mapper/class_methods/build_spec.rb +0 -55
  120. data/spec/unit/rom/mapper/dump_spec.rb +0 -11
  121. data/spec/unit/rom/mapper/group_spec.rb +0 -35
  122. data/spec/unit/rom/mapper/header/each_spec.rb +0 -26
  123. data/spec/unit/rom/mapper/header/element_reader_spec.rb +0 -21
  124. data/spec/unit/rom/mapper/header/group_spec.rb +0 -18
  125. data/spec/unit/rom/mapper/header/join_spec.rb +0 -14
  126. data/spec/unit/rom/mapper/header/keys_spec.rb +0 -29
  127. data/spec/unit/rom/mapper/header/project_spec.rb +0 -13
  128. data/spec/unit/rom/mapper/header/rename_spec.rb +0 -11
  129. data/spec/unit/rom/mapper/header/to_ast_spec.rb +0 -11
  130. data/spec/unit/rom/mapper/header/wrap_spec.rb +0 -18
  131. data/spec/unit/rom/mapper/identity_from_tuple_spec.rb +0 -11
  132. data/spec/unit/rom/mapper/identity_spec.rb +0 -11
  133. data/spec/unit/rom/mapper/join_spec.rb +0 -15
  134. data/spec/unit/rom/mapper/load_spec.rb +0 -11
  135. data/spec/unit/rom/mapper/new_object_spec.rb +0 -14
  136. data/spec/unit/rom/mapper/project_spec.rb +0 -11
  137. data/spec/unit/rom/mapper/rename_spec.rb +0 -16
  138. data/spec/unit/rom/mapper/wrap_spec.rb +0 -35
  139. data/spec/unit/rom/relation/delete_spec.rb +0 -15
  140. data/spec/unit/rom/relation/drop_spec.rb +0 -11
  141. data/spec/unit/rom/relation/each_spec.rb +0 -23
  142. data/spec/unit/rom/relation/first_spec.rb +0 -19
  143. data/spec/unit/rom/relation/group_spec.rb +0 -29
  144. data/spec/unit/rom/relation/inject_mapper_spec.rb +0 -17
  145. data/spec/unit/rom/relation/insert_spec.rb +0 -13
  146. data/spec/unit/rom/relation/last_spec.rb +0 -19
  147. data/spec/unit/rom/relation/one_spec.rb +0 -49
  148. data/spec/unit/rom/relation/rename_spec.rb +0 -21
  149. data/spec/unit/rom/relation/replace_spec.rb +0 -13
  150. data/spec/unit/rom/relation/restrict_spec.rb +0 -25
  151. data/spec/unit/rom/relation/sort_by_spec.rb +0 -25
  152. data/spec/unit/rom/relation/take_spec.rb +0 -11
  153. data/spec/unit/rom/relation/to_a_spec.rb +0 -20
  154. data/spec/unit/rom/relation/update_spec.rb +0 -25
  155. data/spec/unit/rom/relation/wrap_spec.rb +0 -29
  156. data/spec/unit/rom/repository/class_methods/build_spec.rb +0 -27
  157. data/spec/unit/rom/repository/element_reader_spec.rb +0 -21
  158. data/spec/unit/rom/repository/element_writer_spec.rb +0 -18
  159. data/spec/unit/rom/schema/builder/class_methods/build_spec.rb +0 -103
  160. data/spec/unit/rom/schema/element_reader_spec.rb +0 -15
  161. data/spec/unit/rom/session/class_methods/start_spec.rb +0 -23
  162. data/spec/unit/rom/session/clean_predicate_spec.rb +0 -21
  163. data/spec/unit/rom/session/environment/element_reader_spec.rb +0 -13
  164. data/spec/unit/rom/session/flush_spec.rb +0 -58
  165. data/spec/unit/rom/session/mapper/load_spec.rb +0 -47
  166. data/spec/unit/rom/session/relation/delete_spec.rb +0 -28
  167. data/spec/unit/rom/session/relation/dirty_predicate_spec.rb +0 -35
  168. data/spec/unit/rom/session/relation/identity_spec.rb +0 -11
  169. data/spec/unit/rom/session/relation/new_spec.rb +0 -50
  170. data/spec/unit/rom/session/relation/save_spec.rb +0 -50
  171. data/spec/unit/rom/session/relation/state_spec.rb +0 -23
  172. data/spec/unit/rom/session/relation/track_spec.rb +0 -23
  173. data/spec/unit/rom/session/relation/tracking_predicate_spec.rb +0 -23
  174. data/spec/unit/rom/session/relation/update_attributes_spec.rb +0 -45
  175. data/spec/unit/rom/session/state_spec.rb +0 -79
@@ -0,0 +1,27 @@
1
+ require 'rom/boot/base_relation_dsl'
2
+
3
+ module ROM
4
+ class Boot
5
+
6
+ class SchemaDSL
7
+ attr_reader :env, :schema
8
+
9
+ def initialize(env, schema = {})
10
+ @env = env
11
+ @schema = schema
12
+ end
13
+
14
+ def base_relation(name, &block)
15
+ dsl = BaseRelationDSL.new(env, name)
16
+ definition = dsl.call(&block)
17
+ (schema[dsl.repository] ||= []) << definition
18
+ end
19
+
20
+ def call
21
+ schema
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
data/lib/rom/env.rb ADDED
@@ -0,0 +1,48 @@
1
+ module ROM
2
+
3
+ # Exposes defined repositories, schema, relations and mappers
4
+ #
5
+ # @api public
6
+ class Env
7
+ include Adamantium::Flat
8
+
9
+ attr_reader :repositories, :schema, :relations, :mappers
10
+
11
+ # @api private
12
+ def initialize(repositories, schema, relations, mappers)
13
+ @repositories = repositories
14
+ @schema = schema
15
+ @relations = relations
16
+ @mappers = mappers
17
+ end
18
+
19
+ # Returns a reader with access to defined mappers
20
+ #
21
+ # @example
22
+ #
23
+ # rom.read(:users).adults.to_a
24
+ #
25
+ # @api public
26
+ def read(name)
27
+ mappers[name]
28
+ end
29
+
30
+ # @api private
31
+ def [](name)
32
+ repositories.fetch(name)
33
+ end
34
+
35
+ # @api private
36
+ def respond_to_missing?(name, include_private = false)
37
+ repositories.key?(name)
38
+ end
39
+
40
+ private
41
+
42
+ # @api private
43
+ def method_missing(name, *args)
44
+ repositories.fetch(name)
45
+ end
46
+ end
47
+
48
+ end
data/lib/rom/header.rb ADDED
@@ -0,0 +1,123 @@
1
+ module ROM
2
+
3
+ # @api private
4
+ class Header
5
+ include Enumerable
6
+ include Equalizer.new(:attributes)
7
+
8
+ attr_reader :attributes
9
+
10
+ class Attribute
11
+ include Equalizer.new(:name, :key, :type)
12
+
13
+ attr_reader :name, :key, :meta
14
+
15
+ class Embedded < Attribute
16
+ include Equalizer.new(:name, :type, :model, :header)
17
+
18
+ def model
19
+ meta[:model]
20
+ end
21
+
22
+ def header
23
+ meta.fetch(:header)
24
+ end
25
+
26
+ def mapping
27
+ [name, header.mapping]
28
+ end
29
+
30
+ def embedded?
31
+ true
32
+ end
33
+
34
+ end
35
+
36
+ def self.[](type)
37
+ if type == Array || type == Hash
38
+ Embedded
39
+ else
40
+ self
41
+ end
42
+ end
43
+
44
+ def self.coerce(input)
45
+ if input.kind_of?(self)
46
+ input
47
+ else
48
+ name = input[0]
49
+ meta = (input[1] || {}).dup
50
+
51
+ meta[:type] ||= Object
52
+
53
+ if meta.key?(:header)
54
+ meta[:header] = Header.coerce(meta[:header])
55
+ end
56
+
57
+ self[meta[:type]].new(name, meta)
58
+ end
59
+ end
60
+
61
+ def initialize(name, meta = {})
62
+ @name = name
63
+ @meta = meta
64
+ @key = meta.fetch(:from) { name }
65
+ end
66
+
67
+ def type
68
+ meta.fetch(:type)
69
+ end
70
+
71
+ def aliased?
72
+ key != name
73
+ end
74
+
75
+ def embedded?
76
+ false
77
+ end
78
+
79
+ def mapping
80
+ [key, name]
81
+ end
82
+ end
83
+
84
+ def self.coerce(input)
85
+ if input.kind_of?(self)
86
+ input
87
+ else
88
+ attributes = input.each_with_object({}) { |pair, h|
89
+ h[pair.first] = Attribute.coerce(pair)
90
+ }
91
+
92
+ new(attributes)
93
+ end
94
+ end
95
+
96
+ def initialize(attributes)
97
+ @attributes = attributes
98
+ end
99
+
100
+ def each(&block)
101
+ return to_enum unless block
102
+ attributes.values.each(&block)
103
+ end
104
+
105
+ def keys
106
+ attributes.keys
107
+ end
108
+
109
+ def mapping
110
+ Hash[map(&:mapping)]
111
+ end
112
+
113
+ def values
114
+ attributes.values
115
+ end
116
+
117
+ def [](name)
118
+ attributes.fetch(name)
119
+ end
120
+
121
+ end
122
+
123
+ end
data/lib/rom/mapper.rb CHANGED
@@ -1,176 +1,61 @@
1
- # encoding: utf-8
2
-
3
- require 'ostruct'
4
-
5
- require 'rom/constants'
6
- require 'rom/mapper/header'
7
- require 'rom/mapper/loader_builder'
8
-
9
1
  module ROM
10
2
 
11
- # Mappers load tuples into objects and dump objects back into tuples
12
- #
3
+ # @api private
13
4
  class Mapper
14
- include Equalizer.new(:header, :options)
15
-
16
- DEFAULT_LOADER = :load_instance_variables
17
-
18
- attr_reader :header, :loader, :dumper, :model, :type, :options
5
+ attr_reader :header, :model
19
6
 
20
- # Build a mapper
21
- #
22
- # @example
23
- #
24
- # User = Class.new { attr_reader :id, :name }
25
- #
26
- # mapper = ROM::Mapper.build([[:id, from: :user_id], [:name, from: :user_name]], model: User)
27
- #
28
- # user = mapper.load(user_id: 1, user_name: 'Jane')
29
- # # => #<User:0x007fee3b8bf2c8 @id=1, @name="Jane">
30
- #
31
- # tuple = mapper.dump(user)
32
- # # => [1, "Jane"]
33
- #
34
- # @return [Mapper]
35
- #
36
- # @api public
37
- def self.build(attributes, options = EMPTY_HASH)
38
- defaults = { type: DEFAULT_LOADER, model: OpenStruct }.update(options)
7
+ class Basic < Mapper
8
+ attr_reader :mapping
39
9
 
40
- header = Header.build(attributes)
41
- loader = LoaderBuilder.call(header, defaults[:model], defaults[:type])
42
-
43
- new(header, loader, defaults)
44
- end
45
-
46
- # @api private
47
- def initialize(header, loader, options)
48
- @header = header
49
- @loader = loader
50
- @dumper = loader.inverse
51
- @model = options.fetch(:model)
52
- @type = options.fetch(:type)
53
- @options = options
54
- end
55
-
56
- # Retrieve identity from the given object
57
- #
58
- # @example
59
- #
60
- # mapper.identity(user) # => [1]
61
- #
62
- # @param [Object]
63
- #
64
- # @return [Array]
65
- #
66
- # @api public
67
- def identity(object)
68
- header.keys.map { |key| object.send(key.name) }
69
- end
70
-
71
- # Return identity from the given tuple
72
- #
73
- # @example
74
- #
75
- # mapper.identity_from_tuple({id: 1}) # => [1]
76
- #
77
- # @param [Axiom::Tuple,Hash]
78
- #
79
- # @return [Array]
80
- #
81
- # @api public
82
- def identity_from_tuple(tuple)
83
- header.keys.map { |key| tuple[key.name] }
84
- end
10
+ def initialize(header, model)
11
+ super
12
+ @mapping = header.mapping
13
+ end
85
14
 
86
- # Build a new model instance
87
- #
88
- # @example
89
- #
90
- # mapper = Mapper.build(header, User)
91
- # mapper.new_object(id: 1, name: 'Jane') # => #<User @id=1 @name="Jane">
92
- #
93
- # @api public
94
- def new_object(*args, &block)
95
- model.new(*args, &block)
96
- end
15
+ def load(tuple, mapping = self.mapping)
16
+ model.new(Hash[call(tuple, mapping)])
17
+ end
97
18
 
98
- # Load an object instance from the tuple
99
- #
100
- # @api public
101
- def load(tuple)
102
- loader.call(tuple)
19
+ def call(tuple, mapping = self.mapping)
20
+ tuple.map { |key, value| [mapping[key], value] }
21
+ end
103
22
  end
104
23
 
105
- # Dump an object into a tuple
106
- #
107
- # @api public
108
- #
109
- # TODO: it's not clear how a tuple should look like for grouped/wrapped
110
- # relation. the current implementation is temporary
111
- def dump(object)
112
- ary = dumper.call(object)
113
-
114
- ary.each_with_object([]) do |(name, value), tuple|
115
- attribute = header.detect { |attr| attr.tuple_key == name }
116
-
117
- if attribute.respond_to?(:header)
118
- names = attribute.header.attribute_names
119
-
120
- if value.is_a?(Hash)
121
- tuple << value.values_at(*names)
122
- elsif value.is_a?(Array)
123
- tuple << value.map { |v| v.values_at(*names) }
24
+ class Recursive < Basic
25
+ def call(tuple, mapping = self.mapping)
26
+ tuple.map do |key, value|
27
+ case value
28
+ when Hash then [key, Hash[call(value, mapping[key])]]
29
+ when Array then [key, value.map { |v| Hash[call(v, mapping[key])] }]
124
30
  else
125
- raise NotImplementedError
31
+ [mapping[key], value]
126
32
  end
127
- else
128
- tuple << value
129
33
  end
130
34
  end
131
35
  end
132
36
 
133
- # TODO: this should map the wrapping hash into {Symbol => Mapper::Header}
134
- # otherwise header is coupled to mapper
135
- #
136
- # @api public
137
- def wrap(other)
138
- new(header.wrap(other))
139
- end
140
-
141
- # TODO: this should map the grouping hash into {Symbol => Mapper::Header}
142
- # otherwise header is coupled to mapper
143
- #
144
- # @api public
145
- def group(other)
146
- new(header.group(other))
147
- end
148
-
149
- # @api public
150
- def join(other)
151
- new(header.join(other.header))
152
- end
153
-
154
- # @api public
155
- def project(names)
156
- new(header.project(names))
157
- end
37
+ def self.build(header, model)
38
+ klass =
39
+ if header.any? { |attribute| attribute.embedded? }
40
+ Recursive
41
+ elsif header.any? { |attribute| attribute.aliased? }
42
+ Basic
43
+ else
44
+ self
45
+ end
158
46
 
159
- # @api public
160
- def rename(names)
161
- new(header.rename(names))
47
+ klass.new(header, model)
162
48
  end
163
49
 
164
- # @api private
165
- def attribute(type, name)
166
- type.build(name, type: model, header: header, node: loader.node)
50
+ def initialize(header, model)
51
+ @header = header
52
+ @model = model
167
53
  end
168
54
 
169
- # @api private
170
- def new(new_header)
171
- self.class.build(new_header, options)
55
+ def load(tuple)
56
+ model.new(tuple)
172
57
  end
173
58
 
174
- end # Mapper
59
+ end
175
60
 
176
- end # ROM
61
+ end
@@ -0,0 +1,85 @@
1
+ require 'rom/model_builder'
2
+
3
+ module ROM
4
+
5
+ # @api private
6
+ class MapperBuilder
7
+
8
+ class AttributeDSL
9
+ attr_reader :attributes
10
+
11
+ def initialize
12
+ @attributes = []
13
+ end
14
+
15
+ def header
16
+ Header.coerce(attributes)
17
+ end
18
+
19
+ def attribute(name, options)
20
+ attributes << [name, options]
21
+ end
22
+ end
23
+
24
+ attr_reader :name, :root, :prefix,
25
+ :model_builder, :model_class, :attributes
26
+
27
+ def initialize(name, root, options = {})
28
+ @name = name
29
+ @root = root
30
+ @prefix = options[:prefix]
31
+ @attributes = root.header.map { |attr| [prefix ? :"#{prefix}_#{attr}" : attr] }
32
+ end
33
+
34
+ def model(options)
35
+ if options.is_a?(Class)
36
+ @model_class = options
37
+ else
38
+ @model_builder = ModelBuilder[options.fetch(:type) { :poro }].new(options)
39
+ end
40
+
41
+ self
42
+ end
43
+
44
+ def attribute(name, options = {})
45
+ options[:from] = :"#{prefix}_#{name}" if prefix
46
+ attributes << [name, options]
47
+ end
48
+
49
+ def exclude(name)
50
+ attributes.delete([name])
51
+ end
52
+
53
+ def group(options, &block)
54
+ attribute_dsl(options, Array, &block)
55
+ end
56
+
57
+ def wrap(options, &block)
58
+ attribute_dsl(options, Hash, &block)
59
+ end
60
+
61
+ def call
62
+ header = Header.coerce(attributes)
63
+
64
+ @model_class = model_builder.call(header) if model_builder
65
+
66
+ Mapper.build(header, model_class)
67
+ end
68
+
69
+ private
70
+
71
+ def attribute_dsl(options, type, &block)
72
+ if block
73
+ dsl = AttributeDSL.new
74
+ dsl.instance_exec(&block)
75
+ attributes << [options, header: dsl.header, type: type]
76
+ else
77
+ options.each do |name, header|
78
+ attributes << [name, header: header.zip, type: type]
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+
85
+ end