alba 1.3.0 → 1.6.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.
@@ -1,5 +1,7 @@
1
1
  module Alba
2
- # This module represents the inflector, which is used by default
2
+ # This module has two purposes.
3
+ # One is that we require `active_support/inflector` in this module so that we don't do that all over the place.
4
+ # Another is that `ActiveSupport::Inflector` doesn't have `camelize_lower` method that we want it to have, so this module works as an adapter.
3
5
  module DefaultInflector
4
6
  begin
5
7
  require 'active_support/inflector'
@@ -11,7 +13,7 @@ module Alba
11
13
 
12
14
  # Camelizes a key
13
15
  #
14
- # @params key [String] key to be camelized
16
+ # @param key [String] key to be camelized
15
17
  # @return [String] camelized key
16
18
  def camelize(key)
17
19
  ActiveSupport::Inflector.camelize(key)
@@ -19,7 +21,7 @@ module Alba
19
21
 
20
22
  # Camelizes a key, 1st letter lowercase
21
23
  #
22
- # @params key [String] key to be camelized
24
+ # @param key [String] key to be camelized
23
25
  # @return [String] camelized key
24
26
  def camelize_lower(key)
25
27
  ActiveSupport::Inflector.camelize(key, false)
@@ -27,10 +29,26 @@ module Alba
27
29
 
28
30
  # Dasherizes a key
29
31
  #
30
- # @params key [String] key to be dasherized
32
+ # @param key [String] key to be dasherized
31
33
  # @return [String] dasherized key
32
34
  def dasherize(key)
33
35
  ActiveSupport::Inflector.dasherize(key)
34
36
  end
37
+
38
+ # Underscore a key
39
+ #
40
+ # @param key [String] key to be underscore
41
+ # @return [String] underscored key
42
+ def underscore(key)
43
+ ActiveSupport::Inflector.underscore(key)
44
+ end
45
+
46
+ # Classify a key
47
+ #
48
+ # @param key [String] key to be classified
49
+ # @return [String] classified key
50
+ def classify(key)
51
+ ActiveSupport::Inflector.classify(key)
52
+ end
35
53
  end
36
54
  end
@@ -0,0 +1,14 @@
1
+ module Alba
2
+ # Module for printing deprecation warning
3
+ module Deprecation
4
+ # Similar to {Kernel.warn} but prints caller as well
5
+ #
6
+ # @param message [String] main message to print
7
+ # @return void
8
+ def warn(message)
9
+ Kernel.warn(message)
10
+ Kernel.warn(caller_locations(2..2).first) # For performance reason we use (2..2).first
11
+ end
12
+ module_function :warn
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module Alba
2
+ # Base class for Errors
3
+ class Error < StandardError; end
4
+
5
+ # Error class for backend which is not supported
6
+ class UnsupportedBackend < Error; end
7
+
8
+ # Error class for type which is not supported
9
+ class UnsupportedType < Error; end
10
+ end
data/lib/alba/resource.rb CHANGED
@@ -1,14 +1,13 @@
1
- require_relative 'one'
2
- require_relative 'many'
3
- require_relative 'key_transform_factory'
1
+ require_relative 'association'
4
2
  require_relative 'typed_attribute'
3
+ require_relative 'deprecation'
5
4
 
6
5
  module Alba
7
6
  # This module represents what should be serialized
8
7
  module Resource
9
8
  # @!parse include InstanceMethods
10
9
  # @!parse extend ClassMethods
11
- DSLS = {_attributes: {}, _key: nil, _transform_key_function: nil, _transforming_root_key: false, _on_error: nil}.freeze
10
+ DSLS = {_attributes: {}, _key: nil, _key_for_collection: nil, _meta: nil, _transform_type: :none, _transforming_root_key: false, _on_error: nil, _on_nil: nil, _layout: nil}.freeze # rubocop:disable Layout/LineLength
12
11
  private_constant :DSLS
13
12
 
14
13
  WITHIN_DEFAULT = Object.new.freeze
@@ -33,23 +32,33 @@ module Alba
33
32
 
34
33
  # @param object [Object] the object to be serialized
35
34
  # @param params [Hash] user-given Hash for arbitrary data
36
- # @param within [Hash] determines what associations to be serialized. If not set, it serializes all associations.
35
+ # @param within [Object, nil, false, true] determines what associations to be serialized. If not set, it serializes all associations.
37
36
  def initialize(object, params: {}, within: WITHIN_DEFAULT)
