lazy_mapper 0.2.1 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9fc03c578aa1fc21f450802874c88cacfd78512e963d8dd840c59a3258bb18cf
4
- data.tar.gz: 6566aec14a6fd1c00eac05f3e5c973c5a48628e086c2631641c426426240bd97
3
+ metadata.gz: d96e0b06dde82ad35dad5af9b8df984d184350697d3b52bc13bca736d4fddc83
4
+ data.tar.gz: 3da907ac56b03e014ac47a0bcc21fdb9bd15727efe34ac72ceba9c80f2fe2687
5
5
  SHA512:
6
- metadata.gz: 8ef3c23e999803cae1da99eeb44cc6185be584507e32f1cf2ba827fe218d09ee9ff3d7d891b3647fa8bb71500d8208d0fbc868af7d72c1c3fc4b748ac6a01d2a
7
- data.tar.gz: abd2639ae80601c08b13a861e9d76ae7271e3da5d93f1027e81f4623f681614b6c8fadaed0bb22ef54ffb4806eb81b7e09e54a5e494f78ca43af5ea53bb58ef1
6
+ metadata.gz: 0ec71a118de6245dcf684f3a7380f2b83400305c9a62ac1734f88672eff5b97c9b253e10408b13bdde3b12b37dafbfd8f3b7f775737145a2ff42b8479875810d
7
+ data.tar.gz: 0da914f451230d8a9bbbe341aa47fb806e5465a5a0b60adb868b0484ed3a63b7895cea42788f077b606afeda188729e865c2a1f7559667f025dd098797bc8403
data/.rubocop.yml ADDED
@@ -0,0 +1,124 @@
1
+ Metrics/CyclomaticComplexity:
2
+ Enabled: false
3
+
4
+ Metrics/LineLength:
5
+ Max: 120
6
+ # To make it possible to copy or click on URIs in the code, we allow lines
7
+ # containing a URI to be longer than Max.
8
+ AllowHeredoc: true
9
+ AllowURI: true
10
+ URISchemes:
11
+ - http
12
+ - https
13
+
14
+ Metrics/MethodLength:
15
+ CountComments: false # count full line comments?
16
+ Max: 15
17
+
18
+ Metrics/ClassLength:
19
+ CountComments: false # count full line comments?
20
+ Max: 150
21
+
22
+ Metrics/ModuleLength:
23
+ CountComments: false # count full line comments?
24
+ Max: 150
25
+
26
+ Metrics/BlockLength:
27
+ CountComments: false # count full line comments?
28
+ Max: 150 # Nothing wrong with e.g. big Structs
29
+
30
+ Layout/SpaceInsideStringInterpolation:
31
+ EnforcedStyle: space
32
+
33
+ Layout/SpaceInsideArrayLiteralBrackets:
34
+ Enabled: false
35
+
36
+ Style/RedundantSelf:
37
+ Enabled: false
38
+
39
+ Style/BlockDelimiters:
40
+ Enabled: false
41
+
42
+ Style/SignalException:
43
+ Enabled: false
44
+
45
+ Layout/EmptyLinesAroundBlockBody:
46
+ Enabled: false
47
+
48
+ Layout/EmptyLinesAroundBlockBody:
49
+ Description: "Keeps track of empty lines around block bodies."
50
+ Enabled: false
51
+
52
+ Layout/EmptyLinesAroundClassBody:
53
+ Description: "Keeps track of empty lines around class bodies."
54
+ Enabled: false
55
+
56
+ Layout/EmptyLinesAroundModuleBody:
57
+ Description: "Keeps track of empty lines around module bodies."
58
+ Enabled: false
59
+
60
+ Layout/EmptyLinesAroundMethodBody:
61
+ Description: "Keeps track of empty lines around method bodies."
62
+ Enabled: false
63
+
64
+ Style/DoubleNegation:
65
+ Enabled: false
66
+
67
+ Style/Documentation:
68
+ Enabled: false
69
+
70
+ Metrics/AbcSize:
71
+ Enabled: false
72
+
73
+ Style/RaiseArgs:
74
+ Enabled: false
75
+
76
+ Style/RegexpLiteral:
77
+ Enabled: false
78
+
79
+ Layout/AlignHash:
80
+ EnforcedColonStyle: table
81
+ EnforcedHashRocketStyle: table
82
+
83
+ Layout/AlignParameters:
84
+ EnforcedStyle: with_first_parameter
85
+
86
+ Layout/IndentArray:
87
+ EnforcedStyle: consistent
88
+
89
+ Layout/IndentHash:
90
+ EnforcedStyle: consistent
91
+
92
+ Style/AsciiComments:
93
+ Enabled: false
94
+
95
+ Style/FrozenStringLiteralComment:
96
+ Enabled: true
97
+
98
+ Style/MutableConstant:
99
+ Enabled: false
100
+
101
+ Style/MethodDefParentheses:
102
+ Enabled: false
103
+ EnforcedStyle: require_no_parentheses_except_multiline
104
+
105
+ Style/StabbyLambdaParentheses:
106
+ Enabled: false
107
+
108
+ Layout/SpaceInLambdaLiteral:
109
+ Enabled: false
110
+
111
+ Style/StructInheritance:
112
+ Enabled: false
113
+
114
+ Naming/PredicateName:
115
+ Enabled: false
116
+
117
+ Style/FormatStringToken:
118
+ Enabled: false
119
+
120
+ Rails/DynamicFindBy:
121
+ Enabled: false
122
+
123
+ Style/RescueStandardError:
124
+ EnforcedStyle: implicit
data/Gemfile CHANGED
@@ -10,8 +10,8 @@ group :test do
10
10
  end
