alba 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/.rubocop.yml +2 -1
 - data/CHANGELOG.md +12 -0
 - data/README.md +38 -4
 - data/alba.gemspec +1 -1
 - data/benchmark/collection.rb +392 -0
 - data/benchmark/{local.rb → single_resource.rb} +45 -16
 - data/lib/alba.rb +1 -0
 - data/lib/alba/association.rb +17 -9
 - data/lib/alba/default_inflector.rb +36 -0
 - data/lib/alba/key_transform_factory.rb +33 -0
 - data/lib/alba/many.rb +1 -1
 - data/lib/alba/resource.rb +58 -72
 - data/lib/alba/typed_attribute.rb +64 -0
 - data/lib/alba/version.rb +1 -1
 - metadata +9 -7
 - data/lib/alba/key_transformer.rb +0 -32
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: b2c2e8c84ddccf4db9f9f18dd155361567f2a1733c55f817f5b4d97d573675d5
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 3f11dd120c8b57aef909d79f6570482b8af810cd19c57ddcaa0d7b2ee70c2d6b
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 8948a681fb88b3d84e3751e6df0f5ca28314d6c9b5e183666780be95b14fd3c7728e6ad1eb13309d4b7114115b56edbb28fe929c2376bbcc5b762846a7d00404
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 9a2430efc4cf3b7a24b27bb40228dad67e00bd0cb10c9e0fc3764eb49e9caafda5b6d9fa0cc0335c77edc42e0a60416b20343dee5cee23dcfbfe350bed90e9a6
         
     | 
    
        data/.rubocop.yml
    CHANGED
    
    | 
         @@ -49,7 +49,8 @@ Metrics/MethodLength: 
     | 
|
| 
       49 
49 
     | 
    
         | 
| 
       50 
50 
     | 
    
         
             
            # `Resource` module is a core module and its length tends to be long...
         
     | 
| 
       51 
51 
     | 
    
         
             
            Metrics/ModuleLength:
         
     | 
| 
       52 
     | 
    
         
            -
               
     | 
| 
      
 52 
     | 
    
         
            +
              Exclude:
         
     | 
| 
      
 53 
     | 
    
         
            +
                - 'lib/alba/resource.rb'
         
     | 
| 
       53 
54 
     | 
    
         | 
| 
       54 
55 
     | 
    
         
             
            # Resource class includes DSLs, which tend to accept long list of parameters
         
     | 
| 
       55 
56 
     | 
    
         
             
            Metrics/ParameterLists:
         
     | 
    
        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 
     | 
    
         
            +
            ## [1.3.0] 2021-05-31
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            - [Perf] Improve performance for `many` [641d8f9]
         
     | 
| 
      
 12 
     | 
    
         
            +
              - https://github.com/okuramasafumi/alba/pull/125
         
     | 
