primalize 0.1.0 → 0.2.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
  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