alba 3.2.0 → 3.3.1
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/.rubocop.yml +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile +5 -3
- data/README.md +40 -4
- data/Rakefile +2 -0
- data/alba.gemspec +2 -0
- data/benchmark/Gemfile +24 -0
- data/benchmark/README.md +78 -44
- data/benchmark/collection.rb +4 -18
- data/benchmark/prep.rb +2 -28
- data/bin/console +1 -0
- data/gemfiles/without_active_support.gemfile +2 -0
- data/gemfiles/without_oj.gemfile +2 -0
- data/lib/alba/association.rb +2 -0
- data/lib/alba/conditional_attribute.rb +2 -0
- data/lib/alba/constants.rb +2 -0
- data/lib/alba/default_inflector.rb +2 -0
- data/lib/alba/deprecation.rb +2 -0
- data/lib/alba/errors.rb +2 -0
- data/lib/alba/layout.rb +2 -0
- data/lib/alba/nested_attribute.rb +2 -0
- data/lib/alba/railtie.rb +2 -0
- data/lib/alba/resource.rb +3 -17
- data/lib/alba/type.rb +2 -0
- data/lib/alba/typed_attribute.rb +2 -0
- data/lib/alba/version.rb +3 -1
- data/lib/alba.rb +26 -1
- metadata +19 -9
- data/.github/workflows/perf.yml +0 -16
- data/script/perf_check.rb +0 -107
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 38b89f99bfe18cf66179ed46c6fdcb5cb25f3d34b8f709fcb9c9de634f7a129b
         | 
| 4 | 
            +
              data.tar.gz: b117d86ab11bb7a0b1abe8e2089ae869c8864fd37b066ea544d0ac51ad5082db
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 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. | 
| 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. | 
| 16 | 
            -
            gem 'rubocop-performance', '~> 1. | 
| 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 | 
             
            [](https://codeclimate.com/github/okuramasafumi/alba/maintainability)
         | 
| 7 7 | 
             
            
         | 
| 8 8 | 
             
            
         | 
| 9 | 
            -
            []( | 
| 9 | 
            +
            [](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,  | 
| 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  | 
| 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"}]," | 
| 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
    
    
    
        data/alba.gemspec
    CHANGED
    
    
    
        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  | 
| 14 | 
            -
            |CPU| | 
| 15 | 
            -
            |RAM| | 
| 16 | 
            -
            |Ruby|ruby 3. | 
| 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| | 
| 23 | 
            -
            |blueprinter| | 
| 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. | 
| 26 | 
            +
            |oj|3.16.6|
         | 
| 27 27 | 
             
            |simple_ams|0.2.6|
         | 
| 28 28 | 
             
            |representable|3.2.0|
         | 
| 29 | 
            -
            |turbostreamer|1. | 
| 30 | 
            -
            |jbuilder|2. | 
| 31 | 
            -
            |panko_serializer|0. | 
| 32 | 
            -
            |active_model_serializers|0.10. | 
| 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:       | 
| 39 | 
            -
                     jserializer:       | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
                 fast_serializer:        | 
| 45 | 
            -
                     blueprinter:        | 
| 46 | 
            -
                   representable:        | 
| 47 | 
            -
                      simple_ams:        | 
| 48 | 
            -
                             ams:        | 
| 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:       | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
                     alba_inline:       | 
| 59 | 
            -
             | 
| 60 | 
            -
                 fast_serializer:        | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
                   representable:        | 
| 64 | 
            -
                      simple_ams:        | 
| 65 | 
            -
                             ams: | 
| 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:      | 
| 73 | 
            -
                   turbostreamer:      | 
| 74 | 
            -
                     jserializer:      | 
| 75 | 
            -
                            alba: | 
| 76 | 
            -
                     alba_inline: | 
| 77 | 
            -
                 fast_serializer:     | 
| 78 | 
            -
                           rails:     | 
| 79 | 
            -
                     blueprinter:     | 
| 80 | 
            -
                   representable:     | 
| 81 | 
            -
                             ams:     | 
| 82 | 
            -
                      simple_ams:     | 
| 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.
         | 
    
        data/benchmark/collection.rb
    CHANGED
    
    | @@ -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 | 
            -
             | 
| 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 | 
| 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
    
    
    
        data/gemfiles/without_oj.gemfile
    CHANGED
    
    
    
        data/lib/alba/association.rb
    CHANGED
    
    
    
        data/lib/alba/constants.rb
    CHANGED
    
    
    
        data/lib/alba/deprecation.rb
    CHANGED
    
    
    
        data/lib/alba/errors.rb
    CHANGED
    
    
    
        data/lib/alba/layout.rb
    CHANGED
    
    
    
        data/lib/alba/railtie.rb
    CHANGED
    
    
    
        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 | 
            -
                     | 
| 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
    
    
    
        data/lib/alba/typed_attribute.rb
    CHANGED
    
    
    
        data/lib/alba/version.rb
    CHANGED
    
    
    
        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. | 
| 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- | 
| 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. | 
| 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: []
         | 
    
        data/.github/workflows/perf.yml
    DELETED
    
    | @@ -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)
         |