alba 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9018588ddacac0cf7db8dac1d23c8165665c7a93976b581d25ab51357ead7834
4
- data.tar.gz: 6bde71c65d8fb6965d46cea2769cd9a97d4f76407136e47de4392cdfa1a58333
3
+ metadata.gz: 86253dcf425b1a8bf489db53327a4f9a13c1ae046f87a5f558b75b9c1df18964
4
+ data.tar.gz: de8b3a29bd9b12f8cd6718a04f6140bec7611bedbf654232e9119f541d7f904e
5
5
  SHA512:
6
- metadata.gz: a7d907446dad8ff8a19814cbf27ba74bfc84a0f00fae8366f561efd5de03e1ac16d66f3b31641e8ec83b5081e6e5fc61074c5a5e47509343fade989ab65e41da
7
- data.tar.gz: d81e0055f6899698d70ab1522e71adc8ce9e22e3a8855ad2a3db8b54e551d2ea459a77bc92242bc5c7f8121d150c322f3b99f6d286fd7118f5df2f94d0dc3fdc
6
+ metadata.gz: dea93b6391ceaab7ec2759758d24df0eb14e8c59c52d8a174aeda79373afac23ca9f909a65aae3c2442106dd9d8dc700668eb6b791002ef0f9cf34833f53099a
7
+ data.tar.gz: 535c33bd2bea00d3029ab07a0848e37e8a30b8c6d66c3a1f894b51ad9b4aae30fc498dd000086c3e6a851c31069e6ab5d5ce11f8d96b4c687c26ae0174d42e54
data/CHANGELOG.md CHANGED
@@ -6,6 +6,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.1.0] 2022-12-03
10
+
11
+ ### Added
12
+
13
+ - Add `select` method for filtering attributes [#270](https://github.com/okuramasafumi/alba/pull/270)
14
+ - Allow ConditionalAttribute with 2-arity proc to reject nil attributes [#273](https://github.com/okuramasafumi/alba/pull/273)
15
+
16
+ ### Fixed
17
+
18
+ - Add support for proc resource in one polymorphic associations [#281](https://github.com/okuramasafumi/alba/pull/281)
19
+
20
+ ### Deprecated
21
+
22
+ - Deprecate `inference` related methods in favor of a unified `inflector` interface.
23
+ Deprecated methods are: `Alba.enable_inference!`, `Alba.disable_inference!`, and `Alba.inferring`.
24
+ Use `Alba.inflector = :active_support/:dry` or `Alba.inflector = SomeInflector` to enable.
25
+ Use `Alba.inflector = nil` to disable.
26
+ Use `Alba.inflector` to check if enabled.
27
+
9
28
  ## [2.0.1] 2022-11-02
10
29
 
11
30
  ### Fix
@@ -17,9 +36,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
17
36
 
18
37
  ### Breaking changes
19
38
 
20
- - All Hash-related methods now return String key instead of Symbol key
21
- This affects all users, but you can use `deep_symbolize_keys` in Rails environment if you prefer Symbol keys
22
- Some DSLs that take key argument such as `on_nil` and `on_error`, are also affected
39
+ - All Hash-related methods now return String keys instead of Symbol keys.
40
+ This affects all users, but you can use `deep_symbolize_keys` in Rails environment if you prefer Symbol keys, or `with_indifferent_access` to support both String and Symbol keys.
41
+ Some DSLs that take key argument such as `on_nil` and `on_error`, are also affected.
23
42
  - Remove deprecated methods: `Resource#to_hash`, `Resource.ignoring`, `Alba.on_nil`, `Alba.on_error`, `Alba.enable_root_key_transformation!` and `Alba.disable_root_key_transformation!`
24
43
  - If using `transform_keys`, the default inflector is no longer set by default [d02245c8](https://github.com/okuramasafumi/alba/commit/d02245c87e9df303cb20e354a81e5457ea460bdd#diff-ecd8c835d2390b8cb89e7ff75e599f0c15cdbe18c30981d6090f4a515566686f)
25
44
  To retain this functionality in Rails, add an initializer with the following:
data/Gemfile CHANGED
@@ -6,11 +6,10 @@ gemspec
6
6
  gem 'activesupport', require: false # For backend
7
7
  gem 'dry-inflector', require: false # For inflection
8
8
  gem 'ffaker', require: false # For testing
9
- gem 'inch', require: false # For inline documents
10
9
  gem 'minitest', '~> 5.14' # For test
11
10
  gem 'rake', '~> 13.0' # For test and automation
12
11
  gem 'rubocop', '>= 0.79.0', require: false # For lint
13
- gem 'rubocop-minitest', '~> 0.23.0', require: false # For lint
12
+ gem 'rubocop-minitest', '~> 0.24.0', require: false # For lint
14
13
  gem 'rubocop-performance', '~> 1.15.0', require: false # For lint
15
14
  gem 'rubocop-rake', '>= 0.5.1', require: false # For lint
16
15
  gem 'rubocop-sensible', '~> 0.3.0', require: false # For lint
data/README.md CHANGED
@@ -37,7 +37,7 @@ Alba is easy to use because there are only a few methods to remember. It's also
37
37
 
38
38
  ### Feature rich
39
39
 
40
- While Alba's core is simple, it provides additional features when you need them, For example, Alba provides [a way to control circular associations](#circular-associations-control), [inferring resource classes, root key and associations](#inference) and [supports layouts](#layout).
40
+ While Alba's core is simple, it provides additional features when you need them, For example, Alba provides [a way to control circular associations](#circular-associations-control), [root key and association resource name inference](#root-key-and-association-resource-name-inference) and [supports layouts](#layout).
41
41
 
42
42
  ## Installation
43
43
 
@@ -57,7 +57,7 @@ Or install it yourself as:
57
57
 
58
58
  ## Supported Ruby versions
59
59
 
60
- Alba supports CRuby 2.5 and higher and latest JRuby and TruffleRuby.
60
+ Alba supports CRuby 2.6 and higher and latest JRuby and TruffleRuby.
61
61
 
62
62
  ## Documentation
63
63
 
@@ -68,10 +68,9 @@ You can find the documentation on [RubyDoc](https://rubydoc.info/github/okuramas
68
68
  * Conditional attributes and associations
69
69
  * Selectable backend
70
70
  * Key transformation
71
- * Root key inference
71
+ * Root key and association resource name inference
72
72
  * Error handling
73
73
  * Nil handling
74
- * Resource name inflection based on association name
75
74
  * Circular associations control
76
75
  * [Experimental] Types for validation and conversion
77
76
  * Layout
@@ -113,19 +112,33 @@ You can consider setting a backend with Symbol as a shortcut to set encoder.
113
112
 
114
113
  #### Inference configuration
115
114
 
116
- You can enable inference feature using `enable_inference!` method.
115
+ You can enable the inference feature using the `Alba.inflector = SomeInflector` API. For example, in a Rails initializer:
117
116
 
118
117
  ```ruby
119
- Alba.enable_inference!(with: :active_support)
118
+ Alba.inflector = :active_support
120
119
  ```
121
120
 
122
- You can choose which inflector Alba uses for inference. Possible value for `with` option are:
121
+ You can choose which inflector Alba uses for inference. Possible options are:
123
122
 
124
123
  - `:active_support` for `ActiveSupport::Inflector`
125
124
  - `:dry` for `Dry::Inflector`
126
- - any object which responds to some methods (see [below](#custom-inflector))
125
+ - any object which conforms to the protocol (see [below](#custom-inflector))
127
126
 
128
- For the details, see [Error handling section](#error-handling)
127
+ To disable inference, set the `inflector` to `nil`:
128
+
129
+ ```ruby
130
+ Alba.inflector = nil
131
+ ```
132
+
133
+ To check if inference is enabled etc, inspect the return value of `inflector`:
134
+
135
+ ```ruby
136
+ if Alba.inflector == nil
137
+ puts "inflector not set"
138
+ else
139
+ puts "inflector is set to #{Alba.inflector}"
140
+ end
141
+ ```
129
142
 
130
143
  ### Simple serialization with root key
131
144
 
@@ -157,7 +170,7 @@ end
157
170
 
158
171
  user = User.new(1, 'Masafumi OKURA', 'masafumi@example.com')
159
172
  UserResource.new(user).serialize
160
- # => "{\"user\":{\"id\":1,\"name\":\"Masafumi OKURA\",\"name_with_email\":\"Masafumi OKURA: masafumi@example.com\"}}"
173
+ # => '{"user":{"id":1,"name":"Masafumi OKURA","name_with_email":"Masafumi OKURA: masafumi@example.com"}}'
161
174
  ```
162
175
 
163
176
  You can define instance methods on resources so that you can use it as attribute name in `attributes`.
@@ -184,7 +197,7 @@ This even works with users collection.
184
197
  user1 = User.new(1, 'Masafumi OKURA', 'masafumi@example.com')
185
198
  user2 = User.new(2, 'Test User', 'test@example.com')
186
199
  UserResource.new([user1, user2]).serialize
187
- # => "{\"users\":[{\"id\":1,\"name\":\"Masafumi OKURA\",\"name_with_email\":\"Masafumi OKURA: masafumi@example.com\"},{\"id\":2,\"name\":\"Test User\",\"name_with_email\":\"Test User: test@example.com\"}]}"
200
+ # => '{"users":[{"id":1,"name":"Masafumi OKURA","name_with_email":"Masafumi OKURA: masafumi@example.com"},{"id":2,"name":"Test User","name_with_email":"Test User: test@example.com"}]}'
188
201
  ```
189
202
 
190
203
  If you have a simple case where you want to change only the name, you can use the Symbol to Proc shortcut:
@@ -210,8 +223,8 @@ class UserResource
210
223
  end
211
224
 
212
225
  user = User.new(1, 'Masa', 'test@example.com')
213
- UserResource.new(user).serialize # => "{\"name\":\"foo\"}"
214
- UserResource.new(user, params: {upcase: true}).serialize # => "{\"name\":\"FOO\"}"
226
+ UserResource.new(user).serialize # => '{"name":"Masa"}'
227
+ UserResource.new(user, params: {upcase: true}).serialize # => '{"name":"MASA"}'
215
228
  ```
216
229
 
217
230
  ### Serialization with associations
@@ -368,9 +381,11 @@ UserResource.new(user).serialize
368
381
  # => '{"id":1,"my_articles":[{"title":"Hello World!"}]}'
369
382
  ```
370
383
 
371
- You can omit resource option if you enable Alba's inference feature.
384
+ You can omit the resource option if you enable Alba's [inference](#inference-configuration) feature.
372
385
 
373
386
  ```ruby
387
+ Alba.inflector = :active_support
388
+
374
389
  class UserResource
375
390
  include Alba::Resource
376
391
 
@@ -390,7 +405,7 @@ class UserResource
390
405
 
391
406
  attributes :id
392
407
 
393
- many :articles, ->(article) { article.with_comment? ? ArticleWithCommentResource : ArticleResource }
408
+ many :articles, resource: ->(article) { article.with_comment? ? ArticleWithCommentResource : ArticleResource }
394
409
  end
395
410
  ```
396
411
 
@@ -564,13 +579,19 @@ end
564
579
  Foo = Struct.new(:bar, :baz)
565
580
  foo = Foo.new(1, 2)
566
581
  FooResource.new(foo).serialize # => '{"foo":{"bar":1}}'
567
- ExtendedFooResource.new(foo).serialize # => '{"foo":{"bar":1,"baz":2}}'
582
+ ExtendedFooResource.new(foo).serialize # => '{"foofoo":{"bar":1,"baz":2}}'
568
583
  ```
569
584
 
570
585
  In this example we add `baz` attribute and change `root_key`. This way, you can extend existing resource classes just like normal OOP. Don't forget that when your inheritance structure is too deep it'll become difficult to modify existing classes.
571
586
 
572
587
  ### Filtering attributes
573
588
 
589
+ Filtering attributes can be done in two ways - with `attributes` and `select`. They have different semantics and usage.
590
+
591
+ `select` is a new and more intuitive API, so generally it's recommended to use `select`.
592
+
593
+ #### Filtering attributes with `attributes`
594
+
574
595
  You can filter out certain attributes by overriding `attributes` instance method. This is useful when you want to customize existing resource with inheritance.
575
596
 
576
597
  You can access raw attributes via `super` call. It returns a Hash whose keys are the name of the attribute and whose values are the body. Usually you need only keys to filter out, like below.
@@ -598,19 +619,52 @@ class RestrictedFooResource < GenericFooResource
598
619
  end
599
620
  end
600
621
 
622
+ foo = Foo.new(1, 'my foo', 'body')
623
+
601
624
  RestrictedFooResource.new(foo).serialize
602
625
  # => '{"name":"my foo"}'
603
626
  ```
604
627
 
605
- ### Key transformation
628
+ #### Filtering attributes with `select`
629
+
630
+ When you want to filter attributes based on more complex logic, you can use `select` instance method. `select` takes two parameters, the name of an attribute and the value of an attribute. If it returns false that attribute is rejected.
631
+
632
+ ```ruby
633
+ class Foo
634
+ attr_accessor :id, :name, :body
635
+
636
+ def initialize(id, name, body)
637
+ @id = id
638
+ @name = name
639
+ @body = body
640
+ end
641
+ end
642
+
643
+ class GenericFooResource
644
+ include Alba::Resource
645
+
646
+ attributes :id, :name, :body
647
+ end
648
+
649
+ class RestrictedFooResource < GenericFooResource
650
+ def select(_key, value)
651
+ !value.nil?
652
+ end
653
+ end
606
654
 
607
- 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:
608
- * install it
609
- * use a [custom inflector](#custom-inflector)
655
+ foo = Foo.new(1, nil, 'body')
610
656
 
611
- With `transform_keys` DSL, you can transform attribute keys.
657
+ RestrictedFooResource.new(foo).serialize
658
+ # => '{"id":1,"body":"body"}'
659
+ ```
660
+
661
+ ### Key transformation
662
+
663
+ If you have [inference](#inference-configuration) enabled, you can use the `transform_keys` DSL to transform attribute keys.
612
664
 
613
665
  ```ruby
666
+ Alba.inflector = :active_support
667
+
614
668
  class User
615
669
  attr_reader :id, :first_name, :last_name
616
670
 
@@ -646,12 +700,12 @@ Possible values for `transform_keys` argument are:
646
700
 
647
701
  You can also transform root key when:
648
702
 
649
- * `Alba.enable_inference!` is called
703
+ * `Alba.inflector` is set
650
704
  * `root_key!` is called in Resource class
651
705
  * `root` option of `transform_keys` is set to true
652
706
 
653
707
  ```ruby
654
- Alba.enable_inference!(with: :active_support) # with :dry also works
708
+ Alba.inflector = :active_support
655
709
 
656
710
  class BankAccount
657
711
  attr_reader :account_number
@@ -675,7 +729,9 @@ BankAccountResource.new(bank_account).serialize
675
729
  # => '{"bank-account":{"account-number":123456789}}'
676
730
  ```
677
731
 
678
- This behavior to transform root key will become default at version 2.
732
+ This is the default behavior from version 2.
733
+
734
+ Find more details in the [Inference configuration](#inference-configuration) section.
679
735
 
680
736
  #### Key transformation cascading
681
737
 
@@ -687,7 +743,7 @@ You can also turn it off by setting `cascade: false` option to `transform_keys`.
687
743
 
688
744
  ```ruby
689
745
  class User
690
- attr_reader :id, :first_name, :last_name
746
+ attr_reader :id, :first_name, :last_name, :bank_account
691
747
 
692
748
  def initialize(id, first_name, last_name)
693
749
  @id = id
@@ -746,7 +802,7 @@ module CustomInflector
746
802
  end
747
803
  end
748
804
 
749
- Alba.enable_inference!(with: CustomInflector)
805
+ Alba.inflector = CustomInflector
750
806
  ```
751
807
 
752
808
  ### Conditional attributes
@@ -757,7 +813,7 @@ In these cases, conditional attributes works well. We can pass `if` option to `a
757
813
 
758
814
  ```ruby
759
815
  class User
760
- attr_accessor :id, :name, :email, :created_at, :updated_at
816
+ attr_accessor :id, :name, :email
761
817
 
762
818
  def initialize(id, name, email)
763
819
  @id = id
@@ -790,12 +846,12 @@ end
790
846
 
791
847
  We believe this is clearer than using some (not implemented yet) DSL such as `default` because there are some conditions where default values should be applied (`nil`, `blank?`, `empty?` etc.)
792
848
 
793
- ### Inference
849
+ ### Root key and association resource name inference
794
850
 
795
- After `Alba.enable_inference!` called, Alba tries to infer root key and association resource name.
851
+ If [inference](#inference-configuration) is enabled, Alba tries to infer the root key and association resource names.
796
852
 
797
853
  ```ruby
798
- Alba.enable_inference!(with: :active_support) # with :dry also works
854
+ Alba.inflector = :active_support
799
855
 
800
856
  class User
801
857
  attr_reader :id
@@ -825,7 +881,7 @@ end
825
881
  class UserResource
826
882
  include Alba::Resource
827
883
 
828
- key!
884
+ root_key!
829
885
 
830
886
  attributes :id
831
887
 
@@ -843,6 +899,8 @@ This resource automatically sets its root key to either "users" or "user", depen
843
899
 
844
900
  Also, you don't have to specify which resource class to use with `many`. Alba infers it from association name.
845
901
 
902
+ Find more details in the [Inference configuration](#inference-configuration) section.
903
+
846
904
  ### Error handling
847
905
 
848
906
  You can set error handler globally or per resource using `on_error`.
@@ -934,7 +992,7 @@ class UserResource
934
992
  include Alba::Resource
935
993
 
936
994
  on_nil do |object, key|
937
- if key == age
995
+ if key == 'age'
938
996
  20
939
997
  else
940
998
  "User#{object.id}"
@@ -990,7 +1048,7 @@ class UserResourceWithoutMeta
990
1048
  attributes :id, :name
991
1049
  end
992
1050
 
993
- UserResource.new([user]).serialize(meta: {foo: :bar})
1051
+ UserResourceWithoutMeta.new([user]).serialize(meta: {foo: :bar})
994
1052
  # => '{"users":[{"id":1,"name":"Masafumi OKURA"}],"meta":{"foo":"bar"}}'
995
1053
  ```
996
1054
 
@@ -1,88 +1,7 @@
1
1
  # Benchmark script to run varieties of JSON serializers
2
2
  # Fetch Alba from local, otherwise fetch latest from RubyGems
3
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 "fast_serializer_ruby"
19
- gem "jbuilder"
20
- gem 'turbostreamer'
21
- gem "jserializer"
22
- gem "multi_json"
23
- gem "panko_serializer"
24
- gem "pg"
25
- gem "primalize"
26
- gem "oj"
27
- gem "representable"
28
- gem "simple_ams"
29
- gem "sqlite3"
30
- end
31
-
32
- # --- Test data model setup ---
33
-
34
- require "pg"
35
- require "active_record"
36
- require "active_record/connection_adapters/postgresql_adapter"
37
- require "logger"
38
- require "oj"
39
- require "sqlite3"
40
- Oj.optimize_rails
41
-
42
- ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
43
- # ActiveRecord::Base.logger = Logger.new($stdout)
44
-
45
- ActiveRecord::Schema.define do
46
- create_table :posts, force: true do |t|
47
- t.string :body
48
- end
49
-
50
- create_table :comments, force: true do |t|
51
- t.integer :post_id
52
- t.string :body
53
- t.integer :commenter_id
54
- end
55
-
56
- create_table :users, force: true do |t|
57
- t.string :name
58
- end
59
- end
60
-
61
- class Post < ActiveRecord::Base
62
- has_many :comments
63
- has_many :commenters, through: :comments, class_name: 'User', source: :commenter
64
-
65
- def attributes
66
- {id: nil, body: nil, commenter_names: commenter_names}
67
- end
68
-
69
- def commenter_names
70
- commenters.pluck(:name)
71
- end
72
- end
73
-
74
- class Comment < ActiveRecord::Base
75
- belongs_to :post
76
- belongs_to :commenter, class_name: 'User'
77
-
78
- def attributes
79
- {id: nil, body: nil}
80
- end
81
- end
82
-
83
- class User < ActiveRecord::Base
84
- has_many :comments
85
- end
4
+ require_relative 'prep'
86
5
 
87
6
  # --- Alba serializers ---
88
7
 
@@ -160,30 +79,6 @@ class FastSerializerPostResource
160
79
  has_many :comments, serializer: FastSerializerCommentResource
161
80
  end
162
81
 
163
- # --- JBuilder serializers ---
164
-
165
- require "jbuilder"
166
-
167
- class Post
168
- def to_builder
169
- Jbuilder.new do |post|
170
- post.call(self, :id, :body, :commenter_names, :comments)
171
- end
172
- end
173
-
174
- def commenter_names
175
- commenters.pluck(:name)
176
- end
177
- end
178
-
179
- class Comment
180
- def to_builder
181
- Jbuilder.new do |comment|
182
- comment.call(self, :id, :body)
183
- end
184
- end
185
- end
186
-
187
82
  # --- Jserializer serializers ---
188
83
 
189
84
  require 'jserializer'
@@ -220,31 +115,6 @@ class PankoPostSerializer < Panko::Serializer
220
115
  end
221
116
  end
222
117
 
223
- # --- Primalize serializers ---
224
- #
225
- class PrimalizeCommentResource < Primalize::Single
226
- attributes id: integer, body: string
227
- end
228
-
229
- class PrimalizePostResource < Primalize::Single
230
- alias post object
231
-
232
- attributes(
233
- id: integer,
234
- body: string,
235
- comments: array(primalize(PrimalizeCommentResource)),
236
- commenter_names: array(string),
237
- )
238
-
239
- def commenter_names
240
- post.commenters.pluck(:name)
241
- end
242
- end
243
-
244
- class PrimalizePostsResource < Primalize::Many
245
- attributes posts: enumerable(PrimalizePostResource)
246
- end
247
-
248
118
  # --- Representable serializers ---
249
119
 
250
120
  require "representable"
@@ -349,13 +219,6 @@ end
349
219
  ams = Proc.new { ActiveModelSerializers::SerializableResource.new(posts, {each_serializer: AMSPostSerializer}).to_json }
350
220
  blueprinter = Proc.new { PostBlueprint.render(posts) }
351
221
  fast_serializer = Proc.new { FastSerializerPostResource.new(posts).to_json }
352
- jbuilder = Proc.new do
353
- Jbuilder.new do |json|
354
- json.array!(posts) do |post|
355
- json.post post.to_builder
356
- end
357
- end.target!
358
- end
359
222
  jserializer = Proc.new { JserializerPostSerializer.new(posts, is_collection: true).to_json }
360
223
  panko = proc { Panko::ArraySerializer.new(posts, each_serializer: PankoPostSerializer).to_json }
361
224
  primalize = proc { PrimalizePostsResource.new(posts: posts).to_json }
@@ -368,22 +231,25 @@ turbostreamer = Proc.new { TurbostreamerSerializer.new(posts).to_json }
368
231
 
369
232
  # --- Execute the serializers to check their output ---
370
233
  GC.disable
371
- puts "Serializer outputs ----------------------------------"
234
+ puts "Checking outputs..."
235
+ correct = alba.call
236
+ parsed_correct = JSON.parse(correct)
372
237
  {
373
- alba: alba,
374
238
  alba_inline: alba_inline,
375
239
  ams: ams,
376
240
  blueprinter: blueprinter,
377
241
  fast_serializer: fast_serializer,
378
- jbuilder: jbuilder, # different order
379
242
  jserializer: jserializer,
380
243
  panko: panko,
381
- primalize: primalize,
382
244
  rails: rails,
383
245
  representable: representable,
384
246
  simple_ams: simple_ams,
385
247
  turbostreamer: turbostreamer
386
- }.each { |name, serializer| puts "#{name.to_s.ljust(24, ' ')} #{serializer.call}" }
248
+ }.each do |name, serializer|
249
+ result = serializer.call
250
+ parsed_result = JSON.parse(result)
251
+ puts "#{name} yields wrong output: #{parsed_result}" unless parsed_result == parsed_correct
252
+ end
387
253
 
388
254
  # --- Run the benchmarks ---
389
255
 
@@ -394,10 +260,8 @@ Benchmark.ips do |x|
394
260
  x.report(:ams, &ams)
395
261
  x.report(:blueprinter, &blueprinter)
396
262
  x.report(:fast_serializer, &fast_serializer)
397
- x.report(:jbuilder, &jbuilder)
398
263
  x.report(:jserializer, &jserializer)
399
264
  x.report(:panko, &panko)
400
- x.report(:primalize, &primalize)
401
265
  x.report(:rails, &rails)
402
266
  x.report(:representable, &representable)
403
267
  x.report(:simple_ams, &simple_ams)
@@ -414,10 +278,8 @@ Benchmark.memory do |x|
414
278
  x.report(:ams, &ams)
415
279
  x.report(:blueprinter, &blueprinter)
416
280
  x.report(:fast_serializer, &fast_serializer)
417
- x.report(:jbuilder, &jbuilder)
418
281
  x.report(:jserializer, &jserializer)
419
282
  x.report(:panko, &panko)
420
- x.report(:primalize, &primalize)
421
283
  x.report(:rails, &rails)
422
284
  x.report(:representable, &representable)
423
285
  x.report(:simple_ams, &simple_ams)
data/benchmark/prep.rb ADDED
@@ -0,0 +1,82 @@
1
+ # --- Bundle dependencies ---
2
+
3
+ require "bundler/inline"
4
+
5
+ gemfile(true) do
6
+ source "https://rubygems.org"
7
+ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
8
+
9
+ gem "active_model_serializers"
10
+ gem "activerecord", "6.1.3"
11
+ gem "alba", path: '../'
12
+ gem "benchmark-ips"
13
+ gem "benchmark-memory"
14
+ gem "blueprinter"
15
+ gem "fast_serializer_ruby"
16
+ gem "jbuilder"
17
+ gem 'turbostreamer'
18
+ gem "jserializer"
19
+ gem "multi_json"
20
+ gem "panko_serializer"
21
+ gem "pg"
22
+ gem "primalize"
23
+ gem "oj"
24
+ gem "representable"
25
+ gem "simple_ams"
26
+ gem "sqlite3"
27
+ end
28
+
29
+ # --- Test data model setup ---
30
+
31
+ require "pg"
32
+ require "active_record"
33
+ require "active_record/connection_adapters/postgresql_adapter"
34
+ require "logger"
35
+ require "oj"
36
+ require "sqlite3"
37
+ Oj.optimize_rails unless ENV['NO_OJ_OPTIMIZE_RAILS']
38
+
39
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
40
+ # ActiveRecord::Base.logger = Logger.new($stdout)
41
+
42
+ ActiveRecord::Schema.define do
43
+ create_table :posts, force: true do |t|
44
+ t.string :body
45
+ end
46
+
47
+ create_table :comments, force: true do |t|
48
+ t.integer :post_id
49
+ t.string :body
50
+ t.integer :commenter_id
51
+ end
52
+
53
+ create_table :users, force: true do |t|
54
+ t.string :name
55
+ end
56
+ end
57
+
58
+ class Post < ActiveRecord::Base
59
+ has_many :comments
60
+ has_many :commenters, through: :comments, class_name: 'User', source: :commenter
61
+
62
+ def attributes
63
+ {id: nil, body: nil, commenter_names: commenter_names}
64
+ end
65
+
66
+ def commenter_names
67
+ commenters.pluck(:name)
68
+ end
69
+ end
70
+
71
+ class Comment < ActiveRecord::Base
72
+ belongs_to :post
73
+ belongs_to :commenter, class_name: 'User'
74
+
75
+ def attributes
76
+ {id: nil, body: nil}
77
+ end
78
+ end
79
+
80
+ class User < ActiveRecord::Base
81
+ has_many :comments
82
+ end
@@ -1,88 +1,7 @@
1
1
  # Benchmark script to run varieties of JSON serializers
2
2
  # Fetch Alba from local, otherwise fetch latest from RubyGems
3
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 'turbostreamer'
20
- gem "jserializer"
21
- gem "jsonapi-serializer" # successor of fast_jsonapi
22
- gem "multi_json"
23
- gem "panko_serializer"
24
- gem "pg"
25
- gem "primalize"
26
- gem "oj"
27
- gem "representable"
28
- gem "simple_ams"
29
- gem "sqlite3"
30
- end
31
-
32
- # --- Test data model setup ---
33
-
34
- require "pg"
35
- require "active_record"
36
- require "active_record/connection_adapters/postgresql_adapter"
37
- require "logger"
38
- require "oj"
39
- require "sqlite3"
40
- Oj.optimize_rails
41
-
42
- ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
43
- # ActiveRecord::Base.logger = Logger.new($stdout)
44
-
45
- ActiveRecord::Schema.define do
46
- create_table :posts, force: true do |t|
47
- t.string :body
48
- end
49
-
50
- create_table :comments, force: true do |t|
51
- t.integer :post_id
52
- t.string :body
53
- t.integer :commenter_id
54
- end
55
-
56
- create_table :users, force: true do |t|
57
- t.string :name
58
- end
59
- end
60
-
61
- class Post < ActiveRecord::Base
62
- has_many :comments
63
- has_many :commenters, through: :comments, class_name: 'User', source: :commenter
64
-
65
- def attributes
66
- {id: nil, body: nil, commenter_names: commenter_names}
67
- end
68
-
69
- def commenter_names
70
- commenters.pluck(:name)
71
- end
72
- end
73
-
74
- class Comment < ActiveRecord::Base
75
- belongs_to :post
76
- belongs_to :commenter, class_name: 'User'
77
-
78
- def attributes
79
- {id: nil, body: nil}
80
- end
81
- end
82
-
83
- class User < ActiveRecord::Base
84
- has_many :comments
85
- end
4
+ require_relative 'prep'
86
5
 
87
6
  # --- Alba serializers ---
88
7
 
@@ -177,70 +96,8 @@ class JserializerPostSerializer < Jserializer::Base
177
96
  end
178
97
  end
179
98
 
180
-
181
- # --- JSONAPI:Serializer serializers / (successor of fast_jsonapi) ---
182
-
183
- class JsonApiStandardCommentSerializer
184
- include JSONAPI::Serializer
185
-
186
- attribute :id
187
- attribute :body
188
- end
189
-
190
- class JsonApiStandardPostSerializer
191
- include JSONAPI::Serializer
192
-
193
- # set_type :post # optional
194
- attribute :id
195
- attribute :body
196
- attribute :commenter_names
197
-
198
- attribute :comments do |post|
199
- post.comments.map { |comment| JsonApiSameFormatCommentSerializer.new(comment) }
200
- end
201
- end
202
-
203
- # --- JSONAPI:Serializer serializers that format the code the same flat way as the other gems here ---
204
-
205
- # code to convert from JSON:API output to "flat" JSON, like the other serializers build
206
- class JsonApiSameFormatSerializer
207
- include JSONAPI::Serializer
208
-
209
- def as_json(*_options)
210
- hash = serializable_hash
211
-
212
- if hash[:data].is_a? Hash
213
- hash[:data][:attributes]
214
-
215
- elsif hash[:data].is_a? Array
216
- hash[:data].pluck(:attributes)
217
-
218
- elsif hash[:data].nil?
219
- { }
220
-
221
- else
222
- raise "unexpected data type #{hash[:data].class}"
223
- end
224
- end
225
- end
226
-
227
- class JsonApiSameFormatCommentSerializer < JsonApiSameFormatSerializer
228
- attribute :id
229
- attribute :body
230
- end
231
-
232
- class JsonApiSameFormatPostSerializer < JsonApiSameFormatSerializer
233
- attribute :id
234
- attribute :body
235
- attribute :commenter_names
236
-
237
- attribute :comments do |post|
238
- post.comments.map { |comment| JsonApiSameFormatCommentSerializer.new(comment) }
239
- end
240
- end
241
-
242
99
  # --- Panko serializers ---
243
- #
100
+
244
101
  require "panko_serializer"
245
102
 
246
103
  class PankoCommentSerializer < Panko::Serializer
@@ -259,7 +116,7 @@ class PankoPostSerializer < Panko::Serializer
259
116
  end
260
117
 
261
118
  # --- Primalize serializers ---
262
- #
119
+
263
120
  class PrimalizeCommentResource < Primalize::Single
264
121
  attributes id: integer, body: string
265
122
  end
@@ -376,8 +233,6 @@ ams = Proc.new { AMSPostSerializer.new(post, {}).to_json }
376
233
  blueprinter = Proc.new { PostBlueprint.render(post) }
377
234
  jbuilder = Proc.new { post.to_builder.target! }
378
235
  jserializer = Proc.new { JserializerPostSerializer.new(post).to_json }
379
- jsonapi = proc { JsonApiStandardPostSerializer.new(post).to_json }
380
- jsonapi_same_format = proc { JsonApiSameFormatPostSerializer.new(post).to_json }
381
236
  panko = proc { PankoPostSerializer.new.serialize_to_json(post) }
382
237
  primalize = proc { PrimalizePostResource.new(post).to_json }
383
238
  rails = Proc.new { ActiveSupport::JSON.encode(post.serializable_hash(include: :comments)) }
@@ -395,8 +250,6 @@ puts "Serializer outputs ----------------------------------"
395
250
  blueprinter: blueprinter,
396
251
  jbuilder: jbuilder, # different order
397
252
  jserializer: jserializer,
398
- jsonapi: jsonapi, # nested JSON:API format
399
- jsonapi_same_format: jsonapi_same_format,
400
253
  panko: panko,
401
254
  primalize: primalize,
402
255
  rails: rails,
@@ -417,8 +270,6 @@ Benchmark.ips do |x|
417
270
  x.report(:blueprinter, &blueprinter)
418
271
  x.report(:jbuilder, &jbuilder)
419
272
  x.report(:jserializer, &jserializer)
420
- x.report(:jsonapi, &jsonapi)
421
- x.report(:jsonapi_same_format, &jsonapi_same_format)
422
273
  x.report(:panko, &panko)
423
274
  x.report(:primalize, &primalize)
424
275
  x.report(:rails, &rails)
@@ -438,8 +289,6 @@ Benchmark.memory do |x|
438
289
  x.report(:blueprinter, &blueprinter)
439
290
  x.report(:jbuilder, &jbuilder)
440
291
  x.report(:jserializer, &jserializer)
441
- x.report(:jsonapi, &jsonapi)
442
- x.report(:jsonapi_same_format, &jsonapi_same_format)
443
292
  x.report(:panko, &panko)
444
293
  x.report(:primalize, &primalize)
445
294
  x.report(:rails, &rails)
@@ -12,7 +12,7 @@ This guide is aimed at helping ActiveModelSerializers users transition to Alba,
12
12
 
13
13
  ## Example class
14
14
 
15
- Example clsss is inherited `ActiveRecord::Base`, because [serializing PORO with AMS is pretty hard](https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/howto/serialize_poro.md).
15
+ Example class is inherited `ActiveRecord::Base`, because [serializing PORO with AMS is pretty hard](https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/howto/serialize_poro.md).
16
16
 
17
17
  ```rb
18
18
  class User < ActiveRecord::Base
@@ -175,7 +175,7 @@ class UserSerializer < ActiveModel::Serializer
175
175
  has_many :articles, serializer: ArticleSerializer # For has_many relation
176
176
  end
177
177
  user = User.create!
178
- user.craete_profile! email: email
178
+ user.create_profile! email: email
179
179
  user.articles.create! title: title, body: body
180
180
  ActiveModelSerializers::SerializableResource.new(
181
181
  user
data/docs/rails.md CHANGED
@@ -14,7 +14,7 @@ You might want to add some configurations to initializer file such as `alba.rb`
14
14
  ```ruby
15
15
  # alba.rb
16
16
  Alba.backend = :active_support
17
- Alba.enable_inference!(:active_support)
17
+ Alba.enable_inference!(with: :active_support)
18
18
  ```
19
19
 
20
20
  You can also use `:oj_rails` for backend if you prefer using Oj.
@@ -37,8 +37,10 @@ module Alba
37
37
  @object = @condition.call(object, params, target) if @condition
38
38
  return if @object.nil?
39
39
 
40
- if @resource.is_a?(Proc) && @object.is_a?(Enumerable)
41
- to_h_with_each_resource(within, params)
40
+ if @resource.is_a?(Proc)
41
+ return to_h_with_each_resource(within, params) if @object.is_a?(Enumerable)
42
+
43
+ @resource.call(@object).new(@object, within: within, params: params).to_h
42
44
  else
43
45
  to_h_with_constantize_resource(within, params)
44
46
  end
@@ -63,10 +65,10 @@ module Alba
63
65
  klass.transform_keys(key_transformation)
64
66
  klass.class_eval(&block)
65
67
  klass
66
- elsif Alba.inferring
68
+ elsif Alba.inflector
67
69
  Alba.infer_resource_class(@name, nesting: nesting)
68
70
  else
69
- raise ArgumentError, 'When Alba.inferring is false, either resource or block is required'
71
+ raise ArgumentError, 'When Alba.inflector is nil, either resource or block is required'
70
72
  end
71
73
  end
72
74
 
@@ -20,7 +20,7 @@ module Alba
20
20
  return Alba::REMOVE_KEY unless condition_passes?(resource, object)
21
21
 
22
22
  fetched_attribute = yield(@body)
23
- return fetched_attribute if fetched_attribute.nil? || !with_two_arity_proc_condition
23
+ return fetched_attribute if !with_two_arity_proc_condition
24
24
 
25
25
  return Alba::REMOVE_KEY unless resource.instance_exec(object, attribute_from_association_body_or(fetched_attribute), &@condition)
26
26
 
data/lib/alba/resource.rb CHANGED
@@ -41,7 +41,6 @@ module Alba
41
41
  @object = object
42
42
  @params = params
43
43
  @within = within
44
- @method_existence = {} # Cache for `respond_to?` result
45
44
  DSLS.each_key { |name| instance_variable_set("@#{name}", self.class.__send__(name)) }
46
45
  end
47
46
 
@@ -149,7 +148,7 @@ module Alba
149
148
  end
150
149
 
151
150
  def _key_for_collection
152
- if Alba.inferring
151
+ if Alba.inflector
153
152
  @_key_for_collection == true ? resource_name(pluralized: true) : @_key_for_collection.to_s
154
153
  else
155
154
  @_key_for_collection == true ? raise_root_key_inference_error : @_key_for_collection.to_s
@@ -158,7 +157,7 @@ module Alba
158
157
 
159
158
  # @return [String]
160
159
  def _key
161
- if Alba.inferring
160
+ if Alba.inflector
162
161
  @_key == true ? resource_name(pluralized: false) : @_key.to_s
163
162
  else
164
163
  @_key == true ? raise_root_key_inference_error : @_key.to_s
@@ -174,7 +173,7 @@ module Alba
174
173
  end
175
174
 
176
175
  def raise_root_key_inference_error
177
- raise Alba::Error, 'You must call Alba.enable_inference! to set root_key to true for inferring root key.'
176
+ raise Alba::Error, 'You must set inflector when setting root key as true.'
178
177
  end
179
178
 
180
179
  def transforming_root_key?
@@ -182,27 +181,27 @@ module Alba
182
181
  end
183
182
 
184
183
  def converter
185
- lambda do |object|
186
- attributes_to_hash(object, {})
184
+ lambda do |obj|
185
+ attributes_to_hash(obj, {})
187
186
  end
188
187
  end
189
188
 
190
189
  def collection_converter
191
- lambda do |object, a|
190
+ lambda do |obj, a|
192
191
  a << {}
193
192
  h = a.last
194
- attributes_to_hash(object, h)
193
+ attributes_to_hash(obj, h)
195
194
  a
196
195
  end
197
196
  end
198
197
 
199
- def attributes_to_hash(object, hash)
198
+ def attributes_to_hash(obj, hash)
200
199
  attributes.each do |key, attribute|
201
- set_key_and_attribute_body_from(object, key, attribute, hash)
200
+ set_key_and_attribute_body_from(obj, key, attribute, hash)
202
201
  rescue ::Alba::Error, FrozenError, TypeError
203
202
  raise
204
203
  rescue StandardError => e
205
- handle_error(e, object, key, attribute, hash)
204
+ handle_error(e, obj, key, attribute, hash)
206
205
  end
207
206
  hash
208
207
  end
@@ -213,20 +212,28 @@ module Alba
213
212
  @_attributes
214
213
  end
215
214
 
216
- def set_key_and_attribute_body_from(object, key, attribute, hash)
215
+ # Default implementation for selecting attributes
216
+ # Override this method to filter attributes based on key and value
217
+ def select(_key, _value)
218
+ true
219
+ end
220
+
221
+ def set_key_and_attribute_body_from(obj, key, attribute, hash)
217
222
  key = transform_key(key)
218
- value = fetch_attribute(object, key, attribute)
223
+ value = fetch_attribute(obj, key, attribute)
224
+ return unless select(key, value)
225
+
219
226
  hash[key] = value unless value == Alba::REMOVE_KEY
220
227
  end
221
228
 
222
- def handle_error(error, object, key, attribute, hash)
229
+ def handle_error(error, obj, key, attribute, hash)
223
230
  on_error = @_on_error || :raise
224
231
  case on_error # rubocop:disable Style/MissingElse
225
232
  when :raise, nil then raise(error)
226
233
  when :nullify then hash[key] = nil
227
234
  when :ignore then nil
228
235
  when Proc
229
- key, value = on_error.call(error, object, key, attribute, self.class)
236
+ key, value = on_error.call(error, obj, key, attribute, self.class)
230
237
  hash[key] = value
231
238
  end
232
239
  end
@@ -237,7 +244,7 @@ module Alba
237
244
  return key if @_transform_type == :none || key.empty? # We can skip transformation
238
245
 
239
246
  inflector = Alba.inflector
240
- raise Alba::Error, 'Inflector is nil. You can set inflector with `Alba.enable_inference!(with: :active_support)` for example.' unless inflector
247
+ raise Alba::Error, 'Inflector is nil. You must set inflector before transforming keys.' unless inflector
241
248
 
242
249
  case @_transform_type # rubocop:disable Style/MissingElse
243
250
  when :camel then inflector.camelize(key)
@@ -247,23 +254,23 @@ module Alba
247
254
  end
248
255
  end
249
256
 
250
- def fetch_attribute(object, key, attribute) # rubocop:disable Metrics/CyclomaticComplexity
257
+ def fetch_attribute(obj, key, attribute) # rubocop:disable Metrics/CyclomaticComplexity
251
258
  value = case attribute
252
- when Symbol then fetch_attribute_from_object_and_resource(object, attribute)
253
- when Proc then instance_exec(object, &attribute)
254
- when Alba::Association then yield_if_within(attribute.name.to_sym) { |within| attribute.to_h(object, params: params, within: within) }
255
- when TypedAttribute, NestedAttribute then attribute.value(object)
256
- when ConditionalAttribute then attribute.with_passing_condition(resource: self, object: object) { |attr| fetch_attribute(object, key, attr) }
259
+ when Symbol then fetch_attribute_from_object_and_resource(obj, attribute)
260
+ when Proc then instance_exec(obj, &attribute)
261
+ when Alba::Association then yield_if_within(attribute.name.to_sym) { |within| attribute.to_h(obj, params: params, within: within) }
262
+ when TypedAttribute, NestedAttribute then attribute.value(obj)
263
+ when ConditionalAttribute then attribute.with_passing_condition(resource: self, object: obj) { |attr| fetch_attribute(obj, key, attr) }
257
264
  else
258
265
  raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
259
266
  end
260
- value.nil? && nil_handler ? instance_exec(object, key, attribute, &nil_handler) : value
267
+ value.nil? && nil_handler ? instance_exec(obj, key, attribute, &nil_handler) : value
261
268
  end
262
269
 
263
- def fetch_attribute_from_object_and_resource(object, attribute)
264
- has_method = @method_existence[attribute]
265
- has_method = @method_existence[attribute] = object.respond_to?(attribute) if has_method.nil?
266
- has_method ? object.__send__(attribute) : __send__(attribute, object)
270
+ def fetch_attribute_from_object_and_resource(obj, attribute)
271
+ obj.__send__(attribute)
272
+ rescue NoMethodError
273
+ __send__(attribute, obj)
267
274
  end
268
275
 
269
276
  def nil_handler
@@ -313,7 +320,7 @@ module Alba
313
320
  # @param attrs_with_types [Hash<[Symbol, String], [Array<Symbol, Proc>, Symbol]>]
314
321
  # attributes with name in its key and type and optional type converter in its value
315
322
  # @return [void]
316
- def attributes(*attrs, if: nil, **attrs_with_types) # rubocop:disable Naming/MethodParameterName
323
+ def attributes(*attrs, if: nil, **attrs_with_types)
317
324
  if_value = binding.local_variable_get(:if)
318
325
  assign_attributes(attrs, if_value)
319
326
  assign_attributes_with_types(attrs_with_types, if_value)
data/lib/alba/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Alba
2
- VERSION = '2.0.1'.freeze
2
+ VERSION = '2.1.0'.freeze
3
3
  end
data/lib/alba.rb CHANGED
@@ -7,10 +7,10 @@ require_relative 'alba/deprecation'
7
7
  # Core module
8
8
  module Alba
9
9
  class << self
10
- attr_reader :backend, :encoder, :inferring
10
+ attr_reader :backend, :encoder
11
11
 
12
- # Accessor for inflector, a module responsible for inflecting strings
13
- attr_accessor :inflector
12
+ # Getter for inflector, a module responsible for inflecting strings
13
+ attr_reader :inflector
14
14
 
15
15
  # Set the backend, which actually serializes object into JSON
16
16
  #
@@ -54,14 +54,36 @@ module Alba
54
54
  # @param with [Symbol, Class, Module] inflector
55
55
  # When it's a Symbol, it sets inflector with given name
56
56
  # When it's a Class or a Module, it sets given object to inflector
57
+ # @deprecated Use {#inflector=} instead
57
58
  def enable_inference!(with:)
59
+ Alba::Deprecation.warn('Alba.enable_inference! is deprecated. Use `Alba.inflector=` instead.')
58
60
  @inflector = inflector_from(with)
59
61
  @inferring = true
60
62
  end
61
63
 
62
64
  # Disable inference for key and resource name
65
+ #
66
+ # @deprecated Use {#inflector=} instead
63
67
  def disable_inference!
68
+ Alba::Deprecation.warn('Alba.disable_inference! is deprecated. Use `Alba.inflector = nil` instead.')
64
69
  @inferring = false
70
+ @inflector = nil
71
+ end
72
+
73
+ # @deprecated Use {#inflector} instead
74
+ # @return [Boolean] whether inference is enabled or not
75
+ def inferring
76
+ Alba::Deprecation.warn('Alba.inferring is deprecated. Use `Alba.inflector` instead.')
77
+ @inferring
78
+ end
79
+
80
+ # Set an inflector
81
+ #
82
+ # @param inflector [Symbol, Class, Module] inflector
83
+ # When it's a Symbol, it accepts `:default`, `:active_support` or `:dry`
84
+ # When it's a Class or a Module, it should have some methods, see {Alba::DefaultInflector}
85
+ def inflector=(inflector)
86
+ @inflector = inflector_from(inflector)
65
87
  end
66
88
 
67
89
  # @param block [Block] resource body
@@ -77,7 +99,7 @@ module Alba
77
99
  # @param nesting [String, nil] namespace Alba tries to find resource class in
78
100
  # @return [Class<Alba::Resource>] resource class
79
101
  def infer_resource_class(name, nesting: nil)
80
- raise Alba::Error, 'Inference is disabled so Alba cannot infer resource name. Use `Alba.enable_inference!` before use.' unless Alba.inferring
102
+ raise Alba::Error, 'Inference is disabled so Alba cannot infer resource name. Set inflector before use.' unless Alba.inflector
81
103
 
82
104
  const_parent = nesting.nil? ? Object : Object.const_get(nesting)
83
105
  const_parent.const_get("#{inflector.classify(name)}Resource")
@@ -95,6 +117,7 @@ module Alba
95
117
 
96
118
  def inflector_from(name_or_module)
97
119
  case name_or_module
120
+ when nil then nil
98
121
  when :default, :active_support
99
122
  require_relative 'alba/default_inflector'
100
123
  Alba::DefaultInflector
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alba
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.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: 2022-11-02 00:00:00.000000000 Z
11
+ date: 2022-12-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Alba is the fastest JSON serializer for Ruby. It focuses on performance,
14
14
  flexibility and usability.
@@ -40,6 +40,7 @@ files:
40
40
  - alba.gemspec
41
41
  - benchmark/README.md
42
42
  - benchmark/collection.rb
43
+ - benchmark/prep.rb
43
44
  - benchmark/single_resource.rb
44
45
  - bin/console
45
46
  - bin/setup