38
37
  @object = object
39
38
  @params = params.freeze
40
39
  @within = within
40
+ @method_existence = {} # Cache for `respond_to?` result
41
41
  DSLS.each_key { |name| instance_variable_set("@#{name}", self.class.public_send(name)) }
42
42
  end
43
43
 
44
44
  # Serialize object into JSON string
45
45
  #
46
- # @param key [Symbol]
46
+ # @param key [Symbol, nil, true] DEPRECATED, use root_key instead
47
+ # @param root_key [Symbol, nil, true]
48
+ # @param meta [Hash] metadata for this seialization
47
49
  # @return [String] serialized JSON string
48
- def serialize(key: nil)
49
- key = key.nil? ? _key : key
50
- hash = key && key != '' ? {key.to_s => serializable_hash} : serializable_hash
51
- Alba.encoder.call(hash)
50
+ def serialize(key: nil, root_key: nil, meta: {})
51
+ Alba::Deprecation.warn '`key` option to `serialize` method is deprecated, use `root_key` instead.' if key
52
+ key = key.nil? && root_key.nil? ? fetch_key : root_key || key
53
+ hash = if key && key != ''
54
+ h = {key.to_s => serializable_hash}
55
+ hash_with_metadata(h, meta)
56
+ else
57
+ serializable_hash
58
+ end
59
+ serialize_with(hash)
52
60
  end
61
+ alias to_json serialize
53
62
 
54
63
  # A Hash for serialization
55
64
  #
@@ -57,127 +66,214 @@ module Alba
57
66
  def serializable_hash
58
67
  collection? ? @object.map(&converter) : converter.call(@object)
59
68
  end
60
- alias to_hash serializable_hash
69
+ alias to_h serializable_hash
70
+
71
+ # @deprecated Use {#serializable_hash} instead
72
+ def to_hash
73
+ warn '[DEPRECATION] `to_hash` is deprecated, use `serializable_hash` instead.'
74
+ serializable_hash
75
+ end
61
76
 
62
77
  private
63
78
 
79
+ attr_reader :serialized_json # Mainly for layout
80
+
81
+ def encode(hash)
82
+ Alba.encoder.call(hash)
83
+ end
84
+
85
+ def serialize_with(hash)
86
+ serialized_json = encode(hash)
87
+ return serialized_json unless @_layout
88
+
89
+ @serialized_json = serialized_json
90
+ if @_layout.is_a?(String) # file
91
+ ERB.new(File.read(@_layout)).result(binding)
92
+
93
+ else # inline
94
+ serialize_within_inline_layout
95
+ end
96
+ end
97
+
98
+ def serialize_within_inline_layout
99
+ inline = instance_eval(&@_layout)
100
+ case inline
101
+ when Hash then encode(inline)
102
+ when String then inline
103
+ else
104
+ raise Alba::Error, 'Inline layout must be a Proc returning a Hash or a String'
105
+ end
106
+ end
107
+
108
+ def hash_with_metadata(hash, meta)
109
+ return hash if meta.empty? && @_meta.nil?
110
+
111
+ metadata = @_meta ? instance_eval(&@_meta).merge(meta) : meta
112
+ hash[:meta] = metadata
113
+ hash
114
+ end
115
+
116
+ def fetch_key
117
+ collection? ? _key_for_collection : _key
118
+ end
119
+
120
+ def _key_for_collection
121
+ return @_key_for_collection.to_s unless @_key_for_collection == true && Alba.inferring
122
+
123
+ key = resource_name.pluralize
124
+ transforming_root_key? ? transform_key(key) : key
125
+ end
126
+
64
127
  # @return [String]
65
128
  def _key
66
129
  return @_key.to_s unless @_key == true && Alba.inferring
67
130
 
68
- transforming_root_key? ? transform_key(key_from_resource_name) : key_from_resource_name
69
- end
70
-
71
- def key_from_resource_name
72
- collection? ? resource_name.pluralize : resource_name
131
+ transforming_root_key? ? transform_key(resource_name) : resource_name
73
132
  end
74
133
 
75
134
  def resource_name
76
- self.class.name.demodulize.delete_suffix('Resource').underscore
135
+ @resource_name ||= self.class.name.demodulize.delete_suffix('Resource').underscore
77
136
  end
78
137
 
79
138
  def transforming_root_key?
80
139
  @_transforming_root_key.nil? ? Alba.transforming_root_key : @_transforming_root_key
