alba 3.2.0 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3b0683f5d43a9e7ce7eaea591c2a67267f56d7327a045ab0e2da081256a4543
4
- data.tar.gz: 0dd80fd3c618fe35bc7b727f01c6ce8c9357fe1b0d303e2a756daf245f6d7e50
3
+ metadata.gz: 38b89f99bfe18cf66179ed46c6fdcb5cb25f3d34b8f709fcb9c9de634f7a129b
4
+ data.tar.gz: b117d86ab11bb7a0b1abe8e2089ae869c8864fd37b066ea544d0ac51ad5082db
5
5
  SHA512:
6
- metadata.gz: ec6b56b091d9fe52bf05dd8ac7f9d67bc33db86e480e2281e2914cc075939a3c21b3b2cc1e6680a435c0a69069b3e73db0983b3a3d6433bb1c12b65f83ee307a
7
- data.tar.gz: afb843e8dbaa8e45181526128704a4fbd0ed427306bb294d73dc6889477e037d86091ec2fc94bf9db6d973f5da07551ce74977d9469184c67fbc3354c904f906
6
+ metadata.gz: b62b63a9a7a4b1d85ba180941752a49d4bec97529794f328092b0bb7bc325daa683f5392a703d277f2c4e0b66e6af13b956706ecef6bfc729695aeff0c43e4d0
7
+ data.tar.gz: 3336d2097e5e4c78b690c6b3c178fdcef2db47271e1b929c1aeb246fb832632b69c26923abaf5e5e8df1e165d62495da85adce3e66aa8c404b103e65b1a82df1
data/.rubocop.yml CHANGED
@@ -23,6 +23,10 @@ AllCops:
23
23
  EnabledByDefault: true
24
24
  TargetRubyVersion: 3.0
25
25
 
26
+ Bundler/GemComment:
27
+ Exclude:
28
+ - 'benchmark/**/*'
29
+
26
30
  # Items in Gemfile is dev dependencies and we don't have to specify versions.
27
31
  Bundler/GemVersion:
28
32
  Enabled: false
@@ -121,10 +125,6 @@ Style/DocumentationMethod:
121
125
  Exclude:
122
126
  - 'README.md'
123
127
 
124
- # This might be true in the future, but not many good things
125
- Style/FrozenStringLiteralComment:
126
- Enabled: false
127
-
128
128
  # I don't want to think about error class in example code
129
129
  Style/ImplicitRuntimeError:
130
130
  Exclude:
