alba 1.6.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/alba/resource.rb CHANGED
@@ -1,13 +1,16 @@
1
1
  require_relative 'association'
2
+ require_relative 'conditional_attribute'
2
3
  require_relative 'typed_attribute'
4
+ require_relative 'nested_attribute'
3
5
  require_relative 'deprecation'
6
+ require_relative 'layout'
4
7
 
5
8
  module Alba
6
9
  # This module represents what should be serialized
7
10
  module Resource
8
11
  # @!parse include InstanceMethods
9
12
  # @!parse extend ClassMethods
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
13
+ 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, _collection_key: nil}.freeze # rubocop:disable Layout/LineLength
11
14
  private_constant :DSLS
12
15
 
13
16
  WITHIN_DEFAULT = Object.new.freeze
@@ -35,74 +38,91 @@ module Alba
35
38
  # @param within [Object, nil, false, true] determines what associations to be serialized. If not set, it serializes all associations.
36
39
  def initialize(object, params: {}, within: WITHIN_DEFAULT)
37
40
  @object = object
38
- @params = params.freeze
41
+ @params = params
39
42
  @within = within
40
43
  @method_existence = {} # Cache for `respond_to?` result
41
- DSLS.each_key { |name| instance_variable_set("@#{name}", self.class.public_send(name)) }
44
+ DSLS.each_key { |name| instance_variable_set("@#{name}", self.class.__send__(name)) }
42
45
  end
43
46
 
44
47
  # Serialize object into JSON string
45
48
  #
46
- # @param key [Symbol, nil, true] DEPRECATED, use root_key instead
47
49
  # @param root_key [Symbol, nil, true]
48
50
  # @param meta [Hash] metadata for this seialization
49
51
  # @return [String] serialized JSON string
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)
60
- end
61
- alias to_json serialize
52
+ def serialize(root_key: nil, meta: {})
53
+ serialize_with(as_json(root_key: root_key, meta: meta))
54
+ end
55
+
56
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.0')
57
+ # For Rails compatibility
58
+ # The first options is a dummy parameter but required
59
+ # You can pass empty Hash if you don't want to pass any arguments
60
+ #
61
+ # @see #serialize
62
+ # @see https://github.com/rails/rails/blob/7-0-stable/actionpack/lib/action_controller/metal/renderers.rb#L156
63
+ def to_json(options, root_key: nil, meta: {})
64
+ _to_json(root_key, meta, options)
65
+ end
66
+ else
67
+ # For Rails compatibility
68
+ # The first options is a dummy parameter
69
+ #
70
+ # @see #serialize
71
+ # @see https://github.com/rails/rails/blob/7-0-stable/actionpack/lib/action_controller/metal/renderers.rb#L156
72
+ def to_json(options = {}, root_key: nil, meta: {})
73
+ _to_json(root_key, meta, options)
74
+ end
75
+ end
76
+
77
+ # Returns a Hash correspondng {Resource#serialize}
78
+ #
79
+ # @param root_key [Symbol, nil, true]
80
+ # @param meta [Hash] metadata for this seialization
81
+ # @param symbolize_root_key [Boolean] determines if root key should be symbolized
82
+ # @return [Hash]
83
+ def as_json(root_key: nil, meta: {})
84
+ key = root_key.nil? ? fetch_key : root_key.to_s
85
+ if key && !key.empty?
86
+ h = {key => serializable_hash}
87
+ hash_with_metadata(h, meta)
88
+ else
89
+ serializable_hash
90
+ end
91
+ end
62
92
 
63
93
  # A Hash for serialization
64
94
  #
65
95
  # @return [Hash]
66
96
  def serializable_hash
67
- collection? ? @object.map(&converter) : converter.call(@object)
97
+ collection? ? serializable_hash_for_collection : converter.call(@object)
68
98
  end
69
99
  alias to_h serializable_hash
70
100
 
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
76
-
77
101
  private
78
102
 
79
- attr_reader :serialized_json # Mainly for layout
80
-
81
103
  def encode(hash)
82
104
  Alba.encoder.call(hash)
83
105
  end
84
106
 