81
140
  end
82
141
 
142
+ # rubocop:disable Metrics/MethodLength
83
143
  def converter
84
144
  lambda do |object|
85
- arrays = @_attributes.map do |key, attribute|
145
+ arrays = attributes.map do |key, attribute|
86
146
  key_and_attribute_body_from(object, key, attribute)
87
147
  rescue ::Alba::Error, FrozenError, TypeError
88
148
  raise
89
149
  rescue StandardError => e
90
150
  handle_error(e, object, key, attribute)
91
151
  end
92
- arrays.reject(&:empty?).to_h
152
+ arrays.compact!
153
+ arrays.to_h
93
154
  end
94
155
  end
156
+ # rubocop:enable Metrics/MethodLength
157
+
158
+ # This is default behavior for getting attributes for serialization
159
+ # Override this method to filter certain attributes
160
+ def attributes
161
+ @_attributes
162
+ end
95
163
 
96
164
  def key_and_attribute_body_from(object, key, attribute)
97
165
  key = transform_key(key)
98
166
  if attribute.is_a?(Array) # Conditional
99
167
  conditional_attribute(object, key, attribute)
100
168
  else
101
- [key, fetch_attribute(object, attribute)]
169
+ fetched_attribute = fetch_attribute(object, key, attribute)
170
+ [key, fetched_attribute]
102
171
  end
103
172
  end
104
173
 
105
174
  def conditional_attribute(object, key, attribute)
106
175
  condition = attribute.last
176
+ if condition.is_a?(Proc)
177
+ conditional_attribute_with_proc(object, key, attribute.first, condition)
178
+ else
179
+ conditional_attribute_with_symbol(object, key, attribute.first, condition)
180
+ end
181
+ end
182
+
183
+ def conditional_attribute_with_proc(object, key, attribute, condition)
107
184
  arity = condition.arity
108
- return [] if arity <= 1 && !instance_exec(object, &condition)
185
+ # We can return early to skip fetch_attribute
186
+ return if arity <= 1 && !instance_exec(object, &condition)
109
187
 
110
- fetched_attribute = fetch_attribute(object, attribute.first)
111
- attr = if attribute.first.is_a?(Alba::Association)
112
- attribute.first.object
113
- else
114
- fetched_attribute
115
- end
116
- return [] if arity >= 2 && !instance_exec(object, attr, &condition)
188
+ fetched_attribute = fetch_attribute(object, key, attribute)
189
+ attr = attribute.is_a?(Alba::Association) ? attribute.object : fetched_attribute
190
+ return if arity >= 2 && !instance_exec(object, attr, &condition)
117
191
 
118
192
  [key, fetched_attribute]
119
193
  end
120
194
 
195
+ def conditional_attribute_with_symbol(object, key, attribute, condition)
196
+ return unless __send__(condition)
197
+
198
+ [key, fetch_attribute(object, key, attribute)]
199
+ end
200
+
121
201
  def handle_error(error, object, key, attribute)
122
202
  on_error = @_on_error || Alba._on_error
123
203
  case on_error
124
- when :raise, nil
125
- raise
126
- when :nullify
127
- [key, nil]
128
- when :ignore
129
- []
130
- when Proc
131
- on_error.call(error, object, key, attribute, self.class)
204
+ when :raise, nil then raise
205
+ when :nullify then [key, nil]
206
+ when :ignore then nil
207
+ when Proc then on_error.call(error, object, key, attribute, self.class)
132
208
  else
133
209
  raise ::Alba::Error, "Unknown on_error: #{on_error.inspect}"
134
210
  end
135
211
  end
136
212
 
137
- # Override this method to supply custom key transform method
213
+ # rubocop:disable Metrics/MethodLength
214
+ # @return [Symbol]
138
215
  def transform_key(key)
