lazy_mapper 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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