107
+ def _to_json(root_key, meta, options)
108
+ options.reject! { |k, _| %i[layout prefixes template status].include?(k) } # Rails specific guard
109
+ # TODO: use `filter_map` after dropping support of Ruby 2.6
110
+ names = options.map { |k, v| k unless v.nil? }
111
+ names.compact!
112
+ unless names.empty?
113
+ names.sort!
114
+ names.map! { |s| "\"#{s}\"" }
115
+ message = "You passed #{names.join(', ')} options but ignored. Please refer to the document: https://github.com/okuramasafumi/alba/blob/main/docs/rails.md"
116
+ Kernel.warn(message)
117
+ end
118
+ serialize(root_key: root_key, meta: meta)
119
+ end
120
+
85
121
  def serialize_with(hash)
86
122
  serialized_json = encode(hash)
87
123
  return serialized_json unless @_layout
88
124
 
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
125
+ @_layout.serialize(resource: self, serialized_json: serialized_json, binding: binding)
106
126
  end
107
127
 
108
128
  def hash_with_metadata(hash, meta)
@@ -113,130 +133,126 @@ module Alba
113
133
  hash
114
134
  end
115
135
 
136
+ def serializable_hash_for_collection
137
+ if @_collection_key
138
+ @object.to_h { |item| [item.public_send(@_collection_key).to_s, converter.call(item)] }
139
+ else
140
+ @object.each_with_object([], &collection_converter)
141
+ end
142
+ end
143
+
144
+ # @return [String]
116
145
  def fetch_key
117
- collection? ? _key_for_collection : _key
146
+ k = collection? ? _key_for_collection : _key
147
+ transforming_root_key? ? transform_key(k) : k
118
148
  end
119
149
 
120
150
  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
151
+ if Alba.inferring
152
+ @_key_for_collection == true ? resource_name(pluralized: true) : @_key_for_collection.to_s
153
+ else
154
+ @_key_for_collection == true ? raise_root_key_inference_error : @_key_for_collection.to_s
155
+ end
125
156
  end
126
157
 
127
158
  # @return [String]
128
159
  def _key
129
- return @_key.to_s unless @_key == true && Alba.inferring
160
+ if Alba.inferring
161
+ @_key == true ? resource_name(pluralized: false) : @_key.to_s
162
+ else
163
+ @_key == true ? raise_root_key_inference_error : @_key.to_s
164
+ end
165
+ end
130
166
 
131
- transforming_root_key? ? transform_key(resource_name) : resource_name
167
+ def resource_name(pluralized: false)
168
+ class_name = self.class.name
169
+ inflector = Alba.inflector
170
+ name = inflector.demodulize(class_name).delete_suffix('Resource')
171
+ underscore_name = inflector.underscore(name)
172
+ pluralized ? inflector.pluralize(underscore_name) : underscore_name
132
173
  end
133
174
 
134
- def resource_name
135
- @resource_name ||= self.class.name.demodulize.delete_suffix('Resource').underscore
175
+ def raise_root_key_inference_error
176
+ raise Alba::Error, 'You must call Alba.enable_inference! to set root_key to true for inferring root key.'
136
177
  end
137
178
 
138
179
  def transforming_root_key?
139
- @_transforming_root_key.nil? ? Alba.transforming_root_key : @_transforming_root_key
180
+ @_transforming_root_key
140
181
  end
141
182
 
142
- # rubocop:disable Metrics/MethodLength
143
183
  def converter
144
184
  lambda do |object|
145
- arrays = attributes.map do |key, attribute|
146
- key_and_attribute_body_from(object, key, attribute)
147
- rescue ::Alba::Error, FrozenError, TypeError
148
- raise
149
- rescue StandardError => e
150
- handle_error(e, object, key, attribute)
151
- end
152
- arrays.compact!
153
- arrays.to_h
185
+ attributes_to_hash(object, {})
154
186
  end
155
187
  end
156
- # rubocop:enable Metrics/MethodLength
157
188
 
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
163
-
164
- def key_and_attribute_body_from(object, key, attribute)
165
- key = transform_key(key)
166
- if attribute.is_a?(Array) # Conditional
167
- conditional_attribute(object, key, attribute)
168
- else
169
- fetched_attribute = fetch_attribute(object, key, attribute)
170
- [key, fetched_attribute]
189
+ def collection_converter
190
+ lambda do |object, a|
191
+ a << {}
192
+ h = a.last
193
+ attributes_to_hash(object, h)
194
+ a
171
195
  end
172
196
  end
173
197
 
