alba 3.9.1 → 3.11.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 +4 -4
- data/CHANGELOG.md +31 -1
- data/README.md +34 -11
- data/lib/alba/association.rb +1 -9
- data/lib/alba/nested_attribute.rb +7 -5
- data/lib/alba/railtie.rb +4 -4
- data/lib/alba/resource.rb +32 -21
- data/lib/alba/typed_attribute.rb +4 -3
- data/lib/alba/version.rb +1 -1
- data/lib/alba.rb +33 -11
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 18b9be1d51ec5b7bed2d31fc59904a57c8dc7f4e24eb1a7cb6364a42ec8a27ec
|
|
4
|
+
data.tar.gz: 4112d0ace0fda10a9e6aee754e2b056b6488924fddbd5f12040652a2fcbbda75
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7bee8581bad84469254b1282b3c81bdaf493be4f2c5ee1b31747b16f2908f4e2639d783ac9fa7e6f345b361117512f0ce4b208a81a2f000e05455d3bc875b08b
|
|
7
|
+
data.tar.gz: 6939052cd6b8ea09f23df209874c858aadc032193a0ab5729bd04d33bbf7d24e3223cc642494a0095ca4a8f7a4b182fdd4cbd4e9781c1d4689e205953c2ca2e7
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## 3.11.0 2026-07-25
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Rails: `serialize` and `render_serialized_json` now takes `params` [#509](https://github.com/okuramasafumi/alba/pull/509)
|
|
14
|
+
- Add `Alba.non_collection_types` for declaring Enumerable classes that should not be treated as collections [#532](https://github.com/okuramasafumi/alba/pull/532)
|
|
15
|
+
- Add default superclass configuration [#547](https://github.com/okuramasafumi/alba/pull/547)
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Trait redefining base-level attribute causes wrong result with multiple traits [#498](https://github.com/okuramasafumi/alba/issues/498) and [#502](https://github.com/okuramasafumi/alba/pull/502)
|
|
20
|
+
- Thank you for reporting this issue, @yukihiro-numata
|
|
21
|
+
- Pass params to resource in serialize when with is given [#524](https://github.com/okuramasafumi/alba/pull/524)
|
|
22
|
+
- Thank you, @JohnnyKei
|
|
23
|
+
- `Alba.serialize(single, with: SomeResource)` crash
|
|
24
|
+
- helpers are now available in NestedAttribute [#503](https://github.com/okuramasafumi/alba/pull/503)
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- More strict types
|
|
29
|
+
|
|
30
|
+
## 3.10.0 2025-11-11
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- Support type validation and coercion for a single attribute method [#470](https://github.com/okuramasafumi/alba/pull/470)
|
|
35
|
+
- Thank you [@denblackstache](https://github.com/denblackstache) for requesting the feature
|
|
36
|
+
- Fix hash object resource methods [#475](https://github.com/okuramasafumi/alba/pull/475)
|
|
37
|
+
- Thank you, [@jkmcrg](https://github.com/jkmcrg)
|
|
38
|
+
|
|
9
39
|
## 3.9.1 2025-09-27
|
|
10
40
|
|
|
11
41
|
### Added
|
|
@@ -189,7 +219,7 @@ This change is supposed to be released as 3.8.0 with the change in 3.7.4, but I
|
|
|
189
219
|
|
|
190
220
|
## [2.4.1] 2023-08-02
|
|
191
221
|
|
|
192
|
-
|
|
222
|
+
### Fixed
|
|
193
223
|
|
|
194
224
|
- Fix the bug of resource name inference for classes whose name end with "Serializer" [No PR](https://github.com/okuramasafumi/alba/commit/1695af4351981725231fd071aaef5b2e4174fb26)
|
|
195
225
|
|
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://badge.fury.io/rb/alba)
|
|
4
4
|
[](https://github.com/okuramasafumi/alba/actions/workflows/main.yml)
|
|
5
5
|
[](https://codecov.io/gh/okuramasafumi/alba)
|
|
6
|
-
[](https://app.codacy.com/gh/okuramasafumi/alba/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
7
7
|

|
|
8
8
|

|
|
9
9
|
[](CODE_OF_CONDUCT.md)
|
|
@@ -56,6 +56,12 @@ UserResource.new(user).serialize
|
|
|
56
56
|
|
|
57
57
|
Seems useful? Continue reading!
|
|
58
58
|
|
|
59
|
+
Pro tip: You can find more examples in separate Ruby files under "examples" directory.
|
|
60
|
+
|
|
61
|
+
### Coming from ActiveModelSerializers(AMS)?
|
|
62
|
+
|
|
63
|
+
If you are using ActiveModelSerializers and interested in Alba, we have an automatic converter! [alba_migration](https://github.com/ShoheiMitani/alba_migration) gem from [ShoheiMitani](https://github.com/ShoheiMitani) "provides a command-line tool to convert AMS serializer classes to Alba resource classes, making your migration process easier and less error-prone."
|
|
64
|
+
|
|
59
65
|
## Discussions
|
|
60
66
|
|
|
61
67
|
Alba uses [GitHub Discussions](https://github.com/okuramasafumi/alba/discussions) to openly discuss the project.
|
|
@@ -100,6 +106,7 @@ While Alba's core is simple, it provides additional features when you need them.
|
|
|
100
106
|
- Well tested, the test coverage is 99%
|
|
101
107
|
- Well maintained, getting frequent update and new releases (see [version history](https://rubygems.org/gems/alba/versions))
|
|
102
108
|
|
|
109
|
+
|
|
103
110
|
## Comparison with other serializers
|
|
104
111
|
|
|
105
112
|
Alba aims to provide a well-balanced combination of simplicity, performance, and features. Here's how it compares to other popular Ruby JSON serializers:
|
|
@@ -138,7 +145,7 @@ Or install it yourself as:
|
|
|
138
145
|
|
|
139
146
|
## Supported Ruby versions
|
|
140
147
|
|
|
141
|
-
Alba
|
|
148
|
+
Alba works with CRuby 3.0 and higher and latest JRuby and TruffleRuby. However, Ruby 3.0 is not actively tested, so use it at your own risk.
|
|
142
149
|
|
|
143
150
|
## Documentation
|
|
144
151
|
|
|
@@ -228,6 +235,20 @@ else
|
|
|
228
235
|
end
|
|
229
236
|
```
|
|
230
237
|
|
|
238
|
+
#### Default superclass configuration
|
|
239
|
+
|
|
240
|
+
You can set the default superclass for resource classes created for Nested Attributes and Traits.
|
|
241
|
+
|
|
242
|
+
```ruby
|
|
243
|
+
Alba.default_superclass = MyBaseSerializer
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Note that in some environments like Rails applications, the class object is not loaded in the initializer phase. You can also set `String`.
|
|
247
|
+
|
|
248
|
+
```ruby
|
|
249
|
+
Alba.default_superclass = 'MyBaseSerializer'
|
|
250
|
+
```
|
|
251
|
+
|
|
231
252
|
### Naming
|
|
232
253
|
|
|
233
254
|
Alba tries to infer resource name from class name like the following.
|
|
@@ -349,7 +370,7 @@ end
|
|
|
349
370
|
class FooResource
|
|
350
371
|
include Alba::Resource
|
|
351
372
|
|
|
352
|
-
attributes :
|
|
373
|
+
attributes :format
|
|
353
374
|
|
|
354
375
|
# Here, `format` method is available
|
|
355
376
|
end
|
|
@@ -1921,16 +1942,18 @@ Don't forget calling `super` in this way.
|
|
|
1921
1942
|
|
|
1922
1943
|
### Treating specific classes as non-collection
|
|
1923
1944
|
|
|
1924
|
-
Sometimes we need to serialize an object that's `Enumerable` but not a collection. By default, Alba treats `Hash`, `Range` and `Struct` as non-collection
|
|
1945
|
+
Sometimes we need to serialize an object that's `Enumerable` but not a collection. By default, Alba treats `Hash`, `Range` and `Struct` as non-collection objects. You can add additional classes to this list via `Alba.non_collection_types`:
|
|
1925
1946
|
|
|
1926
1947
|
```ruby
|
|
1927
|
-
Alba.
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1948
|
+
Alba.non_collection_types << Stripe::StripeObject
|
|
1949
|
+
Alba.non_collection_types << MyEnumerableEntity
|
|
1950
|
+
```
|
|
1951
|
+
|
|
1952
|
+
You can inspect the current list of excluded types (including the defaults) at any time:
|
|
1953
|
+
|
|
1954
|
+
```ruby
|
|
1955
|
+
Alba.non_collection_types
|
|
1956
|
+
# => [Struct, Range, Hash, Stripe::StripeObject, MyEnumerableEntity]
|
|
1934
1957
|
```
|
|
1935
1958
|
|
|
1936
1959
|
### Adding indexes to `many` association
|
data/lib/alba/association.rb
CHANGED
|
@@ -101,7 +101,7 @@ module Alba
|
|
|
101
101
|
|
|
102
102
|
def assign_resource(nesting, key_transformation, block, helper)
|
|
103
103
|
@resource = if block
|
|
104
|
-
|
|
104
|
+
Alba.resource_class(helper: helper, key_transformation: key_transformation, &block)
|
|
105
105
|
elsif Alba.inflector
|
|
106
106
|
Alba.infer_resource_class(@name, nesting: nesting)
|
|
107
107
|
else
|
|
@@ -109,14 +109,6 @@ module Alba
|
|
|
109
109
|
end
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
-
def charged_resource_class(helper, key_transformation, block)
|
|
113
|
-
klass = Alba.resource_class
|
|
114
|
-
klass.helper(helper) if helper
|
|
115
|
-
klass.transform_keys(key_transformation)
|
|
116
|
-
klass.class_eval(&block)
|
|
117
|
-
klass
|
|
118
|
-
end
|
|
119
|
-
|
|
120
112
|
def to_h_with_each_resource(object, within, params)
|
|
121
113
|
object.map do |item|
|
|
122
114
|
@resource.call(item).new(item, within: within, params: params, with_traits: @with_traits).to_h
|
|
@@ -7,9 +7,11 @@ module Alba
|
|
|
7
7
|
# Setter for key_transformation, used when it's changed after class definition
|
|
8
8
|
attr_writer :key_transformation
|
|
9
9
|
|
|
10
|
+
# @param klass [Class<Alba::Resource>] the parent for this nested attribute
|
|
10
11
|
# @param key_transformation [Symbol] determines how to transform keys
|
|
11
12
|
# @param block [Proc] class body
|
|
12
|
-
def initialize(key_transformation: :none, &block)
|
|
13
|
+
def initialize(klass:, key_transformation: :none, &block)
|
|
14
|
+
@klass = klass
|
|
13
15
|
@key_transformation = key_transformation
|
|
14
16
|
@block = block
|
|
15
17
|
end
|
|
@@ -17,13 +19,13 @@ module Alba
|
|
|
17
19
|
# @param object [Object] the object being serialized
|
|
18
20
|
# @param params [Hash] params Hash inherited from Resource
|
|
19
21
|
# @param within [Object, nil, false, true] determines what associations to be serialized. If not set, it serializes all associations.
|
|
20
|
-
# @param select [Method] select method object from its origin
|
|
21
22
|
# @return [Hash] hash serialized from running the class body in the object
|
|
22
|
-
def value(object:, params:, within
|
|
23
|
-
resource_class =
|
|
23
|
+
def value(object:, params:, within:)
|
|
24
|
+
resource_class = Class.new(@klass)
|
|
25
|
+
resource_class.instance_variable_set(:@_attributes, {}) # reset
|
|
24
26
|
resource_class.transform_keys(@key_transformation)
|
|
25
27
|
resource_class.class_eval(&@block)
|
|
26
|
-
resource_class.new(object, params: params, within: within
|
|
28
|
+
resource_class.new(object, params: params, within: within).serializable_hash
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
end
|
data/lib/alba/railtie.rb
CHANGED
|
@@ -7,13 +7,13 @@ module Alba
|
|
|
7
7
|
Alba.inflector = :active_support
|
|
8
8
|
|
|
9
9
|
ActiveSupport.on_load(:action_controller) do
|
|
10
|
-
define_method(:serialize) do |obj, with: nil, root_key: nil, meta: {}, &block|
|
|
11
|
-
resource = with.nil? ? Alba.resource_for(obj, &block) : with.new(obj)
|
|
10
|
+
define_method(:serialize) do |obj, params: {}, with: nil, root_key: nil, meta: {}, &block|
|
|
11
|
+
resource = with.nil? ? Alba.resource_for(obj, params: params, &block) : with.new(obj, params: params)
|
|
12
12
|
resource.to_json(root_key: root_key, meta: meta)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
define_method(:render_serialized_json) do |obj, with: nil, root_key: nil, meta: {}, &block|
|
|
16
|
-
json = with.nil? ? Alba.resource_for(obj, &block) : with.new(obj)
|
|
15
|
+
define_method(:render_serialized_json) do |obj, params: {}, with: nil, root_key: nil, meta: {}, &block|
|
|
16
|
+
json = with.nil? ? Alba.resource_for(obj, params: params, &block) : with.new(obj, params: params)
|
|
17
17
|
render json: json.to_json(root_key: root_key, meta: meta)
|
|
18
18
|
end
|
|
19
19
|
end
|
data/lib/alba/resource.rb
CHANGED
|
@@ -20,6 +20,9 @@ module Alba
|
|
|
20
20
|
WITHIN_DEFAULT = Object.new.freeze
|
|
21
21
|
private_constant :WITHIN_DEFAULT
|
|
22
22
|
|
|
23
|
+
EMPTY_HASH = {}.freeze
|
|
24
|
+
private_constant :EMPTY_HASH
|
|
25
|
+
|
|
23
26
|
# `setup` method is meta-programmatically defined here for performance.
|
|
24
27
|
# @api private
|
|
25
28
|
def self.included(base) # rubocop:disable Metrics/MethodLength
|
|
@@ -48,15 +51,13 @@ module Alba
|
|
|
48
51
|
# @param within [Alba::WITHIN_DEFAULT, Hash, Array, nil, false, true]
|
|
49
52
|
# determines what associations to be serialized. If not set, it serializes all associations.
|
|
50
53
|
# @param with_traits [Symbol, Array<Symbol>, nil] specified traits
|
|
51
|
-
# @param select [Method]
|
|
52
|
-
def initialize(object, params:
|
|
54
|
+
# @param select [Method] DEPRECATED noop
|
|
55
|
+
def initialize(object, params: EMPTY_HASH, within: WITHIN_DEFAULT, with_traits: nil, select: nil)
|
|
53
56
|
@object = object
|
|
54
57
|
@params = params
|
|
55
58
|
@within = within
|
|
56
59
|
@with_traits = with_traits
|
|
57
|
-
|
|
58
|
-
# Trait and NestedAttribute generates anonymous class so it checks if it's anonymous class to prevent accidental overriding
|
|
59
|
-
self.class.define_method(:select, &select) if select && self.class.name.nil?
|
|
60
|
+
warn '`select` keyword for Alba::Resource is deprecated', category: :deprecated, uplevel: 1 if select
|
|
60
61
|
_setup
|
|
61
62
|
end
|
|
62
63
|
|
|
@@ -65,7 +66,7 @@ module Alba
|
|
|
65
66
|
# @param root_key [Symbol, nil]
|
|
66
67
|
# @param meta [Hash] metadata for this serialization
|
|
67
68
|
# @return [String] serialized JSON string
|
|
68
|
-
def serialize(root_key: nil, meta:
|
|
69
|
+
def serialize(root_key: nil, meta: EMPTY_HASH)
|
|
69
70
|
serialize_with(as_json(root_key: root_key, meta: meta))
|
|
70
71
|
end
|
|
71
72
|
|
|
@@ -74,7 +75,7 @@ module Alba
|
|
|
74
75
|
#
|
|
75
76
|
# @see #serialize
|
|
76
77
|
# @see https://github.com/rails/rails/blob/7-0-stable/actionpack/lib/action_controller/metal/renderers.rb#L156
|
|
77
|
-
def to_json(options =
|
|
78
|
+
def to_json(options = EMPTY_HASH, root_key: nil, meta: EMPTY_HASH)
|
|
78
79
|
confusing_keys = [:only, :except]
|
|
79
80
|
confusing_options = options.keys.select { |k| confusing_keys.include?(k.to_sym) }
|
|
80
81
|
unless confusing_options.empty?
|
|
@@ -92,7 +93,7 @@ module Alba
|
|
|
92
93
|
# @param root_key [Symbol, nil]
|
|
93
94
|
# @param meta [Hash] metadata for this serialization
|
|
94
95
|
# @return [Hash]
|
|
95
|
-
def as_json(_options =
|
|
96
|
+
def as_json(_options = EMPTY_HASH, root_key: nil, meta: EMPTY_HASH)
|
|
96
97
|
key = root_key.nil? ? fetch_key : root_key
|
|
97
98
|
key = Alba.regularize_key(key)
|
|
98
99
|
if key && !key.empty?
|
|
@@ -119,9 +120,10 @@ module Alba
|
|
|
119
120
|
Array(@with_traits).each_with_object({}) do |trait, hash|
|
|
120
121
|
body = @_traits.fetch(trait) { raise Alba::Error, "Trait not found: #{trait}" }
|
|
121
122
|
resource_class = Class.new(self.class)
|
|
123
|
+
resource_class.instance_variable_set(:@_attributes, {})
|
|
122
124
|
resource_class.class_eval(&body)
|
|
123
125
|
resource_class.transform_keys(@_transform_type) unless @_transform_type == :none
|
|
124
|
-
hash.merge!(resource_class.new(obj, params: params, within: @within
|
|
126
|
+
hash.merge!(resource_class.new(obj, params: params, within: @within).serializable_hash)
|
|
125
127
|
end
|
|
126
128
|
end
|
|
127
129
|
|
|
@@ -290,8 +292,8 @@ module Alba
|
|
|
290
292
|
when Symbol then fetch_attribute_from_object_and_resource(obj, attribute)
|
|
291
293
|
when Proc then instance_exec(obj, &attribute)
|
|
292
294
|
when Alba::Association then yield_if_within(attribute.name.to_sym) { |within| attribute.to_h(obj, params: params, within: within) }
|
|
293
|
-
when TypedAttribute then attribute.value { |attr| fetch_attribute(obj, key, attr) }
|
|
294
|
-
when NestedAttribute then attribute.value(object: obj, params: params, within: @within
|
|
295
|
+
when TypedAttribute then attribute.value(object: obj) { |attr| fetch_attribute(obj, key, attr) }
|
|
296
|
+
when NestedAttribute then attribute.value(object: obj, params: params, within: @within)
|
|
295
297
|
when ConditionalAttribute then attribute.with_passing_condition(resource: self, object: obj) { |attr| fetch_attribute(obj, key, attr) }
|
|
296
298
|
# :nocov:
|
|
297
299
|
else raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
|
|
@@ -308,7 +310,7 @@ module Alba
|
|
|
308
310
|
return obj.fetch(attribute) if obj.is_a?(Hash)
|
|
309
311
|
|
|
310
312
|
obj.__send__(attribute)
|
|
311
|
-
rescue NoMethodError
|
|
313
|
+
rescue NoMethodError, KeyError
|
|
312
314
|
__send__(attribute, obj)
|
|
313
315
|
end
|
|
314
316
|
|
|
@@ -320,6 +322,8 @@ module Alba
|
|
|
320
322
|
else
|
|
321
323
|
obj.__send__(attribute)
|
|
322
324
|
end
|
|
325
|
+
rescue KeyError
|
|
326
|
+
__send__(attribute, obj)
|
|
323
327
|
end
|
|
324
328
|
|
|
325
329
|
def nil_handler
|
|
@@ -399,11 +403,11 @@ module Alba
|
|
|
399
403
|
end
|
|
400
404
|
private :assign_attributes
|
|
401
405
|
|
|
402
|
-
def assign_attributes_with_types(attrs_with_types, if_value)
|
|
406
|
+
def assign_attributes_with_types(attrs_with_types, if_value, &block)
|
|
403
407
|
attrs_with_types.each do |attr_name, type_and_converter|
|
|
404
408
|
attr_name = attr_name.to_sym
|
|
405
409
|
type, type_converter = type_and_converter
|
|
406
|
-
typed_attr = TypedAttribute.new(name: attr_name, type: type, converter: type_converter)
|
|
410
|
+
typed_attr = TypedAttribute.new(name: attr_name, type: type, converter: type_converter, &block)
|
|
407
411
|
attr = if_value ? ConditionalAttribute.new(body: typed_attr, condition: if_value) : typed_attr
|
|
408
412
|
@_attributes[attr_name] = attr
|
|
409
413
|
end
|
|
@@ -413,15 +417,21 @@ module Alba
|
|
|
413
417
|
# Set an attribute with the given block
|
|
414
418
|
#
|
|
415
419
|
# @param name [String, Symbol] key name
|
|
416
|
-
# @param
|
|
417
|
-
# @option options [Proc] if a condition to decide if this attribute should be serialized
|
|
420
|
+
# @param if [Proc] condition to decide if it should serialize these attributes
|
|
418
421
|
# @param block [Block] the block called during serialization
|
|
419
422
|
# @raise [ArgumentError] if block is absent
|
|
420
423
|
# @return [void]
|
|
421
|
-
def attribute(name, **
|
|
424
|
+
def attribute(name = nil, if: nil, **name_with_type, &block)
|
|
425
|
+
if_value = binding.local_variable_get(:if)
|
|
422
426
|
raise ArgumentError, 'No block given in attribute method' unless block
|
|
427
|
+
raise ArgumentError, 'You must specify either name or name with type' if name.nil? && name_with_type.empty?
|
|
423
428
|
|
|
424
|
-
|
|
429
|
+
if name.nil?
|
|
430
|
+
assign_attributes_with_types(name_with_type, if_value, &block)
|
|
431
|
+
else # Symbol
|
|
432
|
+
attr = if_value ? ConditionalAttribute.new(body: block, condition: if_value) : block
|
|
433
|
+
@_attributes[name.to_sym] = attr
|
|
434
|
+
end
|
|
425
435
|
end
|
|
426
436
|
|
|
427
437
|
# Set association
|
|
@@ -441,7 +451,7 @@ module Alba
|
|
|
441
451
|
# @param block [Block]
|
|
442
452
|
# @return [void]
|
|
443
453
|
# @see Alba::Association#initialize
|
|
444
|
-
def association(name, condition = nil, resource: nil, serializer: nil, source: nil, key: nil, with_traits: nil, params:
|
|
454
|
+
def association(name, condition = nil, resource: nil, serializer: nil, source: nil, key: nil, with_traits: nil, params: EMPTY_HASH, **options, &block)
|
|
445
455
|
resource ||= serializer
|
|
446
456
|
transformation = @_key_transformation_cascade ? @_transform_type : :none
|
|
447
457
|
assoc = Association.new(
|
|
@@ -477,7 +487,7 @@ module Alba
|
|
|
477
487
|
raise ArgumentError, 'No block given in attribute method' unless block
|
|
478
488
|
|
|
479
489
|
key_transformation = @_key_transformation_cascade ? @_transform_type : :none
|
|
480
|
-
attribute = NestedAttribute.new(key_transformation: key_transformation, &block)
|
|
490
|
+
attribute = NestedAttribute.new(klass: self, key_transformation: key_transformation, &block)
|
|
481
491
|
@_attributes[name.to_sym] = options[:if] ? ConditionalAttribute.new(body: attribute, condition: options[:if]) : attribute
|
|
482
492
|
end
|
|
483
493
|
alias nested nested_attribute
|
|
@@ -622,7 +632,8 @@ module Alba
|
|
|
622
632
|
# @return [void]
|
|
623
633
|
def helper(mod = @_helper || Module.new, &block)
|
|
624
634
|
mod.module_eval(&block) if block
|
|
625
|
-
|
|
635
|
+
include(mod)
|
|
636
|
+
extend(mod)
|
|
626
637
|
|
|
627
638
|
@_helper = mod
|
|
628
639
|
end
|
data/lib/alba/typed_attribute.rb
CHANGED
|
@@ -9,7 +9,7 @@ module Alba
|
|
|
9
9
|
# @param name [Symbol, String]
|
|
10
10
|
# @param type [Symbol, Class]
|
|
11
11
|
# @param converter [Proc, true, false, nil]
|
|
12
|
-
def initialize(name:, type:, converter
|
|
12
|
+
def initialize(name:, type:, converter:, &block)
|
|
13
13
|
@name = name
|
|
14
14
|
t = Alba.find_type(type)
|
|
15
15
|
@type = case converter
|
|
@@ -18,11 +18,12 @@ module Alba
|
|
|
18
18
|
else
|
|
19
19
|
t.dup.tap { _1.auto_convert_with(converter) }
|
|
20
20
|
end
|
|
21
|
+
@block = block
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
# @return [String, Integer, Boolean] type-checked or type-converted object
|
|
24
|
-
def value
|
|
25
|
-
v = yield(@name)
|
|
25
|
+
def value(object: nil)
|
|
26
|
+
v = @block ? @block.call(object) : yield(@name)
|
|
26
27
|
result = @type.check(v)
|
|
27
28
|
result ? v : @type.convert(v)
|
|
28
29
|
rescue TypeError
|
data/lib/alba/version.rb
CHANGED
data/lib/alba.rb
CHANGED
|
@@ -16,6 +16,16 @@ module Alba
|
|
|
16
16
|
# Getter for inflector, a module responsible for inflecting strings
|
|
17
17
|
attr_reader :inflector
|
|
18
18
|
|
|
19
|
+
# @return [Array<Class>] classes that include Enumerable but should not be treated as collections
|
|
20
|
+
attr_reader :non_collection_types
|
|
21
|
+
|
|
22
|
+
# Set the default superclass for resource classes created with {.resource_class}
|
|
23
|
+
#
|
|
24
|
+
# @param value [Class, String, Symbol] the default superclass
|
|
25
|
+
# @example
|
|
26
|
+
# Alba.default_superclass = '::MyApp::BaseResource'
|
|
27
|
+
attr_writer :default_superclass
|
|
28
|
+
|
|
19
29
|
# Set the backend, which actually serializes object into JSON
|
|
20
30
|
#
|
|
21
31
|
# @param backend [#to_sym, nil] the name of the backend
|
|
@@ -54,7 +64,7 @@ module Alba
|
|
|
54
64
|
h = hashify_collection(object, with, root_key, &block)
|
|
55
65
|
Alba.encoder.call(h)
|
|
56
66
|
else
|
|
57
|
-
resource = resource_for(object, &block)
|
|
67
|
+
resource = resource_for(object, with: with, &block)
|
|
58
68
|
resource.serialize(root_key: root_key)
|
|
59
69
|
end
|
|
60
70
|
end
|
|
@@ -73,17 +83,18 @@ module Alba
|
|
|
73
83
|
if collection?(object)
|
|
74
84
|
hashify_collection(object, with, root_key, &block)
|
|
75
85
|
else
|
|
76
|
-
resource = resource_for(object, &block)
|
|
86
|
+
resource = resource_for(object, with: with, &block)
|
|
77
87
|
resource.as_json(root_key: root_key)
|
|
78
88
|
end
|
|
79
89
|
end
|
|
80
90
|
|
|
81
91
|
# Detect if object is a collection or not.
|
|
82
|
-
#
|
|
92
|
+
# Types in {.non_collection_types} (default: Struct, Range, Hash) are
|
|
93
|
+
# considered non-collection even if they include Enumerable.
|
|
83
94
|
#
|
|
84
95
|
# @api private
|
|
85
96
|
def collection?(object)
|
|
86
|
-
object.is_a?(Enumerable) &&
|
|
97
|
+
object.is_a?(Enumerable) && @non_collection_types.none? { |type| object.is_a?(type) }
|
|
87
98
|
end
|
|
88
99
|
|
|
89
100
|
# Enable inference for key and resource name
|
|
@@ -124,11 +135,15 @@ module Alba
|
|
|
124
135
|
reset_transform_keys
|
|
125
136
|
end
|
|
126
137
|
|
|
138
|
+
# @param helper [Module] helper module to include
|
|
139
|
+
# @param key_transformation [Symbol] key transformation type
|
|
127
140
|
# @param block [Block] resource body
|
|
128
141
|
# @return [Class<Alba::Resource>] resource class
|
|
129
|
-
def resource_class(&block)
|
|
130
|
-
klass = Class.new
|
|
142
|
+
def resource_class(helper: nil, key_transformation: :none, &block)
|
|
143
|
+
klass = Class.new(resolved_default_superclass)
|
|
131
144
|
klass.include(Alba::Resource)
|
|
145
|
+
klass.helper(helper) if helper
|
|
146
|
+
klass.transform_keys(key_transformation)
|
|
132
147
|
klass.class_eval(&block) if block
|
|
133
148
|
klass
|
|
134
149
|
end
|
|
@@ -219,6 +234,8 @@ module Alba
|
|
|
219
234
|
@_on_error = :raise
|
|
220
235
|
@_on_nil = nil
|
|
221
236
|
@types = {}
|
|
237
|
+
@non_collection_types = [Struct, Range, Hash]
|
|
238
|
+
@default_superclass = ::Object
|
|
222
239
|
reset_transform_keys
|
|
223
240
|
register_default_types
|
|
224
241
|
end
|
|
@@ -234,6 +251,7 @@ module Alba
|
|
|
234
251
|
# Otherwise, it behaves depending on `with` argument
|
|
235
252
|
#
|
|
236
253
|
# @param object [Object] the object whose class name is used for inferring resource class
|
|
254
|
+
# @param params [Hash] user-given Hash for arbitrary data
|
|
237
255
|
# @param with [:inference, Proc, Class<Alba::Resource>] determines how to get resource class for `object`
|
|
238
256
|
# When it's `:inference`, it infers resource class from `object`'s class name
|
|
239
257
|
# When it's a Proc, it calls the Proc with `object` as an argument
|
|
@@ -241,13 +259,13 @@ module Alba
|
|
|
241
259
|
# Otherwise, it raises an ArgumentError
|
|
242
260
|
# @return [Alba::Resource] resource class with `object` as its target object
|
|
243
261
|
# @raise [ArgumentError] if `with` argument is not one of `:inference`, Proc or Class
|
|
244
|
-
def resource_for(object, with: :inference, &block)
|
|
245
|
-
_resource_for(object, with: with, &block)
|
|
262
|
+
def resource_for(object, params: {}, with: :inference, &block)
|
|
263
|
+
_resource_for(object, params: params, with: with, &block)
|
|
246
264
|
end
|
|
247
265
|
|
|
248
266
|
private
|
|
249
267
|
|
|
250
|
-
def _resource_for(object, with: :inference, &block) # rubocop:disable Metrics/MethodLength
|
|
268
|
+
def _resource_for(object, params: {}, with: :inference, &block) # rubocop:disable Metrics/MethodLength
|
|
251
269
|
klass = if block
|
|
252
270
|
resource_class(&block)
|
|
253
271
|
else
|
|
@@ -259,7 +277,7 @@ module Alba
|
|
|
259
277
|
end
|
|
260
278
|
end
|
|
261
279
|
|
|
262
|
-
klass.new(object)
|
|
280
|
+
klass.new(object, params: params)
|
|
263
281
|
end
|
|
264
282
|
|
|
265
283
|
def inflector_from(name_or_module)
|
|
@@ -336,6 +354,10 @@ module Alba
|
|
|
336
354
|
@_transformed_keys = Hash.new { |h, k| h[k] = {} }
|
|
337
355
|
end
|
|
338
356
|
|
|
357
|
+
def resolved_default_superclass
|
|
358
|
+
@default_superclass.is_a?(Class) ? @default_superclass : Object.const_get(@default_superclass.to_s)
|
|
359
|
+
end
|
|
360
|
+
|
|
339
361
|
def register_default_types # rubocop:disable Metrics/AbcSize
|
|
340
362
|
[String, :String].each do |t|
|
|
341
363
|
register_type(t, check: ->(obj) { obj.is_a?(String) }, converter: lambda(&:to_s))
|
|
@@ -345,7 +367,7 @@ module Alba
|
|
|
345
367
|
end
|
|
346
368
|
register_type(:Boolean, check: ->(obj) { [true, false].include?(obj) }, converter: ->(obj) { !!obj })
|
|
347
369
|
[String, Integer].each do |t|
|
|
348
|
-
register_type(:"ArrayOf#{t}", check: ->(d) { d.is_a?(Array) && d.all?
|
|
370
|
+
register_type(:"ArrayOf#{t}", check: ->(d) { d.is_a?(Array) && d.all?(t) })
|
|
349
371
|
end
|
|
350
372
|
end
|
|
351
373
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: alba
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- OKURA Masafumi
|
|
@@ -9,8 +9,8 @@ bindir: exe
|
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
|
-
description: Alba is
|
|
13
|
-
flexibility and usability.
|
|
12
|
+
description: Alba is a JSON serializer for Ruby, JRuby and TruffleRuby. It focuses
|
|
13
|
+
on performance, flexibility and usability.
|
|
14
14
|
email:
|
|
15
15
|
- masafumi.o1988@gmail.com
|
|
16
16
|
executables: []
|
|
@@ -59,5 +59,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
59
59
|
requirements: []
|
|
60
60
|
rubygems_version: 3.6.7
|
|
61
61
|
specification_version: 4
|
|
62
|
-
summary: Alba is
|
|
62
|
+
summary: Alba is a JSON serializer for Ruby, JRuby and TruffleRuby.
|
|
63
63
|
test_files: []
|