alba 0.13.0 → 0.13.1

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: f4a5b866825838f457bb17c0c1037f68c3e88a9b96c86dd9e0c456d101f69158
4
- data.tar.gz: d1f451fff558385b3ae4610355a3abb9aced052ce138eff9913169a12c8a23c6
3
+ metadata.gz: 993f4b887c19f4e1149ddb850cd07a8cb8c2042cde0fb3974b1380537707a55d
4
+ data.tar.gz: acf77a0aa35f7fe23fc3f98843064d2800e0b4e0739e587dd29aab65f06269ad
5
5
  SHA512:
6
- metadata.gz: 71fdab1911c6fc9e1ba88e8cbdc553311b99aecd975462b05958e5be1e491aa10734b6b6f6f15f24ae98c8ab5a1b1021d6c544a172befcedd23ca80283529e98
7
- data.tar.gz: 05f06f2e7f3ec93e0a616bec6e3d71a90590b68c7ce397050bb9c019d2bbf206b070ed1cf44603cd301fa5dd2634df50c4e08b75a8c478b2f0063b6551b5bdcc
6
+ metadata.gz: 9b8e52dcaf4ca33cba0685c2a0a06c16df69cd04b6d399c092e920548f5baa6a21aeab8097f90e92ab35ac9c260d83858c19462a9ec2a689d97c6999daef5e3a
7
+ data.tar.gz: e525a66c30477cab6741436128398a6f0309a0f786040fe946a9f2783d08f619df00d85157d04c5876cc579e19cceabf22dcb3556addf6ad061d44d1f0cfa888
@@ -0,0 +1,25 @@
1
+ name: Ruby
2
+
3
+ on: [push,pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ os: [ubuntu-latest, windows-latest, macos-latest]
11
+ ruby: [2.5, 2.6, 2.7, 3.0, head, truffleruby]
12
+ exclude:
13
+ - os: windows-latest
14
+ ruby: truffleruby
15
+ runs-on: ${{ matrix.os }}
16
+ steps:
17
+ - uses: actions/checkout@v2
18
+ - name: Set up Ruby
19
+ uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ bundler-cache: true
23
+ - name: Run the default task
24
+ run: |
25
+ bundle exec rake
data/.rubocop.yml CHANGED
@@ -12,6 +12,7 @@ AllCops:
12
12
  Exclude:
13
13
  - 'Rakefile'
14
14
  - 'alba.gemspec'
15
+ - 'benchmark/**/*.rb'
15
16
  NewCops: enable
16
17
  EnabledByDefault: true
17
18
 
data/Gemfile CHANGED
@@ -10,7 +10,7 @@ gem 'oj', '~> 3.11', platform: :ruby, require: false # For backend
10
10
  gem 'rake', '~> 13.0' # For test and automation
11
11
  gem 'rubocop', '>= 0.79.0', require: false # For lint
12
12
  gem 'rubocop-minitest', '~> 0.10.3', require: false # For lint
13
- gem 'rubocop-performance', '~> 1.9.2', require: false # For lint
13
+ gem 'rubocop-performance', '~> 1.10.1', require: false # For lint
14
14
  gem 'rubocop-rake', '>= 0.5.1', require: false # For lint
15
15
  gem 'rubocop-sensible', '~> 0.3.0', require: false # For lint
16
16
  gem 'yard', require: false
data/Gemfile.lock CHANGED
@@ -1,19 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- alba (0.13.0)
4
+ alba (0.13.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- activesupport (6.1.1)
9
+ activesupport (6.1.3)
10
10
  concurrent-ruby (~> 1.0, >= 1.0.2)
11
11
  i18n (>= 1.6, < 2)
12
12
  minitest (>= 5.1)
13
13
  tzinfo (~> 2.0)
14
14
  zeitwerk (~> 2.3)
15
- ast (2.4.1)
16
- concurrent-ruby (1.1.7)
15
+ ast (2.4.2)
16
+ concurrent-ruby (1.1.8)
17
17
  coveralls (0.8.23)
18
18
  json (>= 1.8, < 3)
19
19
  simplecov (~> 0.16.1)
@@ -21,19 +21,19 @@ GEM
21
21
  thor (>= 0.19.4, < 2.0)
22
22
  tins (~> 1.6)
23
23
  docile (1.3.2)
24
- i18n (1.8.7)
24
+ i18n (1.8.9)
25
25
  concurrent-ruby (~> 1.0)
26
26
  json (2.3.1)
27
27
  minitest (5.14.3)
28
- oj (3.11.0)
28
+ oj (3.11.2)
29
29
  parallel (1.20.1)
30
30
  parser (3.0.0.0)
31
31
  ast (~> 2.4.1)
32
32
  rainbow (3.0.0)
33
33
  rake (13.0.3)
34
- regexp_parser (2.0.3)
34
+ regexp_parser (2.1.1)
35
35
  rexml (3.2.4)
36
- rubocop (1.8.1)
36
+ rubocop (1.11.0)
37
37
  parallel (~> 1.10)
38
38
  parser (>= 3.0.0.0)
39
39
  rainbow (>= 2.2.2, < 4.0)
@@ -42,11 +42,11 @@ GEM
42
42
  rubocop-ast (>= 1.2.0, < 2.0)
43
43
  ruby-progressbar (~> 1.7)
44
44
  unicode-display_width (>= 1.4.0, < 3.0)
45
- rubocop-ast (1.4.0)
45
+ rubocop-ast (1.4.1)
46
46
  parser (>= 2.7.1.5)
47
47
  rubocop-minitest (0.10.3)
48
48
  rubocop (>= 0.87, < 2.0)
49
- rubocop-performance (1.9.2)
49
+ rubocop-performance (1.10.1)
50
50
  rubocop (>= 0.90.0, < 2.0)
51
51
  rubocop-ast (>= 0.4.0)
52
52
  rubocop-rake (0.5.1)
@@ -83,7 +83,7 @@ DEPENDENCIES
83
83
  rake (~> 13.0)
84
84
  rubocop (>= 0.79.0)
85
85
  rubocop-minitest (~> 0.10.3)
86
- rubocop-performance (~> 1.9.2)
86
+ rubocop-performance (~> 1.10.1)
87
87
  rubocop-rake (>= 0.5.1)
88
88
  rubocop-sensible (~> 0.3.0)
89
89
  yard
data/README.md CHANGED
@@ -19,11 +19,11 @@ Alba has some advantages over other JSON serializers which we've wanted to have.
19
19
 
20
20
  DSL is great. It makes the coding experience natural and intuitive. However, remembering lots of DSL requires us a lot of effort. Unfortunately, most of the existing libraries have implemented their features via DSL and it's not easy to understand how they behave entirely. Alba's core DSL are only four (`attributes`, `attribute`, `one` and `many`) so it's easy to understand how to use.
21
21
 
22
- Alba is also understandable internally. The codebase is much smaller than the alternatives. In fact, it's less than 300 lines of code. Look at the code on [GitHub](https://github.com/okuramasafumi/alba/tree/master/lib) and you'll be surprised how simple it is!
22
+ Alba is also understandable internally. The codebase is much smaller than the alternatives. In fact, it's about 330 lines of code. Look at the code on [GitHub](https://github.com/okuramasafumi/alba/tree/master/lib) and you'll be surprised how simple it is!
23
23
 
24
24
  ### Performance
25
25
 
26
- Alba is faster than most of the alternatives. We have a [benchmark](https://gist.github.com/okuramasafumi/4e375525bd3a28e4ca812d2a3b3e5829).
26
+ Alba is faster than most of the alternatives. We have a [benchmark](https://github.com/okuramasafumi/alba/tree/master/benchmark).
27
27
 
28
28
  ## Installation
29
29
 
@@ -47,7 +47,7 @@ Alba supports CRuby 2.5.7 and higher and latest TruffleRuby.
47
47
 
48
48
  ## Documentation
49
49
 
50
- You can find the documentation on [RubyDoc](https://rubydoc.info/gems/alba).
50
+ You can find the documentation on [RubyDoc](https://rubydoc.info/github/okuramasafumi/alba).
51
51
 
52
52
  ## Features
53
53
 
@@ -59,6 +59,7 @@ You can find the documentation on [RubyDoc](https://rubydoc.info/gems/alba).
59
59
  * Setting root key separately in Serializer
60
60
  * Adding metadata
61
61
  * Selectable backend
62
+ * Key transformation
62
63
  * No runtime dependencies
63
64
 
64
65
  ## Anti features
@@ -253,6 +254,44 @@ UserResourceCamel.new(user).serialize
253
254
 
254
255
  Supported transformation types are :camel, :lower_camel and :dash.
255
256
 
257
+ ### Filtering attributes
258
+
259
+ You can filter attributes by overriding `Alba::Resource#converter` method, but it's a bit tricky.
260
+
261
+ ```ruby
262
+ class User
263
+ attr_accessor :id, :name, :email, :created_at, :updated_at
264
+
265
+ def initialize(id, name, email)
266
+ @id = id
267
+ @name = name
268
+ @email = email
269
+ end
270
+ end
271
+
272
+ class UserResource
273
+ include Alba::Resource
274
+
275
+ attributes :id, :name, :email
276
+
277
+ private
278
+
279
+ # Here using `Proc#>>` method to compose a proc from `super`
280
+ def converter
281
+ super >> proc { |hash| hash.compact }
282
+ end
283
+ end
284
+
285
+ user = User.new(1, nil, nil)
286
+ UserResource.new(user).serialize # => '{"id":1}'
287
+
288
+
289
+ ```
290
+
291
+ The key part is the use of `Proc#>>` since `Alba::Resource#converter` returns a `Proc` which contains the basic logic and it's impossible to change its behavior by just overriding the method.
292
+
293
+ It's not recommended to swap the whole conversion logic. It's recommended to always call `super` when you override `converter`.
294
+
256
295
  ## Comparison
257
296
 
258
297
  Alba is faster than alternatives.
@@ -0,0 +1,198 @@
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
@@ -24,7 +24,7 @@ module Alba
24
24
  when :dash
25
25
  ActiveSupport::Inflector.dasherize(key)
26
26
  else
27
- raise ::Alba::Error, "Unknown transform_type: #{transform_type}. Supported transform_type are :camel and :dash."
27
+ raise ::Alba::Error, "Unknown transform_type: #{transform_type}. Supported transform_type are :camel, :lower_camel and :dash."
28
28
  end
29
29
  end
30
30
  end
data/lib/alba/many.rb CHANGED
@@ -11,6 +11,8 @@ module Alba
11
11
  def to_hash(target, params: {})
12
12
  objects = target.public_send(@name)
13
13
  objects = @condition.call(objects, params) if @condition
14
+ return if objects.nil?
15
+
14
16
  objects.map { |o| @resource.new(o, params: params).to_hash }
15
17
  end
16
18
  end
data/lib/alba/one.rb CHANGED
@@ -11,6 +11,8 @@ module Alba
11
11
  def to_hash(target, params: {})
12
12
  object = target.public_send(@name)
13
13
  object = @condition.call(object, params) if @condition
14
+ return if object.nil?
15
+
14
16
  @resource.new(object, params: params).to_hash
15
17
  end
16
18
  end
data/lib/alba/resource.rb CHANGED
@@ -196,7 +196,7 @@ module Alba
196
196
 
197
197
  # Transform keys as specified type
198
198
  #
199
- # @params type [String, Symbol]
199
+ # @param type [String, Symbol]
200
200
  def transform_keys(type)
201
201
  @_transform_keys = type.to_sym
202
202
  end
@@ -7,10 +7,8 @@ module Alba
7
7
  # @private
8
8
  def self.included(base)
9
9
  super
10
- base.class_eval do
11
- @_opts = {} unless instance_variable_defined?('@_opts')
12
- @_metadata = {} unless instance_variable_defined?('@_metadata')
13
- end
10
+ base.instance_variable_set('@_opts', {}) unless base.instance_variable_defined?('@_opts')
11
+ base.instance_variable_set('@_metadata', {}) unless base.instance_variable_defined?('@_metadata')
14
12
  base.include InstanceMethods
15
13
  base.extend ClassMethods
16
14
  end
data/lib/alba/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Alba
2
- VERSION = '0.13.0'.freeze
2
+ VERSION = '0.13.1'.freeze
3
3
  end
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: 0.13.0
4
+ version: 0.13.1
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-01-22 00:00:00.000000000 Z
11
+ date: 2021-03-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Alba is designed to be a simple, easy to use and fast alternative to
14
14
  existing JSON serializers. Its performance is better than almost all gems which
@@ -19,9 +19,9 @@ executables: []
19
19
  extensions: []
20
20
  extra_rdoc_files: []
21
21
  files:
22
+ - ".github/workflows/main.yml"
22
23
  - ".gitignore"
23
24
  - ".rubocop.yml"
24
- - ".travis.yml"
25
25
  - ".yardopts"
26
26
  - CODE_OF_CONDUCT.md
27
27
  - Gemfile
@@ -30,6 +30,7 @@ files:
30
30
  - README.md
31
31
  - Rakefile
32
32
  - alba.gemspec
33
+ - benchmark/local.rb
33
34
  - bin/console
34
35
  - bin/setup
35
36
  - lib/alba.rb
@@ -63,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
64
  - !ruby/object:Gem::Version
64
65
  version: '0'
65
66
  requirements: []
66
- rubygems_version: 3.0.3
67
+ rubygems_version: 3.2.11
67
68
  signing_key:
68
69
  specification_version: 4
69
70
  summary: Alba is the fastest JSON serializer for Ruby.
data/.travis.yml DELETED
@@ -1,10 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.5.8
6
- - 2.6.6
7
- - 2.7.1
8
- # - ruby-head # oj doesn't work with Ruby 2.8.0
9
- - truffleruby
10
- before_install: gem install bundler -v 2.1.4