174
- def conditional_attribute(object, key, attribute)
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)
198
+ def attributes_to_hash(object, hash)
199
+ attributes.each do |key, attribute|
200
+ set_key_and_attribute_body_from(object, key, attribute, hash)
201
+ rescue ::Alba::Error, FrozenError, TypeError
202
+ raise
203
+ rescue StandardError => e
204
+ handle_error(e, object, key, attribute, hash)
180
205
  end
206
+ hash
181
207
  end
182
208
 
183
- def conditional_attribute_with_proc(object, key, attribute, condition)
184
- arity = condition.arity
185
- # We can return early to skip fetch_attribute
186
- return if arity <= 1 && !instance_exec(object, &condition)
187
-
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)
191
-
192
- [key, fetched_attribute]
209
+ # This is default behavior for getting attributes for serialization
210
+ # Override this method to filter certain attributes
211
+ def attributes
212
+ @_attributes
193
213
  end
194
214
 
195
- def conditional_attribute_with_symbol(object, key, attribute, condition)
196
- return unless __send__(condition)
197
-
198
- [key, fetch_attribute(object, key, attribute)]
215
+ def set_key_and_attribute_body_from(object, key, attribute, hash)
216
+ key = transform_key(key)
217
+ value = fetch_attribute(object, key, attribute)
218
+ hash[key] = value unless value == ConditionalAttribute::CONDITION_UNMET
199
219
  end
200
220
 
201
- def handle_error(error, object, key, attribute)
202
- on_error = @_on_error || Alba._on_error
203
- case on_error
204
- when :raise, nil then raise
205
- when :nullify then [key, nil]
221
+ def handle_error(error, object, key, attribute, hash)
222
+ on_error = @_on_error || :raise
223
+ case on_error # rubocop:disable Style/MissingElse
224
+ when :raise, nil then raise(error)
225
+ when :nullify then hash[key] = nil
206
226
  when :ignore then nil
207
- when Proc then on_error.call(error, object, key, attribute, self.class)
208
- else
209
- raise ::Alba::Error, "Unknown on_error: #{on_error.inspect}"
227
+ when Proc
228
+ key, value = on_error.call(error, object, key, attribute, self.class)
229
+ hash[key] = value
210
230
  end
211
231
  end
212
232
 
213
- # rubocop:disable Metrics/MethodLength
214
233
  # @return [Symbol]
215
- def transform_key(key)
216
- return key if @_transform_type == :none
217
-
234
+ def transform_key(key) # rubocop:disable Metrics/CyclomaticComplexity
218
235
  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
236
+ return key if @_transform_type == :none || key.empty? # We can skip transformation
237
+
238
+ inflector = Alba.inflector
239
+ raise Alba::Error, 'Inflector is nil. You can set inflector with `Alba.enable_inference!(with: :active_support)` for example.' unless inflector
240
+
225
241
  case @_transform_type # rubocop:disable Style/MissingElse
226
242
  when :camel then inflector.camelize(key)
227
243
  when :lower_camel then inflector.camelize_lower(key)
228
244
  when :dash then inflector.dasherize(key)
229
245
  when :snake then inflector.underscore(key)
230
- end.to_sym
246
+ end
231
247
  end
232
- # rubocop:enable Metrics/MethodLength
233
248
 
234
- def fetch_attribute(object, key, attribute)
249
+ def fetch_attribute(object, key, attribute) # rubocop:disable Metrics/CyclomaticComplexity
235
250
  value = case attribute
236
251
  when Symbol then fetch_attribute_from_object_and_resource(object, attribute)
237
252
  when Proc then instance_exec(object, &attribute)
238
253
  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)
254
+ when TypedAttribute, NestedAttribute then attribute.value(object)
255
+ when ConditionalAttribute then attribute.with_passing_condition(resource: self, object: object) { |attr| fetch_attribute(object, key, attr) }
240
256
  else
241
257
  raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
242
258
  end
@@ -246,11 +262,11 @@ module Alba
246
262
  def fetch_attribute_from_object_and_resource(object, attribute)
247
263
  has_method = @method_existence[attribute]
248
264
  has_method = @method_existence[attribute] = object.respond_to?(attribute) if has_method.nil?
249
- has_method ? object.public_send(attribute) : __send__(attribute, object)
265
+ has_method ? object.__send__(attribute) : __send__(attribute, object)
250
266
  end
251
267
 
252
268
  def nil_handler
