primalize 0.1.0 → 0.2.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
  SHA1:
3
- metadata.gz: f9454407dd6619d27027fc4a5ef40252868dc8ae
4
- data.tar.gz: e841a6d57e23800b2fc273141e58ededbe969205
3
+ metadata.gz: 211551a4a7fc66702f544d35f053e4e9f65d1fe1
4
+ data.tar.gz: b6f715a19f9b32fae1b4c025ae195ed1643faf65
5
5
  SHA512:
6
- metadata.gz: 2574db91856d1145c4738ab69831a4862227908f857e78668970c5dd59efe6397a06f79a4d033b2f5a885961fdccbf7afeac4f8334c381524a6dbebe6d320e96
7
- data.tar.gz: 7eb666e43e360456289f70537262c1134d966fe47bb9eb89e4cd4d1399a777277957df148182f84cb2724bdfcdb884d1b65794c384a7c11f3cb07ed564632152
6
+ metadata.gz: 1557c13cf41e2924453083053dd5de8b08b258cbdca01a2f55cf9d72f2f1a6ab048bb94fe564467346daea9292f8a436fd932db6dca4fc989d4b1a8aebf601ab
7
+ data.tar.gz: 133145cfb6bca06af9fd920eca885aa16707ca2af8b49e7c4c059112d65052232af87ab6a7e6049d701497c143e15008a22ae8be8fe5a6b1e18e756518e63a2e
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- primalize (0.1.0)
4
+ primalize (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -112,6 +112,19 @@ class ShipmentSerializer < Primalize::Single
112
112
  end
113
113
  ```
114
114
 
115
+ ### Type Checking
116
+
117
+ By default, subclasses of `Primalize::Single` will raise an `ArgumentError` if there is a mismatch between the types declared in its `attributes` call and what is passed in to be primalized. In production, you might not want that to happen, so you can change that in your production config:
118
+
119
+ ```ruby
120
+ Primalize::Single.type_mismatch_handler = proc do |attr, type, value|
121
+ msg = "Type mismatch: #{attr} is expected to be #{type.inspect}, but is a #{value.inspect} - " +
122
+ caller.grep(Regexp.new(Rails.root))
123
+
124
+ Slack.notify '#bugs', msg
125
+ end
126
+ ```
127
+
115
128
  ## Development
116
129
 
117
130
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -28,6 +28,10 @@ module Primalize
28
28
  define_singleton_method :inspect do
29
29
  "enumerable(#{serializer_class.inspect})"
30
30
  end
31
+
32
+ define_singleton_method :attributes do
33
+ serializer_class.attributes
34
+ end
31
35
  end
32
36
  end
33
37
 
@@ -86,5 +90,22 @@ module Primalize
86
90
  def to_json
87
91
  call.to_json
88
92
  end
93
+
94
+ def to_csv attr
95
+ CSV.generate do |csv|
96
+ result = call[attr]
97
+
98
+ csv << self.class.attributes[attr].attributes.keys
99
+
100
+ case result
101
+ when Hash
102
+ csv << result.values
103
+ when Array
104
+ result.each do |hash|
105
+ csv << hash.values
106
+ end
107
+ end
108
+ end
109
+ end
89
110
  end
90
111
  end
@@ -1,10 +1,11 @@
1
1
  require 'json'
2
2
  require 'date'
3
+ require 'csv'
3
4
 
4
5
  module Primalize
5
6
  class Single
6
- @type_mismatch_handler = proc do |attr, type, value|
7
- raise TypeError, "#{self}##{attr} is specified as #{type.inspect}, but is #{value.inspect}"
7
+ @type_mismatch_handler = proc do |klass, attr, type, value|
8
+ raise TypeError, "#{klass}##{attr} is specified as #{type.inspect}, but is #{value.inspect}"
8
9
  end
9
10
 
10
11
  class << self
@@ -24,12 +25,7 @@ module Primalize
24
25
 
25
26
  attrs.each do |attr, type|
26
27
  define_method attr do
27
- value = type.coerce(object.public_send(attr))
28
- if type === value
29
- value
30
- else
31
- self.class.type_mismatch_handler.call attr, type, value
32
- end
28
+ type.coerce(object.public_send(attr))
33
29
  end
34
30
  end
35
31
  end
@@ -58,6 +54,10 @@ module Primalize
58
54
  Float.new(&coerce)
59
55
  end
60
56
 
57
+ def number &coerce
58
+ Number.new(&coerce)
59
+ end
60
+
61
61
  def optional *types, &coerce
62
62
  Optional.new(types, &coerce)
63
63
  end
@@ -70,6 +70,14 @@ module Primalize
70
70
  Timestamp.new(&coerce)
71
71
  end
72
72
 
73
+ def any *types, &coerce
74
+ Any.new(types, &coerce)
75
+ end
76
+
77
+ def primalize primalizer, &coerce
78
+ Primalizer.new(primalizer, &coerce)
79
+ end
80
+
73
81
  def type_mismatch_handler= handler
74
82
  @type_mismatch_handler = handler
75
83
  end
@@ -90,20 +98,42 @@ module Primalize
90
98
  attr_reader :object
91
99
 
92
100
  def initialize object
101
+ raise ArgumentError, "#{self.class.inspect} cannot serialize `nil'" if object.nil?
93
102
  @object = object
94
103
  end
95
104
 
96
105
  def call
97
- self.class.attributes.each_with_object({}) do |(attr, _), hash|
98
- hash[attr] = public_send(attr)
106
+ self.class.attributes.each_with_object({}) do |(attr, type), hash|
107
+ value = public_send(attr)
108
+
109
+ if type === value
110
+ hash[attr] = value
111
+ else
112
+ self.class.type_mismatch_handler.call self.class, attr, type, value
113
+ end
99
114
  end
100
115
  end
101
116
 
102
- # TYPES
117
+ # CONVERSION
103
118
 
104
- DEFAULT_COERCION = proc { |arg| arg } # Don't coerce by default
119
+ def to_json
120
+ call.to_json
121
+ end
122
+
123
+ def csv_headers
124
+ self.class.attributes.keys.map(&:to_s)
125
+ end
126
+
127
+ def to_csv
128
+ hash = call
129
+ CSV.generate { |csv| csv << hash.values }
130
+ end
131
+
132
+ # TYPES
105
133
 
106
134
  module Type
135
+ DEFAULT_COERCION = proc { |arg| arg } # Don't coerce by default
136
+
107
137
  def coerce *args
108
138
  (@coercion || DEFAULT_COERCION).call(*args)
109
139
  end
@@ -141,6 +171,18 @@ module Primalize
141
171
  end
142
172
  end
143
173
 
174
+ class Number
175
+ include Type
176
+
177
+ def === value
178
+ ::Numeric === value
179
+ end
180
+
181
+ def inspect
182
+ 'number'
183
+ end
184
+ end
185
+
144
186
  class String
145
187
  include Type
146
188
 
@@ -203,7 +245,7 @@ module Primalize
203
245
 
204
246
  def initialize types, &coercion
205
247
  @types = types
206
- @coercion = coercion || DEFAULT_COERCION
248
+ @coercion = coercion
207
249
  end
208
250
 
209
251
  def === value
@@ -233,6 +275,30 @@ module Primalize
233
275
  end
234
276
  end
235
277
 
278
+ class Primalizer
279
+ include Type
280
+
281
+ def initialize primalizer, &coercion
282
+ @primalizer = primalizer
283
+ @coercion = coercion || proc do |obj|
284
+ # FIXME: this is dumb
285
+ begin
286
+ primalizer.new(obj).call
287
+ rescue ArgumentError => e
288
+ raise TypeError.new(e)
289
+ end
290
+ end
291
+ end
292
+
293
+ def === value
294
+ true
295
+ end
296
+
297
+ def inspect
298
+ "primalize(#{@primalizer.inspect})"
299
+ end
300
+ end
301
+
236
302
  class Optional
237
303
  include Type
238
304
 
@@ -249,5 +315,22 @@ module Primalize
249
315
  "optional(#{@types.map(&:inspect).join(', ')})"
250
316
  end
251
317
  end
318
+
319
+ class Any
320
+ include Type
321
+
322
+ def initialize types, &coercion
323
+ @types = types
324
+ end
325
+
326
+ def === value
327
+ @types.empty? || @types.any? { |type| type === value }
328
+ end
329
+
330
+ def inspect
331
+ params = "(#{@types.map(&:inspect).join(', ')})"
332
+ "any#{@types.empty? ? nil : params}"
333
+ end
334
+ end
252
335
  end
253
336
  end
@@ -1,3 +1,3 @@
1
1
  module Primalize
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: primalize
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie Gaskins
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-09-08 00:00:00.000000000 Z
11
+ date: 2017-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler