alba 2.0.1 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -1
- data/.rubocop.yml +6 -1
- data/CHANGELOG.md +36 -3
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +3 -3
- data/README.md +102 -34
- data/alba.gemspec +1 -1
- data/benchmark/collection.rb +9 -147
- data/benchmark/prep.rb +82 -0
- data/benchmark/single_resource.rb +3 -154
- data/docs/migrate_from_active_model_serializers.md +2 -2
- data/docs/rails.md +1 -1
- data/lib/alba/association.rb +6 -4
- data/lib/alba/conditional_attribute.rb +1 -1
- data/lib/alba/layout.rb +2 -2
- data/lib/alba/railtie.rb +8 -0
- data/lib/alba/resource.rb +38 -32
- data/lib/alba/version.rb +1 -1
- data/lib/alba.rb +29 -4
- metadata +6 -4
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
|
-
|
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
|
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.
|
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.
|
data/lib/alba/association.rb
CHANGED
@@ -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)
|
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.
|
68
|
+
elsif Alba.inflector
|
67
69
|
Alba.infer_resource_class(@name, nesting: nesting)
|
68
70
|
else
|
69
|
-
raise ArgumentError, 'When Alba.
|
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
|
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/layout.rb
CHANGED
@@ -8,8 +8,8 @@ module Alba
|
|
8
8
|
|
9
9
|
def_delegators :@resource, :object, :params, :serializable_hash, :to_h
|
10
10
|
|
11
|
-
# @
|
12
|
-
# @
|
11
|
+
# @param file [String] name of the layout file
|
12
|
+
# @param inline [Proc] a proc returning JSON string or a Hash representing JSON
|
13
13
|
def initialize(file:, inline:)
|
14
14
|
if file
|
15
15
|
raise ArgumentError, 'File layout must be a String representing filename' unless file.is_a?(String)
|
data/lib/alba/railtie.rb
ADDED
data/lib/alba/resource.rb
CHANGED
@@ -11,7 +11,7 @@ module Alba
|
|
11
11
|
module Resource
|
12
12
|
# @!parse include InstanceMethods
|
13
13
|
# @!parse extend ClassMethods
|
14
|
-
DSLS = {_attributes: {}, _key: nil, _key_for_collection: nil, _meta: nil, _transform_type: :none, _transforming_root_key: false, _on_error: nil, _on_nil: nil, _layout: nil, _collection_key: nil}.freeze # rubocop:disable Layout/LineLength
|
14
|
+
DSLS = {_attributes: {}, _key: nil, _key_for_collection: nil, _meta: nil, _transform_type: :none, _transforming_root_key: false, _key_transformation_cascade: true, _on_error: nil, _on_nil: nil, _layout: nil, _collection_key: nil}.freeze # rubocop:disable Layout/LineLength
|
15
15
|
private_constant :DSLS
|
16
16
|
|
17
17
|
WITHIN_DEFAULT = Object.new.freeze
|
@@ -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
|
|
@@ -79,7 +78,6 @@ module Alba
|
|
79
78
|
#
|
80
79
|
# @param root_key [Symbol, nil, true]
|
81
80
|
# @param meta [Hash] metadata for this seialization
|
82
|
-
# @param symbolize_root_key [Boolean] determines if root key should be symbolized
|
83
81
|
# @return [Hash]
|
84
82
|
def as_json(root_key: nil, meta: {})
|
85
83
|
key = root_key.nil? ? fetch_key : root_key.to_s
|
@@ -149,7 +147,7 @@ module Alba
|
|
149
147
|
end
|
150
148
|
|
151
149
|
def _key_for_collection
|
152
|
-
if Alba.
|
150
|
+
if Alba.inflector
|
153
151
|
@_key_for_collection == true ? resource_name(pluralized: true) : @_key_for_collection.to_s
|
154
152
|
else
|
155
153
|
@_key_for_collection == true ? raise_root_key_inference_error : @_key_for_collection.to_s
|
@@ -158,7 +156,7 @@ module Alba
|
|
158
156
|
|
159
157
|
# @return [String]
|
160
158
|
def _key
|
161
|
-
if Alba.
|
159
|
+
if Alba.inflector
|
162
160
|
@_key == true ? resource_name(pluralized: false) : @_key.to_s
|
163
161
|
else
|
164
162
|
@_key == true ? raise_root_key_inference_error : @_key.to_s
|
@@ -174,7 +172,7 @@ module Alba
|
|
174
172
|
end
|
175
173
|
|
176
174
|
def raise_root_key_inference_error
|
177
|
-
raise Alba::Error, 'You must
|
175
|
+
raise Alba::Error, 'You must set inflector when setting root key as true.'
|
178
176
|
end
|
179
177
|
|
180
178
|
def transforming_root_key?
|
@@ -182,27 +180,27 @@ module Alba
|
|
182
180
|
end
|
183
181
|
|
184
182
|
def converter
|
185
|
-
lambda do |
|
186
|
-
attributes_to_hash(
|
183
|
+
lambda do |obj|
|
184
|
+
attributes_to_hash(obj, {})
|
187
185
|
end
|
188
186
|
end
|
189
187
|
|
190
188
|
def collection_converter
|
191
|
-
lambda do |
|
189
|
+
lambda do |obj, a|
|
192
190
|
a << {}
|
193
191
|
h = a.last
|
194
|
-
attributes_to_hash(
|
192
|
+
attributes_to_hash(obj, h)
|
195
193
|
a
|
196
194
|
end
|
197
195
|
end
|
198
196
|
|
199
|
-
def attributes_to_hash(
|
197
|
+
def attributes_to_hash(obj, hash)
|
200
198
|
attributes.each do |key, attribute|
|
201
|
-
set_key_and_attribute_body_from(
|
199
|
+
set_key_and_attribute_body_from(obj, key, attribute, hash)
|
202
200
|
rescue ::Alba::Error, FrozenError, TypeError
|
203
201
|
raise
|
204
202
|
rescue StandardError => e
|
205
|
-
handle_error(e,
|
203
|
+
handle_error(e, obj, key, attribute, hash)
|
206
204
|
end
|
207
205
|
hash
|
208
206
|
end
|
@@ -213,20 +211,28 @@ module Alba
|
|
213
211
|
@_attributes
|
214
212
|
end
|
215
213
|
|
216
|
-
|
214
|
+
# Default implementation for selecting attributes
|
215
|
+
# Override this method to filter attributes based on key and value
|
216
|
+
def select(_key, _value)
|
217
|
+
true
|
218
|
+
end
|
219
|
+
|
220
|
+
def set_key_and_attribute_body_from(obj, key, attribute, hash)
|
217
221
|
key = transform_key(key)
|
218
|
-
value = fetch_attribute(
|
222
|
+
value = fetch_attribute(obj, key, attribute)
|
223
|
+
return unless select(key, value)
|
224
|
+
|
219
225
|
hash[key] = value unless value == Alba::REMOVE_KEY
|
220
226
|
end
|
221
227
|
|
222
|
-
def handle_error(error,
|
228
|
+
def handle_error(error, obj, key, attribute, hash)
|
223
229
|
on_error = @_on_error || :raise
|
224
230
|
case on_error # rubocop:disable Style/MissingElse
|
225
231
|
when :raise, nil then raise(error)
|
226
232
|
when :nullify then hash[key] = nil
|
227
233
|
when :ignore then nil
|
228
234
|
when Proc
|
229
|
-
key, value = on_error.call(error,
|
235
|
+
key, value = on_error.call(error, obj, key, attribute, self.class)
|
230
236
|
hash[key] = value
|
231
237
|
end
|
232
238
|
end
|
@@ -237,7 +243,7 @@ module Alba
|
|
237
243
|
return key if @_transform_type == :none || key.empty? # We can skip transformation
|
238
244
|
|
239
245
|
inflector = Alba.inflector
|
240
|
-
raise Alba::Error, 'Inflector is nil. You
|
246
|
+
raise Alba::Error, 'Inflector is nil. You must set inflector before transforming keys.' unless inflector
|
241
247
|
|
242
248
|
case @_transform_type # rubocop:disable Style/MissingElse
|
243
249
|
when :camel then inflector.camelize(key)
|
@@ -247,23 +253,23 @@ module Alba
|
|
247
253
|
end
|
248
254
|
end
|
249
255
|
|
250
|
-
def fetch_attribute(
|
256
|
+
def fetch_attribute(obj, key, attribute) # rubocop:disable Metrics/CyclomaticComplexity
|
251
257
|
value = case attribute
|
252
|
-
when Symbol then fetch_attribute_from_object_and_resource(
|
253
|
-
when Proc then instance_exec(
|
254
|
-
when Alba::Association then yield_if_within(attribute.name.to_sym) { |within| attribute.to_h(
|
255
|
-
when TypedAttribute, NestedAttribute then attribute.value(
|
256
|
-
when ConditionalAttribute then attribute.with_passing_condition(resource: self, object:
|
258
|
+
when Symbol then fetch_attribute_from_object_and_resource(obj, attribute)
|
259
|
+
when Proc then instance_exec(obj, &attribute)
|
260
|
+
when Alba::Association then yield_if_within(attribute.name.to_sym) { |within| attribute.to_h(obj, params: params, within: within) }
|
261
|
+
when TypedAttribute, NestedAttribute then attribute.value(obj)
|
262
|
+
when ConditionalAttribute then attribute.with_passing_condition(resource: self, object: obj) { |attr| fetch_attribute(obj, key, attr) }
|
257
263
|
else
|
258
264
|
raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
|
259
265
|
end
|
260
|
-
value.nil? && nil_handler ? instance_exec(
|
266
|
+
value.nil? && nil_handler ? instance_exec(obj, key, attribute, &nil_handler) : value
|
261
267
|
end
|
262
268
|
|
263
|
-
def fetch_attribute_from_object_and_resource(
|
264
|
-
|
265
|
-
|
266
|
-
|
269
|
+
def fetch_attribute_from_object_and_resource(obj, attribute)
|
270
|
+
obj.__send__(attribute)
|
271
|
+
rescue NoMethodError
|
272
|
+
__send__(attribute, obj)
|
267
273
|
end
|
268
274
|
|
269
275
|
def nil_handler
|
@@ -313,7 +319,7 @@ module Alba
|
|
313
319
|
# @param attrs_with_types [Hash<[Symbol, String], [Array<Symbol, Proc>, Symbol]>]
|
314
320
|
# attributes with name in its key and type and optional type converter in its value
|
315
321
|
# @return [void]
|
316
|
-
def attributes(*attrs, if: nil, **attrs_with_types)
|
322
|
+
def attributes(*attrs, if: nil, **attrs_with_types)
|
317
323
|
if_value = binding.local_variable_get(:if)
|
318
324
|
assign_attributes(attrs, if_value)
|
319
325
|
assign_attributes_with_types(attrs_with_types, if_value)
|
@@ -435,8 +441,8 @@ module Alba
|
|
435
441
|
|
436
442
|
# Set layout
|
437
443
|
#
|
438
|
-
# @
|
439
|
-
# @
|
444
|
+
# @param file [String] name of the layout file
|
445
|
+
# @param inline [Proc] a proc returning JSON string or a Hash representing JSON
|
440
446
|
def layout(file: nil, inline: nil)
|
441
447
|
@_layout = Layout.new(file: file, inline: inline)
|
442
448
|
end
|
data/lib/alba/version.rb
CHANGED
data/lib/alba.rb
CHANGED
@@ -4,13 +4,15 @@ require_relative 'alba/errors'
|
|
4
4
|
require_relative 'alba/resource'
|
5
5
|
require_relative 'alba/deprecation'
|
6
6
|
|
7
|
+
require_relative 'alba/railtie' if defined?(Rails::Railtie)
|
8
|
+
|
7
9
|
# Core module
|
8
10
|
module Alba
|
9
11
|
class << self
|
10
|
-
attr_reader :backend, :encoder
|
12
|
+
attr_reader :backend, :encoder
|
11
13
|
|
12
|
-
#
|
13
|
-
|
14
|
+
# Getter for inflector, a module responsible for inflecting strings
|
15
|
+
attr_reader :inflector
|
14
16
|
|
15
17
|
# Set the backend, which actually serializes object into JSON
|
16
18
|
#
|
@@ -54,14 +56,36 @@ module Alba
|
|
54
56
|
# @param with [Symbol, Class, Module] inflector
|
55
57
|
# When it's a Symbol, it sets inflector with given name
|
56
58
|
# When it's a Class or a Module, it sets given object to inflector
|
59
|
+
# @deprecated Use {#inflector=} instead
|
57
60
|
def enable_inference!(with:)
|
61
|
+
Alba::Deprecation.warn('Alba.enable_inference! is deprecated. Use `Alba.inflector=` instead.')
|
58
62
|
@inflector = inflector_from(with)
|
59
63
|
@inferring = true
|
60
64
|
end
|
61
65
|
|
62
66
|
# Disable inference for key and resource name
|
67
|
+
#
|
68
|
+
# @deprecated Use {#inflector=} instead
|
63
69
|
def disable_inference!
|
70
|
+
Alba::Deprecation.warn('Alba.disable_inference! is deprecated. Use `Alba.inflector = nil` instead.')
|
64
71
|
@inferring = false
|
72
|
+
@inflector = nil
|
73
|
+
end
|
74
|
+
|
75
|
+
# @deprecated Use {#inflector} instead
|
76
|
+
# @return [Boolean] whether inference is enabled or not
|
77
|
+
def inferring
|
78
|
+
Alba::Deprecation.warn('Alba.inferring is deprecated. Use `Alba.inflector` instead.')
|
79
|
+
@inferring
|
80
|
+
end
|
81
|
+
|
82
|
+
# Set an inflector
|
83
|
+
#
|
84
|
+
# @param inflector [Symbol, Class, Module] inflector
|
85
|
+
# When it's a Symbol, it accepts `:default`, `:active_support` or `:dry`
|
86
|
+
# When it's a Class or a Module, it should have some methods, see {Alba::DefaultInflector}
|
87
|
+
def inflector=(inflector)
|
88
|
+
@inflector = inflector_from(inflector)
|
65
89
|
end
|
66
90
|
|
67
91
|
# @param block [Block] resource body
|
@@ -77,7 +101,7 @@ module Alba
|
|
77
101
|
# @param nesting [String, nil] namespace Alba tries to find resource class in
|
78
102
|
# @return [Class<Alba::Resource>] resource class
|
79
103
|
def infer_resource_class(name, nesting: nil)
|
80
|
-
raise Alba::Error, 'Inference is disabled so Alba cannot infer resource name.
|
104
|
+
raise Alba::Error, 'Inference is disabled so Alba cannot infer resource name. Set inflector before use.' unless Alba.inflector
|
81
105
|
|
82
106
|
const_parent = nesting.nil? ? Object : Object.const_get(nesting)
|
83
107
|
const_parent.const_get("#{inflector.classify(name)}Resource")
|
@@ -95,6 +119,7 @@ module Alba
|
|
95
119
|
|
96
120
|
def inflector_from(name_or_module)
|
97
121
|
case name_or_module
|
122
|
+
when nil then nil
|
98
123
|
when :default, :active_support
|
99
124
|
require_relative 'alba/default_inflector'
|
100
125
|
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
|
4
|
+
version: 2.2.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:
|
11
|
+
date: 2023-02-17 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
|
@@ -58,6 +59,7 @@ files:
|
|
58
59
|
- lib/alba/errors.rb
|
59
60
|
- lib/alba/layout.rb
|
60
61
|
- lib/alba/nested_attribute.rb
|
62
|
+
- lib/alba/railtie.rb
|
61
63
|
- lib/alba/resource.rb
|
62
64
|
- lib/alba/typed_attribute.rb
|
63
65
|
- lib/alba/version.rb
|
@@ -82,14 +84,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
84
|
requirements:
|
83
85
|
- - ">="
|
84
86
|
- !ruby/object:Gem::Version
|
85
|
-
version: 2.
|
87
|
+
version: 2.7.0
|
86
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
89
|
requirements:
|
88
90
|
- - ">="
|
89
91
|
- !ruby/object:Gem::Version
|
90
92
|
version: '0'
|
91
93
|
requirements: []
|
92
|
-
rubygems_version: 3.
|
94
|
+
rubygems_version: 3.4.6
|
93
95
|
signing_key:
|
94
96
|
specification_version: 4
|
95
97
|
summary: Alba is the fastest JSON serializer for Ruby.
|