253
- @nil_handler ||= (@_on_nil || Alba._on_nil)
269
+ @_on_nil
254
270
  end
255
271
 
256
272
  def yield_if_within(association_name)
@@ -304,7 +320,7 @@ module Alba
304
320
 
305
321
  def assign_attributes(attrs, if_value)
306
322
  attrs.each do |attr_name|
307
- attr = if_value ? [attr_name.to_sym, if_value] : attr_name.to_sym
323
+ attr = if_value ? ConditionalAttribute.new(body: attr_name.to_sym, condition: if_value) : attr_name.to_sym
308
324
  @_attributes[attr_name.to_sym] = attr
309
325
  end
310
326
  end
@@ -315,7 +331,7 @@ module Alba
315
331
  attr_name = attr_name.to_sym
316
332
  type, type_converter = type_and_converter
317
333
  typed_attr = TypedAttribute.new(name: attr_name, type: type, converter: type_converter)
318
- attr = if_value ? [typed_attr, if_value] : typed_attr
334
+ attr = if_value ? ConditionalAttribute.new(body: typed_attr, condition: if_value) : typed_attr
319
335
  @_attributes[attr_name] = attr
320
336
  end
321
337
  end
@@ -332,38 +348,59 @@ module Alba
332
348
  def attribute(name, **options, &block)
333
349
  raise ArgumentError, 'No block given in attribute method' unless block
334
350
 
335
- @_attributes[name.to_sym] = options[:if] ? [block, options[:if]] : block
351
+ @_attributes[name.to_sym] = options[:if] ? ConditionalAttribute.new(body: block, condition: options[:if]) : block
336
352
  end
337
353
 
338
354
  # Set association
339
355
  #
340
356
  # @param name [String, Symbol] name of the association, used as key when `key` param doesn't exist
341
357
  # @param condition [Proc, nil] a Proc to modify the association
342
- # @param resource [Class<Alba::Resource>, String, nil] representing resource for this association
358
+ # @param resource [Class<Alba::Resource>, String, Proc, nil] representing resource for this association
343
359
  # @param key [String, Symbol, nil] used as key when given
360
+ # @param params [Hash] params override for the association
344
361
  # @param options [Hash<Symbol, Proc>]
345
362
  # @option options [Proc] if a condition to decide if this association should be serialized
346
363
  # @param block [Block]
347
364
  # @return [void]
348
365
  # @see Alba::Association#initialize
349
- def association(name, condition = nil, resource: nil, key: nil, **options, &block)
350
- nesting = self.name&.rpartition('::')&.first
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
366
+ def association(name, condition = nil, resource: nil, key: nil, params: {}, **options, &block)
367
+ key_transformation = @_key_transformation_cascade ? @_transform_type : :none
368
+ assoc = Association.new(
369
+ name: name, condition: condition, resource: resource, params: params, nesting: nesting, key_transformation: key_transformation,
370
+ &block
371
+ )
372
+ @_attributes[key&.to_sym || name.to_sym] = options[:if] ? ConditionalAttribute.new(body: assoc, condition: options[:if]) : assoc
353
373
  end
354
374
  alias one association
355
375
  alias many association
356
376
  alias has_one association
357
377
  alias has_many association
358
378
 
359
- # Set key
379
+ def nesting
380
+ if name.nil?
381
+ nil
382
+ else
383
+ name.rpartition('::').first.tap { |n| n.empty? ? nil : n }
384
+ end
385
+ end
386
+ private :nesting
387
+
388
+ # Set a nested attribute with the given block
360
389
  #
361
- # @param key [String, Symbol]
362
- # @deprecated Use {#root_key} instead
363
- def key(key)
364
- Alba::Deprecation.warn '[DEPRECATION] `key` is deprecated, use `root_key` instead.'
365
- @_key = key.respond_to?(:to_sym) ? key.to_sym : key
390
+ # @param name [String, Symbol] key name
391
+ # @param options [Hash<Symbol, Proc>]
392
+ # @option options [Proc] if a condition to decide if this attribute should be serialized
393
+ # @param block [Block] the block called during serialization
394
+ # @raise [ArgumentError] if block is absent
395
+ # @return [void]
396
+ def nested_attribute(name, **options, &block)
397
+ raise ArgumentError, 'No block given in attribute method' unless block
398
+
399
+ key_transformation = @_key_transformation_cascade ? @_transform_type : :none
400
+ attribute = NestedAttribute.new(key_transformation: key_transformation, &block)
401
+ @_attributes[name.to_sym] = options[:if] ? ConditionalAttribute.new(body: attribute, condition: options[:if]) : attribute
366
402
  end