11
11
 
12
12
  group :tools do
13
- gem 'pry-byebug', platform: :mri
14
13
  gem 'pry', platform: :jruby
14
+ gem 'pry-byebug', platform: :mri
15
15
 
16
16
  unless ENV['TRAVIS']
17
17
  gem 'mutant', git: 'https://github.com/mbj/mutant'
data/README.md CHANGED
@@ -15,7 +15,7 @@ Example:
15
15
 
16
16
  ## Documentation
17
17
 
18
- See [RubyDoc](https://www.rubydoc.info/gems/lazy_mapper/LazyMapper)
18
+ See [RubyDoc](https://www.rubydoc.info/gems/lazy_mapper/0.3.0)
19
19
 
20
20
  ## License
21
21
 
data/lazy_mapper.gemspec CHANGED
@@ -1,9 +1,9 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = 'lazy_mapper'
3
- spec.version = '0.2.1'
4
- spec.summary = "A lazy object mapper"
5
- spec.description = "Wraps primitive data in a semantically rich model"
6
- spec.authors = ["Adam Lett"]
3
+ spec.version = '0.3.0'
4
+ spec.summary = 'A lazy object mapper'
5
+ spec.description = 'Wraps primitive data in a semantically rich model'
6
+ spec.authors = ['Adam Lett']
7
7
  spec.email = 'adam@bruun-rasmussen.dk'
8
8
  spec.homepage = 'https://github.com/bruun-rasmussen/lazy_mapper'
9
9
  spec.license = 'MIT'
data/lib/lazy_mapper.rb CHANGED
@@ -3,11 +3,10 @@ require 'bigdecimal/util'
3
3
  require 'time'
4
4
 
5
5
  #
6
- # Wraps a JSON object and lazily maps its attributes to domain objects
7
- # using either a set of default mappers (for Ruby's built-in types), or
8
- # custom mappers specified by the client.
9
- #
10
- # The mapped values are memoized.
6
+ # Wraps a Hash or Hash-like data structure of primitive values and lazily maps
7
+ # its attributes to semantically rich domain objects using either a set of
8
+ # default mappers (for Ruby's built-in value types), or custom mappers which
9
+ # can be added either at the class level or at the instance level.
11
10
  #
12
11
  # Example:
13
12
  # class Foo < LazyMapper
@@ -17,7 +16,6 @@ require 'time'
17
16
  # many :users, User, map: ->(u) { User.new(u) }
18
17
  # end
19
18
  #
20
-
21
19
  class LazyMapper
22
20
 
23
21
  #
@@ -70,32 +68,40 @@ class LazyMapper
70
68
  @mappers ||= DEFAULT_MAPPINGS
71
69
  end
72
70
 
73
- def self.inherited(klass)
74
- klass.instance_variable_set IVAR[:mappers], self.mappers.dup
75
- klass.instance_variable_set IVAR[:default_values], self.default_values.dup
71
+ def self.attributes
72
+ @attributes ||= {}
76
73
  end
77
74
 
75
+ def self.inherited(klass)
76
+ # Make the subclass "inherit" the values of these class instance variables
77
+ %i[
78
+ mappers
79
+ default_values
80
+ attributes
81
+ ].each do |s|
82
+ klass.instance_variable_set IVAR[s], self.send(s).dup
83
+ end
84
+ end
78
85
 
79
86
  def mappers
80
87
  @mappers ||= self.class.mappers
81
88
  end
82
89
 
83
- IVAR = -> name {
90
+ IVAR = lambda { |name| # :nodoc:
84
91
  name_as_str = name.to_s
85
- if name_as_str[-1] == '?'
86
- name_as_str = name_as_str[0...-1]
87
- end
92
+ name_as_str = name_as_str[0...-1] if name_as_str[-1] == '?'
88
93
 
89
94
  ('@' + name_as_str).freeze
90
95
  }
91
96
 
92
- WRITER = -> name { (name.to_s.gsub('?', '') + '=').to_sym }
97
+ WRITER = -> name { (name.to_s.delete('?') + '=').to_sym }
93
98
 
94
99
  #
95
100
  # Creates a new instance by giving a Hash of attribues.
96
101
  #
97
102
  # Attribute values are type checked according to how they were defined.
98
- # If a value has the wrong type, a `TypeError` is raised.
103
+ #
104
+ # Fails with +TypeError+, if a value doesn't have the expected type.
99
105
  #
100
106
  # == Example
101
107
  #
@@ -110,7 +116,6 @@ class LazyMapper
110
116
  # ]
111
117
 
112
118
  def initialize(values = {})
113
- @json = {}
114
119
  @mappers = {}
115
120
  values.each do |name, value|
116
121
  send(WRITER[name], value)
@@ -124,7 +129,7 @@ class LazyMapper
124
129
  #
125
130
  # == Arguments
126
131
  #
127
- # +json+ - The unmapped data as a Hash(-like object). Must respond to #to_h.
132
+ # +unmapped_data+ - The unmapped data as a Hash(-like object). Must respond to #to_h.
128
133
  # Keys are assumed to be camelCased string
129
134
  #
130
135
  # +mappers:+ - Optional instance-level mappers.
@@ -133,7 +138,7 @@ class LazyMapper
133
138
  #
134
139
  # == Example
135
140
  #
136
- # Foo.from_json({
141
+ # Foo.from({
137
142
  # "xmlId" => 42,
138
143
  # "createdAt" => "2015-07-29 14:07:35 +0200",
139
144
  # "amount" => "$2.00",
@@ -146,17 +151,18 @@ class LazyMapper
146
151
  # :amount => -> x { Money.new(x) },
147
152
  # User => User.method(:new) })
148
153
  #
149
- def self.from_json json, mappers: {}
150
- return nil if json.nil?
151
- fail TypeError, "#{ json.inspect } is not a Hash" unless json.respond_to? :to_h
154
+ def self.from unmapped_data, mappers: {}
155
+ return nil if unmapped_data.nil?
156
+ fail TypeError, "#{ unmapped_data.inspect } is not a Hash" unless unmapped_data.respond_to? :to_h
152
157
  instance = new
153
- instance.send :json=, json.to_h
158
+ instance.send :unmapped_data=, unmapped_data.to_h
154
159
  instance.send :mappers=, mappers
155
160
  instance
156
161
  end
157
162
 
158
- def self.attributes
159
- @attributes ||= {}
163
+ def self.from_json *args, &block
164
+ warn "#{ self }.from_json is deprecated. Use #{ self }.from instead."
165
+ from *args, &block
160
166
  end
161
167
 
162
168
  #
@@ -201,7 +207,7 @@ class LazyMapper
201
207
  # Define reader
202
208
  define_method(name) {
203
209
  memoize(name, ivar) {
204
- unmapped_value = json[from]
210
+ unmapped_value = unmapped_data[from]
205
211
  mapped_value(name, unmapped_value, type, **args)
206
212
  }
207
213
  }
@@ -210,7 +216,7 @@ class LazyMapper
210
216
  end
211
217
 
212
218
  #
213
- # Converts a value to true or false according to its truthyness
219
+ # Converts a value to +true+ or +false+ according to its truthyness
214
220
  #
215
221
  TO_BOOL = -> b { !!b }
216
222
 
@@ -251,15 +257,14 @@ class LazyMapper
251
257
  #
252
258
  # +type+ - The type of the elements in the collection.
253
259
  #
254
- # +from:+ - Specifies the name of the wrapped array in the JSON object.
260
+ # +from:+ - Specifies the name of the wrapped array in the unmapped data.
255
261
  # Defaults to camelCased version of +name+.
256
262
  #
257
263
  # +map:+ - Specifies a custom mapper to apply to each elements in the wrapped collection.
258
264
  # If unspecified, it defaults to the default mapper for the specified +type+ or simply the identity mapper
259
265
  # if no default mapper exists.
260
266
  #
261
- # +default:+ - The default value to use, if the wrapped value is not present
262
- # in the wrapped JSON object.
267
+ # +default:+ - The default value to use, if the unmapped value is missing.
263
268
  #
264
269
  # == Example
265
270
  #
@@ -279,7 +284,7 @@ class LazyMapper
279
284
  # Define getter
280
285
  define_method(name) {
281
286
  memoize(name) {
282
- unmapped_value = json[from]
287
+ unmapped_value = unmapped_data[from]
283
288
  if unmapped_value.is_a? Array
284
289
  unmapped_value.map { |v| mapped_value(name, v, type, **args) }
285
290
  else
@@ -296,30 +301,28 @@ class LazyMapper
296
301
  mappers[type] = block
297
302
  end
298
303
 
304
+ def to_h
305
+ attributes.each_with_object({}) {|(key, _value), h|
306
+ h[key] = self.send key
307
+ }
308
+ end
309
+
299
310
  def inspect
300
311
  @__under_inspection__ ||= 0
301
312
  return "<#{ self.class.name } ... >" if @__under_inspection__ > 0
302
313
  @__under_inspection__ += 1
303
- attributes = self.class.attributes
304
- if self.class.superclass.respond_to? :attributes
305
- attributes = self.class.superclass.attributes.merge attributes
306
- end
307
- present_attributes = attributes.keys.each_with_object({}) {|name, memo|
314
+ present_attributes = attributes.keys.each_with_object({}) { |name, memo|
308
315
  value = self.send name
309
316
  memo[name] = value unless value.nil?
310
317
  }
311
- "<#{ self.class.name } #{ present_attributes.map {|k,v| k.to_s + ': ' + v.inspect }.join(', ') } >"
312
- res = "<#{ self.class.name } #{ present_attributes.map {|k,v| k.to_s + ': ' + v.inspect }.join(', ') } >"
318
+ "<#{ self.class.name } #{ present_attributes.map { |k, v| k.to_s + ': ' + v.inspect }.join(', ') } >"
319
+ res = "<#{ self.class.name } #{ present_attributes.map { |k, v| k.to_s + ': ' + v.inspect }.join(', ') } >"
313
320
  @__under_inspection__ -= 1
314
321
  res
315
322
  end
316
323
 
317
324
  protected
318
325
 
319
- def json
320
- @json ||= {}
321
- end
322
-
323
326
  #
324
327
  # Defines how to map an attribute name
325
328
  # to the corresponding name in the unmapped
@@ -333,9 +336,13 @@ class LazyMapper
333
336
 
334
337
  private
335
338
 
336
- attr_writer :json
339
+ attr_writer :unmapped_data
337
340
  attr_writer :mappers
338
341
 
342
+ def unmapped_data
343
+ @unmapped_data ||= {}
344
+ end
345
+
339
346
  def mapping_for(name, type)
340
347
  mappers[name] || mappers[type] || self.class.mappers[type]
341
348
  end
@@ -344,6 +351,10 @@ class LazyMapper
344
351
  self.class.default_values[type]
345
352
  end
346
353
 
354
+ def attributes
355
+ self.class.attributes
356
+ end
357
+
347
358
  def mapped_value(name, unmapped_value, type, map: mapping_for(name, type), default: default_value(type))
348
359
  if unmapped_value.nil?
349
360
  # Duplicate to prevent accidental sharing between instances
@@ -369,12 +380,11 @@ class LazyMapper
369
380
  [ all_but_last.join(separator), last ].join conjunction
370
381
  end
371
382
 
372
-
373
383
  def memoize name, ivar = IVAR[name]
374
384
  send WRITER[name], yield unless instance_variable_defined?(ivar)
375
385
  instance_variable_get(ivar)
376
386
  end
377
387
 
378
388
  SNAKE_CASE_PATTERN = /(_[a-z])/ # :nodoc:
379
- CAMELIZE = -> name { name.to_s.gsub(SNAKE_CASE_PATTERN) { |x| x[1].upcase }.gsub('?', '') }
389
+ CAMELIZE = -> name { name.to_s.gsub(SNAKE_CASE_PATTERN) { |x| x[1].upcase }.delete('?') }
380
390
  end
@@ -5,11 +5,18 @@ require 'lazy_mapper'
5
5
 
6
6
  describe LazyMapper do
7
7
 
8
- describe 'when constructed with .from_json' do
8
+ describe 'when constructed from unmapped data' do
9
9
 
10
- subject(:instance) { klass.from_json json }
10
+ subject(:instance) { klass.from unmapped_data }
11
11
 
12
- let(:json) { nil }
12
+ let(:unmapped_data) {
13
+ {
14
+ 'createdAt' => '2015-07-27',
15
+ 'updatedAt' => ['2015-01-01', '2015-01-02'],
16
+ 'foo' => '42',
17
+ 'blue' => true
18
+ }
19
+ }
13
20
  let(:klass) {
14
21
  t = type
15
22
  m = map
@@ -25,11 +32,13 @@ describe LazyMapper do
25
32
  let(:type) { Integer }
26
33
 
27
34
  context 'if the supplied data is nil' do
35
+ let(:unmapped_data) { nil }
36
+
28
37
  it { is_expected.to be_nil }
29
38
  end
30
39
 
31
40
  context 'when invalid data is supplied' do
32
- let(:json) { 'not a hash' }
41
+ let(:unmapped_data) { 'not a hash' }
33
42
 
34
43
  it 'fails with a TypeError' do
35
44
  expect { instance }.to raise_error(TypeError)
@@ -38,20 +47,11 @@ describe LazyMapper do
38
47
 
39
48
  context 'when valid data is supplied' do
40
49
 
41
- let(:json) {
42
- {
43
- 'createdAt' => '2015-07-27',
44
- 'updatedAt' => ['2015-01-01', '2015-01-02'],
45
- 'foo' => '42',
46
- 'blue' => true
47
- }
48
- }
49
-
50
- it 'maps JSON attributes to domain objects' do
50
+ it 'maps primitives to domain objects' do
51
51
  expect(instance.created_at).to eq(Date.new(2015, 7, 27))
52
52
  end
53
53
 
54
- it 'maps arrays of JSON values to arrays of domain objects' do
54
+ it 'maps arrays of primitives to arrays of domain objects' do
55
55
  expect(instance.updated_at).to be_a(Array)
56
56
  expect(instance.updated_at.first).to be_a(Date)
57
57
  expect(instance).to be_blue
@@ -79,8 +79,8 @@ describe LazyMapper do
79
79
 
80
80
  subject(:instance) { foo }
81
81
 
82
- let(:foo) { klass_foo.from_json 'bar' => 'bar' }
83
- let(:bar) { klass_bar.from_json 'foo' => 'foo' }
82
+ let(:foo) { klass_foo.from 'bar' => 'bar' }
83
+ let(:bar) { klass_bar.from 'foo' => 'foo' }
84
84
  let(:foo_builder) { proc { foo } }
85
85
  let(:bar_builder) { proc { bar } }
86
86
 
@@ -116,9 +116,9 @@ describe LazyMapper do
116
116
  end
117
117
  }
118
118
 
119
- let(:json) { { 'BAZ' => 999, 'hairy' => true } }
119
+ let(:unmapped_data) { { 'BAZ' => 999, 'hairy' => true } }
120
120
 
121
- it 'specifies a different name in the JSON object for the attribute' do
121
+ it 'specifies the name of the attribute in the unmapped data' do
122
122
  expect(instance.baz).to eq(999)
123
123
  end
124
124
 
@@ -135,7 +135,7 @@ describe LazyMapper do
135
135
  }
136
136
 
137
137
  it 'fails with a TypeError when an attribute is accessed' do
138
- instance = klass.from_json 'bar' => 42
138
+ instance = klass.from 'bar' => 42
139
139
  expect { instance.bar }.to raise_error(TypeError)
140
140
  end
141
141
  end
@@ -146,7 +146,7 @@ describe LazyMapper do
146
146
  one :composite, type
147
147
  end
148
148
 
149
- instance = klass.from_json 'composite' => '123 456'
149
+ instance = klass.from 'composite' => '123 456'
150
150
  instance.add_mapper_for(type) { |unmapped_value| type.new(*unmapped_value.split(' ')) }
151
151
 
152
152
  expect(instance.composite).to eq type.new('123', '456')
@@ -155,35 +155,6 @@ describe LazyMapper do
155
155
  expect(instance.composite).to eq type.new('abc', 'cde')
156
156
  end
157
157
 
158
- it 'supports adding inheritable default mappers to derived classes' do
159
- type = Struct.new(:val1, :val2)
160
-
161
- klass = Class.new LazyMapper do
162
- mapper_for type, ->(unmapped_value) { type.new(*unmapped_value.split(' ')) }
163
- one :composite, type
164
- end
165
-
166
- klass2 = Class.new(klass)
167
- instance = klass.from_json 'composite' => '123 456'
168
- expect(instance.composite).to eq type.new('123', '456')
169
-
170
- instance2 = klass2.from_json 'composite' => '456 789'
171
- expect(instance2.composite).to eq type.new('456', '789')
172
- end
173
-
174
- it 'supports adding or overriding inheritable default values for types to derived classes' do
175
- type = Struct.new(:val1, :val2)
176
-
177
- klass = Class.new LazyMapper do
178
- default_value_for type, type.new('321', '123')
179
- one :composite, type
180
- end
181
-
182
- klass2 = Class.new(klass)
183
- instance = klass2.from_json({})
184
- expect(instance.composite).to eq type.new('321', '123')
185
- end
186
-
187
158
  it 'supports injection of customer mappers during instantiation' do
188
159
  type = Struct.new(:val1, :val2)
189
160
  klass = Class.new LazyMapper do
@@ -191,7 +162,7 @@ describe LazyMapper do
191
162
  one :bar, type
192
163
  end
193
164
 
194
- instance = klass.from_json({ 'foo' => '123 456', 'bar' => 'abc def' },
165
+ instance = klass.from({ 'foo' => '123 456', 'bar' => 'abc def' },
195
166
  mappers: {
196
167
  foo: ->(f) { type.new(*f.split(' ').reverse) },
197
168
  type => ->(t) { type.new(*t.split(' ')) }
@@ -207,11 +178,37 @@ describe LazyMapper do
207
178
  many :bars, String, map: ->(v) { return v }
208
179
  end
209
180
 
210
- instance = klass.from_json 'foos' => 'abc', 'bars' => 'abc'
181
+ instance = klass.from 'foos' => 'abc', 'bars' => 'abc'
211
182
 
212
183
  expect(instance.foos).to eq %w[a b c]
213
184
  expect { instance.bars }.to raise_error(TypeError)
214
185
  end
186
+
187
+ context 'when it is derived from another LazyMapper' do
188
+ let(:klass) { Class.new(base) }
189
+ let(:composite_type) { Struct.new(:val1, :val2) }
190
+ let(:base) {
191
+ type = composite_type
192
+ Class.new(LazyMapper) do
193
+ default_value_for type, type.new('321', '123')
194
+ mapper_for type, ->(unmapped_value) { type.new(*unmapped_value.split(' ')) }
195
+ one :composite, type
196
+ end
197
+ }
198
+
199
+ it 'inherits attributes' do
200
+ expect(klass.attributes.keys).to eq [:composite]
201
+ expect(instance).to respond_to(:composite)
202
+ end
203
+
204
+ it 'inherits default values' do
205
+ expect(instance.composite).to eq composite_type.new('321', '123')
206
+ end
207
+
208
+ it 'inherits default mappers' do
209
+ expect(klass.from('composite' => 'abc def').composite).to eq composite_type.new('abc', 'def')
210
+ end
211
+ end
215
212
  end
216
213
 
217
214
  context 'when constructed with .new' do
@@ -289,6 +286,19 @@ describe LazyMapper do
289
286
  expect(instance2.tags).to be_empty
290
287
  expect(instance2.things).to_not be_empty
291
288
  end
289
+
290
+ it 'still includes every attribute when converted to Hash' do
291
+ expect(instance.to_h).to eq(
292
+ title: '',
293
+ count: 0,
294
+ rate: 0.0,
295
+ tags: [],
296
+ widget: nil,
297
+ things: ['something'],
298
+ green?: false,
299
+ flowers?: false
300
+ )
301
+ end
292
302
  end
293
303
  end
294
304
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lazy_mapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Lett
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-15 00:00:00.000000000 Z
11
+ date: 2018-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -45,6 +45,7 @@ extensions: []
45
45
  extra_rdoc_files: []
46
46
  files:
47
47
  - ".gitignore"
48
+ - ".rubocop.yml"
48
49
  - Gemfile
49
50
  - LICENCE
50
51
  - README.md