139
- return key if @_transform_key_function.nil?
216
+ return key if @_transform_type == :none
217
+
218
+ key = key.to_s
219
+ # TODO: Using default inflector here is for backward compatibility
220
+ # From 2.0 it'll raise error when inflector is nil
221
+ inflector = Alba.inflector || begin
222
+ require_relative 'default_inflector'
223
+ Alba::DefaultInflector
224
+ end
225
+ case @_transform_type # rubocop:disable Style/MissingElse
226
+ when :camel then inflector.camelize(key)
227
+ when :lower_camel then inflector.camelize_lower(key)
228
+ when :dash then inflector.dasherize(key)
229
+ when :snake then inflector.underscore(key)
230
+ end.to_sym
231
+ end
232
+ # rubocop:enable Metrics/MethodLength
233
+
234
+ def fetch_attribute(object, key, attribute)
235
+ value = case attribute
236
+ when Symbol then fetch_attribute_from_object_and_resource(object, attribute)
237
+ when Proc then instance_exec(object, &attribute)
238
+ when Alba::Association then yield_if_within(attribute.name.to_sym) { |within| attribute.to_h(object, params: params, within: within) }
239
+ when TypedAttribute then attribute.value(object)
240
+ else
241
+ raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
242
+ end
243
+ value.nil? && nil_handler ? instance_exec(object, key, attribute, &nil_handler) : value
244
+ end
140
245
 
141
- @_transform_key_function.call(key.to_s)
246
+ def fetch_attribute_from_object_and_resource(object, attribute)
247
+ has_method = @method_existence[attribute]
248
+ has_method = @method_existence[attribute] = object.respond_to?(attribute) if has_method.nil?
249
+ has_method ? object.public_send(attribute) : __send__(attribute, object)
142
250
  end
143
251
 
144
- def fetch_attribute(object, attribute)
145
- case attribute
146
- when Symbol
147
- object.public_send attribute
148
- when Proc
149
- instance_exec(object, &attribute)
150
- when Alba::One, Alba::Many
151
- within = check_within(attribute.name.to_sym)
152
- return unless within
252
+ def nil_handler
253
+ @nil_handler ||= (@_on_nil || Alba._on_nil)
254
+ end
153
255
 
154
- attribute.to_hash(object, params: params, within: within)
155
- when TypedAttribute
156
- attribute.value(object)
157
- else
158
- raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
159
- end
256
+ def yield_if_within(association_name)
257
+ within = check_within(association_name)
258
+ yield(within) if within
160
259
  end
161
260
 
162
261
  def check_within(association_name)
163
262
  case @within
164
- when WITHIN_DEFAULT # Default value, doesn't check within tree
165
- WITHIN_DEFAULT
166
- when Hash # Traverse within tree
167
- @within.fetch(association_name, nil)
168
- when Array # within tree ends with Array
169
- @within.find { |item| item.to_sym == association_name }
170
- when Symbol # within tree could end with Symbol
171
- @within == association_name
172
- when nil, true, false # In these cases, Alba stops serialization here.
173
- false
263
+ when WITHIN_DEFAULT then WITHIN_DEFAULT # Default value, doesn't check within tree
264
+ when Hash then @within.fetch(association_name, nil) # Traverse within tree
265
+ when Array then @within.find { |item| item.to_sym == association_name }
266
+ when Symbol then @within == association_name
267
+ when nil, true, false then false # Stop here
174
268
  else
175
269
  raise Alba::Error, "Unknown type for within option: #{@within.class}"
176
270
  end
177
271
  end
178
272
 
273
+ # Detect if object is a collection or not.
274
+ # When object is a Struct, it's Enumerable but not a collection
179
275
  def collection?
180
- @object.is_a?(Enumerable)
276
+ @object.is_a?(Enumerable) && !@object.is_a?(Struct)
181
277
  end
182
278
  end
183
279
 
@@ -191,11 +287,15 @@ module Alba
191
287
  DSLS.each_key { |name| subclass.instance_variable_set("@#{name}", instance_variable_get("@#{name}").clone) }
192
288
  end
193
289
 
290
+ # Defining methods for DSLs and disable parameter number check since for users' benefits increasing params is fine
291
+
194
292
  # Set multiple attributes at once
195
293
  #
196
294
  # @param attrs [Array<String, Symbol>]
197
- # @param if [Boolean] condition to decide if it should render these attributes
198
- # @param attrs_with_types [Hash] attributes with name in its key and type and optional type converter in its value
295
+ # @param if [Proc] condition to decide if it should serialize these attributes
296
+ # @param attrs_with_types [Hash<[Symbol, String], [Array<Symbol, Proc>, Symbol]>]
297
+ # attributes with name in its key and type and optional type converter in its value
298
+ # @return [void]
199
299
  def attributes(*attrs, if: nil, **attrs_with_types) # rubocop:disable Naming/MethodParameterName
200
300
  if_value = binding.local_variable_get(:if)
201
301
  assign_attributes(attrs, if_value)
@@ -224,65 +324,109 @@ module Alba
224
324
  # Set an attribute with the given block