403
+ alias nested nested_attribute
367
404
 
368
405
  # Set root key
369
406
  #
@@ -375,13 +412,13 @@ module Alba
375
412
  @_key_for_collection = key_for_collection&.to_sym
376
413
  end
377
414
 
378
- # Set key to true
415
+ # Set root key for collection
379
416
  #
380
- # @deprecated Use {#root_key!} instead
381
- def key!
382
- Alba::Deprecation.warn '[DEPRECATION] `key!` is deprecated, use `root_key!` instead.'
417
+ # @param key [String, Symbol]
418
+ # @raise [NoMethodError] when key doesn't respond to `to_sym` method
419
+ def root_key_for_collection(key)
383
420
  @_key = true
384
- @_key_for_collection = true
421
+ @_key_for_collection = key.to_sym
385
422
  end
386
423
 
387
424
  # Set root key to true
@@ -400,45 +437,17 @@ module Alba
400
437
  # @params file [String] name of the layout file
401
438
  # @params inline [Proc] a proc returning JSON string or a Hash representing JSON
402
439
  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
-
424
- # Delete attributes
425
- # Use this DSL in child class to ignore certain attributes
426
- #
427
- # @param attributes [Array<String, Symbol>]
428
- def ignoring(*attributes)
429
- Alba::Deprecation.warn '`ignoring` is deprecated now. Instead please use `attributes` instance method to filter out attributes.'
430
- attributes.each do |attr_name|
431
- @_attributes.delete(attr_name.to_sym)
432
- end
440
+ @_layout = Layout.new(file: file, inline: inline)
433
441
  end
434
442
 
435
443
  # Transform keys as specified type
436
444
  #
437
445
  # @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
446
+ # @param root [Boolean] decides if root key also should be transformed
447
+ # @param cascade [Boolean] decides if key transformation cascades into inline association
448
+ # Default is true but can be set false for old (v1) behavior
440
449
  # @raise [Alba::Error] when type is not supported
441
- def transform_keys(type, root: nil)
450
+ def transform_keys(type, root: true, cascade: true)
442
451
  type = type.to_sym
443
452
  unless %i[none snake camel lower_camel dash].include?(type)
444
453
  # This should be `ArgumentError` but for backward compatibility it raises `Alba::Error`
@@ -447,6 +456,14 @@ module Alba
447
456
 
448
457
  @_transform_type = type
449
458
  @_transforming_root_key = root
459
+ @_key_transformation_cascade = cascade
460
+ end
461
+
462
+ # Sets key for collection serialization
463
+ #
464
+ # @param key [String, Symbol]
465
+ def collection_key(key)
466
+ @_collection_key = key.to_sym
450
467
  end
451
468
 
452
469
  # Set error handler
@@ -458,8 +475,19 @@ module Alba
458
475
  raise ArgumentError, 'You cannot specify error handler with both Symbol and block' if handler && block
459
476
  raise ArgumentError, 'You must specify error handler with either Symbol or block' unless handler || block
460
477
 
461
- @_on_error = handler || block
478
+ @_on_error = block || validated_error_handler(handler)
479
+ end
480
+
481
+ def validated_error_handler(handler)
482
+ unless %i[raise ignore nullify].include?(handler)
483
+ # For backward compatibility
484
+ # TODO: Change this to ArgumentError
485
+ raise Alba::Error, "Unknown error handler: #{handler}. It must be one of `:raise`, `:ignore` or `:nullify`."
486
+ end
487
+
488
+ handler
462
489
  end
490
+ private :validated_error_handler
463
491
 
464
492
  # Set nil handler
465
493
  #
@@ -26,7 +26,7 @@ module Alba
26
26
  private
27
27
 
28
28
  def check(object)
29
- value = object.public_send(@name)
29
+ value = object.__send__(@name)
30
30
  type_correct = case @type
31
31
  when :String, ->(klass) { klass == String } then value.is_a?(String)
32
32
  when :Integer, ->(klass) { klass == Integer } then value.is_a?(Integer)
data/lib/alba/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Alba
2
- VERSION = '1.6.0'.freeze
2
+ VERSION = '2.0.0'.freeze
3
3
  end