| 
      
 13 
     | 
    
         
            +
            - [Feat] Add custom inflector feature (#126) [ad73291]
         
     | 
| 
      
 14 
     | 
    
         
            +
              - https://github.com/okuramasafumi/alba/pull/126
         
     | 
| 
      
 15 
     | 
    
         
            +
              - Thank you @wuarmin !
         
     | 
| 
      
 16 
     | 
    
         
            +
            - [Feat] Support params in if condition [6e9915e]
         
     | 
| 
      
 17 
     | 
    
         
            +
              - https://github.com/okuramasafumi/alba/pull/128
         
     | 
| 
      
 18 
     | 
    
         
            +
            - [Fix] fundamentally broken "circular association control" [fbbc9a1]
         
     | 
| 
      
 19 
     | 
    
         
            +
              - https://github.com/okuramasafumi/alba/pull/130
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
       9 
21 
     | 
    
         
             
            ## [1.2.0] 2021-05-09
         
     | 
| 
       10 
22 
     | 
    
         | 
| 
       11 
23 
     | 
    
         
             
            - [Fix] multiple word key inference [6c18e73]
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -66,7 +66,7 @@ You can find the documentation on [RubyDoc](https://rubydoc.info/github/okuramas 
     | 
|
| 
       66 
66 
     | 
    
         
             
            * Error handling
         
     | 
| 
       67 
67 
     | 
    
         
             
            * Resource name inflection based on association name
         
     | 
| 
       68 
68 
     | 
    
         
             
            * Circular associations control
         
     | 
| 
       69 
     | 
    
         
            -
            * Types for validation and conversion
         
     | 
| 
      
 69 
     | 
    
         
            +
            * [Experimental] Types for validation and conversion
         
     | 
| 
       70 
70 
     | 
    
         
             
            * No runtime dependencies
         
     | 
| 
       71 
71 
     | 
    
         | 
| 
       72 
72 
     | 
    
         
             
            ## Anti features
         
     | 
| 
         @@ -246,9 +246,11 @@ end 
     | 
|
| 
       246 
246 
     | 
    
         | 
| 
       247 
247 
     | 
    
         
             
            ### Key transformation
         
     | 
| 
       248 
248 
     | 
    
         | 
| 
       249 
     | 
    
         
            -
             
     | 
| 
      
 249 
     | 
    
         
            +
            If you want to use `transform_keys` DSL and you already have `active_support` installed, key transformation will work out of the box, using `ActiveSupport::Inflector`. If `active_support` is not around, you have 2 possibilities:
         
     | 
| 
      
 250 
     | 
    
         
            +
            * install it
         
     | 
| 
      
 251 
     | 
    
         
            +
            * use a [custom inflector](#custom-inflector)
         
     | 
| 
       250 
252 
     | 
    
         | 
| 
       251 
     | 
    
         
            -
            With ` 
     | 
| 
      
 253 
     | 
    
         
            +
            With `transform_keys` DSL, you can transform attribute keys.
         
     | 
| 
       252 
254 
     | 
    
         | 
| 
       253 
255 
     | 
    
         
             
            ```ruby
         
     | 
| 
       254 
256 
     | 
    
         
             
            class User
         
     | 
| 
         @@ -309,6 +311,34 @@ This behavior to transform root key will become default at version 2. 
     | 
|
| 
       309 
311 
     | 
    
         | 
| 
       310 
312 
     | 
    
         
             
            Supported transformation types are :camel, :lower_camel and :dash.
         
     | 
| 
       311 
313 
     | 
    
         | 
| 
      
 314 
     | 
    
         
            +
            #### Custom inflector
         
     | 
| 
      
 315 
     | 
    
         
            +
             
     | 
| 
      
 316 
     | 
    
         
            +
            A custom inflector can be plugged in as follows...
         
     | 
| 
      
 317 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 318 
     | 
    
         
            +
            Alba.inflector = MyCustomInflector
         
     | 
| 
      
 319 
     | 
    
         
            +
            ```
         
     | 
| 
      
 320 
     | 
    
         
            +
            ...and has to implement following interface (the parameter `key` is of type `String`):
         
     | 
| 
      
 321 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 322 
     | 
    
         
            +
            module InflectorInterface
         
     | 
| 
      
 323 
     | 
    
         
            +
              def camelize(key)
         
     | 
| 
      
 324 
     | 
    
         
            +
                raise "Not implemented"
         
     | 
| 
      
 325 
     | 
    
         
            +
              end
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
              def camelize_lower(key)
         
     | 
| 
      
 328 
     | 
    
         
            +
                raise "Not implemented"
         
     | 
| 
      
 329 
     | 
    
         
            +
              end
         
     | 
| 
      
 330 
     | 
    
         
            +
             
     | 
| 
      
 331 
     | 
    
         
            +
              def dasherize(key)
         
     | 
| 
      
 332 
     | 
    
         
            +
                raise "Not implemented"
         
     | 
| 
      
 333 
     | 
    
         
            +
              end
         
     | 
| 
      
 334 
     | 
    
         
            +
            end
         
     | 
| 
      
 335 
     | 
    
         
            +
             
     | 
| 
      
 336 
     | 
    
         
            +
            ```
         
     | 
| 
      
 337 
     | 
    
         
            +
            For example you could use `Dry::Inflector`, which implements exactly the above interface. If you are developing a `Hanami`-Application `Dry::Inflector` is around. In this case the following would be sufficient:
         
     | 
| 
      
 338 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 339 
     | 
    
         
            +
            Alba.inflector = Dry::Inflector.new
         
     | 
| 
      
 340 
     | 
    
         
            +
            ```
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
       312 
342 
     | 
    
         
             
            ### Filtering attributes
         
     | 
| 
       313 
343 
     | 
    
         | 
| 
       314 
344 
     | 
    
         
             
            You can filter attributes by overriding `Alba::Resource#converter` method, but it's a bit tricky.
         
     | 
| 
         @@ -482,11 +512,13 @@ end 
     | 
|
| 
       482 
512 
     | 
    
         | 
| 
       483 
513 
     | 
    
         
             
            ### Circular associations control
         
     | 
| 
       484 
514 
     | 
    
         | 
| 
      
 515 
     | 
    
         
            +
            **Note that this feature works correctly since version 1.3. In previous versions it doesn't work as expected.**
         
     | 
| 
      
 516 
     | 
    
         
            +
             
     | 
| 
       485 
517 
     | 
    
         
             
            You can control circular associations with `within` option. `within` option is a nested Hash such as `{book: {authors: books}}`. In this example, Alba serializes a book's authors' books. This means you can reference `BookResource` from `AuthorResource` and vice versa. This is really powerful when you have a complex data structure and serialize certain parts of it.
         
     | 
| 
       486 
518 
     | 
    
         | 
| 
       487 
519 
     | 
    
         
             
            For more details, please refer to [test code](https://github.com/okuramasafumi/alba/blob/master/test/usecases/circular_association_test.rb)
         
     | 
| 
       488 
520 
     | 
    
         | 
| 
       489 
     | 
    
         
            -
            ###  
     | 
| 
      
 521 
     | 
    
         
            +
            ### Experimental support of types
         
     | 
| 
       490 
522 
     | 
    
         | 
| 
       491 
523 
     | 
    
         
             
            You can validate and convert input with types.
         
     | 
| 
       492 
524 
     | 
    
         | 
| 
         @@ -525,6 +557,8 @@ UserResource.new(user).serialize 
     | 
|
| 
       525 
557 
     | 
    
         
             
            # => TypeError, 'Attribute bio is expected to be String but actually nil.'
         
     | 
| 
       526 
558 
     | 
    
         
             
            ```
         
     | 
| 
       527 
559 
     | 
    
         | 
| 
      
 560 
     | 
    
         
            +
            Note that this feature is experimental and interfaces are subject to change.
         
     | 
| 
      
 561 
     | 
    
         
            +
             
     | 
| 
       528 
562 
     | 
    
         
             
            ### Caching
         
     | 
| 
       529 
563 
     | 
    
         | 
| 
       530 
564 
     | 
    
         
             
            Currently, Alba doesn't support caching, primarily due to the behavior of `ActiveRecord::Relation`'s cache. See [the issue](https://github.com/rails/rails/issues/41784).
         
     | 
    
        data/alba.gemspec
    CHANGED
    
    | 
         @@ -7,7 +7,7 @@ Gem::Specification.new do |spec| 
     | 
|
| 
       7 
7 
     | 
    
         
             
              spec.email         = ['masafumi.o1988@gmail.com']
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
              spec.summary       = 'Alba is the fastest JSON serializer for Ruby.'
         
     | 
| 
       10 
     | 
    
         
            -
              spec.description   = "Alba is  
     | 
| 
      
 10 
     | 
    
         
            +
              spec.description   = "Alba is the fastest JSON serializer for Ruby. It focuses on performance, flexibility and usability."
         
     | 
| 
       11 
11 
     | 
    
         
             
              spec.homepage      = 'https://github.com/okuramasafumi/alba'
         
     | 
| 
       12 
12 
     | 
    
         
             
              spec.license       = 'MIT'
         
     | 
| 
       13 
13 
     | 
    
         
             
              spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
         
     | 
| 
         @@ -0,0 +1,392 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Benchmark script to run varieties of JSON serializers
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Fetch Alba from local, otherwise fetch latest from RubyGems
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            # --- Bundle dependencies ---
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            require "bundler/inline"
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            gemfile(true) do
         
     | 
| 
      
 9 
     | 
    
         
            +
              source "https://rubygems.org"
         
     | 
| 
      
 10 
     | 
    
         
            +
              git_source(:github) { |repo| "https://github.com/#{repo}.git" }
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              gem "active_model_serializers"
         
     | 
| 
      
 13 
     | 
    
         
            +
              gem "activerecord", "6.1.3"
         
     | 
| 
      
 14 
     | 
    
         
            +
              gem "alba", path: '../'
         
     | 
| 
      
 15 
     | 
    
         
            +
              gem "benchmark-ips"
         
     | 
| 
      
 16 
     | 
    
         
            +
              gem "benchmark-memory"
         
     | 
| 
      
 17 
     | 
    
         
            +
              gem "blueprinter"
         
     | 
| 
      
 18 
     | 
    
         
            +
              gem "jbuilder"
         
     | 
| 
      
 19 
     | 
    
         
            +
              gem "jsonapi-serializer" # successor of fast_jsonapi
         
     | 
| 
      
 20 
     | 
    
         
            +
              gem "multi_json"
         
     | 
| 
      
 21 
     | 
    
         
            +
              gem "primalize"
         
     | 
| 
      
 22 
     | 
    
         
            +
              gem "oj"
         
     | 
| 
      
 23 
     | 
    
         
            +
              gem "representable"
         
     | 
| 
      
 24 
     | 
    
         
            +
              gem "simple_ams"
         
     | 
| 
      
 25 
     | 
    
         
            +
              gem "sqlite3"
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            # --- Test data model setup ---
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            require "active_record"
         
     | 
| 
      
 31 
     | 
    
         
            +
            require "logger"
         
     | 
| 
      
 32 
     | 
    
         
            +
            require "oj"
         
     | 
| 
      
 33 
     | 
    
         
            +
            require "sqlite3"
         
     | 
| 
      
 34 
     | 
    
         
            +
            Oj.optimize_rails
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
         
     | 
| 
      
 37 
     | 
    
         
            +
            # ActiveRecord::Base.logger = Logger.new($stdout)
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            ActiveRecord::Schema.define do
         
     | 
| 
      
 40 
     | 
    
         
            +
              create_table :posts, force: true do |t|
         
     | 
| 
      
 41 
     | 
    
         
            +
                t.string :body
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              create_table :comments, force: true do |t|
         
     | 
| 
      
 45 
     | 
    
         
            +
                t.integer :post_id
         
     | 
| 
      
 46 
     | 
    
         
            +
                t.string :body
         
     | 
| 
      
 47 
     | 
    
         
            +
                t.integer :commenter_id
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              create_table :users, force: true do |t|
         
     | 
| 
      
 51 
     | 
    
         
            +
                t.string :name
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
            end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            class Post < ActiveRecord::Base
         
     | 
| 
      
 56 
     | 
    
         
            +
              has_many :comments
         
     | 
| 
      
 57 
     | 
    
         
            +
              has_many :commenters, through: :comments, class_name: 'User', source: :commenter
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
              def attributes
         
     | 
| 
      
 60 
     | 
    
         
            +
                {id: nil, body: nil, commenter_names: commenter_names}
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
              def commenter_names
         
     | 
| 
      
 64 
     | 
    
         
            +
                commenters.pluck(:name)
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
            end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            class Comment < ActiveRecord::Base
         
     | 
| 
      
 69 
     | 
    
         
            +
              belongs_to :post
         
     | 
| 
      
 70 
     | 
    
         
            +
              belongs_to :commenter, class_name: 'User'
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
              def attributes
         
     | 
| 
      
 73 
     | 
    
         
            +
                {id: nil, body: nil}
         
     | 
| 
      
 74 
     | 
    
         
            +
              end
         
     | 
| 
      
 75 
     | 
    
         
            +
            end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
            class User < ActiveRecord::Base
         
     | 
| 
      
 78 
     | 
    
         
            +
              has_many :comments
         
     | 
| 
      
 79 
     | 
    
         
            +
            end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            # --- Alba serializers ---
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            require "alba"
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            class AlbaCommentResource
         
     | 
| 
      
 86 
     | 
    
         
            +
              include ::Alba::Resource
         
     | 
| 
      
 87 
     | 
    
         
            +
              attributes :id, :body
         
     | 
| 
      
 88 
     | 
    
         
            +
            end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
            class AlbaPostResource
         
     | 
| 
      
 91 
     | 
    
         
            +
              include ::Alba::Resource
         
     | 
| 
      
 92 
     | 
    
         
            +
              attributes :id, :body
         
     | 
| 
      
 93 
     | 
    
         
            +
              attribute :commenter_names do |post|
         
     | 
| 
      
 94 
     | 
    
         
            +
                post.commenters.pluck(:name)
         
     | 
| 
      
 95 
     | 
    
         
            +
              end
         
     | 
| 
      
 96 
     | 
    
         
            +
              many :comments, resource: AlbaCommentResource
         
     | 
| 
      
 97 
     | 
    
         
            +
            end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
            # --- ActiveModelSerializer serializers ---
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
            require "active_model_serializers"
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            ActiveModelSerializers.logger = Logger.new(nil)
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
            class AMSCommentSerializer < ActiveModel::Serializer
         
     | 
| 
      
 106 
     | 
    
         
            +
              attributes :id, :body
         
     | 
| 
      
 107 
     | 
    
         
            +
            end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
            class AMSPostSerializer < ActiveModel::Serializer
         
     | 
| 
      
 110 
     | 
    
         
            +
              attributes :id, :body
         
     | 
| 
      
 111 
     | 
    
         
            +
              attribute :commenter_names
         
     | 
| 
      
 112 
     | 
    
         
            +
              has_many :comments, serializer: AMSCommentSerializer
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
              def commenter_names
         
     | 
| 
      
 115 
     | 
    
         
            +
                object.commenters.pluck(:name)
         
     | 
| 
      
 116 
     | 
    
         
            +
              end
         
     | 
| 
      
 117 
     | 
    
         
            +
            end
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
            # --- Blueprint serializers ---
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
            require "blueprinter"
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
            class CommentBlueprint < Blueprinter::Base
         
     | 
| 
      
 124 
     | 
    
         
            +
              fields :id, :body
         
     | 
| 
      
 125 
     | 
    
         
            +
            end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
            class PostBlueprint < Blueprinter::Base
         
     | 
| 
      
 128 
     | 
    
         
            +
              fields :id, :body, :commenter_names
         
     | 
| 
      
 129 
     | 
    
         
            +
              association :comments, blueprint: CommentBlueprint
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
              def commenter_names
         
     | 
| 
      
 132 
     | 
    
         
            +
                commenters.pluck(:name)
         
     | 
| 
      
 133 
     | 
    
         
            +
              end
         
     | 
| 
      
 134 
     | 
    
         
            +
            end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
            # --- JBuilder serializers ---
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
            require "jbuilder"
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
            class Post
         
     | 
| 
      
 141 
     | 
    
         
            +
              def to_builder
         
     | 
| 
      
 142 
     | 
    
         
            +
                Jbuilder.new do |post|
         
     | 
| 
      
 143 
     | 
    
         
            +
                  post.call(self, :id, :body, :commenter_names, :comments)
         
     | 
| 
      
 144 
     | 
    
         
            +
                end
         
     | 
| 
      
 145 
     | 
    
         
            +
              end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
              def commenter_names
         
     | 
| 
      
 148 
     | 
    
         
            +
                commenters.pluck(:name)
         
     | 
| 
      
 149 
     | 
    
         
            +
              end
         
     | 
| 
      
 150 
     | 
    
         
            +
            end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
            class Comment
         
     | 
| 
      
 153 
     | 
    
         
            +
              def to_builder
         
     | 
| 
      
 154 
     | 
    
         
            +
                Jbuilder.new do |comment|
         
     | 
| 
      
 155 
     | 
    
         
            +
                  comment.call(self, :id, :body)
         
     | 
| 
      
 156 
     | 
    
         
            +
                end
         
     | 
| 
      
 157 
     | 
    
         
            +
              end
         
     | 
| 
      
 158 
     | 
    
         
            +
            end
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
            # --- JSONAPI:Serializer serializers / (successor of fast_jsonapi) ---
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
            class JsonApiStandardCommentSerializer
         
     | 
| 
      
 163 
     | 
    
         
            +
              include JSONAPI::Serializer
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
              attribute :id
         
     | 
| 
      
 166 
     | 
    
         
            +
              attribute :body
         
     | 
| 
      
 167 
     | 
    
         
            +
            end
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
            class JsonApiStandardPostSerializer
         
     | 
| 
      
 170 
     | 
    
         
            +
              include JSONAPI::Serializer
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
              # set_type :post  # optional
         
     | 
| 
      
 173 
     | 
    
         
            +
              attribute :id
         
     | 
| 
      
 174 
     | 
    
         
            +
              attribute :body
         
     | 
| 
      
 175 
     | 
    
         
            +
              attribute :commenter_names
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
              attribute :comments do |post|
         
     | 
| 
      
 178 
     | 
    
         
            +
                post.comments.map { |comment| JsonApiSameFormatCommentSerializer.new(comment) }
         
     | 
| 
      
 179 
     | 
    
         
            +
              end
         
     | 
| 
      
 180 
     | 
    
         
            +
            end
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
            # --- JSONAPI:Serializer serializers that format the code the same flat way as the other gems here ---
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
            # code to convert from JSON:API output to "flat" JSON, like the other serializers build
         
     | 
| 
      
 185 
     | 
    
         
            +
            class JsonApiSameFormatSerializer
         
     | 
| 
      
 186 
     | 
    
         
            +
              include JSONAPI::Serializer
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
              def as_json(*_options)
         
     | 
| 
      
 189 
     | 
    
         
            +
                hash = serializable_hash
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
                if hash[:data].is_a? Hash
         
     | 
| 
      
 192 
     | 
    
         
            +
                  hash[:data][:attributes]
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                elsif hash[:data].is_a? Array
         
     | 
| 
      
 195 
     | 
    
         
            +
                  hash[:data].pluck(:attributes)
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                elsif hash[:data].nil?
         
     | 
| 
      
 198 
     | 
    
         
            +
                  { }
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                else
         
     | 
| 
      
 201 
     | 
    
         
            +
                  raise "unexpected data type #{hash[:data].class}"
         
     | 
| 
      
 202 
     | 
    
         
            +
                end
         
     | 
| 
      
 203 
     | 
    
         
            +
              end
         
     | 
| 
      
 204 
     | 
    
         
            +
            end
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
            class JsonApiSameFormatCommentSerializer < JsonApiSameFormatSerializer
         
     | 
| 
      
 207 
     | 
    
         
            +
              attribute :id
         
     | 
| 
      
 208 
     | 
    
         
            +
              attribute :body
         
     | 
| 
      
 209 
     | 
    
         
            +
            end
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
            class JsonApiSameFormatPostSerializer < JsonApiSameFormatSerializer
         
     | 
| 
      
 212 
     | 
    
         
            +
              attribute :id
         
     | 
| 
      
 213 
     | 
    
         
            +
              attribute :body
         
     | 
| 
      
 214 
     | 
    
         
            +
              attribute :commenter_names
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
              attribute :comments do |post|
         
     | 
| 
      
 217 
     | 
    
         
            +
                post.comments.map { |comment| JsonApiSameFormatCommentSerializer.new(comment) }
         
     | 
| 
      
 218 
     | 
    
         
            +
              end
         
     | 
| 
      
 219 
     | 
    
         
            +
            end
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
            # --- Primalize serializers ---
         
     | 
| 
      
 222 
     | 
    
         
            +
            #
         
     | 
| 
      
 223 
     | 
    
         
            +
            class PrimalizeCommentResource < Primalize::Single
         
     | 
| 
      
 224 
     | 
    
         
            +
              attributes id: integer, body: string
         
     | 
| 
      
 225 
     | 
    
         
            +
            end
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
      
 227 
     | 
    
         
            +
            class PrimalizePostResource < Primalize::Single
         
     | 
| 
      
 228 
     | 
    
         
            +
              alias post object
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
              attributes(
         
     | 
| 
      
 231 
     | 
    
         
            +
                id: integer,
         
     | 
| 
      
 232 
     | 
    
         
            +
                body: string,
         
     | 
| 
      
 233 
     | 
    
         
            +
                comments: array(primalize(PrimalizeCommentResource)),
         
     | 
| 
      
 234 
     | 
    
         
            +
                commenter_names: array(string),
         
     | 
| 
      
 235 
     | 
    
         
            +
              )
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
              def commenter_names
         
     | 
| 
      
 238 
     | 
    
         
            +
                post.commenters.pluck(:name)
         
     | 
| 
      
 239 
     | 
    
         
            +
              end
         
     | 
| 
      
 240 
     | 
    
         
            +
            end
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
            class PrimalizePostsResource < Primalize::Many
         
     | 
| 
      
 243 
     | 
    
         
            +
              attributes posts: enumerable(PrimalizePostResource)
         
     | 
| 
      
 244 
     | 
    
         
            +
            end
         
     | 
| 
      
 245 
     | 
    
         
            +
             
     | 
| 
      
 246 
     | 
    
         
            +
            # --- Representable serializers ---
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
            require "representable"
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
            class CommentRepresenter < Representable::Decorator
         
     | 
| 
      
 251 
     | 
    
         
            +
              include Representable::JSON
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
              property :id
         
     | 
| 
      
 254 
     | 
    
         
            +
              property :body
         
     | 
| 
      
 255 
     | 
    
         
            +
            end
         
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
      
 257 
     | 
    
         
            +
            class PostsRepresenter < Representable::Decorator
         
     | 
| 
      
 258 
     | 
    
         
            +
              include Representable::JSON::Collection
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
      
 260 
     | 
    
         
            +
              items class: Post do
         
     | 
| 
      
 261 
     | 
    
         
            +
                property :id
         
     | 
| 
      
 262 
     | 
    
         
            +
                property :body
         
     | 
| 
      
 263 
     | 
    
         
            +
                property :commenter_names
         
     | 
| 
      
 264 
     | 
    
         
            +
                collection :comments
         
     | 
| 
      
 265 
     | 
    
         
            +
              end
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
      
 267 
     | 
    
         
            +
              def commenter_names
         
     | 
| 
      
 268 
     | 
    
         
            +
                commenters.pluck(:name)
         
     | 
| 
      
 269 
     | 
    
         
            +
              end
         
     | 
| 
      
 270 
     | 
    
         
            +
            end
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
            # --- SimpleAMS serializers ---
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
            require "simple_ams"
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
            class SimpleAMSCommentSerializer
         
     | 
| 
      
 277 
     | 
    
         
            +
              include SimpleAMS::DSL
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
              attributes :id, :body
         
     | 
| 
      
 280 
     | 
    
         
            +
            end
         
     | 
| 
      
 281 
     | 
    
         
            +
             
     | 
| 
      
 282 
     | 
    
         
            +
            class SimpleAMSPostSerializer
         
     | 
| 
      
 283 
     | 
    
         
            +
              include SimpleAMS::DSL
         
     | 
| 
      
 284 
     | 
    
         
            +
             
     | 
| 
      
 285 
     | 
    
         
            +
              attributes :id, :body
         
     | 
| 
      
 286 
     | 
    
         
            +
              attribute :commenter_names
         
     | 
| 
      
 287 
     | 
    
         
            +
              has_many :comments, serializer: SimpleAMSCommentSerializer
         
     | 
| 
      
 288 
     | 
    
         
            +
             
     | 
| 
      
 289 
     | 
    
         
            +
              def commenter_names
         
     | 
| 
      
 290 
     | 
    
         
            +
                object.commenters.pluck(:name)
         
     | 
| 
      
 291 
     | 
    
         
            +
              end
         
     | 
| 
      
 292 
     | 
    
         
            +
            end
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
            # --- Test data creation ---
         
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
            100.times do |i|
         
     | 
| 
      
 297 
     | 
    
         
            +
              post = Post.create!(body: "post#{i}")
         
     | 
| 
      
 298 
     | 
    
         
            +
              user1 = User.create!(name: "John#{i}")
         
     | 
| 
      
 299 
     | 
    
         
            +
              user2 = User.create!(name: "Jane#{i}")
         
     | 
| 
      
 300 
     | 
    
         
            +
              10.times do |n|
         
     | 
| 
      
 301 
     | 
    
         
            +
                post.comments.create!(commenter: user1, body: "Comment1_#{i}_#{n}")
         
     | 
| 
      
 302 
     | 
    
         
            +
                post.comments.create!(commenter: user2, body: "Comment2_#{i}_#{n}")
         
     | 
| 
      
 303 
     | 
    
         
            +
              end
         
     | 
| 
      
 304 
     | 
    
         
            +
            end
         
     | 
| 
      
 305 
     | 
    
         
            +
             
     | 
| 
      
 306 
     | 
    
         
            +
            posts = Post.all.to_a
         
     | 
| 
      
 307 
     | 
    
         
            +
             
     | 
| 
      
 308 
     | 
    
         
            +
            # --- Store the serializers in procs ---
         
     | 
| 
      
 309 
     | 
    
         
            +
             
     | 
| 
      
 310 
     | 
    
         
            +
            alba = Proc.new { AlbaPostResource.new(posts).serialize }
         
     | 
| 
      
 311 
     | 
    
         
            +
            alba_inline = Proc.new do
         
     | 
| 
      
 312 
     | 
    
         
            +
              Alba.serialize(posts) do
         
     | 
| 
      
 313 
     | 
    
         
            +
                attributes :id, :body
         
     | 
| 
      
 314 
     | 
    
         
            +
                attribute :commenter_names do |post|
         
     | 
| 
      
 315 
     | 
    
         
            +
                  post.commenters.pluck(:name)
         
     | 
| 
      
 316 
     | 
    
         
            +
                end
         
     | 
| 
      
 317 
     | 
    
         
            +
                many :comments do
         
     | 
| 
      
 318 
     | 
    
         
            +
                  attributes :id, :body
         
     | 
| 
      
 319 
     | 
    
         
            +
                end
         
     | 
| 
      
 320 
     | 
    
         
            +
              end
         
     | 
| 
      
 321 
     | 
    
         
            +
            end
         
     | 
| 
      
 322 
     | 
    
         
            +
            ams = Proc.new { ActiveModelSerializers::SerializableResource.new(posts, {}).as_json }
         
     | 
| 
      
 323 
     | 
    
         
            +
            blueprinter = Proc.new { PostBlueprint.render(posts) }
         
     | 
| 
      
 324 
     | 
    
         
            +
            jbuilder = Proc.new do
         
     | 
| 
      
 325 
     | 
    
         
            +
              Jbuilder.new do |json|
         
     | 
| 
      
 326 
     | 
    
         
            +
                json.array!(posts) do |post|
         
     | 
| 
      
 327 
     | 
    
         
            +
                  json.post post.to_builder
         
     | 
| 
      
 328 
     | 
    
         
            +
                end
         
     | 
| 
      
 329 
     | 
    
         
            +
              end.target!
         
     | 
| 
      
 330 
     | 
    
         
            +
            end
         
     | 
| 
      
 331 
     | 
    
         
            +
            jsonapi = proc { JsonApiStandardPostSerializer.new(posts).to_json }
         
     | 
| 
      
 332 
     | 
    
         
            +
            jsonapi_same_format = proc { JsonApiSameFormatPostSerializer.new(posts).to_json }
         
     | 
| 
      
 333 
     | 
    
         
            +
            primalize = proc { PrimalizePostsResource.new(posts: posts).to_json }
         
     | 
| 
      
 334 
     | 
    
         
            +
            rails = Proc.new do
         
     | 
| 
      
 335 
     | 
    
         
            +
              ActiveSupport::JSON.encode(posts.map{ |post| post.serializable_hash(include: :comments) })
         
     | 
| 
      
 336 
     | 
    
         
            +
            end
         
     | 
| 
      
 337 
     | 
    
         
            +
            representable = Proc.new { PostsRepresenter.new(posts).to_json }
         
     | 
| 
      
 338 
     | 
    
         
            +
            simple_ams = Proc.new { SimpleAMS::Renderer::Collection.new(posts, serializer: SimpleAMSPostSerializer).to_json }
         
     | 
| 
      
 339 
     | 
    
         
            +
             
     | 
| 
      
 340 
     | 
    
         
            +
            # --- Execute the serializers to check their output ---
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
      
 342 
     | 
    
         
            +
            puts "Serializer outputs ----------------------------------"
         
     | 
| 
      
 343 
     | 
    
         
            +
            {
         
     | 
| 
      
 344 
     | 
    
         
            +
              alba: alba,
         
     | 
| 
      
 345 
     | 
    
         
            +
              alba_inline: alba_inline,
         
     | 
| 
      
 346 
     | 
    
         
            +
              ams: ams,
         
     | 
| 
      
 347 
     | 
    
         
            +
              blueprinter: blueprinter,
         
     | 
| 
      
 348 
     | 
    
         
            +
              jbuilder: jbuilder, # different order
         
     | 
| 
      
 349 
     | 
    
         
            +
              jsonapi: jsonapi, # nested JSON:API format
         
     | 
| 
      
 350 
     | 
    
         
            +
              jsonapi_same_format: jsonapi_same_format,
         
     | 
| 
      
 351 
     | 
    
         
            +
              primalize: primalize,
         
     | 
| 
      
 352 
     | 
    
         
            +
              rails: rails,
         
     | 
| 
      
 353 
     | 
    
         
            +
              representable: representable,
         
     | 
| 
      
 354 
     | 
    
         
            +
              simple_ams: simple_ams,
         
     | 
| 
      
 355 
     | 
    
         
            +
            }.each { |name, serializer| puts "#{name.to_s.ljust(24, ' ')} #{serializer.call}" }
         
     | 
| 
      
 356 
     | 
    
         
            +
             
     | 
| 
      
 357 
     | 
    
         
            +
            # --- Run the benchmarks ---
         
     | 
| 
      
 358 
     | 
    
         
            +
             
     | 
| 
      
 359 
     | 
    
         
            +
            require 'benchmark/ips'
         
     | 
| 
      
 360 
     | 
    
         
            +
            Benchmark.ips do |x|
         
     | 
| 
      
 361 
     | 
    
         
            +
              x.report(:alba, &alba)
         
     | 
| 
      
 362 
     | 
    
         
            +
              x.report(:alba_inline, &alba_inline)
         
     | 
| 
      
 363 
     | 
    
         
            +
              x.report(:ams, &ams)
         
     | 
| 
      
 364 
     | 
    
         
            +
              x.report(:blueprinter, &blueprinter)
         
     | 
| 
      
 365 
     | 
    
         
            +
              x.report(:jbuilder, &jbuilder)
         
     | 
| 
      
 366 
     | 
    
         
            +
              x.report(:jsonapi, &jsonapi)
         
     | 
| 
      
 367 
     | 
    
         
            +
              x.report(:jsonapi_same_format, &jsonapi_same_format)
         
     | 
| 
      
 368 
     | 
    
         
            +
              x.report(:primalize, &primalize)
         
     | 
| 
      
 369 
     | 
    
         
            +
              x.report(:rails, &rails)
         
     | 
| 
      
 370 
     | 
    
         
            +
              x.report(:representable, &representable)
         
     | 
| 
      
 371 
     | 
    
         
            +
              x.report(:simple_ams, &simple_ams)
         
     | 
| 
      
 372 
     | 
    
         
            +
             
     | 
| 
      
 373 
     | 
    
         
            +
              x.compare!
         
     | 
| 
      
 374 
     | 
    
         
            +
            end
         
     | 
| 
      
 375 
     | 
    
         
            +
             
     | 
| 
      
 376 
     | 
    
         
            +
             
     | 
| 
      
 377 
     | 
    
         
            +
            require 'benchmark/memory'
         
     | 
| 
      
 378 
     | 
    
         
            +
            Benchmark.memory do |x|
         
     | 
| 
      
 379 
     | 
    
         
            +
              x.report(:alba, &alba)
         
     | 
| 
      
 380 
     | 
    
         
            +
              x.report(:alba_inline, &alba_inline)
         
     | 
| 
      
 381 
     | 
    
         
            +
              x.report(:ams, &ams)
         
     | 
| 
      
 382 
     | 
    
         
            +
              x.report(:blueprinter, &blueprinter)
         
     | 
| 
      
 383 
     | 
    
         
            +
              x.report(:jbuilder, &jbuilder)
         
     | 
| 
      
 384 
     | 
    
         
            +
              x.report(:jsonapi, &jsonapi)
         
     | 
| 
      
 385 
     | 
    
         
            +
              x.report(:jsonapi_same_format, &jsonapi_same_format)
         
     | 
| 
      
 386 
     | 
    
         
            +
              x.report(:primalize, &primalize)
         
     | 
| 
      
 387 
     | 
    
         
            +
              x.report(:rails, &rails)
         
     | 
| 
      
 388 
     | 
    
         
            +
              x.report(:representable, &representable)
         
     | 
| 
      
 389 
     | 
    
         
            +
              x.report(:simple_ams, &simple_ams)
         
     | 
| 
      
 390 
     | 
    
         
            +
             
     | 
| 
      
 391 
     | 
    
         
            +
              x.compare!
         
     | 
| 
      
 392 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -20,6 +20,7 @@ gemfile(true) do 
     | 
|
| 
       20 
20 
     | 
    
         
             
              gem "primalize"
         
     | 
| 
       21 
21 
     | 
    
         
             
              gem "oj"
         
     | 
| 
       22 
22 
     | 
    
         
             
              gem "representable"
         
     | 
| 
      
 23 
     | 
    
         
            +
              gem "simple_ams"
         
     | 
| 
       23 
24 
     | 
    
         
             
              gem "sqlite3"
         
     | 
| 
       24 
25 
     | 
    
         
             
            end
         
     | 
| 
       25 
26 
     | 
    
         | 
| 
         @@ -259,6 +260,28 @@ class PostRepresenter < Representable::Decorator 
     | 
|
| 
       259 
260 
     | 
    
         
             
              end
         
     | 
| 
       260 
261 
     | 
    
         
             
            end
         
     | 
| 
       261 
262 
     | 
    
         | 
| 
      
 263 
     | 
    
         
            +
            # --- SimpleAMS serializers ---
         
     | 
| 
      
 264 
     | 
    
         
            +
             
     | 
| 
      
 265 
     | 
    
         
            +
            require "simple_ams"
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
      
 267 
     | 
    
         
            +
            class SimpleAMSCommentSerializer
         
     | 
| 
      
 268 
     | 
    
         
            +
              include SimpleAMS::DSL
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
      
 270 
     | 
    
         
            +
              attributes :id, :body
         
     | 
| 
      
 271 
     | 
    
         
            +
            end
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
      
 273 
     | 
    
         
            +
            class SimpleAMSPostSerializer
         
     | 
| 
      
 274 
     | 
    
         
            +
              include SimpleAMS::DSL
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
              attributes :id, :body
         
     | 
| 
      
 277 
     | 
    
         
            +
              attribute :commenter_names
         
     | 
| 
      
 278 
     | 
    
         
            +
              has_many :comments, serializer: SimpleAMSCommentSerializer
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
              def commenter_names
         
     | 
| 
      
 281 
     | 
    
         
            +
                object.commenters.pluck(:name)
         
     | 
| 
      
 282 
     | 
    
         
            +
              end
         
     | 
| 
      
 283 
     | 
    
         
            +
            end
         
     | 
| 
      
 284 
     | 
    
         
            +
             
     | 
| 
       262 
285 
     | 
    
         
             
            # --- Test data creation ---
         
     | 
| 
       263 
286 
     | 
    
         | 
| 
       264 
287 
     | 
    
         
             
            post = Post.create!(body: 'post')
         
     | 
| 
         @@ -290,6 +313,7 @@ jsonapi_same_format = proc { JsonApiSameFormatPostSerializer.new(post).to_json } 
     | 
|
| 
       290 
313 
     | 
    
         
             
            primalize = proc { PrimalizePostResource.new(post).to_json }
         
     | 
| 
       291 
314 
     | 
    
         
             
            rails = Proc.new { ActiveSupport::JSON.encode(post.serializable_hash(include: :comments)) }
         
     | 
| 
       292 
315 
     | 
    
         
             
            representable = Proc.new { PostRepresenter.new(post).to_json }
         
     | 
| 
      
 316 
     | 
    
         
            +
            simple_ams = Proc.new { SimpleAMS::Renderer.new(post, serializer: SimpleAMSPostSerializer).to_json }
         
     | 
| 
       293 
317 
     | 
    
         | 
| 
       294 
318 
     | 
    
         
             
            # --- Execute the serializers to check their output ---
         
     | 
| 
       295 
319 
     | 
    
         | 
| 
         @@ -304,26 +328,12 @@ puts "Serializer outputs ----------------------------------" 
     | 
|
| 
       304 
328 
     | 
    
         
             
              jsonapi_same_format: jsonapi_same_format,
         
     | 
| 
       305 
329 
     | 
    
         
             
              primalize: primalize,
         
     | 
| 
       306 
330 
     | 
    
         
             
              rails: rails,
         
     | 
| 
       307 
     | 
    
         
            -
              representable: representable
         
     | 
| 
      
 331 
     | 
    
         
            +
              representable: representable,
         
     | 
| 
      
 332 
     | 
    
         
            +
              simple_ams: simple_ams,
         
     | 
| 
       308 
333 
     | 
    
         
             
            }.each { |name, serializer| puts "#{name.to_s.ljust(24, ' ')} #{serializer.call}" }
         
     | 
| 
       309 
334 
     | 
    
         | 
| 
       310 
335 
     | 
    
         
             
            # --- Run the benchmarks ---
         
     | 
| 
       311 
336 
     | 
    
         | 
| 
       312 
     | 
    
         
            -
            require 'benchmark'
         
     | 
| 
       313 
     | 
    
         
            -
            time = 1000
         
     | 
| 
       314 
     | 
    
         
            -
            Benchmark.bmbm do |x|
         
     | 
| 
       315 
     | 
    
         
            -
              x.report(:alba) { time.times(&alba) }
         
     | 
| 
       316 
     | 
    
         
            -
              x.report(:alba_inline) { time.times(&alba_inline) }
         
     | 
| 
       317 
     | 
    
         
            -
              x.report(:ams) { time.times(&ams) }
         
     | 
| 
       318 
     | 
    
         
            -
              x.report(:blueprinter) { time.times(&blueprinter) }
         
     | 
| 
       319 
     | 
    
         
            -
              x.report(:jbuilder) { time.times(&jbuilder) }
         
     | 
| 
       320 
     | 
    
         
            -
              x.report(:jsonapi) { time.times(&jsonapi) }
         
     | 
| 
       321 
     | 
    
         
            -
              x.report(:jsonapi_same_format) { time.times(&jsonapi_same_format) }
         
     | 
| 
       322 
     | 
    
         
            -
              x.report(:primalize) { time.times(&primalize) }
         
     | 
| 
       323 
     | 
    
         
            -
              x.report(:rails) { time.times(&rails) }
         
     | 
| 
       324 
     | 
    
         
            -
              x.report(:representable) { time.times(&representable) }
         
     | 
| 
       325 
     | 
    
         
            -
            end
         
     | 
| 
       326 
     | 
    
         
            -
             
     | 
| 
       327 
337 
     | 
    
         
             
            require 'benchmark/ips'
         
     | 
| 
       328 
338 
     | 
    
         
             
            Benchmark.ips do |x|
         
     | 
| 
       329 
339 
     | 
    
         
             
              x.report(:alba, &alba)
         
     | 
| 
         @@ -336,6 +346,25 @@ Benchmark.ips do |x| 
     | 
|
| 
       336 
346 
     | 
    
         
             
              x.report(:primalize, &primalize)
         
     | 
| 
       337 
347 
     | 
    
         
             
              x.report(:rails, &rails)
         
     | 
| 
       338 
348 
     | 
    
         
             
              x.report(:representable, &representable)
         
     | 
| 
      
 349 
     | 
    
         
            +
              x.report(:simple_ams, &simple_ams)
         
     | 
| 
      
 350 
     | 
    
         
            +
             
     | 
| 
      
 351 
     | 
    
         
            +
              x.compare!
         
     | 
| 
      
 352 
     | 
    
         
            +
            end
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
             
     | 
| 
      
 355 
     | 
    
         
            +
            require 'benchmark/memory'
         
     | 
| 
      
 356 
     | 
    
         
            +
            Benchmark.memory do |x|
         
     | 
| 
      
 357 
     | 
    
         
            +
              x.report(:alba, &alba)
         
     | 
| 
      
 358 
     | 
    
         
            +
              x.report(:alba_inline, &alba_inline)
         
     | 
| 
      
 359 
     | 
    
         
            +
              x.report(:ams, &ams)
         
     | 
| 
      
 360 
     | 
    
         
            +
              x.report(:blueprinter, &blueprinter)
         
     | 
| 
      
 361 
     | 
    
         
            +
              x.report(:jbuilder, &jbuilder)
         
     | 
| 
      
 362 
     | 
    
         
            +
              x.report(:jsonapi, &jsonapi)
         
     | 
| 
      
 363 
     | 
    
         
            +
              x.report(:jsonapi_same_format, &jsonapi_same_format)
         
     | 
| 
      
 364 
     | 
    
         
            +
              x.report(:primalize, &primalize)
         
     | 
| 
      
 365 
     | 
    
         
            +
              x.report(:rails, &rails)
         
     | 
| 
      
 366 
     | 
    
         
            +
              x.report(:representable, &representable)
         
     | 
| 
      
 367 
     | 
    
         
            +
              x.report(:simple_ams, &simple_ams)
         
     | 
| 
       339 
368 
     | 
    
         | 
| 
       340 
369 
     | 
    
         
             
              x.compare!
         
     | 
| 
       341 
370 
     | 
    
         
             
            end
         
     | 
    
        data/lib/alba.rb
    CHANGED
    
    
    
        data/lib/alba/association.rb
    CHANGED
    
    | 
         @@ -2,7 +2,7 @@ module Alba 
     | 
|
| 
       2 
2 
     | 
    
         
             
              # Base class for `One` and `Many`
         
     | 
| 
       3 
3 
     | 
    
         
             
              # Child class should implement `to_hash` method
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Association
         
     | 
| 
       5 
     | 
    
         
            -
                attr_reader :object
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_reader :object, :name
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
                # @param name [Symbol] name of the method to fetch association
         
     | 
| 
       8 
8 
     | 
    
         
             
                # @param condition [Proc] a proc filtering data
         
     | 
| 
         @@ -15,14 +15,7 @@ module Alba 
     | 
|
| 
       15 
15 
     | 
    
         
             
                  @resource = resource
         
     | 
| 
       16 
16 
     | 
    
         
             
                  return if @resource
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                   
     | 
| 
       19 
     | 
    
         
            -
                    @resource = resource_class
         
     | 
| 
       20 
     | 
    
         
            -
                  elsif Alba.inferring
         
     | 
| 
       21 
     | 
    
         
            -
                    const_parent = nesting.nil? ? Object : Object.const_get(nesting)
         
     | 
| 
       22 
     | 
    
         
            -
                    @resource = const_parent.const_get("#{ActiveSupport::Inflector.classify(@name)}Resource")
         
     | 
| 
       23 
     | 
    
         
            -
                  else
         
     | 
| 
       24 
     | 
    
         
            -
                    raise ArgumentError, 'When Alba.inferring is false, either resource or block is required'
         
     | 
| 
       25 
     | 
    
         
            -
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  assign_resource(nesting)
         
     | 
| 
       26 
19 
     | 
    
         
             
                end
         
     | 
| 
       27 
20 
     | 
    
         | 
| 
       28 
21 
     | 
    
         
             
                private
         
     | 
| 
         @@ -36,11 +29,26 @@ module Alba 
     | 
|
| 
       36 
29 
     | 
    
         
             
                  end
         
     | 
| 
       37 
30 
     | 
    
         
             
                end
         
     | 
| 
       38 
31 
     | 
    
         | 
| 
      
 32 
     | 
    
         
            +
                def assign_resource(nesting)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @resource = if @block
         
     | 
| 
      
 34 
     | 
    
         
            +
                                resource_class
         
     | 
| 
      
 35 
     | 
    
         
            +
                              elsif Alba.inferring
         
     | 
| 
      
 36 
     | 
    
         
            +
                                resource_class_with_nesting(nesting)
         
     | 
| 
      
 37 
     | 
    
         
            +
                              else
         
     | 
| 
      
 38 
     | 
    
         
            +
                                raise ArgumentError, 'When Alba.inferring is false, either resource or block is required'
         
     | 
| 
      
 39 
     | 
    
         
            +
                              end
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
       39 
42 
     | 
    
         
             
                def resource_class
         
     | 
| 
       40 
43 
     | 
    
         
             
                  klass = Class.new
         
     | 
| 
       41 
44 
     | 
    
         
             
                  klass.include(Alba::Resource)
         
     | 
| 
       42 
45 
     | 
    
         
             
                  klass.class_eval(&@block)
         
     | 
| 
       43 
46 
     | 
    
         
             
                  klass
         
     | 
| 
       44 
47 
     | 
    
         
             
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                def resource_class_with_nesting(nesting)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  const_parent = nesting.nil? ? Object : Object.const_get(nesting)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  const_parent.const_get("#{ActiveSupport::Inflector.classify(@name)}Resource")
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
       45 
53 
     | 
    
         
             
              end
         
     | 
| 
       46 
54 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Alba
         
     | 
| 
      
 2 
     | 
    
         
            +
              # This module represents the inflector, which is used by default
         
     | 
| 
      
 3 
     | 
    
         
            +
              module DefaultInflector
         
     | 
| 
      
 4 
     | 
    
         
            +
                begin
         
     | 
| 
      
 5 
     | 
    
         
            +
                  require 'active_support/inflector'
         
     | 
| 
      
 6 
     | 
    
         
            +
                rescue LoadError
         
     | 
| 
      
 7 
     | 
    
         
            +
                  raise ::Alba::Error, 'To use transform_keys, please install `ActiveSupport` gem.'
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                module_function
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                # Camelizes a key
         
     | 
| 
      
 13 
     | 
    
         
            +
                #
         
     | 
| 
      
 14 
     | 
    
         
            +
                # @params key [String] key to be camelized
         
     | 
| 
      
 15 
     | 
    
         
            +
                # @return [String] camelized key
         
     | 
| 
      
 16 
     | 
    
         
            +
                def camelize(key)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  ActiveSupport::Inflector.camelize(key)
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                # Camelizes a key, 1st letter lowercase
         
     | 
| 
      
 21 
     | 
    
         
            +
                #
         
     | 
| 
      
 22 
     | 
    
         
            +
                # @params key [String] key to be camelized
         
     | 
| 
      
 23 
     | 
    
         
            +
                # @return [String] camelized key
         
     | 
| 
      
 24 
     | 
    
         
            +
                def camelize_lower(key)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  ActiveSupport::Inflector.camelize(key, false)
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                # Dasherizes a key
         
     | 
| 
      
 29 
     | 
    
         
            +
                #
         
     | 
| 
      
 30 
     | 
    
         
            +
                # @params key [String] key to be dasherized
         
     | 
| 
      
 31 
     | 
    
         
            +
                # @return [String] dasherized key
         
     | 
| 
      
 32 
     | 
    
         
            +
                def dasherize(key)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  ActiveSupport::Inflector.dasherize(key)
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,33 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Alba
         
     | 
| 
      
 2 
     | 
    
         
            +
              # This module creates key transform functions
         
     | 
| 
      
 3 
     | 
    
         
            +
              module KeyTransformFactory
         
     | 
| 
      
 4 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 5 
     | 
    
         
            +
                  # Create key transform function for given transform_type
         
     | 
| 
      
 6 
     | 
    
         
            +
                  #
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # @params transform_type [Symbol] transform type
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # @return [Proc] transform function
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @raise [Alba::Error] when transform_type is not supported
         
     | 
| 
      
 10 
     | 
    
         
            +
                  def create(transform_type)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    case transform_type
         
     | 
| 
      
 12 
     | 
    
         
            +
                    when :camel
         
     | 
| 
      
 13 
     | 
    
         
            +
                      ->(key) { _inflector.camelize(key) }
         
     | 
| 
      
 14 
     | 
    
         
            +
                    when :lower_camel
         
     | 
| 
      
 15 
     | 
    
         
            +
                      ->(key) { _inflector.camelize_lower(key) }
         
     | 
| 
      
 16 
     | 
    
         
            +
                    when :dash
         
     | 
| 
      
 17 
     | 
    
         
            +
                      ->(key) { _inflector.dasherize(key) }
         
     | 
| 
      
 18 
     | 
    
         
            +
                    else
         
     | 
| 
      
 19 
     | 
    
         
            +
                      raise ::Alba::Error, "Unknown transform_type: #{transform_type}. Supported transform_type are :camel, :lower_camel and :dash."
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  private
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  def _inflector
         
     | 
| 
      
 26 
     | 
    
         
            +
                    Alba.inflector || begin
         
     | 
| 
      
 27 
     | 
    
         
            +
                      require_relative './default_inflector'
         
     | 
| 
      
 28 
     | 
    
         
            +
                      Alba::DefaultInflector
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/alba/many.rb
    CHANGED
    
    
    
        data/lib/alba/resource.rb
    CHANGED
    
    | 
         @@ -1,14 +1,19 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require_relative 'one'
         
     | 
| 
       2 
2 
     | 
    
         
             
            require_relative 'many'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'key_transform_factory'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'typed_attribute'
         
     | 
| 
       3 
5 
     | 
    
         | 
| 
       4 
6 
     | 
    
         
             
            module Alba
         
     | 
| 
       5 
7 
     | 
    
         
             
              # This module represents what should be serialized
         
     | 
| 
       6 
8 
     | 
    
         
             
              module Resource
         
     | 
| 
       7 
9 
     | 
    
         
             
                # @!parse include InstanceMethods
         
     | 
| 
       8 
10 
     | 
    
         
             
                # @!parse extend ClassMethods
         
     | 
| 
       9 
     | 
    
         
            -
                DSLS = {_attributes: {}, _key: nil,  
     | 
| 
      
 11 
     | 
    
         
            +
                DSLS = {_attributes: {}, _key: nil, _transform_key_function: nil, _transforming_root_key: false, _on_error: nil}.freeze
         
     | 
| 
       10 
12 
     | 
    
         
             
                private_constant :DSLS
         
     | 
| 
       11 
13 
     | 
    
         | 
| 
      
 14 
     | 
    
         
            +
                WITHIN_DEFAULT = Object.new.freeze
         
     | 
| 
      
 15 
     | 
    
         
            +
                private_constant :WITHIN_DEFAULT
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
       12 
17 
     | 
    
         
             
                # @private
         
     | 
| 
       13 
18 
     | 
    
         
             
                def self.included(base)
         
     | 
| 
       14 
19 
     | 
    
         
             
                  super
         
     | 
| 
         @@ -29,7 +34,7 @@ module Alba 
     | 
|
| 
       29 
34 
     | 
    
         
             
                  # @param object [Object] the object to be serialized
         
     | 
| 
       30 
35 
     | 
    
         
             
                  # @param params [Hash] user-given Hash for arbitrary data
         
     | 
| 
       31 
36 
     | 
    
         
             
                  # @param within [Hash] determines what associations to be serialized. If not set, it serializes all associations.
         
     | 
| 
       32 
     | 
    
         
            -
                  def initialize(object, params: {}, within:  
     | 
| 
      
 37 
     | 
    
         
            +
                  def initialize(object, params: {}, within: WITHIN_DEFAULT)
         
     | 
| 
       33 
38 
     | 
    
         
             
                    @object = object
         
     | 
| 
       34 
39 
     | 
    
         
             
                    @params = params.freeze
         
     | 
| 
       35 
40 
     | 
    
         
             
                    @within = within
         
     | 
| 
         @@ -60,21 +65,25 @@ module Alba 
     | 
|
| 
       60 
65 
     | 
    
         
             
                  def _key
         
     | 
| 
       61 
66 
     | 
    
         
             
                    return @_key.to_s unless @_key == true && Alba.inferring
         
     | 
| 
       62 
67 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
                     
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
      
 68 
     | 
    
         
            +
                    transforming_root_key? ? transform_key(key_from_resource_name) : key_from_resource_name
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  def key_from_resource_name
         
     | 
| 
      
 72 
     | 
    
         
            +
                    collection? ? resource_name.pluralize : resource_name
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  def resource_name
         
     | 
| 
      
 76 
     | 
    
         
            +
                    self.class.name.demodulize.delete_suffix('Resource').underscore
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                  def transforming_root_key?
         
     | 
| 
      
 80 
     | 
    
         
            +
                    @_transforming_root_key.nil? ? Alba.transforming_root_key : @_transforming_root_key
         
     | 
| 
       67 
81 
     | 
    
         
             
                  end
         
     | 
| 
       68 
82 
     | 
    
         | 
| 
       69 
83 
     | 
    
         
             
                  def converter
         
     | 
| 
       70 
84 
     | 
    
         
             
                    lambda do |object|
         
     | 
| 
       71 
85 
     | 
    
         
             
                      arrays = @_attributes.map do |key, attribute|
         
     | 
| 
       72 
     | 
    
         
            -
                        key  
     | 
| 
       73 
     | 
    
         
            -
                        if attribute.is_a?(Array) # Conditional
         
     | 
| 
       74 
     | 
    
         
            -
                          conditional_attribute(object, key, attribute)
         
     | 
| 
       75 
     | 
    
         
            -
                        else
         
     | 
| 
       76 
     | 
    
         
            -
                          [key, fetch_attribute(object, attribute)]
         
     | 
| 
       77 
     | 
    
         
            -
                        end
         
     | 
| 
      
 86 
     | 
    
         
            +
                        key_and_attribute_body_from(object, key, attribute)
         
     | 
| 
       78 
87 
     | 
    
         
             
                      rescue ::Alba::Error, FrozenError, TypeError
         
     | 
| 
       79 
88 
     | 
    
         
             
                        raise
         
     | 
| 
       80 
89 
     | 
    
         
             
                      rescue StandardError => e
         
     | 
| 
         @@ -84,10 +93,19 @@ module Alba 
     | 
|
| 
       84 
93 
     | 
    
         
             
                    end
         
     | 
| 
       85 
94 
     | 
    
         
             
                  end
         
     | 
| 
       86 
95 
     | 
    
         | 
| 
      
 96 
     | 
    
         
            +
                  def key_and_attribute_body_from(object, key, attribute)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    key = transform_key(key)
         
     | 
| 
      
 98 
     | 
    
         
            +
                    if attribute.is_a?(Array) # Conditional
         
     | 
| 
      
 99 
     | 
    
         
            +
                      conditional_attribute(object, key, attribute)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    else
         
     | 
| 
      
 101 
     | 
    
         
            +
                      [key, fetch_attribute(object, attribute)]
         
     | 
| 
      
 102 
     | 
    
         
            +
                    end
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
       87 
105 
     | 
    
         
             
                  def conditional_attribute(object, key, attribute)
         
     | 
| 
       88 
106 
     | 
    
         
             
                    condition = attribute.last
         
     | 
| 
       89 
107 
     | 
    
         
             
                    arity = condition.arity
         
     | 
| 
       90 
     | 
    
         
            -
                    return [] if arity <= 1 && ! 
     | 
| 
      
 108 
     | 
    
         
            +
                    return [] if arity <= 1 && !instance_exec(object, &condition)
         
     | 
| 
       91 
109 
     | 
    
         | 
| 
       92 
110 
     | 
    
         
             
                    fetched_attribute = fetch_attribute(object, attribute.first)
         
     | 
| 
       93 
111 
     | 
    
         
             
                    attr = if attribute.first.is_a?(Alba::Association)
         
     | 
| 
         @@ -95,7 +113,7 @@ module Alba 
     | 
|
| 
       95 
113 
     | 
    
         
             
                           else
         
     | 
| 
       96 
114 
     | 
    
         
             
                             fetched_attribute
         
     | 
| 
       97 
115 
     | 
    
         
             
                           end
         
     | 
| 
       98 
     | 
    
         
            -
                    return [] if arity >= 2 && ! 
     | 
| 
      
 116 
     | 
    
         
            +
                    return [] if arity >= 2 && !instance_exec(object, attr, &condition)
         
     | 
| 
       99 
117 
     | 
    
         | 
| 
       100 
118 
     | 
    
         
             
                    [key, fetched_attribute]
         
     | 
| 
       101 
119 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -118,10 +136,9 @@ module Alba 
     | 
|
| 
       118 
136 
     | 
    
         | 
| 
       119 
137 
     | 
    
         
             
                  # Override this method to supply custom key transform method
         
     | 
| 
       120 
138 
     | 
    
         
             
                  def transform_key(key)
         
     | 
| 
       121 
     | 
    
         
            -
                    return key  
     | 
| 
      
 139 
     | 
    
         
            +
                    return key if @_transform_key_function.nil?
         
     | 
| 
       122 
140 
     | 
    
         | 
| 
       123 
     | 
    
         
            -
                     
     | 
| 
       124 
     | 
    
         
            -
                    KeyTransformer.transform(key, @_transform_keys)
         
     | 
| 
      
 141 
     | 
    
         
            +
                    @_transform_key_function.call(key.to_s)
         
     | 
| 
       125 
142 
     | 
    
         
             
                  end
         
     | 
| 
       126 
143 
     | 
    
         | 
| 
       127 
144 
     | 
    
         
             
                  def fetch_attribute(object, attribute)
         
     | 
| 
         @@ -131,70 +148,28 @@ module Alba 
     | 
|
| 
       131 
148 
     | 
    
         
             
                    when Proc
         
     | 
| 
       132 
149 
     | 
    
         
             
                      instance_exec(object, &attribute)
         
     | 
| 
       133 
150 
     | 
    
         
             
                    when Alba::One, Alba::Many
         
     | 
| 
       134 
     | 
    
         
            -
                      within = check_within
         
     | 
| 
      
 151 
     | 
    
         
            +
                      within = check_within(attribute.name.to_sym)
         
     | 
| 
       135 
152 
     | 
    
         
             
                      return unless within
         
     | 
| 
       136 
153 
     | 
    
         | 
| 
       137 
154 
     | 
    
         
             
                      attribute.to_hash(object, params: params, within: within)
         
     | 
| 
       138 
     | 
    
         
            -
                    when  
     | 
| 
       139 
     | 
    
         
            -
                       
     | 
| 
      
 155 
     | 
    
         
            +
                    when TypedAttribute
         
     | 
| 
      
 156 
     | 
    
         
            +
                      attribute.value(object)
         
     | 
| 
       140 
157 
     | 
    
         
             
                    else
         
     | 
| 
       141 
158 
     | 
    
         
             
                      raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
         
     | 
| 
       142 
159 
     | 
    
         
             
                    end
         
     | 
| 
       143 
160 
     | 
    
         
             
                  end
         
     | 
| 
       144 
161 
     | 
    
         | 
| 
       145 
     | 
    
         
            -
                  def  
     | 
| 
       146 
     | 
    
         
            -
                    attr_name = hash[:attr_name]
         
     | 
| 
       147 
     | 
    
         
            -
                    type = hash[:type]
         
     | 
| 
       148 
     | 
    
         
            -
                    type_converter = hash[:type_converter]
         
     | 
| 
       149 
     | 
    
         
            -
                    value, result = type_check(object, attr_name, type)
         
     | 
| 
       150 
     | 
    
         
            -
                    return value if result
         
     | 
| 
       151 
     | 
    
         
            -
                    raise TypeError if !result && !type_converter
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
                    type_converter = type_converter_for(type) if type_converter == true
         
     | 
| 
       154 
     | 
    
         
            -
                    type_converter.call(value)
         
     | 
| 
       155 
     | 
    
         
            -
                  rescue TypeError
         
     | 
| 
       156 
     | 
    
         
            -
                    raise TypeError, "Attribute #{attr_name} is expected to be #{type} but actually #{value.nil? ? 'nil' : value.class.name}."
         
     | 
| 
       157 
     | 
    
         
            -
                  end
         
     | 
| 
       158 
     | 
    
         
            -
             
     | 
| 
       159 
     | 
    
         
            -
                  def type_check(object, attr_name, type)
         
     | 
| 
       160 
     | 
    
         
            -
                    value = object.public_send(attr_name)
         
     | 
| 
       161 
     | 
    
         
            -
                    type_correct = case type
         
     | 
| 
       162 
     | 
    
         
            -
                                   when :String, ->(klass) { klass == String }
         
     | 
| 
       163 
     | 
    
         
            -
                                     value.is_a?(String)
         
     | 
| 
       164 
     | 
    
         
            -
                                   when :Integer, ->(klass) { klass == Integer }
         
     | 
| 
       165 
     | 
    
         
            -
                                     value.is_a?(Integer)
         
     | 
| 
       166 
     | 
    
         
            -
                                   when :Boolean
         
     | 
| 
       167 
     | 
    
         
            -
                                     [true, false].include?(attr_name)
         
     | 
| 
       168 
     | 
    
         
            -
                                   else
         
     | 
| 
       169 
     | 
    
         
            -
                                     raise Alba::UnsupportedType, "Unknown type: #{type}"
         
     | 
| 
       170 
     | 
    
         
            -
                                   end
         
     | 
| 
       171 
     | 
    
         
            -
                    [value, type_correct]
         
     | 
| 
       172 
     | 
    
         
            -
                  end
         
     | 
| 
       173 
     | 
    
         
            -
             
     | 
| 
       174 
     | 
    
         
            -
                  def type_converter_for(type)
         
     | 
| 
       175 
     | 
    
         
            -
                    case type
         
     | 
| 
       176 
     | 
    
         
            -
                    when :String, ->(klass) { klass == String }
         
     | 
| 
       177 
     | 
    
         
            -
                      ->(object) { object.to_s }
         
     | 
| 
       178 
     | 
    
         
            -
                    when :Integer, ->(klass) { klass == Integer }
         
     | 
| 
       179 
     | 
    
         
            -
                      ->(object) { Integer(object) }
         
     | 
| 
       180 
     | 
    
         
            -
                    when :Boolean
         
     | 
| 
       181 
     | 
    
         
            -
                      ->(object) { !!object }
         
     | 
| 
       182 
     | 
    
         
            -
                    else
         
     | 
| 
       183 
     | 
    
         
            -
                      raise Alba::UnsupportedType, "Unknown type: #{type}"
         
     | 
| 
       184 
     | 
    
         
            -
                    end
         
     | 
| 
       185 
     | 
    
         
            -
                  end
         
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
                  def check_within
         
     | 
| 
      
 162 
     | 
    
         
            +
                  def check_within(association_name)
         
     | 
| 
       188 
163 
     | 
    
         
             
                    case @within
         
     | 
| 
      
 164 
     | 
    
         
            +
                    when WITHIN_DEFAULT # Default value, doesn't check within tree
         
     | 
| 
      
 165 
     | 
    
         
            +
                      WITHIN_DEFAULT
         
     | 
| 
       189 
166 
     | 
    
         
             
                    when Hash # Traverse within tree
         
     | 
| 
       190 
     | 
    
         
            -
                      @within.fetch( 
     | 
| 
      
 167 
     | 
    
         
            +
                      @within.fetch(association_name, nil)
         
     | 
| 
       191 
168 
     | 
    
         
             
                    when Array # within tree ends with Array
         
     | 
| 
       192 
     | 
    
         
            -
                      @within.find { |item| item.to_sym ==  
     | 
| 
      
 169 
     | 
    
         
            +
                      @within.find { |item| item.to_sym == association_name }
         
     | 
| 
       193 
170 
     | 
    
         
             
                    when Symbol # within tree could end with Symbol
         
     | 
| 
       194 
     | 
    
         
            -
                      @within ==  
     | 
| 
       195 
     | 
    
         
            -
                    when true # In  
     | 
| 
       196 
     | 
    
         
            -
                      true
         
     | 
| 
       197 
     | 
    
         
            -
                    when nil, false # In these cases, Alba stops serialization here.
         
     | 
| 
      
 171 
     | 
    
         
            +
                      @within == association_name
         
     | 
| 
      
 172 
     | 
    
         
            +
                    when nil, true, false # In these cases, Alba stops serialization here.
         
     | 
| 
       198 
173 
     | 
    
         
             
                      false
         
     | 
| 
       199 
174 
     | 
    
         
             
                    else
         
     | 
| 
       200 
175 
     | 
    
         
             
                      raise Alba::Error, "Unknown type for within option: #{@within.class}"
         
     | 
| 
         @@ -219,21 +194,32 @@ module Alba 
     | 
|
| 
       219 
194 
     | 
    
         
             
                  # Set multiple attributes at once
         
     | 
| 
       220 
195 
     | 
    
         
             
                  #
         
     | 
| 
       221 
196 
     | 
    
         
             
                  # @param attrs [Array<String, Symbol>]
         
     | 
| 
       222 
     | 
    
         
            -
                  # @param  
     | 
| 
      
 197 
     | 
    
         
            +
                  # @param if [Boolean] condition to decide if it should render these attributes
         
     | 
| 
      
 198 
     | 
    
         
            +
                  # @param attrs_with_types [Hash] attributes with name in its key and type and optional type converter in its value
         
     | 
| 
       223 
199 
     | 
    
         
             
                  def attributes(*attrs, if: nil, **attrs_with_types) # rubocop:disable Naming/MethodParameterName
         
     | 
| 
       224 
200 
     | 
    
         
             
                    if_value = binding.local_variable_get(:if)
         
     | 
| 
      
 201 
     | 
    
         
            +
                    assign_attributes(attrs, if_value)
         
     | 
| 
      
 202 
     | 
    
         
            +
                    assign_attributes_with_types(attrs_with_types, if_value)
         
     | 
| 
      
 203 
     | 
    
         
            +
                  end
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
                  def assign_attributes(attrs, if_value)
         
     | 
| 
       225 
206 
     | 
    
         
             
                    attrs.each do |attr_name|
         
     | 
| 
       226 
207 
     | 
    
         
             
                      attr = if_value ? [attr_name.to_sym, if_value] : attr_name.to_sym
         
     | 
| 
       227 
208 
     | 
    
         
             
                      @_attributes[attr_name.to_sym] = attr
         
     | 
| 
       228 
209 
     | 
    
         
             
                    end
         
     | 
| 
      
 210 
     | 
    
         
            +
                  end
         
     | 
| 
      
 211 
     | 
    
         
            +
                  private :assign_attributes
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                  def assign_attributes_with_types(attrs_with_types, if_value)
         
     | 
| 
       229 
214 
     | 
    
         
             
                    attrs_with_types.each do |attr_name, type_and_converter|
         
     | 
| 
       230 
215 
     | 
    
         
             
                      attr_name = attr_name.to_sym
         
     | 
| 
       231 
216 
     | 
    
         
             
                      type, type_converter = type_and_converter
         
     | 
| 
       232 
     | 
    
         
            -
                      typed_attr =  
     | 
| 
      
 217 
     | 
    
         
            +
                      typed_attr = TypedAttribute.new(name: attr_name, type: type, converter: type_converter)
         
     | 
| 
       233 
218 
     | 
    
         
             
                      attr = if_value ? [typed_attr, if_value] : typed_attr
         
     | 
| 
       234 
219 
     | 
    
         
             
                      @_attributes[attr_name] = attr
         
     | 
| 
       235 
220 
     | 
    
         
             
                    end
         
     | 
| 
       236 
221 
     | 
    
         
             
                  end
         
     | 
| 
      
 222 
     | 
    
         
            +
                  private :assign_attributes_with_types
         
     | 
| 
       237 
223 
     | 
    
         | 
| 
       238 
224 
     | 
    
         
             
                  # Set an attribute with the given block
         
     | 
| 
       239 
225 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -307,7 +293,7 @@ module Alba 
     | 
|
| 
       307 
293 
     | 
    
         
             
                  # @param type [String, Symbol]
         
     | 
| 
       308 
294 
     | 
    
         
             
                  # @param root [Boolean] decides if root key also should be transformed
         
     | 
| 
       309 
295 
     | 
    
         
             
                  def transform_keys(type, root: nil)
         
     | 
| 
       310 
     | 
    
         
            -
                    @ 
     | 
| 
      
 296 
     | 
    
         
            +
                    @_transform_key_function = KeyTransformFactory.create(type.to_sym)
         
     | 
| 
       311 
297 
     | 
    
         
             
                    @_transforming_root_key = root
         
     | 
| 
       312 
298 
     | 
    
         
             
                  end
         
     | 
| 
       313 
299 
     | 
    
         | 
| 
         @@ -0,0 +1,64 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Alba
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Representing typed attributes to encapsulate logic about types
         
     | 
| 
      
 3 
     | 
    
         
            +
              class TypedAttribute
         
     | 
| 
      
 4 
     | 
    
         
            +
                # @param name [Symbol, String]
         
     | 
| 
      
 5 
     | 
    
         
            +
                # @param type [Symbol, Class]
         
     | 
| 
      
 6 
     | 
    
         
            +
                # @param converter [Proc]
         
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(name:, type:, converter:)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @name = name
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @type = type
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @converter = case converter
         
     | 
| 
      
 11 
     | 
    
         
            +
                               when true then default_converter
         
     | 
| 
      
 12 
     | 
    
         
            +
                               when false, nil then null_converter
         
     | 
| 
      
 13 
     | 
    
         
            +
                               else converter
         
     | 
| 
      
 14 
     | 
    
         
            +
                               end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                # @param object [Object] target to check and convert type with
         
     | 
| 
      
 18 
     | 
    
         
            +
                # @return [String, Integer, Boolean] type-checked or type-converted object
         
     | 
| 
      
 19 
     | 
    
         
            +
                def value(object)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  value, result = check(object)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  result ? value : @converter.call(value)
         
     | 
| 
      
 22 
     | 
    
         
            +
                rescue TypeError
         
     | 
| 
      
 23 
     | 
    
         
            +
                  raise TypeError, "Attribute #{@name} is expected to be #{@type} but actually #{display_value_for(value)}."
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                private
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def check(object)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  value = object.public_send(@name)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  type_correct = case @type
         
     | 
| 
      
 31 
     | 
    
         
            +
                                 when :String, ->(klass) { klass == String }
         
     | 
| 
      
 32 
     | 
    
         
            +
                                   value.is_a?(String)
         
     | 
| 
      
 33 
     | 
    
         
            +
                                 when :Integer, ->(klass) { klass == Integer }
         
     | 
| 
      
 34 
     | 
    
         
            +
                                   value.is_a?(Integer)
         
     | 
| 
      
 35 
     | 
    
         
            +
                                 when :Boolean
         
     | 
| 
      
 36 
     | 
    
         
            +
                                   [true, false].include?(value)
         
     | 
| 
      
 37 
     | 
    
         
            +
                                 else
         
     | 
| 
      
 38 
     | 
    
         
            +
                                   raise Alba::UnsupportedType, "Unknown type: #{@type}"
         
     | 
| 
      
 39 
     | 
    
         
            +
                                 end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  [value, type_correct]
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def default_converter
         
     | 
| 
      
 44 
     | 
    
         
            +
                  case @type
         
     | 
| 
      
 45 
     | 
    
         
            +
                  when :String, ->(klass) { klass == String }
         
     | 
| 
      
 46 
     | 
    
         
            +
                    ->(object) { object.to_s }
         
     | 
| 
      
 47 
     | 
    
         
            +
                  when :Integer, ->(klass) { klass == Integer }
         
     | 
| 
      
 48 
     | 
    
         
            +
                    ->(object) { Integer(object) }
         
     | 
| 
      
 49 
     | 
    
         
            +
                  when :Boolean
         
     | 
| 
      
 50 
     | 
    
         
            +
                    ->(object) { !!object }
         
     | 
| 
      
 51 
     | 
    
         
            +
                  else
         
     | 
| 
      
 52 
     | 
    
         
            +
                    raise Alba::UnsupportedType, "Unknown type: #{@type}"
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def null_converter
         
     | 
| 
      
 57 
     | 
    
         
            +
                  ->(_) { raise TypeError }
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                def display_value_for(value)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  value.nil? ? 'nil' : value.class.name
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/alba/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,18 +1,17 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: alba
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.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: 2021-05- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2021-05-31 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies: []
         
     | 
| 
       13 
     | 
    
         
            -
            description: Alba is  
     | 
| 
       14 
     | 
    
         
            -
               
     | 
| 
       15 
     | 
    
         
            -
              do similar things. The internal is so simple that it's easy to hack and maintain.
         
     | 
| 
      
 13 
     | 
    
         
            +
            description: Alba is the fastest JSON serializer for Ruby. It focuses on performance,
         
     | 
| 
      
 14 
     | 
    
         
            +
              flexibility and usability.
         
     | 
| 
       16 
15 
     | 
    
         
             
            email:
         
     | 
| 
       17 
16 
     | 
    
         
             
            - masafumi.o1988@gmail.com
         
     | 
| 
       18 
17 
     | 
    
         
             
            executables: []
         
     | 
| 
         @@ -34,7 +33,8 @@ files: 
     | 
|
| 
       34 
33 
     | 
    
         
             
            - Rakefile
         
     | 
| 
       35 
34 
     | 
    
         
             
            - SECURITY.md
         
     | 
| 
       36 
35 
     | 
    
         
             
            - alba.gemspec
         
     | 
| 
       37 
     | 
    
         
            -
            - benchmark/ 
     | 
| 
      
 36 
     | 
    
         
            +
            - benchmark/collection.rb
         
     | 
| 
      
 37 
     | 
    
         
            +
            - benchmark/single_resource.rb
         
     | 
| 
       38 
38 
     | 
    
         
             
            - bin/console
         
     | 
| 
       39 
39 
     | 
    
         
             
            - bin/setup
         
     | 
| 
       40 
40 
     | 
    
         
             
            - codecov.yml
         
     | 
| 
         @@ -43,10 +43,12 @@ files: 
     | 
|
| 
       43 
43 
     | 
    
         
             
            - gemfiles/without_oj.gemfile
         
     | 
| 
       44 
44 
     | 
    
         
             
            - lib/alba.rb
         
     | 
| 
       45 
45 
     | 
    
         
             
            - lib/alba/association.rb
         
     | 
| 
       46 
     | 
    
         
            -
            - lib/alba/ 
     | 
| 
      
 46 
     | 
    
         
            +
            - lib/alba/default_inflector.rb
         
     | 
| 
      
 47 
     | 
    
         
            +
            - lib/alba/key_transform_factory.rb
         
     | 
| 
       47 
48 
     | 
    
         
             
            - lib/alba/many.rb
         
     | 
| 
       48 
49 
     | 
    
         
             
            - lib/alba/one.rb
         
     | 
| 
       49 
50 
     | 
    
         
             
            - lib/alba/resource.rb
         
     | 
| 
      
 51 
     | 
    
         
            +
            - lib/alba/typed_attribute.rb
         
     | 
| 
       50 
52 
     | 
    
         
             
            - lib/alba/version.rb
         
     | 
| 
       51 
53 
     | 
    
         
             
            - sider.yml
         
     | 
| 
       52 
54 
     | 
    
         
             
            homepage: https://github.com/okuramasafumi/alba
         
     | 
    
        data/lib/alba/key_transformer.rb
    DELETED
    
    | 
         @@ -1,32 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            module Alba
         
     | 
| 
       2 
     | 
    
         
            -
              # Transform keys using `ActiveSupport::Inflector`
         
     | 
| 
       3 
     | 
    
         
            -
              module KeyTransformer
         
     | 
| 
       4 
     | 
    
         
            -
                begin
         
     | 
| 
       5 
     | 
    
         
            -
                  require 'active_support/inflector'
         
     | 
| 
       6 
     | 
    
         
            -
                rescue LoadError
         
     | 
| 
       7 
     | 
    
         
            -
                  raise ::Alba::Error, 'To use transform_keys, please install `ActiveSupport` gem.'
         
     | 
| 
       8 
     | 
    
         
            -
                end
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
                module_function
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
                # Transform key as given transform_type
         
     | 
| 
       13 
     | 
    
         
            -
                #
         
     | 
| 
       14 
     | 
    
         
            -
                # @params key [String] key to be transformed
         
     | 
| 
       15 
     | 
    
         
            -
                # @params transform_type [Symbol] transform type
         
     | 
| 
       16 
     | 
    
         
            -
                # @return [String] transformed key
         
     | 
| 
       17 
     | 
    
         
            -
                # @raise [Alba::Error] when transform_type is not supported
         
     | 
| 
       18 
     | 
    
         
            -
                def transform(key, transform_type)
         
     | 
| 
       19 
     | 
    
         
            -
                  key = key.to_s
         
     | 
| 
       20 
     | 
    
         
            -
                  case transform_type
         
     | 
| 
       21 
     | 
    
         
            -
                  when :camel
         
     | 
| 
       22 
     | 
    
         
            -
                    ActiveSupport::Inflector.camelize(key)
         
     | 
| 
       23 
     | 
    
         
            -
                  when :lower_camel
         
     | 
| 
       24 
     | 
    
         
            -
                    ActiveSupport::Inflector.camelize(key, false)
         
     | 
| 
       25 
     | 
    
         
            -
                  when :dash
         
     | 
| 
       26 
     | 
    
         
            -
                    ActiveSupport::Inflector.dasherize(key)
         
     | 
| 
       27 
     | 
    
         
            -
                  else
         
     | 
| 
       28 
     | 
    
         
            -
                    raise ::Alba::Error, "Unknown transform_type: #{transform_type}. Supported transform_type are :camel, :lower_camel and :dash."
         
     | 
| 
       29 
     | 
    
         
            -
                  end
         
     | 
| 
       30 
     | 
    
         
            -
                end
         
     | 
| 
       31 
     | 
    
         
            -
              end
         
     | 
| 
       32 
     | 
    
         
            -
            end
         
     |