alba 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +1 -0
- data/.rubocop.yml +27 -1
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -0
- data/HACKING.md +2 -1
- data/README.md +82 -27
- data/benchmark/README.md +52 -48
- data/docs/rails.md +3 -1
- data/lib/alba/association.rb +1 -1
- data/lib/alba/conditional_attribute.rb +1 -1
- data/lib/alba/nested_attribute.rb +5 -3
- data/lib/alba/resource.rb +36 -35
- data/lib/alba/version.rb +1 -1
- data/lib/alba.rb +44 -6
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ba9736fa95cae41e16375e21770a7244b1ee5af9787090a1dadbe3f50839221
|
4
|
+
data.tar.gz: cb06fc313a5abb4914fceb3eb044911bd556d11cfa2239b3509147f5f992ab9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4814af5d6e0a69d34ba6f3c9ef9292e7a83196ff3d231851d799857518888e9db4bc075a0cbc88ae8e7e39aa20e724085224e1944b843edc7b685ef372cefa71
|
7
|
+
data.tar.gz: 9cb559556d0e44ea4218328d645f4666e0dd5cf63a4b380b64e7e6bf1460724ecd3e04b8eb138ac1aac30176a5d0491db1451e3bdaf2130771ab06bdbb2e4d50
|
data/.codeclimate.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -3,7 +3,12 @@
|
|
3
3
|
inherit_gem:
|
4
4
|
rubocop-sensible: 'config/rubocop.yml'
|
5
5
|
|
6
|
+
inherit_mode:
|
7
|
+
merge:
|
8
|
+
- Exclude
|
9
|
+
|
6
10
|
require:
|
11
|
+
- rubocop-md
|
7
12
|
- rubocop-minitest
|
8
13
|
- rubocop-performance
|
9
14
|
- rubocop-rake
|
@@ -22,6 +27,11 @@ AllCops:
|
|
22
27
|
Bundler/GemVersion:
|
23
28
|
Enabled: false
|
24
29
|
|
30
|
+
# Test class is a class, but not really
|
31
|
+
Layout/ClassStructure:
|
32
|
+
Exclude:
|
33
|
+
- 'test/**/*'
|
34
|
+
|
25
35
|
# We'd like to write something like:
|
26
36
|
# assert_equal(
|
27
37
|
# expected,
|
@@ -80,14 +90,26 @@ Style/Copyright:
|
|
80
90
|
Style/DisableCopsWithinSourceCodeDirective:
|
81
91
|
Enabled: false
|
82
92
|
|
93
|
+
Style/Documentation:
|
94
|
+
Exclude:
|
95
|
+
- 'test/**/*'
|
96
|
+
|
97
|
+
Style/DocumentationMethod:
|
98
|
+
Exclude:
|
99
|
+
- 'README.md'
|
100
|
+
|
83
101
|
Style/FrozenStringLiteralComment:
|
84
102
|
Enabled: false
|
85
103
|
|
104
|
+
Style/ImplicitRuntimeError:
|
105
|
+
Exclude:
|
106
|
+
- 'README.md'
|
107
|
+
|
86
108
|
Style/InlineComment:
|
87
109
|
Enabled: false
|
88
110
|
|
89
111
|
Style/MethodCallWithArgsParentheses:
|
90
|
-
|
112
|
+
AllowedMethods: ['require', 'require_relative', 'include', 'extend', 'puts', 'p', 'warn', 'raise', 'send', 'public_send']
|
91
113
|
Exclude:
|
92
114
|
# There are so many `attributes` call without parenthese and that's absolutely fine
|
93
115
|
- 'test/**/*.rb'
|
@@ -95,3 +117,7 @@ Style/MethodCallWithArgsParentheses:
|
|
95
117
|
# There are so many cases we just want `if` expression!
|
96
118
|
Style/MissingElse:
|
97
119
|
EnforcedStyle: case
|
120
|
+
|
121
|
+
Style/OptionalBooleanParameter:
|
122
|
+
Exclude:
|
123
|
+
- 'README.md'
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [2.3.0] 2023-04-24
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- Add compatibility option for key [#304](https://github.com/okuramasafumi/alba/pull/304)
|
14
|
+
- It now infers resource name from Serializer [#309](https://github.com/okuramasafumi/alba/pull/309)
|
15
|
+
- `Alba.serialize` is easier to use for multiple root keys [#311](https://github.com/okuramasafumi/alba/pull/311)
|
16
|
+
- Gives access to params in nested_attribute [#312](https://github.com/okuramasafumi/alba/pull/312)
|
17
|
+
- Thank you, @GabrielErbetta
|
18
|
+
|
9
19
|
## [2.2.0] 2023-02-17
|
10
20
|
|
11
21
|
### Added
|
data/Gemfile
CHANGED
@@ -10,6 +10,7 @@ gem 'minitest', '~> 5.14' # For test
|
|
10
10
|
gem 'railties', require: false # For Rails integration testing
|
11
11
|
gem 'rake', '~> 13.0' # For test and automation
|
12
12
|
gem 'rubocop', '>= 0.79.0', require: false # For lint
|
13
|
+
gem 'rubocop-md', '~> 1.0', require: false # For lint
|
13
14
|
gem 'rubocop-minitest', '>= 0.25.0', require: false # For lint
|
14
15
|
gem 'rubocop-performance', '>= 1.15.0', require: false # For lint
|
15
16
|
gem 'rubocop-rake', '>= 0.5.1', require: false # For lint
|
data/HACKING.md
CHANGED
@@ -17,6 +17,7 @@ Class methods (DSL):
|
|
17
17
|
* `attribute` for block style attribute
|
18
18
|
* `attributes` for symbol style attribute
|
19
19
|
* `association` and its aliases such as `one` for association
|
20
|
+
* `nested` for nested attribute
|
20
21
|
|
21
22
|
Instance methods:
|
22
23
|
|
@@ -29,7 +30,7 @@ Other methods are rather trivial. They'll be added to this list when it turned o
|
|
29
30
|
|
30
31
|
In `Alba::Resource` module there are some things to note.
|
31
32
|
|
32
|
-
`@object` is an object for serialization. It's either singular object or collection.
|
33
|
+
`@object` is an object for serialization. It's either a singular object or a collection.
|
33
34
|
|
34
35
|
Attribute object can be either `Symbol`, `Proc`, `Alba::Association` or `Alba::TypedAttribute`.
|
35
36
|
|
data/README.md
CHANGED
@@ -43,7 +43,7 @@ Alba is faster than most of the alternatives. We have a [benchmark](https://gith
|
|
43
43
|
|
44
44
|
### Easy
|
45
45
|
|
46
|
-
Alba is easy to use because there are only a few methods to remember. It's also easy to understand due to clean and
|
46
|
+
Alba is easy to use because there are only a few methods to remember. It's also easy to understand due to clean and small codebase. Finally it's easy to extend since it provides some methods for override to change default behavior of Alba.
|
47
47
|
|
48
48
|
### Feature rich
|
49
49
|
|
@@ -143,13 +143,27 @@ Alba.inflector = nil
|
|
143
143
|
To check if inference is enabled etc, inspect the return value of `inflector`:
|
144
144
|
|
145
145
|
```ruby
|
146
|
-
if Alba.inflector
|
147
|
-
puts
|
146
|
+
if Alba.inflector.nil?
|
147
|
+
puts 'inflector not set'
|
148
148
|
else
|
149
149
|
puts "inflector is set to #{Alba.inflector}"
|
150
150
|
end
|
151
151
|
```
|
152
152
|
|
153
|
+
### Naming
|
154
|
+
|
155
|
+
Alba tries to infer resource name from class name like the following.
|
156
|
+
|
157
|
+
|Class name|Resource name|
|
158
|
+
| --- | --- |
|
159
|
+
| FooResource | Foo |
|
160
|
+
| FooSerializer | Foo |
|
161
|
+
| FooElse | FooElse |
|
162
|
+
|
163
|
+
Resource name is used as the default name of the root key, so you might want to name it ending with "Resource" or "Serializer"
|
164
|
+
|
165
|
+
When you use Alba with Rails, it's recommended to put your resource/serializer classes in corresponding directory such as `app/resources` or `app/serializers`.
|
166
|
+
|
153
167
|
### Simple serialization with root key
|
154
168
|
|
155
169
|
You can define attributes with (yes) `attributes` macro with attribute names. If your attribute need some calculations, you can use `attribute` with block.
|
@@ -157,6 +171,7 @@ You can define attributes with (yes) `attributes` macro with attribute names. If
|
|
157
171
|
```ruby
|
158
172
|
class User
|
159
173
|
attr_accessor :id, :name, :email, :created_at, :updated_at
|
174
|
+
|
160
175
|
def initialize(id, name, email)
|
161
176
|
@id = id
|
162
177
|
@name = name
|
@@ -356,11 +371,11 @@ class UserResource
|
|
356
371
|
|
357
372
|
# Second proc works as a filter
|
358
373
|
many :articles,
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
374
|
+
proc { |articles, params, user|
|
375
|
+
filter = params[:filter] || :odd?
|
376
|
+
articles.select { |a| a.id.__send__(filter) && !user.banned }
|
377
|
+
},
|
378
|
+
resource: ArticleResource
|
364
379
|
end
|
365
380
|
|
366
381
|
user = User.new(1)
|
@@ -384,8 +399,8 @@ class UserResource
|
|
384
399
|
attributes :id
|
385
400
|
|
386
401
|
many :articles,
|
387
|
-
|
388
|
-
|
402
|
+
key: 'my_articles', # Set key here
|
403
|
+
resource: ArticleResource
|
389
404
|
end
|
390
405
|
UserResource.new(user).serialize
|
391
406
|
# => '{"id":1,"my_articles":[{"title":"Hello World!"}]}'
|
@@ -452,7 +467,7 @@ class FooResourceWithParamsOverride
|
|
452
467
|
|
453
468
|
root_key :foo
|
454
469
|
|
455
|
-
one :bar, resource: BarResource, params: {
|
470
|
+
one :bar, resource: BarResource, params: {expose_secret: false}
|
456
471
|
end
|
457
472
|
|
458
473
|
Baz = Struct.new(:data, :secret)
|
@@ -544,6 +559,48 @@ Alba.serialize(something)
|
|
544
559
|
|
545
560
|
Although this might be useful sometimes, it's generally recommended to define a class for Resource.
|
546
561
|
|
562
|
+
#### Inline definition for multiple root keys
|
563
|
+
|
564
|
+
While Alba doesn't directly support multiple root keys, you can simulate it with `Alba.serialize`.
|
565
|
+
|
566
|
+
```ruby
|
567
|
+
# Define foo and bar local variables here
|
568
|
+
|
569
|
+
Alba.serialize do
|
570
|
+
attribute :key1 do
|
571
|
+
FooResource.new(foo).to_h
|
572
|
+
end
|
573
|
+
|
574
|
+
attribute :key2 do
|
575
|
+
BarResource.new(bar).to_h
|
576
|
+
end
|
577
|
+
end
|
578
|
+
# => JSON containing "key1" and "key2" as root keys
|
579
|
+
```
|
580
|
+
|
581
|
+
Note that we must use `to_h`, not `serialize`, with resources.
|
582
|
+
|
583
|
+
We can also generate a JSON with multiple root keys without making any class by the combination of `Alba.serialize` and `Alba.hashify`.
|
584
|
+
|
585
|
+
```ruby
|
586
|
+
# Define foo and bar local variables here
|
587
|
+
|
588
|
+
Alba.serialize do
|
589
|
+
attribute :foo do
|
590
|
+
Alba.hashify(foo) do
|
591
|
+
attributes :id, :name # For example
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
attribute :bar do
|
596
|
+
Alba.hashify(bar) do
|
597
|
+
attributes :id
|
598
|
+
end
|
599
|
+
end
|
600
|
+
end
|
601
|
+
# => JSON containing "foo" and "bar" as root keys
|
602
|
+
```
|
603
|
+
|
547
604
|
### Serializable Hash
|
548
605
|
|
549
606
|
Instead of serializing to JSON, you can also output a Hash by calling `serializable_hash` or the `to_h` alias. Note also that the `serialize` method is aliased as `to_json`.
|
@@ -796,20 +853,15 @@ A custom inflector can be plugged in as follows.
|
|
796
853
|
module CustomInflector
|
797
854
|
module_function
|
798
855
|
|
799
|
-
def camelize(string)
|
800
|
-
end
|
856
|
+
def camelize(string); end
|
801
857
|
|
802
|
-
def camelize_lower(string)
|
803
|
-
end
|
858
|
+
def camelize_lower(string); end
|
804
859
|
|
805
|
-
def dasherize(string)
|
806
|
-
end
|
860
|
+
def dasherize(string); end
|
807
861
|
|
808
|
-
def underscore(string)
|
809
|
-
end
|
862
|
+
def underscore(string); end
|
810
863
|
|
811
|
-
def classify(string)
|
812
|
-
end
|
864
|
+
def classify(string); end
|
813
865
|
end
|
814
866
|
|
815
867
|
Alba.inflector = CustomInflector
|
@@ -926,7 +978,7 @@ class User
|
|
926
978
|
end
|
927
979
|
|
928
980
|
def email
|
929
|
-
raise
|
981
|
+
raise 'Error!'
|
930
982
|
end
|
931
983
|
end
|
932
984
|
|
@@ -1122,8 +1174,10 @@ Sometimes we want to serialize a collection into a Hash, not an Array. It's poss
|
|
1122
1174
|
```ruby
|
1123
1175
|
class User
|
1124
1176
|
attr_reader :id, :name
|
1177
|
+
|
1125
1178
|
def initialize(id, name)
|
1126
|
-
@id
|
1179
|
+
@id = id
|
1180
|
+
@name = name
|
1127
1181
|
end
|
1128
1182
|
end
|
1129
1183
|
|
@@ -1289,8 +1343,8 @@ module AlbaExtension
|
|
1289
1343
|
# Here attrs are an Array of Symbol
|
1290
1344
|
def formatted_time_attributes(*attrs)
|
1291
1345
|
attrs.each do |attr|
|
1292
|
-
attribute
|
1293
|
-
time = object.
|
1346
|
+
attribute(attr) do |object|
|
1347
|
+
time = object.__send__(attr)
|
1294
1348
|
time.strftime('%m/%d/%Y')
|
1295
1349
|
end
|
1296
1350
|
end
|
@@ -1347,13 +1401,14 @@ Alba currently doesn't support logging directly, but you can add your own loggin
|
|
1347
1401
|
|
1348
1402
|
```ruby
|
1349
1403
|
module Logging
|
1350
|
-
|
1404
|
+
# `...` was added in Ruby 2.7
|
1405
|
+
def serialize(...)
|
1351
1406
|
puts serializable_hash
|
1352
1407
|
super(...)
|
1353
1408
|
end
|
1354
1409
|
end
|
1355
1410
|
|
1356
|
-
FooResource.prepend
|
1411
|
+
FooResource.prepend(Logging)
|
1357
1412
|
FooResource.new(foo).serialize
|
1358
1413
|
# => "{:id=>1}" is printed
|
1359
1414
|
```
|
data/benchmark/README.md
CHANGED
@@ -10,72 +10,76 @@ Machine spec:
|
|
10
10
|
|
11
11
|
|Key|Value|
|
12
12
|
|---|---|
|
13
|
-
|OS|macOS
|
13
|
+
|OS|macOS 13.2.1|
|
14
14
|
|CPU|Intel Corei7 Quad Core 2.3Ghz|
|
15
15
|
|RAM|32GB|
|
16
|
-
|Ruby|ruby 3.
|
16
|
+
|Ruby|ruby 3.2.1 (2023-02-08 revision 31819e82c8) [x86_64-darwin21]|
|
17
|
+
|
18
|
+
Library versions:
|
19
|
+
|
20
|
+
|Library|Version|
|
21
|
+
|---|---|
|
22
|
+
|alba|2.2.0|
|
23
|
+
|blueprinter|0.25.3|
|
24
|
+
|fast_serializer_ruby|0.6.9|
|
25
|
+
|jserializer|0.2.1|
|
26
|
+
|oj|3.14.2|
|
27
|
+
|simple_ams|0.2.6|
|
28
|
+
|representable|3.2.0|
|
29
|
+
|turbostreamer|1.10.0|
|
30
|
+
|jbuilder|2.11.5|
|
31
|
+
|panko_serializer|0.7.9|
|
32
|
+
|active_model_serializers|0.10.13|
|
17
33
|
|
18
34
|
`benchmark-ips` with `Oj.optimize_rails`:
|
19
35
|
|
20
36
|
```
|
21
37
|
Comparison:
|
22
|
-
panko:
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
blueprinter: 54.1 i/s - 4.95x (± 0.00) slower
|
34
|
-
representable: 35.9 i/s - 7.46x (± 0.00) slower
|
35
|
-
simple_ams: 25.4 i/s - 10.53x (± 0.00) slower
|
36
|
-
ams: 9.1 i/s - 29.39x (± 0.00) slower
|
38
|
+
panko: 310.4 i/s
|
39
|
+
jserializer: 120.6 i/s - 2.57x slower
|
40
|
+
turbostreamer: 117.3 i/s - 2.65x slower
|
41
|
+
rails: 114.0 i/s - 2.72x slower
|
42
|
+
alba_inline: 99.3 i/s - 3.13x slower
|
43
|
+
alba: 94.1 i/s - 3.30x slower
|
44
|
+
fast_serializer: 67.8 i/s - 4.58x slower
|
45
|
+
blueprinter: 57.6 i/s - 5.39x slower
|
46
|
+
representable: 36.3 i/s - 8.56x slower
|
47
|
+
simple_ams: 23.3 i/s - 13.32x slower
|
48
|
+
ams: 10.9 i/s - 28.53x slower
|
37
49
|
```
|
38
50
|
|
39
51
|
`benchmark-ips` without `Oj.optimize_rails`:
|
40
52
|
|
41
53
|
```
|
42
54
|
Comparison:
|
43
|
-
panko:
|
44
|
-
turbostreamer:
|
45
|
-
|
46
|
-
alba_inline:
|
47
|
-
|
48
|
-
fast_serializer:
|
49
|
-
blueprinter:
|
50
|
-
rails:
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
representable: 27.8 i/s - 10.23x (± 0.00) slower
|
55
|
-
jsonapi: 27.5 i/s - 10.34x (± 0.00) slower
|
56
|
-
simple_ams: 16.9 i/s - 16.75x (± 0.00) slower
|
57
|
-
ams: 8.3 i/s - 34.36x (± 0.00) slower
|
55
|
+
panko: 326.1 i/s
|
56
|
+
turbostreamer: 120.6 i/s - 2.70x slower
|
57
|
+
jserializer: 119.2 i/s - 2.74x slower
|
58
|
+
alba_inline: 104.3 i/s - 3.13x slower
|
59
|
+
alba: 102.2 i/s - 3.19x slower
|
60
|
+
fast_serializer: 66.9 i/s - 4.88x slower
|
61
|
+
blueprinter: 56.7 i/s - 5.75x slower
|
62
|
+
rails: 33.9 i/s - 9.63x slower
|
63
|
+
representable: 30.3 i/s - 10.77x slower
|
64
|
+
simple_ams: 16.4 i/s - 19.84x slower
|
65
|
+
ams: 9.4 i/s - 34.56x slower
|
58
66
|
```
|
59
67
|
|
60
68
|
`benchmark-memory`:
|
61
69
|
|
62
70
|
```
|
63
71
|
Comparison:
|
64
|
-
panko:
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
jsonapi: 2279958 allocated - 9.89x more
|
76
|
-
representable: 2869166 allocated - 12.45x more
|
77
|
-
ams: 4473161 allocated - 19.41x more
|
78
|
-
simple_ams: 7868345 allocated - 34.15x more
|
72
|
+
panko: 242426 allocated
|
73
|
+
turbostreamer: 817568 allocated - 3.37x more
|
74
|
+
jserializer: 831705 allocated - 3.43x more
|
75
|
+
alba: 1072217 allocated - 4.42x more
|
76
|
+
alba_inline: 1084889 allocated - 4.48x more
|
77
|
+
fast_serializer: 1244385 allocated - 5.13x more
|
78
|
+
rails: 1272761 allocated - 5.25x more
|
79
|
+
blueprinter: 1680137 allocated - 6.93x more
|
80
|
+
representable: 2892425 allocated - 11.93x more
|
81
|
+
ams: 4479569 allocated - 18.48x more
|
82
|
+
simple_ams: 6957913 allocated - 28.70x more
|
79
83
|
```
|
80
84
|
|
81
|
-
Conclusion: panko is extremely fast but it's a C extension gem. As pure Ruby gems, Alba, turbostreamer and jserializer are notably faster than others. With `Oj.optimize_rails`
|
85
|
+
Conclusion: panko is extremely fast but it's a C extension gem. As pure Ruby gems, Alba, `turbostreamer` and `jserializer` are notably faster than others, but Alba is slightly slower than other two. With `Oj.optimize_rails`, `jbuilder` and Rails standard serialization are also fast.
|
data/docs/rails.md
CHANGED
@@ -14,11 +14,13 @@ You might want to add some configurations to initializer file such as `alba.rb`
|
|
14
14
|
```ruby
|
15
15
|
# alba.rb
|
16
16
|
Alba.backend = :active_support
|
17
|
-
Alba.
|
17
|
+
Alba.inflector = :active_support
|
18
18
|
```
|
19
19
|
|
20
20
|
You can also use `:oj_rails` for backend if you prefer using Oj.
|
21
21
|
|
22
|
+
Alba 2.2 introduced new Rails integration so that you don't have to add initializer file for setting inflector. You still need to add initializer file if you want to set backend or configure inflector with something different from `active_support`.
|
23
|
+
|
22
24
|
## Rendering JSON
|
23
25
|
|
24
26
|
You can render JSON with Rails in two ways. One way is to pass JSON String.
|
data/lib/alba/association.rb
CHANGED
@@ -32,7 +32,7 @@ module Alba
|
|
32
32
|
# @param params [Hash] user-given Hash for arbitrary data
|
33
33
|
# @return [Hash]
|
34
34
|
def to_h(target, within: nil, params: {})
|
35
|
-
params = params.merge(@params)
|
35
|
+
params = params.merge(@params)
|
36
36
|
@object = target.__send__(@name)
|
37
37
|
@object = @condition.call(object, params, target) if @condition
|
38
38
|
return if @object.nil?
|
@@ -20,7 +20,7 @@ module Alba
|
|
20
20
|
return Alba::REMOVE_KEY unless condition_passes?(resource, object)
|
21
21
|
|
22
22
|
fetched_attribute = yield(@body)
|
23
|
-
return fetched_attribute
|
23
|
+
return fetched_attribute unless with_two_arity_proc_condition
|
24
24
|
|
25
25
|
return Alba::REMOVE_KEY unless resource.instance_exec(object, attribute_from_association_body_or(fetched_attribute), &@condition)
|
26
26
|
|
@@ -8,12 +8,14 @@ module Alba
|
|
8
8
|
@block = block
|
9
9
|
end
|
10
10
|
|
11
|
-
# @
|
12
|
-
|
11
|
+
# @param object [Object] the object being serialized
|
12
|
+
# @param params [Hash] params Hash inherited from Resource
|
13
|
+
# @return [Hash] hash serialized from running the class body in the object
|
14
|
+
def value(object:, params:)
|
13
15
|
resource_class = Alba.resource_class
|
14
16
|
resource_class.transform_keys(@key_transformation)
|
15
17
|
resource_class.class_eval(&@block)
|
16
|
-
resource_class.new(object).serializable_hash
|
18
|
+
resource_class.new(object, params: params).serializable_hash
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
data/lib/alba/resource.rb
CHANGED
@@ -17,15 +17,21 @@ module Alba
|
|
17
17
|
WITHIN_DEFAULT = Object.new.freeze
|
18
18
|
private_constant :WITHIN_DEFAULT
|
19
19
|
|
20
|
+
# `setup` method is meta-programmatically defined here for performance.
|
20
21
|
# @private
|
21
|
-
def self.included(base)
|
22
|
+
def self.included(base) # rubocop:disable Metrics/MethodLength
|
22
23
|
super
|
24
|
+
setup_method_body = 'private def _setup;'
|
23
25
|
base.class_eval do
|
24
26
|
# Initialize
|
25
27
|
DSLS.each do |name, initial|
|
26
28
|
instance_variable_set("@#{name}", initial.dup) unless instance_variable_defined?("@#{name}")
|
29
|
+
setup_method_body << "@#{name} = self.class.#{name};"
|
27
30
|
end
|
31
|
+
base.define_method(:encode, Alba.encoder)
|
28
32
|
end
|
33
|
+
setup_method_body << 'end'
|
34
|
+
base.class_eval(setup_method_body, __FILE__, __LINE__ + 1)
|
29
35
|
base.include InstanceMethods
|
30
36
|
base.extend ClassMethods
|
31
37
|
end
|
@@ -41,7 +47,7 @@ module Alba
|
|
41
47
|
@object = object
|
42
48
|
@params = params
|
43
49
|
@within = within
|
44
|
-
|
50
|
+
_setup
|
45
51
|
end
|
46
52
|
|
47
53
|
# Serialize object into JSON string
|
@@ -80,7 +86,8 @@ module Alba
|
|
80
86
|
# @param meta [Hash] metadata for this seialization
|
81
87
|
# @return [Hash]
|
82
88
|
def as_json(root_key: nil, meta: {})
|
83
|
-
key = root_key.nil? ? fetch_key : root_key
|
89
|
+
key = root_key.nil? ? fetch_key : root_key
|
90
|
+
key = Alba.regularize_key(key)
|
84
91
|
if key && !key.empty?
|
85
92
|
h = {key => serializable_hash}
|
86
93
|
hash_with_metadata(h, meta)
|
@@ -99,15 +106,9 @@ module Alba
|
|
99
106
|
|
100
107
|
private
|
101
108
|
|
102
|
-
def encode(hash)
|
103
|
-
Alba.encoder.call(hash)
|
104
|
-
end
|
105
|
-
|
106
109
|
def _to_json(root_key, meta, options)
|
107
110
|
options.reject! { |k, _| %i[layout prefixes template status].include?(k) } # Rails specific guard
|
108
|
-
|
109
|
-
names = options.map { |k, v| k unless v.nil? }
|
110
|
-
names.compact!
|
111
|
+
names = options.filter_map { |k, v| k unless v.nil? }
|
111
112
|
unless names.empty?
|
112
113
|
names.sort!
|
113
114
|
names.map! { |s| "\"#{s}\"" }
|
@@ -134,7 +135,11 @@ module Alba
|
|
134
135
|
|
135
136
|
def serializable_hash_for_collection
|
136
137
|
if @_collection_key
|
137
|
-
@object.to_h
|
138
|
+
@object.to_h do |item|
|
139
|
+
k = item.public_send(@_collection_key)
|
140
|
+
key = Alba.regularize_key(k)
|
141
|
+
[key, converter.call(item)]
|
142
|
+
end
|
138
143
|
else
|
139
144
|
@object.each_with_object([], &collection_converter)
|
140
145
|
end
|
@@ -147,34 +152,26 @@ module Alba
|
|
147
152
|
end
|
148
153
|
|
149
154
|
def _key_for_collection
|
150
|
-
|
151
|
-
|
152
|
-
else
|
153
|
-
@_key_for_collection == true ? raise_root_key_inference_error : @_key_for_collection.to_s
|
154
|
-
end
|
155
|
+
k = @_key_for_collection == true ? resource_name(pluralized: true) : @_key_for_collection
|
156
|
+
Alba.regularize_key(k)
|
155
157
|
end
|
156
158
|
|
157
|
-
# @return [String]
|
158
159
|
def _key
|
159
|
-
|
160
|
-
|
161
|
-
else
|
162
|
-
@_key == true ? raise_root_key_inference_error : @_key.to_s
|
163
|
-
end
|
160
|
+
k = @_key == true ? resource_name(pluralized: false) : @_key
|
161
|
+
Alba.regularize_key(k)
|
164
162
|
end
|
165
163
|
|
166
164
|
def resource_name(pluralized: false)
|
167
|
-
class_name = self.class.name
|
168
165
|
inflector = Alba.inflector
|
169
|
-
|
166
|
+
raise Alba::Error, 'You must set inflector when setting root key as true.' unless inflector
|
167
|
+
|
168
|
+
class_name = self.class.name
|
169
|
+
suffix = class_name.end_with?('Resource') ? 'Resource' : 'Serializer'
|
170
|
+
name = inflector.demodulize(class_name).delete_suffix(suffix)
|
170
171
|
underscore_name = inflector.underscore(name)
|
171
172
|
pluralized ? inflector.pluralize(underscore_name) : underscore_name
|
172
173
|
end
|
173
174
|
|
174
|
-
def raise_root_key_inference_error
|
175
|
-
raise Alba::Error, 'You must set inflector when setting root key as true.'
|
176
|
-
end
|
177
|
-
|
178
175
|
def transforming_root_key?
|
179
176
|
@_transforming_root_key
|
180
177
|
end
|
@@ -237,14 +234,16 @@ module Alba
|
|
237
234
|
end
|
238
235
|
end
|
239
236
|
|
240
|
-
|
241
|
-
|
242
|
-
key = key.to_s
|
243
|
-
return key if @_transform_type == :none || key.empty? # We can skip transformation
|
237
|
+
def transform_key(key)
|
238
|
+
return Alba.regularize_key(key) if @_transform_type == :none || key.nil? || key.empty? # We can skip transformation
|
244
239
|
|
245
240
|
inflector = Alba.inflector
|
246
241
|
raise Alba::Error, 'Inflector is nil. You must set inflector before transforming keys.' unless inflector
|
247
242
|
|
243
|
+
Alba.regularize_key(_transform_key(inflector, key.to_s))
|
244
|
+
end
|
245
|
+
|
246
|
+
def _transform_key(inflector, key)
|
248
247
|
case @_transform_type # rubocop:disable Style/MissingElse
|
249
248
|
when :camel then inflector.camelize(key)
|
250
249
|
when :lower_camel then inflector.camelize_lower(key)
|
@@ -258,7 +257,8 @@ module Alba
|
|
258
257
|
when Symbol then fetch_attribute_from_object_and_resource(obj, attribute)
|
259
258
|
when Proc then instance_exec(obj, &attribute)
|
260
259
|
when Alba::Association then yield_if_within(attribute.name.to_sym) { |within| attribute.to_h(obj, params: params, within: within) }
|
261
|
-
when TypedAttribute
|
260
|
+
when TypedAttribute then attribute.value(obj)
|
261
|
+
when NestedAttribute then attribute.value(object: obj, params: params)
|
262
262
|
when ConditionalAttribute then attribute.with_passing_condition(resource: self, object: obj) { |attr| fetch_attribute(obj, key, attr) }
|
263
263
|
else
|
264
264
|
raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
|
@@ -327,8 +327,9 @@ module Alba
|
|
327
327
|
|
328
328
|
def assign_attributes(attrs, if_value)
|
329
329
|
attrs.each do |attr_name|
|
330
|
-
|
331
|
-
|
330
|
+
attr_name = attr_name.to_sym
|
331
|
+
attr = if_value ? ConditionalAttribute.new(body: attr_name, condition: if_value) : attr_name
|
332
|
+
@_attributes[attr_name] = attr
|
332
333
|
end
|
333
334
|
end
|
334
335
|
private :assign_attributes
|
data/lib/alba/version.rb
CHANGED
data/lib/alba.rb
CHANGED
@@ -44,13 +44,23 @@ module Alba
|
|
44
44
|
# @param block [Block] resource block
|
45
45
|
# @return [String] serialized JSON string
|
46
46
|
# @raise [ArgumentError] if block is absent or `with` argument's type is wrong
|
47
|
-
def serialize(object, root_key: nil, &block)
|
48
|
-
|
49
|
-
|
50
|
-
resource = klass.new(object)
|
47
|
+
def serialize(object = nil, root_key: nil, &block)
|
48
|
+
resource = resource_with(object, &block)
|
51
49
|
resource.serialize(root_key: root_key)
|
52
50
|
end
|
53
51
|
|
52
|
+
# Hashify the object with inline definitions
|
53
|
+
#
|
54
|
+
# @param object [Object] the object to be serialized
|
55
|
+
# @param root_key [Symbol, nil, true]
|
56
|
+
# @param block [Block] resource block
|
57
|
+
# @return [String] serialized JSON string
|
58
|
+
# @raise [ArgumentError] if block is absent or `with` argument's type is wrong
|
59
|
+
def hashify(object = nil, root_key: nil, &block)
|
60
|
+
resource = resource_with(object, &block)
|
61
|
+
resource.as_json(root_key: root_key)
|
62
|
+
end
|
63
|
+
|
54
64
|
# Enable inference for key and resource name
|
55
65
|
#
|
56
66
|
# @param with [Symbol, Class, Module] inflector
|
@@ -107,16 +117,45 @@ module Alba
|
|
107
117
|
const_parent.const_get("#{inflector.classify(name)}Resource")
|
108
118
|
end
|
109
119
|
|
120
|
+
# Configure Alba to symbolize keys
|
121
|
+
def symbolize_keys!
|
122
|
+
@symbolize_keys = true
|
123
|
+
end
|
124
|
+
|
125
|
+
# Configure Alba to stringify (not symbolize) keys
|
126
|
+
def stringify_keys!
|
127
|
+
@symbolize_keys = false
|
128
|
+
end
|
129
|
+
|
130
|
+
# Regularize key to be either Symbol or String depending on @symbolize_keys
|
131
|
+
# Returns nil if key is nil
|
132
|
+
#
|
133
|
+
# @param key [String, Symbol, nil]
|
134
|
+
# @return [Symbol, String, nil]
|
135
|
+
def regularize_key(key)
|
136
|
+
return if key.nil?
|
137
|
+
|
138
|
+
@symbolize_keys ? key.to_sym : key.to_s
|
139
|
+
end
|
140
|
+
|
110
141
|
# Reset config variables
|
111
142
|
# Useful for test cleanup
|
112
143
|
def reset!
|
113
144
|
@encoder = default_encoder
|
145
|
+
@symbolize_keys = false
|
114
146
|
@_on_error = :raise
|
115
147
|
@_on_nil = nil
|
116
148
|
end
|
117
149
|
|
118
150
|
private
|
119
151
|
|
152
|
+
# This method could be part of public API, but for now it's private
|
153
|
+
def resource_with(object, &block)
|
154
|
+
klass = block ? resource_class(&block) : infer_resource_class(object.class.name)
|
155
|
+
|
156
|
+
klass.new(object)
|
157
|
+
end
|
158
|
+
|
120
159
|
def inflector_from(name_or_module)
|
121
160
|
case name_or_module
|
122
161
|
when nil then nil
|
@@ -126,8 +165,7 @@ module Alba
|
|
126
165
|
when :dry
|
127
166
|
require 'dry/inflector'
|
128
167
|
Dry::Inflector.new
|
129
|
-
else
|
130
|
-
validate_inflector(name_or_module)
|
168
|
+
else validate_inflector(name_or_module)
|
131
169
|
end
|
132
170
|
end
|
133
171
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alba
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- OKURA Masafumi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-04-24 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Alba is the fastest JSON serializer for Ruby. It focuses on performance,
|
14
14
|
flexibility and usability.
|
@@ -91,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: '0'
|
93
93
|
requirements: []
|
94
|
-
rubygems_version: 3.4.
|
94
|
+
rubygems_version: 3.4.10
|
95
95
|
signing_key:
|
96
96
|
specification_version: 4
|
97
97
|
summary: Alba is the fastest JSON serializer for Ruby.
|