alba 0.13.1 → 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/.github/ISSUE_TEMPLATE/bug_report.md +26 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/dependabot.yml +26 -0
- data/.github/workflows/main.yml +10 -1
- data/.gitignore +3 -0
- data/.rubocop.yml +33 -2
- data/.yardopts +2 -0
- data/CHANGELOG.md +47 -0
- data/Gemfile +10 -4
- data/README.md +308 -45
- data/Rakefile +4 -1
- data/SECURITY.md +12 -0
- data/alba.gemspec +3 -3
- data/benchmark/collection.rb +392 -0
- data/benchmark/single_resource.rb +370 -0
- data/codecov.yml +8 -0
- data/gemfiles/all.gemfile +19 -0
- data/gemfiles/without_active_support.gemfile +17 -0
- data/gemfiles/without_oj.gemfile +17 -0
- data/lib/alba.rb +57 -19
- data/lib/alba/association.rb +30 -7
- data/lib/alba/default_inflector.rb +36 -0
- data/lib/alba/key_transform_factory.rb +33 -0
- data/lib/alba/many.rb +7 -5
- data/lib/alba/one.rb +7 -5
- data/lib/alba/resource.rb +170 -63
- data/lib/alba/typed_attribute.rb +64 -0
- data/lib/alba/version.rb +1 -1
- data/sider.yml +2 -4
- metadata +21 -12
- data/Gemfile.lock +0 -92
- data/benchmark/local.rb +0 -198
- data/lib/alba/key_transformer.rb +0 -31
- data/lib/alba/serializer.rb +0 -75
@@ -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
data/sider.yml
CHANGED
@@ -49,10 +49,8 @@ linter:
|
|
49
49
|
# norc: true
|
50
50
|
|
51
51
|
# # https://help.sider.review/getting-started/custom-configuration#ignore
|
52
|
-
|
53
|
-
|
54
|
-
# - "*.mp4"
|
55
|
-
# - "images/**"
|
52
|
+
ignore:
|
53
|
+
- 'test/**/*'
|
56
54
|
|
57
55
|
# # https://help.sider.review/getting-started/custom-configuration#branchesexclude
|
58
56
|
# branches:
|
metadata
CHANGED
@@ -1,45 +1,54 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alba
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
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-
|
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: []
|
19
18
|
extensions: []
|
20
19
|
extra_rdoc_files: []
|
21
20
|
files:
|
21
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
22
|
+
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
23
|
+
- ".github/dependabot.yml"
|
22
24
|
- ".github/workflows/main.yml"
|
23
25
|
- ".gitignore"
|
24
26
|
- ".rubocop.yml"
|
25
27
|
- ".yardopts"
|
28
|
+
- CHANGELOG.md
|
26
29
|
- CODE_OF_CONDUCT.md
|
27
30
|
- Gemfile
|
28
|
-
- Gemfile.lock
|
29
31
|
- LICENSE.txt
|
30
32
|
- README.md
|
31
33
|
- Rakefile
|
34
|
+
- SECURITY.md
|
32
35
|
- alba.gemspec
|
33
|
-
- benchmark/
|
36
|
+
- benchmark/collection.rb
|
37
|
+
- benchmark/single_resource.rb
|
34
38
|
- bin/console
|
35
39
|
- bin/setup
|
40
|
+
- codecov.yml
|
41
|
+
- gemfiles/all.gemfile
|
42
|
+
- gemfiles/without_active_support.gemfile
|
43
|
+
- gemfiles/without_oj.gemfile
|
36
44
|
- lib/alba.rb
|
37
45
|
- lib/alba/association.rb
|
38
|
-
- lib/alba/
|
46
|
+
- lib/alba/default_inflector.rb
|
47
|
+
- lib/alba/key_transform_factory.rb
|
39
48
|
- lib/alba/many.rb
|
40
49
|
- lib/alba/one.rb
|
41
50
|
- lib/alba/resource.rb
|
42
|
-
- lib/alba/
|
51
|
+
- lib/alba/typed_attribute.rb
|
43
52
|
- lib/alba/version.rb
|
44
53
|
- sider.yml
|
45
54
|
homepage: https://github.com/okuramasafumi/alba
|
@@ -48,7 +57,7 @@ licenses:
|
|
48
57
|
metadata:
|
49
58
|
homepage_uri: https://github.com/okuramasafumi/alba
|
50
59
|
source_code_uri: https://github.com/okuramasafumi/alba
|
51
|
-
changelog_uri: https://github.com/okuramasafumi/alba/CHANGELOG.md
|
60
|
+
changelog_uri: https://github.com/okuramasafumi/alba/blob/master/CHANGELOG.md
|
52
61
|
post_install_message:
|
53
62
|
rdoc_options: []
|
54
63
|
require_paths:
|
@@ -57,14 +66,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
66
|
requirements:
|
58
67
|
- - ">="
|
59
68
|
- !ruby/object:Gem::Version
|
60
|
-
version: 2.5.
|
69
|
+
version: 2.5.0
|
61
70
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
71
|
requirements:
|
63
72
|
- - ">="
|
64
73
|
- !ruby/object:Gem::Version
|
65
74
|
version: '0'
|
66
75
|
requirements: []
|
67
|
-
rubygems_version: 3.2.
|
76
|
+
rubygems_version: 3.2.16
|
68
77
|
signing_key:
|
69
78
|
specification_version: 4
|
70
79
|
summary: Alba is the fastest JSON serializer for Ruby.
|
data/Gemfile.lock
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
alba (0.13.1)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
activesupport (6.1.3)
|
10
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
-
i18n (>= 1.6, < 2)
|
12
|
-
minitest (>= 5.1)
|
13
|
-
tzinfo (~> 2.0)
|
14
|
-
zeitwerk (~> 2.3)
|
15
|
-
ast (2.4.2)
|
16
|
-
concurrent-ruby (1.1.8)
|
17
|
-
coveralls (0.8.23)
|
18
|
-
json (>= 1.8, < 3)
|
19
|
-
simplecov (~> 0.16.1)
|
20
|
-
term-ansicolor (~> 1.3)
|
21
|
-
thor (>= 0.19.4, < 2.0)
|
22
|
-
tins (~> 1.6)
|
23
|
-
docile (1.3.2)
|
24
|
-
i18n (1.8.9)
|
25
|
-
concurrent-ruby (~> 1.0)
|
26
|
-
json (2.3.1)
|
27
|
-
minitest (5.14.3)
|
28
|
-
oj (3.11.2)
|
29
|
-
parallel (1.20.1)
|
30
|
-
parser (3.0.0.0)
|
31
|
-
ast (~> 2.4.1)
|
32
|
-
rainbow (3.0.0)
|
33
|
-
rake (13.0.3)
|
34
|
-
regexp_parser (2.1.1)
|
35
|
-
rexml (3.2.4)
|
36
|
-
rubocop (1.11.0)
|
37
|
-
parallel (~> 1.10)
|
38
|
-
parser (>= 3.0.0.0)
|
39
|
-
rainbow (>= 2.2.2, < 4.0)
|
40
|
-
regexp_parser (>= 1.8, < 3.0)
|
41
|
-
rexml
|
42
|
-
rubocop-ast (>= 1.2.0, < 2.0)
|
43
|
-
ruby-progressbar (~> 1.7)
|
44
|
-
unicode-display_width (>= 1.4.0, < 3.0)
|
45
|
-
rubocop-ast (1.4.1)
|
46
|
-
parser (>= 2.7.1.5)
|
47
|
-
rubocop-minitest (0.10.3)
|
48
|
-
rubocop (>= 0.87, < 2.0)
|
49
|
-
rubocop-performance (1.10.1)
|
50
|
-
rubocop (>= 0.90.0, < 2.0)
|
51
|
-
rubocop-ast (>= 0.4.0)
|
52
|
-
rubocop-rake (0.5.1)
|
53
|
-
rubocop
|
54
|
-
rubocop-sensible (0.3.0)
|
55
|
-
rubocop (>= 0.60.0)
|
56
|
-
ruby-progressbar (1.11.0)
|
57
|
-
simplecov (0.16.1)
|
58
|
-
docile (~> 1.1)
|
59
|
-
json (>= 1.8, < 3)
|
60
|
-
simplecov-html (~> 0.10.0)
|
61
|
-
simplecov-html (0.10.2)
|
62
|
-
sync (0.5.0)
|
63
|
-
term-ansicolor (1.7.1)
|
64
|
-
tins (~> 1.0)
|
65
|
-
thor (1.0.1)
|
66
|
-
tins (1.25.0)
|
67
|
-
sync
|
68
|
-
tzinfo (2.0.4)
|
69
|
-
concurrent-ruby (~> 1.0)
|
70
|
-
unicode-display_width (2.0.0)
|
71
|
-
yard (0.9.26)
|
72
|
-
zeitwerk (2.4.2)
|
73
|
-
|
74
|
-
PLATFORMS
|
75
|
-
ruby
|
76
|
-
|
77
|
-
DEPENDENCIES
|
78
|
-
activesupport
|
79
|
-
alba!
|
80
|
-
coveralls
|
81
|
-
minitest (~> 5.14)
|
82
|
-
oj (~> 3.11)
|
83
|
-
rake (~> 13.0)
|
84
|
-
rubocop (>= 0.79.0)
|
85
|
-
rubocop-minitest (~> 0.10.3)
|
86
|
-
rubocop-performance (~> 1.10.1)
|
87
|
-
rubocop-rake (>= 0.5.1)
|
88
|
-
rubocop-sensible (~> 0.3.0)
|
89
|
-
yard
|
90
|
-
|
91
|
-
BUNDLED WITH
|
92
|
-
2.2.6
|
data/benchmark/local.rb
DELETED
@@ -1,198 +0,0 @@
|
|
1
|
-
# Benchmark script to run varieties of JSON serializers
|
2
|
-
# Fetch Alba from local, otherwise fetch latest from RubyGems
|
3
|
-
|
4
|
-
require "bundler/inline"
|
5
|
-
|
6
|
-
gemfile(true) do
|
7
|
-
source "https://rubygems.org"
|
8
|
-
|
9
|
-
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
10
|
-
|
11
|
-
gem "activerecord", "6.1.3"
|
12
|
-
gem "sqlite3"
|
13
|
-
gem "jbuilder"
|
14
|
-
gem "active_model_serializers"
|
15
|
-
gem "blueprinter"
|
16
|
-
gem "representable"
|
17
|
-
gem "alba", path: '../'
|
18
|
-
gem "oj"
|
19
|
-
gem "multi_json"
|
20
|
-
end
|
21
|
-
|
22
|
-
require "active_record"
|
23
|
-
require "sqlite3"
|
24
|
-
require "logger"
|
25
|
-
require "oj"
|
26
|
-
Oj.optimize_rails
|
27
|
-
|
28
|
-
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
|
29
|
-
# ActiveRecord::Base.logger = Logger.new(STDOUT)
|
30
|
-
|
31
|
-
ActiveRecord::Schema.define do
|
32
|
-
create_table :posts, force: true do |t|
|
33
|
-
t.string :body
|
34
|
-
end
|
35
|
-
|
36
|
-
create_table :comments, force: true do |t|
|
37
|
-
t.integer :post_id
|
38
|
-
t.string :body
|
39
|
-
t.integer :commenter_id
|
40
|
-
end
|
41
|
-
|
42
|
-
create_table :users, force: true do |t|
|
43
|
-
t.string :name
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class Post < ActiveRecord::Base
|
48
|
-
has_many :comments
|
49
|
-
has_many :commenters, through: :comments, class_name: 'User', source: :commenter
|
50
|
-
|
51
|
-
def attributes
|
52
|
-
{id: nil, body: nil, commenter_names: commenter_names}
|
53
|
-
end
|
54
|
-
|
55
|
-
def commenter_names
|
56
|
-
commenters.pluck(:name)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
class Comment < ActiveRecord::Base
|
61
|
-
belongs_to :post
|
62
|
-
belongs_to :commenter, class_name: 'User'
|
63
|
-
|
64
|
-
def attributes
|
65
|
-
{id: nil, body: nil}
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
class User < ActiveRecord::Base
|
70
|
-
has_many :comments
|
71
|
-
end
|
72
|
-
|
73
|
-
require "alba"
|
74
|
-
Alba.backend = :oj
|
75
|
-
|
76
|
-
class AlbaCommentResource
|
77
|
-
include ::Alba::Resource
|
78
|
-
attributes :id, :body
|
79
|
-
end
|
80
|
-
|
81
|
-
class AlbaPostResource
|
82
|
-
include ::Alba::Resource
|
83
|
-
attributes :id, :body
|
84
|
-
many :comments, resource: AlbaCommentResource
|
85
|
-
attribute :commenter_names do |post|
|
86
|
-
post.commenters.pluck(:name)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
require "jbuilder"
|
91
|
-
class Post
|
92
|
-
def to_builder
|
93
|
-
Jbuilder.new do |post|
|
94
|
-
post.call(self, :id, :body, :comments, :commenter_names)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def commenter_names
|
99
|
-
commenters.pluck(:name)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
class Comment
|
104
|
-
def to_builder
|
105
|
-
Jbuilder.new do |comment|
|
106
|
-
comment.call(self, :id, :body)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
require "active_model_serializers"
|
112
|
-
|
113
|
-
class AMSCommentSerializer < ActiveModel::Serializer
|
114
|
-
attributes :id, :body
|
115
|
-
end
|
116
|
-
|
117
|
-
class AMSPostSerializer < ActiveModel::Serializer
|
118
|
-
attributes :id, :body
|
119
|
-
has_many :comments, serializer: AMSCommentSerializer
|
120
|
-
attribute :commenter_names
|
121
|
-
def commenter_names
|
122
|
-
object.commenters.pluck(:name)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
require "blueprinter"
|
127
|
-
|
128
|
-
class CommentBlueprint < Blueprinter::Base
|
129
|
-
fields :id, :body
|
130
|
-
end
|
131
|
-
|
132
|
-
class PostBlueprint < Blueprinter::Base
|
133
|
-
fields :id, :body, :commenter_names
|
134
|
-
association :comments, blueprint: CommentBlueprint
|
135
|
-
def commenter_names
|
136
|
-
commenters.pluck(:name)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
require "representable"
|
141
|
-
|
142
|
-
class CommentRepresenter < Representable::Decorator
|
143
|
-
include Representable::JSON
|
144
|
-
|
145
|
-
property :id
|
146
|
-
property :body
|
147
|
-
end
|
148
|
-
|
149
|
-
class PostRepresenter < Representable::Decorator
|
150
|
-
include Representable::JSON
|
151
|
-
|
152
|
-
property :id
|
153
|
-
property :body
|
154
|
-
property :commenter_names
|
155
|
-
collection :comments
|
156
|
-
|
157
|
-
def commenter_names
|
158
|
-
commenters.pluck(:name)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
post = Post.create!(body: 'post')
|
163
|
-
user1 = User.create!(name: 'John')
|
164
|
-
user2 = User.create!(name: 'Jane')
|
165
|
-
post.comments.create!(commenter: user1, body: 'Comment1')
|
166
|
-
post.comments.create!(commenter: user2, body: 'Comment2')
|
167
|
-
post.reload
|
168
|
-
|
169
|
-
alba = Proc.new { AlbaPostResource.new(post).serialize }
|
170
|
-
jbuilder = Proc.new { post.to_builder.target! }
|
171
|
-
ams = Proc.new { AMSPostSerializer.new(post, {}).to_json }
|
172
|
-
rails = Proc.new { ActiveSupport::JSON.encode(post.serializable_hash(include: :comments)) }
|
173
|
-
blueprinter = Proc.new { PostBlueprint.render(post) }
|
174
|
-
representable = Proc.new { PostRepresenter.new(post).to_json }
|
175
|
-
alba_inline = Proc.new do
|
176
|
-
Alba.serialize(post) do
|
177
|
-
attributes :id, :body
|
178
|
-
attribute :commenter_names do |post|
|
179
|
-
post.commenters.pluck(:name)
|
180
|
-
end
|
181
|
-
many :comments do
|
182
|
-
attributes :id, :body
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
[alba, jbuilder, ams, rails, blueprinter, representable, alba_inline].each {|x| puts x.call }
|
187
|
-
|
188
|
-
require 'benchmark'
|
189
|
-
time = 1000
|
190
|
-
Benchmark.bmbm do |x|
|
191
|
-
x.report(:alba) { time.times(&alba) }
|
192
|
-
x.report(:jbuilder) { time.times(&jbuilder) }
|
193
|
-
x.report(:ams) { time.times(&ams) }
|
194
|
-
x.report(:rails) { time.times(&rails) }
|
195
|
-
x.report(:blueprinter) { time.times(&blueprinter) }
|
196
|
-
x.report(:representable) { time.times(&representable) }
|
197
|
-
x.report(:alba_inline) { time.times(&alba_inline) }
|
198
|
-
end
|