225
325
  #
226
326
  # @param name [String, Symbol] key name
227
- # @param options [Hash] option hash including `if` that is a condition to render
327
+ # @param options [Hash<Symbol, Proc>]
328
+ # @option options [Proc] if a condition to decide if this attribute should be serialized
228
329
  # @param block [Block] the block called during serialization
229
330
  # @raise [ArgumentError] if block is absent
331
+ # @return [void]
230
332
  def attribute(name, **options, &block)
231
333
  raise ArgumentError, 'No block given in attribute method' unless block
232
334
 
233
335
  @_attributes[name.to_sym] = options[:if] ? [block, options[:if]] : block
234
336
  end
235
337
 
236
- # Set One association
237
- #
238
- # @param name [String, Symbol]
239
- # @param condition [Proc]
240
- # @param resource [Class<Alba::Resource>]
241
- # @param key [String, Symbol] used as key when given
242
- # @param options [Hash] option hash including `if` that is a condition to render
243
- # @param block [Block]
244
- # @see Alba::One#initialize
245
- def one(name, condition = nil, resource: nil, key: nil, **options, &block)
246
- nesting = self.name&.rpartition('::')&.first
247
- one = One.new(name: name, condition: condition, resource: resource, nesting: nesting, &block)
248
- @_attributes[key&.to_sym || name.to_sym] = options[:if] ? [one, options[:if]] : one
249
- end
250
- alias has_one one
251
-
252
- # Set Many association
338
+ # Set association
253
339
  #
254
- # @param name [String, Symbol]
255
- # @param condition [Proc]
256
- # @param resource [Class<Alba::Resource>]
257
- # @param key [String, Symbol] used as key when given
258
- # @param options [Hash] option hash including `if` that is a condition to render
340
+ # @param name [String, Symbol] name of the association, used as key when `key` param doesn't exist
341
+ # @param condition [Proc, nil] a Proc to modify the association
342
+ # @param resource [Class<Alba::Resource>, String, nil] representing resource for this association
343
+ # @param key [String, Symbol, nil] used as key when given
344
+ # @param options [Hash<Symbol, Proc>]
345
+ # @option options [Proc] if a condition to decide if this association should be serialized
259
346
  # @param block [Block]
260
- # @see Alba::Many#initialize
261
- def many(name, condition = nil, resource: nil, key: nil, **options, &block)
347
+ # @return [void]
348
+ # @see Alba::Association#initialize
349
+ def association(name, condition = nil, resource: nil, key: nil, **options, &block)
262
350
  nesting = self.name&.rpartition('::')&.first
263
- many = Many.new(name: name, condition: condition, resource: resource, nesting: nesting, &block)
264
- @_attributes[key&.to_sym || name.to_sym] = options[:if] ? [many, options[:if]] : many
351
+ assoc = Association.new(name: name, condition: condition, resource: resource, nesting: nesting, &block)
352
+ @_attributes[key&.to_sym || name.to_sym] = options[:if] ? [assoc, options[:if]] : assoc
265
353
  end
266
- alias has_many many
354
+ alias one association
355
+ alias many association
356
+ alias has_one association
357
+ alias has_many association
267
358
 
268
359
  # Set key
269
360
  #
270
361
  # @param key [String, Symbol]
362
+ # @deprecated Use {#root_key} instead
271
363
  def key(key)
364
+ Alba::Deprecation.warn '[DEPRECATION] `key` is deprecated, use `root_key` instead.'
272
365
  @_key = key.respond_to?(:to_sym) ? key.to_sym : key
273
366
  end
274
367
 
368
+ # Set root key
369
+ #
370
+ # @param key [String, Symbol]
371
+ # @param key_for_collection [String, Symbol]
372
+ # @raise [NoMethodError] when key doesn't respond to `to_sym` method
373
+ def root_key(key, key_for_collection = nil)
374
+ @_key = key.to_sym
375
+ @_key_for_collection = key_for_collection&.to_sym
376
+ end
377
+
275
378
  # Set key to true
276
379
  #
380
+ # @deprecated Use {#root_key!} instead
277
381
  def key!
382
+ Alba::Deprecation.warn '[DEPRECATION] `key!` is deprecated, use `root_key!` instead.'
278
383
  @_key = true
384
+ @_key_for_collection = true
279
385
  end
280
386
 
