rom 0.2.0 → 0.3.0

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.
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