data/CHANGELOG.md CHANGED
@@ -6,6 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.3.1] 2024-10-17
10
+
11
+ ### Fixed
12
+
13
+ - Add ostruct as gemspec dependency to be prepared for ruby 3.3.5. [#386](https://github.com/okuramasafumi/alba/pull/386)
14
+
15
+ ## [3.3.0] 2024-10-09
16
+
17
+ ### Added
18
+
19
+ - Add `ArrayOfString` and `ArrayOfInteger` type [#378](https://github.com/okuramasafumi/alba/pull/378)
20
+
9
21
  ## [3.2.0] 2024-06-21
10
22
 
11
23
  ### Added
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in alba.gemspec
@@ -9,11 +11,11 @@ gem 'ffaker', require: false # For testing
9
11
  gem 'minitest', '~> 5.14' # For test
10
12
  gem 'railties', require: false # For Rails integration testing
11
13
  gem 'rake', '~> 13.0' # For test and automation
12
- gem 'rubocop', '~> 1.64.0', require: false # For lint
14
+ gem 'rubocop', '~> 1.66.1', require: false # For lint
13
15
  gem 'rubocop-gem_dev', '>= 0.3.0', require: false # For lint
14
16
  gem 'rubocop-md', '~> 1.0', require: false # For lint
15
- gem 'rubocop-minitest', '~> 0.35.0', require: false # For lint
16
- gem 'rubocop-performance', '~> 1.21.0', require: false # For lint
17
+ gem 'rubocop-minitest', '~> 0.36.0', require: false # For lint
18
+ gem 'rubocop-performance', '~> 1.22.1', require: false # For lint
17
19
  gem 'rubocop-rake', '~> 0.6.0', require: false # For lint
18
20
  gem 'simplecov', '~> 0.22.0', require: false # For test coverage
19
21
  gem 'simplecov-cobertura', require: false # For test coverage
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  [![Maintainability](https://api.codeclimate.com/v1/badges/fdab4cc0de0b9addcfe8/maintainability)](https://codeclimate.com/github/okuramasafumi/alba/maintainability)
7
7
  ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/okuramasafumi/alba)
8
8
  ![GitHub](https://img.shields.io/github/license/okuramasafumi/alba)
9
- [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](code_of_conduct.md)
9
+ [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md)
10
10
 
11
11
  # Alba
12
12
 
@@ -98,7 +98,7 @@ While Alba's core is simple, it provides additional features when you need them.
98
98
 
99
99
  - Dependency free, no need to install `oj` or `activesupport` while Alba works well with them
100
100
  - Well tested, the test coverage is 99%
101
- - Well maintained, gettings frequent update and new releases (see [version history](https://rubygems.org/gems/alba/versions))
101
+ - Well maintained, getting frequent update and new releases (see [version history](https://rubygems.org/gems/alba/versions))
102
102
 
103
103
  ## Installation
104
104
 
@@ -317,7 +317,7 @@ end
317
317
  FooResource.new(Foo.new).serialize
318
318
  ```
319
319
 
320
- By default, Alba create the JSON as `'{"bar":"This is FooResource"}'`. This means Alba calls a method on a Resource class and doesn't call a method on a target object. This rule is applied to methods that are explicitly defined on Resource class, so methods that Resource class inherits from `Object` class such as `format` are ignored.
320
+ By default, Alba creates the JSON as `'{"bar":"This is FooResource"}'`. This means Alba calls a method on a Resource class and doesn't call a method on a target object. This rule is applied to methods that are explicitly defined on Resource class, so methods that Resource class inherits from `Object` class such as `format` are ignored.
321
321
 
322
322
  ```ruby
323
323
  class Foo
@@ -1023,6 +1023,36 @@ user = User.new(1, nil, nil)
1023
1023
  UserResource.new(user).serialize # => '{"id":1}'
1024
1024
  ```
1025
1025
 
1026
+ #### Caution for the second parameter in `if` proc
1027
+
1028
+ `if` proc takes two parameters. The first one is the target object, `user` in the example above. The second one is `attribute` representing each attribute `if` option affects. Note that it actually calls attribute methods, so you cannot use it to prevent attribute methods called. This means if the target object is an `ActiveRecord::Base` object and using `association` with `if` option, you might want to skip the second parameter so that the SQL query won't be issued.
1029
+
1030
+ Example:
1031
+
1032
+ ```ruby
1033
+ class User < ApplicationRecord
1034
+ has_many :posts
1035
+ end
1036
+
1037
+ class Post < ApplicationRecord
1038
+ belongs_to :user
1039
+ end
1040
+
1041
+ class UserResource
1042
+ include Alba::Resource
1043
+
1044
+ # Since `_posts` parameter exists, `user.posts` are loaded
1045
+ many :posts, if: proc { |user, _posts| user.admin? }
1046
+ end
1047
+
1048
+ class UserResource2
1049
+ include Alba::Resource
1050
+
1051
+ # Since `_posts` parameter doesn't exist, `user.posts` are NOT loaded
1052
+ many :posts, if: proc { |user| user.admin? && params[:include_post] }
1053
+ end
1054
+ ```
1055
+
1026
1056
  ### Default
1027
1057
 
1028
1058
  Alba doesn't support default value for attributes, but it's easy to set a default value.
@@ -1255,7 +1285,7 @@ UserResourceWithDifferentMetaKey.new([user]).serialize
1255
1285
  # => '{"users":[{"id":1,"name":"Masafumi OKURA"}],"my_meta":{"foo":"bar"}}'
1256
1286
 
1257
1287
  UserResourceWithDifferentMetaKey.new([user]).serialize(meta: {extra: 42})
1258
- # => '{"users":[{"id":1,"name":"Masafumi OKURA"}],"meta":{"size":1,"extra":42}}'
1288
+ # => '{"users":[{"id":1,"name":"Masafumi OKURA"}],"my_meta":{"foo":"bar","extra":42}}'
1259
1289
 
1260
1290
  class UserResourceChangingMetaKeyOnly
1261
1291
  include Alba::Resource
@@ -1379,6 +1409,12 @@ end
1379
1409
 
1380
1410
  You now get `created_at` attribute with `iso8601` format!
1381
1411
 
1412
+ #### Generating TypeScript types with typelizer gem
1413
+
1414
+ We often want TypeScript types corresponding to serializers. That's possible with [typelizer](https://github.com/skryukov/typelizer) gem.
1415
+
1416
+ For more information, please read its README.
1417
+
1382
1418
  ### Collection serialization into Hash
1383
1419
 
1384
1420
  Sometimes we want to serialize a collection into a Hash, not an Array. It's possible with Alba.
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rake/testtask'
3
5
 
data/alba.gemspec CHANGED
@@ -28,4 +28,6 @@ Gem::Specification.new do |spec|
28
28
  spec.bindir = 'exe'
29
29
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
30
  spec.require_paths = ['lib']
31
+
32
+ spec.add_dependency "ostruct", "~> 0.6"
31
33
  end
data/benchmark/Gemfile ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
5
+
6
+ gem 'active_model_serializers'
7
+ gem 'activerecord', '~> 7.1'
8
+ gem 'alba', path: '../'
9
+ gem 'benchmark-ips'
10
+ gem 'benchmark-memory'
11
+ gem 'blueprinter'
12
+ gem 'fast_serializer_ruby'
13
+ gem 'jbuilder'
14
+ gem 'jserializer'
15
+ gem 'multi_json'
16
+ gem 'oj'
17
+ gem 'oj_serializers'
18
+ gem 'panko_serializer'
19
+ gem 'pg'
20
+ gem 'primalize'
21
+ gem 'representable'
22
+ gem 'simple_ams'
23
+ gem 'sqlite3', '~> 1.4'
24
+ gem 'turbostreamer'
data/benchmark/README.md CHANGED
@@ -10,76 +10,110 @@ Machine spec:
10
10
 
11
11
  |Key|Value|
12
12
  |---|---|
13
- |OS|macOS 13.2.1|
14
- |CPU|Intel Corei7 Quad Core 2.3Ghz|
15
- |RAM|32GB|
16
- |Ruby|ruby 3.2.1 (2023-02-08 revision 31819e82c8) [x86_64-darwin21]|
13
+ |OS|macOS 14.7|
14
+ |CPU|Apple M1 Pro|
15
+ |RAM|16GB|
16
+ |Ruby|ruby 3.3.5 (2024-09-03 revision ef084cc8f4) [arm64-darwin23]|
17
17
 
18
18
  Library versions:
19
19
 
20
20
  |Library|Version|
21
21
  |---|---|
22
- |alba|2.2.0|
23
- |blueprinter|0.25.3|
22
+ |alba|3.2.0|
23
+ |blueprinter|1.1.0|
24
24
  |fast_serializer_ruby|0.6.9|
25
25
  |jserializer|0.2.1|
26
- |oj|3.14.2|
26
+ |oj|3.16.6|
27
27
  |simple_ams|0.2.6|
28
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|
29
+ |turbostreamer|1.11.0|
30
+ |jbuilder|2.13.0|
31
+ |panko_serializer|0.8.2|
32
+ |active_model_serializers|0.10.14|
33
33
 
34
34
  `benchmark-ips` with `Oj.optimize_rails`:
35
35
 
36
36
  ```
37
37
  Comparison:
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
38
+ panko: 447.0 i/s
39
+ jserializer: 168.9 i/s - 2.65x slower
40
+ alba_inline: 149.4 i/s - 2.99x slower
41
+ alba: 146.5 i/s - 3.05x slower
42
+ turbostreamer: 138.7 i/s - 3.22x slower
43
+ rails: 105.6 i/s - 4.23x slower
44
+ fast_serializer: 97.6 i/s - 4.58x slower
45
+ blueprinter: 66.7 i/s - 6.70x slower
46
+ representable: 50.6 i/s - 8.83x slower
47
+ simple_ams: 35.5 i/s - 12.57x slower
48
+ ams: 14.8 i/s - 30.25x slower
49
49
  ```
50
50
 
51
51
  `benchmark-ips` without `Oj.optimize_rails`:
52
52
 
53
53
  ```
54
54
  Comparison:
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
55
+ panko: 457.9 i/s
56
+ jserializer: 165.9 i/s - 2.76x slower
57
+ alba: 160.1 i/s - 2.86x slower
58
+ alba_inline: 158.5 i/s - 2.89x slower
59
+ turbostreamer: 141.7 i/s - 3.23x slower
60
+ fast_serializer: 96.2 i/s - 4.76x slower
61
+ rails: 87.2 i/s - 5.25x slower
62
+ blueprinter: 67.4 i/s - 6.80x slower
63
+ representable: 43.4 i/s - 10.55x slower
64
+ simple_ams: 34.7 i/s - 13.20x slower
65
+ ams: 14.2 i/s - 32.28x slower
66
+ ```
67
+
68
+ `benchmark-ips` with `Oj.optimize_rail` and YJIT:
69
+
70
+ ```
71
+ Comparison:
72
+ panko: 676.6 i/s
73
+ jserializer: 285.3 i/s - 2.37x slower
74
+ turbostreamer: 264.2 i/s - 2.56x slower
75
+ alba: 258.9 i/s - 2.61x slower
76
+ fast_serializer: 179.0 i/s - 3.78x slower
77
+ rails: 150.7 i/s - 4.49x slower
78
+ alba_inline: 131.5 i/s - 5.15x slower
79
+ blueprinter: 110.0 i/s - 6.15x slower
80
+ representable: 73.5 i/s - 9.21x slower
81
+ simple_ams: 62.8 i/s - 10.77x slower
82
+ ams: 20.4 i/s - 33.10x slower
83
+ ```
84
+
85
+ `benchmark-ips` with YJIT and without `Oj.optimize_rail`:
86
+
87
+ ```
88
+ Comparison:
89
+ panko: 701.9 i/s
90
+ alba: 311.1 i/s - 2.26x slower
91
+ jserializer: 281.6 i/s - 2.49x slower
92
+ turbostreamer: 240.4 i/s - 2.92x slower
93
+ fast_serializer: 180.5 i/s - 3.89x slower
94
+ alba_inline: 135.6 i/s - 5.18x slower
95
+ rails: 131.4 i/s - 5.34x slower
96
+ blueprinter: 110.7 i/s - 6.34x slower
97
+ representable: 70.5 i/s - 9.96x slower
98
+ simple_ams: 57.3 i/s - 12.24x slower
99
+ ams: 20.3 i/s - 34.51x slower
66
100
  ```
67
101
 
68
102
  `benchmark-memory`:
69
103
 
70
104
  ```
71
105
  Comparison:
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
106
+ panko: 259178 allocated
107
+ turbostreamer: 817800 allocated - 3.16x more
108
+ jserializer: 826425 allocated - 3.19x more
109
+ alba: 846465 allocated - 3.27x more
110
+ alba_inline: 867361 allocated - 3.35x more
111
+ fast_serializer: 1474345 allocated - 5.69x more
112
+ rails: 2265905 allocated - 8.74x more
113
+ blueprinter: 2469905 allocated - 9.53x more
114
+ representable: 4994281 allocated - 19.27x more
115
+ ams: 5233265 allocated - 20.19x more
116
+ simple_ams: 9506817 allocated - 36.68x more
83
117
  ```
84
118
 
85
119
  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.
@@ -221,7 +221,6 @@ blueprinter = Proc.new { PostBlueprint.render(posts) }
221
221
  fast_serializer = Proc.new { FastSerializerPostResource.new(posts).to_json }
222
222
  jserializer = Proc.new { JserializerPostSerializer.new(posts, is_collection: true).to_json }
223
223
  panko = proc { Panko::ArraySerializer.new(posts, each_serializer: PankoPostSerializer).to_json }
224
- primalize = proc { PrimalizePostsResource.new(posts: posts).to_json }
225
224
  rails = Proc.new do
226
225
  ActiveSupport::JSON.encode(posts.map{ |post| post.serializable_hash(include: :comments) })
227
226
  end
@@ -253,8 +252,7 @@ end
253
252
 
254
253
  # --- Run the benchmarks ---
255
254
 
256
- require 'benchmark/ips'
257
- Benchmark.ips do |x|
255
+ benchmark_body = lambda do |x|
258
256
  x.report(:alba, &alba)
259
257
  x.report(:alba_inline, &alba_inline)
260
258
  x.report(:ams, &ams)
@@ -270,20 +268,8 @@ Benchmark.ips do |x|
270
268
  x.compare!
271
269
  end
272
270
 
271
+ require 'benchmark/ips'
272
+ Benchmark.ips(&benchmark_body)
273
273
 
274
274
  require 'benchmark/memory'
275
- Benchmark.memory do |x|
276
- x.report(:alba, &alba)
277
- x.report(:alba_inline, &alba_inline)
278
- x.report(:ams, &ams)
279
- x.report(:blueprinter, &blueprinter)
280
- x.report(:fast_serializer, &fast_serializer)
281
- x.report(:jserializer, &jserializer)
282
- x.report(:panko, &panko)
283
- x.report(:rails, &rails)
284
- x.report(:representable, &representable)
285
- x.report(:simple_ams, &simple_ams)
286
- x.report(:turbostreamer, &turbostreamer)
287
-
288
- x.compare!
289
- end
275
+ Benchmark.memory(&benchmark_body)
data/benchmark/prep.rb CHANGED
@@ -1,33 +1,7 @@
1
- # --- Bundle dependencies ---
2
-
3
- require "bundler/inline"
4
-
5
- gemfile(true) do
6
- source "https://rubygems.org"
7
- git_source(:github) { |repo| "https://github.com/#{repo}.git" }
8
-
9
- gem "active_model_serializers"
10
- gem "activerecord", "~> 7.1"
11
- gem "alba", path: '../'
12
- gem "benchmark-ips"
13
- gem "benchmark-memory"
14
- gem "blueprinter"
15
- gem "fast_serializer_ruby"
16
- gem "jbuilder"
17
- gem 'turbostreamer'
18
- gem "jserializer"
19
- gem "multi_json"
20
- gem "panko_serializer"
21
- gem "pg"
22
- gem "primalize"
23
- gem "oj"
24
- gem "representable"
25
- gem "simple_ams"
26
- gem "sqlite3", "~> 1.4"
27
- end
28
-
29
1
  # --- Test data model setup ---
30
2
 
3
+ RubyVM::YJIT.enable if ENV["YJIT"]
4
+ require "csv"
31
5
  require "pg"
32
6
  require "active_record"
33
7
  require "active_record/connection_adapters/postgresql_adapter"
data/bin/console CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bundler/setup'
4
5
  require 'alba'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gem 'minitest', '~> 5.14' # For test
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gem 'activesupport', require: false # For backend
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Alba
2
4
  # Representing association
3
5
  # @api private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'association'
2
4
  require_relative 'constants'
3
5
  require 'ostruct'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file includes public constants to prevent circular dependencies.
2
4
  module Alba
3
5
  REMOVE_KEY = Object.new.freeze # A constant to remove key from serialized JSON
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'active_support/inflector'
3
5
  require 'active_support/core_ext/module/delegation'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Alba
2
4
  # Module for printing deprecation warning
3
5
  # @api private
data/lib/alba/errors.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Alba
2
4
  # Base class for Errors
3
5
  class Error < StandardError; end
data/lib/alba/layout.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'erb'
2
4
  require 'forwardable'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Alba
2
4
  # Representing nested attribute
3
5
  # @api private
data/lib/alba/railtie.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Alba
2
4
  # Rails integration
3
5
  class Railtie < Rails::Railtie
data/lib/alba/resource.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'association'
2
4
  require_relative 'conditional_attribute'
3
5
  require_relative 'constants'
@@ -234,23 +236,7 @@ module Alba
234
236
  def transform_key(key)
235
237
  return Alba.regularize_key(key) if @_transform_type == :none || key.nil? || key.empty? # We can skip transformation
236
238
 
237
- inflector = Alba.inflector
238
- raise Alba::Error, 'Inflector is nil. You must set inflector before transforming keys.' unless inflector
239
-
240
- Alba.regularize_key(_transform_key(inflector, key.to_s))
241
- end
242
-
243
- def _transform_key(inflector, key)
244
- case @_transform_type
245
- when :camel then inflector.camelize(key)
246
- when :lower_camel then inflector.camelize_lower(key)
247
- when :dash then inflector.dasherize(key)
248
- when :snake then inflector.underscore(key)
249
- else
250
- # :nocov:
251
- raise Alba::Error, "Unknown transform type: #{@_transform_type}"
252
- # :nocov:
253
- end
239
+ Alba.transform_key(key, transform_type: @_transform_type)
254
240
  end
255
241
 
256
242
  def fetch_attribute(obj, key, attribute) # rubocop:disable Metrics/CyclomaticComplexity
data/lib/alba/type.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Alba
2
4
  # Representing type itself, combined with {Alba::TypedAttribute}
3
5
  class Type
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Alba
2
4
  # Representing typed attributes to encapsulate logic about types
3
5
  # @api private
data/lib/alba/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Alba
2
- VERSION = '3.2.0'.freeze
4
+ VERSION = '3.3.1'
3
5
  end
data/lib/alba.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json'
2
4
  require_relative 'alba/version'
3
5
  require_relative 'alba/errors'
@@ -142,6 +144,26 @@ module Alba
142
144
  @symbolize_keys ? key.to_sym : key.to_s
143
145
  end
144
146
 
147
+ # Transform a key with given transform_type
148
+ #
149
+ # @param key [String] a target key
150
+ # @param transform_type [Symbol] a transform type, either one of `camel`, `lower_camel`, `dash` or `snake`
151
+ # @return [String]
152
+ def transform_key(key, transform_type:)
153
+ raise Alba::Error, 'Inflector is nil. You must set inflector before transforming keys.' unless inflector
154
+
155
+ key = key.to_s
156
+
157
+ k = case transform_type
158
+ when :camel then inflector.camelize(key)
159
+ when :lower_camel then inflector.camelize_lower(key)
160
+ when :dash then inflector.dasherize(key)
161
+ when :snake then inflector.underscore(key)
162
+ else raise Alba::Error, "Unknown transform type: #{transform_type}"
163
+ end
164
+ regularize_key(k)
165
+ end
166
+
145
167
  # Register types, used for both builtin and custom types
146
168
  #
147
169
  # @see Alba::Type
@@ -239,7 +261,7 @@ module Alba
239
261
  inflector
240
262
  end
241
263
 
242
- def register_default_types
264
+ def register_default_types # rubocop:disable Mertics/AbcSize
243
265
  [String, :String].each do |t|
244
266
  register_type(t, check: ->(obj) { obj.is_a?(String) }, converter: lambda(&:to_s))
245
267
  end
@@ -247,6 +269,9 @@ module Alba
247
269
  register_type(t, check: ->(obj) { obj.is_a?(Integer) }, converter: ->(obj) { Integer(obj) })
248
270
  end
249
271
  register_type(:Boolean, check: ->(obj) { [true, false].include?(obj) }, converter: ->(obj) { !!obj })
272
+ [String, Integer].each do |t|
273
+ register_type(:"ArrayOf#{t}", check: ->(d) { d.is_a?(Array) && d.all? { _1.is_a?(t) } })
274
+ end
250
275
  end
251
276
  end
252
277
 
metadata CHANGED
@@ -1,15 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alba
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - OKURA Masafumi
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-06-21 00:00:00.000000000 Z
12
- dependencies: []
10
+ date: 2024-10-17 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ostruct
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.6'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.6'
13
26
  description: Alba is the fastest JSON serializer for Ruby. It focuses on performance,
14
27
  flexibility and usability.
15
28
  email:
@@ -26,7 +39,6 @@ files:
26
39
  - ".github/workflows/codeql-analysis.yml"
27
40
  - ".github/workflows/lint.yml"
28
41
  - ".github/workflows/main.yml"
29
- - ".github/workflows/perf.yml"
30
42
  - ".gitignore"
31
43
  - ".rubocop.yml"
32
44
  - ".yardopts"
@@ -40,6 +52,7 @@ files:
40
52
  - Rakefile
41
53
  - SECURITY.md
42
54
  - alba.gemspec
55
+ - benchmark/Gemfile
43
56
  - benchmark/README.md
44
57
  - benchmark/collection.rb
45
58
  - benchmark/prep.rb
@@ -69,7 +82,6 @@ files:
69
82
  - logo/alba-card.png
70
83
  - logo/alba-sign.png
71
84
  - logo/alba-typography.png
72
- - script/perf_check.rb
73
85
  homepage: https://github.com/okuramasafumi/alba
74
86
  licenses:
75
87
  - MIT
@@ -79,7 +91,6 @@ metadata:
79
91
  documentation_uri: https://rubydoc.info/github/okuramasafumi/alba
80
92
  source_code_uri: https://github.com/okuramasafumi/alba
81
93
  rubygems_mfa_required: 'true'
82
- post_install_message:
83
94
  rdoc_options: []
84
95
  require_paths:
85
96
  - lib
@@ -94,8 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
105
  - !ruby/object:Gem::Version
95
106
  version: '0'
96
107
  requirements: []
97
- rubygems_version: 3.5.11
98
- signing_key:
108
+ rubygems_version: 3.6.0.dev
99
109
  specification_version: 4
100
110
  summary: Alba is the fastest JSON serializer for Ruby.
101
111
  test_files: []
@@ -1,16 +0,0 @@
1
- name: Performance Check
2
-
3
- on: [pull_request]
4
-
5
- jobs:
6
- build:
7
- runs-on: ubuntu-latest
8
- steps:
9
- - uses: actions/checkout@v4
10
- - name: Set up Ruby
11
- uses: ruby/setup-ruby@v1
12
- with:
13
- ruby-version: 3.3
14
- - name: Run benchmark
15
- run: |
16
- ruby script/perf_check.rb
data/script/perf_check.rb DELETED
@@ -1,107 +0,0 @@
1
- # Benchmark script to run varieties of JSON serializers
2
- # Fetch Alba from local, otherwise fetch latest from RubyGems
3
- # exit(status)
4
-
5
- require_relative '../benchmark/prep'
6
-
7
- # --- Alba serializers ---
8
-
9
- require "alba"
10
-
11
- class AlbaCommentResource
12
- include ::Alba::Resource
13
- attributes :id, :body
14
- end
15
-
16
- class AlbaPostResource
17
- include ::Alba::Resource
18
- attributes :id, :body
19
- attribute :commenter_names do |post|
20
- post.commenters.pluck(:name)
21
- end
22
- many :comments, resource: AlbaCommentResource
23
- end
24
-
25
- # --- Blueprint serializers ---
26
-
27
- require "blueprinter"
28
-
29
- class CommentBlueprint < Blueprinter::Base
30
- fields :id, :body
31
- end
32
-
33
- class PostBlueprint < Blueprinter::Base
34
- fields :id, :body, :commenter_names
35
- association :comments, blueprint: CommentBlueprint
36
-
37
- def commenter_names
38
- commenters.pluck(:name)
39
- end
40
- end
41
-
42
- # --- JBuilder serializers ---
43
-
44
- require "jbuilder"
45
-
46
- class Post
47
- def to_builder
48
- Jbuilder.new do |post|
49
- post.call(self, :id, :body, :commenter_names, :comments)
50
- end
51
- end
52
-
53
- def commenter_names
54
- commenters.pluck(:name)
55
- end
56
- end
57
-
58
- class Comment
59
- def to_builder
60
- Jbuilder.new do |comment|
61
- comment.call(self, :id, :body)
62
- end
63
- end
64
- end
65
-
66
- # --- Test data creation ---
67
-
68
- 100.times do |i|
69
- post = Post.create!(body: "post#{i}")
70
- user1 = User.create!(name: "John#{i}")
71
- user2 = User.create!(name: "Jane#{i}")
72
- 10.times do |n|
73
- post.comments.create!(commenter: user1, body: "Comment1_#{i}_#{n}")
74
- post.comments.create!(commenter: user2, body: "Comment2_#{i}_#{n}")
75
- end
76
- end
77
-
78
- posts = Post.all.to_a
79
-
80
- # --- Store the serializers in procs ---
81
-
82
- alba = Proc.new { AlbaPostResource.new(posts).serialize }
83
- blueprinter = Proc.new { PostBlueprint.render(posts) }
84
- jbuilder = Proc.new do
85
- Jbuilder.new do |json|
86
- json.array!(posts) do |post|
87
- json.post post.to_builder
88
- end
89
- end.target!
90
- end
91
-
92
- # --- Run the benchmarks ---
93
-
94
- require 'benchmark/ips'
95
- result = Benchmark.ips do |x|
96
- x.report(:alba, &alba)
97
- x.report(:blueprinter, &blueprinter)
98
- x.report(:jbuilder, &jbuilder)
99
- end
100
-
101
- entries = result.entries.map {|entry| [entry.label, entry.iterations]}
102
- alba_ips = entries.find {|e| e.first == :alba }.last
103
- blueprinter_ips = entries.find {|e| e.first == :blueprinter }.last
104
- jbuidler_ips = entries.find {|e| e.first == :jbuilder }.last
105
- # Alba should be as fast as jbuilder and faster than blueprinter
106
- alba_is_fast_enough = (alba_ips - jbuidler_ips) > -10.0 && (alba_ips - blueprinter_ips) > 10.0
107
- exit(alba_is_fast_enough)