387
+ # Set root key to true
388
+ def root_key!
389
+ @_key = true
390
+ @_key_for_collection = true
391
+ end
392
+
393
+ # Set metadata
394
+ def meta(&block)
395
+ @_meta = block
396
+ end
397
+
398
+ # Set layout
399
+ #
400
+ # @params file [String] name of the layout file
401
+ # @params inline [Proc] a proc returning JSON string or a Hash representing JSON
402
+ def layout(file: nil, inline: nil)
403
+ @_layout = validated_file_layout(file) || validated_inline_layout(inline)
404
+ end
405
+
406
+ def validated_file_layout(filename)
407
+ case filename
408
+ when String, nil then filename
409
+ else
410
+ raise ArgumentError, 'File layout must be a String representing filename'
411
+ end
412
+ end
413
+ private :validated_file_layout
414
+
415
+ def validated_inline_layout(inline_layout)
416
+ case inline_layout
417
+ when Proc, nil then inline_layout
418
+ else
419
+ raise ArgumentError, 'Inline layout must be a Proc returning a Hash or a String'
420
+ end
421
+ end
422
+ private :validated_inline_layout
423
+
281
424
  # Delete attributes
282
425
  # Use this DSL in child class to ignore certain attributes
283
426
  #
284
427
  # @param attributes [Array<String, Symbol>]
285
428
  def ignoring(*attributes)
429
+ Alba::Deprecation.warn '`ignoring` is deprecated now. Instead please use `attributes` instance method to filter out attributes.'
286
430
  attributes.each do |attr_name|
287
431
  @_attributes.delete(attr_name.to_sym)
288
432
  end
@@ -290,23 +434,39 @@ module Alba
290
434
 
291
435
  # Transform keys as specified type
292
436
  #
293
- # @param type [String, Symbol]
294
- # @param root [Boolean] decides if root key also should be transformed
437
+ # @param type [String, Symbol] one of `snake`, `:camel`, `:lower_camel`, `:dash` and `none`
438
+ # @param root [Boolean, nil] decides if root key also should be transformed
439
+ # When it's `nil`, Alba's default setting will be applied
440
+ # @raise [Alba::Error] when type is not supported
295
441
  def transform_keys(type, root: nil)
296
- @_transform_key_function = KeyTransformFactory.create(type.to_sym)
442
+ type = type.to_sym
443
+ unless %i[none snake camel lower_camel dash].include?(type)
444
+ # This should be `ArgumentError` but for backward compatibility it raises `Alba::Error`
445
+ raise ::Alba::Error, "Unknown transform type: #{type}. Supported type are :camel, :lower_camel and :dash."
446
+ end
447
+
448
+ @_transform_type = type
297
449
  @_transforming_root_key = root
298
450
  end
299
451
 
300
452
  # Set error handler
453
+ # If this is set it's used as a error handler overriding global one
301
454
  #
302
- # @param [Symbol] handler
303
- # @param [Block]
455
+ # @param handler [Symbol] `:raise`, `:ignore` or `:nullify`
456
+ # @param block [Block]
304
457
  def on_error(handler = nil, &block)
305
458
  raise ArgumentError, 'You cannot specify error handler with both Symbol and block' if handler && block
306
459
  raise ArgumentError, 'You must specify error handler with either Symbol or block' unless handler || block
307
460
 
308
461
  @_on_error = handler || block
309
462
  end
463
+
464
+ # Set nil handler
465
+ #
466
+ # @param block [Block]
467
+ def on_nil(&block)
468
+ @_on_nil = block
469
+ end
310
470
  end
311
471
  end
312
472
  end
@@ -28,12 +28,9 @@ module Alba
28
28
  def check(object)
29
29
  value = object.public_send(@name)
30
30
  type_correct = case @type
31
- when :String, ->(klass) { klass == String }
32
- value.is_a?(String)
33
- when :Integer, ->(klass) { klass == Integer }
34
- value.is_a?(Integer)
35
- when :Boolean
36
- [true, false].include?(value)
31
+ when :String, ->(klass) { klass == String } then value.is_a?(String)
32
+ when :Integer, ->(klass) { klass == Integer } then value.is_a?(Integer)
33
+ when :Boolean then [true, false].include?(value)
37
34
  else
38
35
  raise Alba::UnsupportedType, "Unknown type: #{@type}"
39
36
  end
data/lib/alba/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Alba
2
- VERSION = '1.3.0'.freeze
2
+ VERSION = '1.6.0'.freeze
3
3
  end