alba 0.6.0 → 0.10.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +34 -5
- data/.travis.yml +4 -1
- data/Gemfile +9 -7
- data/Gemfile.lock +25 -6
- data/README.md +91 -2
- data/alba.gemspec +14 -14
- data/lib/alba.rb +43 -4
- data/lib/alba/association.rb +26 -0
- data/lib/alba/many.rb +6 -20
- data/lib/alba/one.rb +6 -20
- data/lib/alba/resource.rb +57 -29
- data/lib/alba/serializer.rb +32 -25
- data/lib/alba/version.rb +1 -1
- data/sider.yml +1 -0
- metadata +8 -8
- data/lib/alba/attribute.rb +0 -19
- data/lib/alba/resources/default_resource.rb +0 -9
- data/lib/alba/serializers/default_serializer.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5b12eead5b50b0e426952a2318fa85d852326a078fa5e285dc7a402ee19688d
|
4
|
+
data.tar.gz: 89dc5fb1295528255ba028e2dfd8e30a2c136ff8a2ac9b9fb65b869a259f9435
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7d13ca3b2c592e97501cfb79de3aba84eb9ffeb107099bccde9a55a81b6bd36c93e9acda83d237b1e36de8dc34b3bb5aabbad68c7dd09cb998a5482d11f86f3
|
7
|
+
data.tar.gz: 8e9ab49f10f5f09669ffc27135d9fe5fe57da8b5d9e57cd7d250d661d7f5cc0f9453992c78d8db3fbd8c08ed22b4b058266faf63977f95668481151a42434d97
|
data/.rubocop.yml
CHANGED
@@ -4,6 +4,7 @@ inherit_gem:
|
|
4
4
|
rubocop-sensible: 'config/rubocop.yml'
|
5
5
|
|
6
6
|
require:
|
7
|
+
- rubocop-minitest
|
7
8
|
- rubocop-performance
|
8
9
|
|
9
10
|
AllCops:
|
@@ -11,17 +12,45 @@ AllCops:
|
|
11
12
|
- 'Rakefile'
|
12
13
|
- 'alba.gemspec'
|
13
14
|
NewCops: enable
|
15
|
+
EnabledByDefault: true
|
16
|
+
|
17
|
+
# Oneline comment is not valid so until it gets valid, we disable it
|
18
|
+
Bundler/GemComment:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Layout/ClassStructure:
|
22
|
+
Enabled: true
|
14
23
|
|
15
24
|
Layout/SpaceInsideHashLiteralBraces:
|
16
25
|
EnforcedStyle: no_space
|
17
26
|
|
27
|
+
Layout/MultilineAssignmentLayout:
|
28
|
+
EnforcedStyle: same_line
|
29
|
+
|
30
|
+
Lint/ConstantResolution:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
Metrics/ClassLength:
|
34
|
+
Exclude:
|
35
|
+
- 'test/alba_test.rb'
|
36
|
+
|
18
37
|
Metrics/MethodLength:
|
19
|
-
Max:
|
38
|
+
Max: 15
|
20
39
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
40
|
+
Style/ConstantVisibility:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
Style/Copyright:
|
44
|
+
Enabled: false
|
45
|
+
|
46
|
+
Style/DocumentationMethod:
|
47
|
+
Enabled: false
|
25
48
|
|
26
49
|
Style/FrozenStringLiteralComment:
|
27
50
|
Enabled: false
|
51
|
+
|
52
|
+
Style/InlineComment:
|
53
|
+
Enabled: false
|
54
|
+
|
55
|
+
Style/MethodCallWithArgsParentheses:
|
56
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -3,10 +3,12 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in alba.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
gem '
|
7
|
-
gem '
|
8
|
-
gem '
|
9
|
-
gem '
|
10
|
-
gem '
|
11
|
-
gem 'rubocop
|
12
|
-
gem 'rubocop-
|
6
|
+
gem 'activesupport', require: false # For backend
|
7
|
+
gem 'coveralls', require: false # For test coverage
|
8
|
+
gem 'minitest', '~> 5.0' # For test
|
9
|
+
gem 'oj', '~> 3.10', platform: :ruby, require: false # For backend
|
10
|
+
gem 'rake', '~> 13.0' # For test and automation
|
11
|
+
gem 'rubocop', '>= 0.79.0', require: false # For lint
|
12
|
+
gem 'rubocop-minitest', '~> 0.10.1', require: false # For lint
|
13
|
+
gem 'rubocop-performance', '~> 1.7.1', require: false # For lint
|
14
|
+
gem 'rubocop-sensible', '~> 0.3.0', require: false # For lint
|
data/Gemfile.lock
CHANGED
@@ -1,12 +1,20 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
alba (0.
|
4
|
+
alba (0.10.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
activesupport (6.0.3.2)
|
10
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
+
i18n (>= 0.7, < 2)
|
12
|
+
minitest (~> 5.1)
|
13
|
+
tzinfo (~> 1.1)
|
14
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
9
15
|
ast (2.4.1)
|
16
|
+
bigdecimal (2.0.0)
|
17
|
+
concurrent-ruby (1.1.6)
|
10
18
|
coveralls (0.8.23)
|
11
19
|
json (>= 1.8, < 3)
|
12
20
|
simplecov (~> 0.16.1)
|
@@ -14,9 +22,12 @@ GEM
|
|
14
22
|
thor (>= 0.19.4, < 2.0)
|
15
23
|
tins (~> 1.6)
|
16
24
|
docile (1.3.2)
|
25
|
+
i18n (1.8.5)
|
26
|
+
concurrent-ruby (~> 1.0)
|
17
27
|
json (2.3.1)
|
18
28
|
minitest (5.14.1)
|
19
|
-
oj (3.10.
|
29
|
+
oj (3.10.12)
|
30
|
+
bigdecimal (>= 1.0, < 3)
|
20
31
|
parallel (1.19.2)
|
21
32
|
parser (2.7.1.4)
|
22
33
|
ast (~> 2.4.1)
|
@@ -24,17 +35,19 @@ GEM
|
|
24
35
|
rake (13.0.1)
|
25
36
|
regexp_parser (1.7.1)
|
26
37
|
rexml (3.2.4)
|
27
|
-
rubocop (0.
|
38
|
+
rubocop (0.89.1)
|
28
39
|
parallel (~> 1.10)
|
29
40
|
parser (>= 2.7.1.1)
|
30
41
|
rainbow (>= 2.2.2, < 4.0)
|
31
42
|
regexp_parser (>= 1.7)
|
32
43
|
rexml
|
33
|
-
rubocop-ast (>= 0.
|
44
|
+
rubocop-ast (>= 0.3.0, < 1.0)
|
34
45
|
ruby-progressbar (~> 1.7)
|
35
46
|
unicode-display_width (>= 1.4.0, < 2.0)
|
36
|
-
rubocop-ast (0.
|
37
|
-
parser (>= 2.7.
|
47
|
+
rubocop-ast (0.3.0)
|
48
|
+
parser (>= 2.7.1.4)
|
49
|
+
rubocop-minitest (0.10.1)
|
50
|
+
rubocop (>= 0.87)
|
38
51
|
rubocop-performance (1.7.1)
|
39
52
|
rubocop (>= 0.82.0)
|
40
53
|
rubocop-sensible (0.3.0)
|
@@ -49,20 +62,26 @@ GEM
|
|
49
62
|
term-ansicolor (1.7.1)
|
50
63
|
tins (~> 1.0)
|
51
64
|
thor (1.0.1)
|
65
|
+
thread_safe (0.3.6)
|
52
66
|
tins (1.25.0)
|
53
67
|
sync
|
68
|
+
tzinfo (1.2.7)
|
69
|
+
thread_safe (~> 0.1)
|
54
70
|
unicode-display_width (1.7.0)
|
71
|
+
zeitwerk (2.4.0)
|
55
72
|
|
56
73
|
PLATFORMS
|
57
74
|
ruby
|
58
75
|
|
59
76
|
DEPENDENCIES
|
77
|
+
activesupport
|
60
78
|
alba!
|
61
79
|
coveralls
|
62
80
|
minitest (~> 5.0)
|
63
81
|
oj (~> 3.10)
|
64
82
|
rake (~> 13.0)
|
65
83
|
rubocop (>= 0.79.0)
|
84
|
+
rubocop-minitest (~> 0.10.1)
|
66
85
|
rubocop-performance (~> 1.7.1)
|
67
86
|
rubocop-sensible (~> 0.3.0)
|
68
87
|
|
data/README.md
CHANGED
@@ -1,10 +1,27 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/alba.svg)](https://badge.fury.io/rb/alba)
|
1
2
|
[![Build Status](https://travis-ci.com/okuramasafumi/alba.svg?branch=master)](https://travis-ci.com/okuramasafumi/alba)
|
2
3
|
[![Coverage Status](https://coveralls.io/repos/github/okuramasafumi/alba/badge.svg?branch=master)](https://coveralls.io/github/okuramasafumi/alba?branch=master)
|
3
4
|
[![Maintainability](https://api.codeclimate.com/v1/badges/fdab4cc0de0b9addcfe8/maintainability)](https://codeclimate.com/github/okuramasafumi/alba/maintainability)
|
4
5
|
|
5
6
|
# Alba
|
6
7
|
|
7
|
-
`Alba` is
|
8
|
+
`Alba` is the fastest JSON serializer for Ruby.
|
9
|
+
|
10
|
+
# Why yet another JSON serializer?
|
11
|
+
|
12
|
+
We know that there are several other JSON serializers for Ruby around, but none of them made us satisfied.
|
13
|
+
|
14
|
+
Alba has some advantages over other JSON serializers which we've wanted to have.
|
15
|
+
|
16
|
+
## Easy to understand
|
17
|
+
|
18
|
+
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.
|
19
|
+
|
20
|
+
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!
|
21
|
+
|
22
|
+
## Performance
|
23
|
+
|
24
|
+
Alba is faster than most of the alternatives. We have a [benchmark](https://gist.github.com/okuramasafumi/4e375525bd3a28e4ca812d2a3b3e5829).
|
8
25
|
|
9
26
|
## Installation
|
10
27
|
|
@@ -22,8 +39,30 @@ Or install it yourself as:
|
|
22
39
|
|
23
40
|
$ gem install alba
|
24
41
|
|
42
|
+
## Supported Ruby versions
|
43
|
+
|
44
|
+
Alba supports CRuby 2.5.7 and higher and latest TruffleRuby.
|
45
|
+
|
25
46
|
## Usage
|
26
47
|
|
48
|
+
### Configuration
|
49
|
+
|
50
|
+
Alba's configuration is fairly simple.
|
51
|
+
|
52
|
+
#### Backend
|
53
|
+
|
54
|
+
Backend is the actual part serializing an object into JSON. Alba supports these backends.
|
55
|
+
|
56
|
+
* Oj, the fastest. Gem installation required.
|
57
|
+
* active_support, mostly for Rails. Gem installation required.
|
58
|
+
* default or json, with no external dependencies.
|
59
|
+
|
60
|
+
You can set a backend like this:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
Alba.backend = :oj
|
64
|
+
```
|
65
|
+
|
27
66
|
### Simple serialization with key
|
28
67
|
|
29
68
|
```ruby
|
@@ -124,15 +163,65 @@ end
|
|
124
163
|
|
125
164
|
Although this might be useful sometimes, it's generally recommended to define a class for both Resource and Serializer.
|
126
165
|
|
166
|
+
### Inheritance and Ignorance
|
167
|
+
|
168
|
+
You can `exclude` or `ignore` certain attributes using `ignoring`.
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
class Foo
|
172
|
+
attr_accessor :id, :name, :body
|
173
|
+
|
174
|
+
def initialize(id, name, body)
|
175
|
+
@id = id
|
176
|
+
@name = name
|
177
|
+
@body = body
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
class GenericFooResource
|
182
|
+
include Alba::Resource
|
183
|
+
|
184
|
+
attributes :id, :name, :body
|
185
|
+
end
|
186
|
+
|
187
|
+
class RestrictedFooResouce < GenericFooResource
|
188
|
+
ignoring :id, :body
|
189
|
+
end
|
190
|
+
|
191
|
+
RestrictedFooResouce.new(foo).serialize
|
192
|
+
# => '{"name":"my foo"}'
|
193
|
+
end
|
194
|
+
```
|
195
|
+
|
127
196
|
## Comparison
|
128
197
|
|
129
|
-
|
198
|
+
Alba is faster than alternatives.
|
130
199
|
For a performance benchmark, see https://gist.github.com/okuramasafumi/4e375525bd3a28e4ca812d2a3b3e5829.
|
131
200
|
|
201
|
+
## Rails
|
202
|
+
|
203
|
+
When you use Alba in Rails, you can create an initializer file with the line below for compatibility with Rails JSON encoder.
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
Alba.backend = :active_support
|
207
|
+
```
|
208
|
+
|
132
209
|
## Why named "Alba"?
|
133
210
|
|
134
211
|
The name "Alba" comes from "albatross", a kind of birds. In Japanese, this bird is called "Aho-dori", which means "stupid bird". I find it funny because in fact albatrosses fly really fast. I hope Alba looks stupid but in fact it does its job quick.
|
135
212
|
|
213
|
+
## Alba internals
|
214
|
+
|
215
|
+
Alba has three component, `Serializer`, `Resource` and `Value` (`Value` is conceptual and not implemented directly).
|
216
|
+
|
217
|
+
`Serializer` is a component responsible for rendering JSON output with `Resource`. `Serializer` can add more data to `Resource` such as `metadata`. Users can define one single `Serializer` and reuse it for all `Resource`s. The main interface is `#serialize`.
|
218
|
+
|
219
|
+
`Resource` is a component responsible for defining how an object (or a collection of objects) is converted into JSON. The difference between `Serializer` and `Resource` is that while `Serializer` can add arbitrary data into JSON, `Resource` can get data only from the object under it. The main interface is `#serializable_hash`.
|
220
|
+
|
221
|
+
`One` and `Many` are the special object fetching other resources and converting them into Hash.
|
222
|
+
|
223
|
+
The main `Alba` module holds config values and one convenience method, `.serialize`.
|
224
|
+
|
136
225
|
## Development
|
137
226
|
|
138
227
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/alba.gemspec
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
require_relative 'lib/alba/version'
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
|
-
spec.name =
|
4
|
+
spec.name = 'alba'
|
5
5
|
spec.version = Alba::VERSION
|
6
|
-
spec.authors = [
|
7
|
-
spec.email = [
|
6
|
+
spec.authors = ['OKURA Masafumi']
|
7
|
+
spec.email = ['masafumi.o1988@gmail.com']
|
8
8
|
|
9
|
-
spec.summary =
|
10
|
-
spec.description = "
|
11
|
-
spec.homepage =
|
12
|
-
spec.license =
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new(
|
9
|
+
spec.summary = 'Alba is the fastest JSON serializer for Ruby.'
|
10
|
+
spec.description = "Alba is designed to be a simple, easy to use and fast alternative to existing JSON serializers. Its performance is better than almost all gems which do similar things. The internal is so simple that it's easy to hack and maintain."
|
11
|
+
spec.homepage = 'https://github.com/okuramasafumi/alba'
|
12
|
+
spec.license = 'MIT'
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.5.7')
|
14
14
|
|
15
|
-
spec.metadata[
|
16
|
-
spec.metadata[
|
17
|
-
spec.metadata[
|
15
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
16
|
+
spec.metadata['source_code_uri'] = 'https://github.com/okuramasafumi/alba'
|
17
|
+
spec.metadata['changelog_uri'] = 'https://github.com/okuramasafumi/alba/CHANGELOG.md'
|
18
18
|
|
19
19
|
# Specify which files should be added to the gem when it is released.
|
20
20
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
-
spec.files
|
21
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
22
22
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
23
|
end
|
24
|
-
spec.bindir =
|
24
|
+
spec.bindir = 'exe'
|
25
25
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
-
spec.require_paths = [
|
26
|
+
spec.require_paths = ['lib']
|
27
27
|
end
|
data/lib/alba.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
require 'alba/version'
|
2
|
-
require 'alba/serializers/default_serializer'
|
3
2
|
require 'alba/serializer'
|
4
3
|
require 'alba/resource'
|
5
|
-
require 'alba/resources/default_resource'
|
6
4
|
|
7
5
|
# Core module
|
8
6
|
module Alba
|
9
7
|
class Error < StandardError; end
|
8
|
+
class UnsupportedBackend < Error; end
|
10
9
|
|
11
10
|
class << self
|
12
|
-
attr_reader :backend
|
11
|
+
attr_reader :backend, :encoder
|
13
12
|
attr_accessor :default_serializer
|
14
13
|
|
15
14
|
def backend=(backend)
|
16
15
|
@backend = backend&.to_sym
|
16
|
+
set_encoder
|
17
17
|
end
|
18
18
|
|
19
19
|
def serialize(object, with: nil, &block)
|
@@ -27,8 +27,47 @@ module Alba
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
+
def set_encoder
|
31
|
+
@encoder = case @backend
|
32
|
+
when :oj
|
33
|
+
try_oj
|
34
|
+
when :active_support
|
35
|
+
try_active_support
|
36
|
+
when nil, :default, :json
|
37
|
+
default_encoder
|
38
|
+
else
|
39
|
+
raise Alba::UnsupportedBackend, "Unsupported backend, #{backend}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def try_oj
|
44
|
+
require 'oj'
|
45
|
+
->(hash) { Oj.dump(hash, mode: :strict) }
|
46
|
+
rescue LoadError
|
47
|
+
default_encoder
|
48
|
+
end
|
49
|
+
|
50
|
+
def try_active_support
|
51
|
+
require 'active_support/json'
|
52
|
+
->(hash) { ActiveSupport::JSON.encode(hash) }
|
53
|
+
rescue LoadError
|
54
|
+
default_encoder
|
55
|
+
end
|
56
|
+
|
57
|
+
def default_encoder
|
58
|
+
lambda do |hash|
|
59
|
+
require 'json'
|
60
|
+
JSON.dump(hash)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
30
64
|
def resource_class
|
31
|
-
|
65
|
+
@resource_class ||= begin
|
66
|
+
klass = Class.new
|
67
|
+
klass.include(Alba::Resource)
|
68
|
+
end
|
32
69
|
end
|
33
70
|
end
|
71
|
+
|
72
|
+
@encoder = default_encoder
|
34
73
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Alba
|
2
|
+
# Base class for `One` and `Many`
|
3
|
+
# Child class should implement `to_hash` method
|
4
|
+
class Association
|
5
|
+
def initialize(name:, condition: nil, resource: nil, &block)
|
6
|
+
@name = name
|
7
|
+
@condition = condition
|
8
|
+
@block = block
|
9
|
+
@resource = resource || resource_class
|
10
|
+
raise ArgumentError, 'resource or block is required' if @resource.nil? && @block.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_hash
|
14
|
+
:not_implemented
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def resource_class
|
20
|
+
klass = Class.new
|
21
|
+
klass.include(Alba::Resource)
|
22
|
+
klass.class_eval(&@block)
|
23
|
+
klass
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/alba/many.rb
CHANGED
@@ -1,26 +1,12 @@
|
|
1
|
+
require 'alba/association'
|
2
|
+
|
1
3
|
module Alba
|
2
4
|
# Representing many association
|
3
|
-
class Many
|
4
|
-
def
|
5
|
-
@name = name
|
6
|
-
@resource = resource
|
7
|
-
@block = block
|
8
|
-
raise ArgumentError, 'resource or block is required' if @resource.nil? && @block.nil?
|
9
|
-
end
|
10
|
-
|
11
|
-
def to_hash(target)
|
5
|
+
class Many < Association
|
6
|
+
def to_hash(target, params: {})
|
12
7
|
objects = target.public_send(@name)
|
13
|
-
@
|
14
|
-
objects.map { |o| @resource.new(o).to_hash }
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def resource_class
|
20
|
-
klass = Class.new
|
21
|
-
klass.include(::Alba::Resource)
|
22
|
-
klass.class_exec(&@block)
|
23
|
-
klass
|
8
|
+
objects = @condition.call(objects) if @condition
|
9
|
+
objects.map { |o| @resource.new(o, params: params).to_hash }
|
24
10
|
end
|
25
11
|
end
|
26
12
|
end
|
data/lib/alba/one.rb
CHANGED
@@ -1,26 +1,12 @@
|
|
1
|
+
require 'alba/association'
|
2
|
+
|
1
3
|
module Alba
|
2
4
|
# Representing one association
|
3
|
-
class One
|
4
|
-
def
|
5
|
-
@name = name
|
6
|
-
@resource = resource
|
7
|
-
@block = block
|
8
|
-
raise ArgumentError, 'resource or block is required' if @resource.nil? && @block.nil?
|
9
|
-
end
|
10
|
-
|
11
|
-
def to_hash(target)
|
5
|
+
class One < Association
|
6
|
+
def to_hash(target, params: {})
|
12
7
|
object = target.public_send(@name)
|
13
|
-
@
|
14
|
-
@resource.new(object).to_hash
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def resource_class
|
20
|
-
klass = Class.new
|
21
|
-
klass.include(::Alba::Resource)
|
22
|
-
klass.class_exec(&@block)
|
23
|
-
klass
|
8
|
+
object = @condition.call(object) if @condition
|
9
|
+
@resource.new(object, params: params).to_hash
|
24
10
|
end
|
25
11
|
end
|
26
12
|
end
|
data/lib/alba/resource.rb
CHANGED
@@ -1,24 +1,17 @@
|
|
1
1
|
require 'alba/serializer'
|
2
|
-
require 'alba/attribute'
|
3
2
|
require 'alba/one'
|
4
3
|
require 'alba/many'
|
5
|
-
require 'alba/serializers/default_serializer'
|
6
4
|
|
7
5
|
module Alba
|
8
6
|
# This module represents what should be serialized
|
9
7
|
module Resource
|
10
|
-
DSLS =
|
8
|
+
DSLS = {_attributes: {}, _serializer: nil, _key: nil}.freeze
|
11
9
|
def self.included(base)
|
10
|
+
super
|
12
11
|
base.class_eval do
|
13
12
|
# Initialize
|
14
|
-
DSLS.each do |name|
|
15
|
-
initial
|
16
|
-
when :_attributes
|
17
|
-
{}
|
18
|
-
when :_serializer, :_name
|
19
|
-
nil
|
20
|
-
end
|
21
|
-
instance_variable_set("@#{name}", initial) unless instance_variable_defined?("@#{name}")
|
13
|
+
DSLS.each do |name, initial|
|
14
|
+
instance_variable_set("@#{name}", initial.dup) unless instance_variable_defined?("@#{name}")
|
22
15
|
end
|
23
16
|
end
|
24
17
|
base.include InstanceMethods
|
@@ -27,15 +20,18 @@ module Alba
|
|
27
20
|
|
28
21
|
# Instance methods
|
29
22
|
module InstanceMethods
|
30
|
-
|
31
|
-
|
32
|
-
|
23
|
+
attr_reader :object, :_key, :params
|
24
|
+
|
25
|
+
def initialize(object, params: {})
|
26
|
+
@object = object
|
27
|
+
@params = params
|
28
|
+
DSLS.each_key { |name| instance_variable_set("@#{name}", self.class.public_send(name)) }
|
33
29
|
end
|
34
30
|
|
35
31
|
def serialize(with: nil)
|
36
32
|
serializer = case with
|
37
33
|
when nil
|
38
|
-
@_serializer ||
|
34
|
+
@_serializer || empty_serializer
|
39
35
|
when ->(obj) { obj.is_a?(Class) && obj <= Alba::Serializer }
|
40
36
|
with
|
41
37
|
when Proc
|
@@ -46,11 +42,8 @@ module Alba
|
|
46
42
|
serializer.new(self).serialize
|
47
43
|
end
|
48
44
|
|
49
|
-
def serializable_hash
|
50
|
-
|
51
|
-
attribute.to_hash(@_resource)
|
52
|
-
end
|
53
|
-
with_key && @_key ? {@_key => serializable_hash} : serializable_hash
|
45
|
+
def serializable_hash
|
46
|
+
collection? ? @object.map(&converter) : converter.call(@object)
|
54
47
|
end
|
55
48
|
alias to_hash serializable_hash
|
56
49
|
|
@@ -60,37 +53,65 @@ module Alba
|
|
60
53
|
|
61
54
|
private
|
62
55
|
|
56
|
+
def converter
|
57
|
+
lambda do |resource|
|
58
|
+
@_attributes.transform_values do |attribute|
|
59
|
+
case attribute
|
60
|
+
when Symbol
|
61
|
+
resource.public_send attribute
|
62
|
+
when Proc
|
63
|
+
instance_exec(resource, &attribute)
|
64
|
+
when Alba::One, Alba::Many
|
65
|
+
attribute.to_hash(resource, params: params)
|
66
|
+
else
|
67
|
+
raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def empty_serializer
|
74
|
+
klass = Class.new
|
75
|
+
klass.include Alba::Serializer
|
76
|
+
klass
|
77
|
+
end
|
78
|
+
|
63
79
|
def inline_extended_serializer(with)
|
64
|
-
klass =
|
80
|
+
klass = empty_serializer
|
65
81
|
klass.class_eval(&with)
|
66
82
|
klass
|
67
83
|
end
|
84
|
+
|
85
|
+
def collection?
|
86
|
+
@object.is_a?(Enumerable)
|
87
|
+
end
|
68
88
|
end
|
69
89
|
|
70
90
|
# Class methods
|
71
91
|
module ClassMethods
|
72
|
-
|
92
|
+
attr_reader(*DSLS.keys)
|
73
93
|
|
74
94
|
def inherited(subclass)
|
75
|
-
|
95
|
+
super
|
96
|
+
DSLS.each_key { |name| subclass.instance_variable_set("@#{name}", instance_variable_get("@#{name}").clone) }
|
76
97
|
end
|
77
98
|
|
78
99
|
def attributes(*attrs)
|
79
|
-
attrs.each { |attr_name| @_attributes[attr_name] =
|
100
|
+
attrs.each { |attr_name| @_attributes[attr_name.to_sym] = attr_name.to_sym }
|
80
101
|
end
|
81
102
|
|
82
103
|
def attribute(name, &block)
|
83
104
|
raise ArgumentError, 'No block given in attribute method' unless block
|
84
105
|
|
85
|
-
@_attributes[name] =
|
106
|
+
@_attributes[name.to_sym] = block
|
86
107
|
end
|
87
108
|
|
88
|
-
def one(name, resource: nil, &block)
|
89
|
-
@_attributes[name.to_sym] = One.new(name: name, resource: resource, &block)
|
109
|
+
def one(name, condition = nil, resource: nil, key: nil, &block)
|
110
|
+
@_attributes[key&.to_sym || name.to_sym] = One.new(name: name, condition: condition, resource: resource, &block)
|
90
111
|
end
|
91
112
|
|
92
|
-
def many(name, resource: nil, &block)
|
93
|
-
@_attributes[name.to_sym] = Many.new(name: name, resource: resource, &block)
|
113
|
+
def many(name, condition = nil, resource: nil, key: nil, &block)
|
114
|
+
@_attributes[key&.to_sym || name.to_sym] = Many.new(name: name, condition: condition, resource: resource, &block)
|
94
115
|
end
|
95
116
|
|
96
117
|
def serializer(name)
|
@@ -100,6 +121,13 @@ module Alba
|
|
100
121
|
def key(key)
|
101
122
|
@_key = key.to_sym
|
102
123
|
end
|
124
|
+
|
125
|
+
# Use this DSL in child class to ignore certain attributes
|
126
|
+
def ignoring(*attributes)
|
127
|
+
attributes.each do |attr_name|
|
128
|
+
@_attributes.delete(attr_name.to_sym)
|
129
|
+
end
|
130
|
+
end
|
103
131
|
end
|
104
132
|
end
|
105
133
|
end
|
data/lib/alba/serializer.rb
CHANGED
@@ -2,6 +2,11 @@ module Alba
|
|
2
2
|
# This module represents how a resource should be serialized.
|
3
3
|
module Serializer
|
4
4
|
def self.included(base)
|
5
|
+
super
|
6
|
+
base.class_eval do
|
7
|
+
@_opts = {} unless instance_variable_defined?('@_opts')
|
8
|
+
@_metadata = {} unless instance_variable_defined?('@_metadata')
|
9
|
+
end
|
5
10
|
base.include InstanceMethods
|
6
11
|
base.extend ClassMethods
|
7
12
|
end
|
@@ -9,44 +14,46 @@ module Alba
|
|
9
14
|
# Instance methods
|
10
15
|
module InstanceMethods
|
11
16
|
def initialize(resource)
|
12
|
-
@
|
13
|
-
|
14
|
-
when true
|
15
|
-
resource.key
|
16
|
-
else
|
17
|
-
@_opts[:key]
|
18
|
-
end
|
19
|
-
@hash = resource.serializable_hash(with_key: false)
|
17
|
+
@resource = resource
|
18
|
+
@hash = resource.serializable_hash
|
20
19
|
@hash = {key.to_sym => @hash} if key
|
20
|
+
# @hash is either Hash or Array
|
21
|
+
@hash.is_a?(Hash) ? @hash.merge!(metadata.to_h) : @hash << metadata
|
21
22
|
end
|
22
23
|
|
23
24
|
def serialize
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
fallback
|
38
|
-
end.call
|
25
|
+
Alba.encoder.call(@hash)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def key
|
31
|
+
opts = self.class._opts
|
32
|
+
opts[:key] == true ? @resource.key : opts[:key]
|
33
|
+
end
|
34
|
+
|
35
|
+
def metadata
|
36
|
+
metadata = self.class._metadata
|
37
|
+
metadata.transform_values { |block| block.call(@resource.object) }
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
42
41
|
# Class methods
|
43
42
|
module ClassMethods
|
44
|
-
attr_reader :_opts
|
43
|
+
attr_reader :_opts, :_metadata
|
44
|
+
|
45
|
+
def inherited(subclass)
|
46
|
+
super
|
47
|
+
%w[_opts _metadata].each { |name| subclass.instance_variable_set("@#{name}", public_send(name).clone) }
|
48
|
+
end
|
45
49
|
|
46
50
|
def set(key: false)
|
47
|
-
@_opts ||= {}
|
48
51
|
@_opts[:key] = key
|
49
52
|
end
|
53
|
+
|
54
|
+
def metadata(name, &block)
|
55
|
+
@_metadata[name] = block
|
56
|
+
end
|
50
57
|
end
|
51
58
|
end
|
52
59
|
end
|
data/lib/alba/version.rb
CHANGED
data/sider.yml
CHANGED
metadata
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alba
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- OKURA Masafumi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
13
|
+
description: Alba is designed to be a simple, easy to use and fast alternative to
|
14
|
+
existing JSON serializers. Its performance is better than almost all gems which
|
15
|
+
do similar things. The internal is so simple that it's easy to hack and maintain.
|
14
16
|
email:
|
15
17
|
- masafumi.o1988@gmail.com
|
16
18
|
executables: []
|
@@ -30,13 +32,11 @@ files:
|
|
30
32
|
- bin/console
|
31
33
|
- bin/setup
|
32
34
|
- lib/alba.rb
|
33
|
-
- lib/alba/
|
35
|
+
- lib/alba/association.rb
|
34
36
|
- lib/alba/many.rb
|
35
37
|
- lib/alba/one.rb
|
36
38
|
- lib/alba/resource.rb
|
37
|
-
- lib/alba/resources/default_resource.rb
|
38
39
|
- lib/alba/serializer.rb
|
39
|
-
- lib/alba/serializers/default_serializer.rb
|
40
40
|
- lib/alba/version.rb
|
41
41
|
- sider.yml
|
42
42
|
homepage: https://github.com/okuramasafumi/alba
|
@@ -54,7 +54,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
54
|
requirements:
|
55
55
|
- - ">="
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: 2.
|
57
|
+
version: 2.5.7
|
58
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
60
|
- - ">="
|
@@ -64,5 +64,5 @@ requirements: []
|
|
64
64
|
rubygems_version: 3.1.4
|
65
65
|
signing_key:
|
66
66
|
specification_version: 4
|
67
|
-
summary:
|
67
|
+
summary: Alba is the fastest JSON serializer for Ruby.
|
68
68
|
test_files: []
|
data/lib/alba/attribute.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Alba
|
2
|
-
# This class represents an attribute, which is serialized
|
3
|
-
# by either sending message or calling a Proc.
|
4
|
-
class Attribute
|
5
|
-
def initialize(name:, method:)
|
6
|
-
@name = name
|
7
|
-
@method = method
|
8
|
-
end
|
9
|
-
|
10
|
-
def to_hash(target)
|
11
|
-
case @method
|
12
|
-
when Symbol, String
|
13
|
-
target.public_send(@method)
|
14
|
-
when Proc
|
15
|
-
@method.arity.zero? ? target.instance_exec(&@method) : @method.call(target)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'alba/serializer'
|
2
|
-
|
3
|
-
module Alba
|
4
|
-
module Serializers
|
5
|
-
# DefaultSerializer class is used when a user doesn't specify serializer opt.
|
6
|
-
# It's basically an alias of Alba::Serializer, but since it's a module this class simply include it.
|
7
|
-
class DefaultSerializer
|
8
|
-
include Alba::Serializer
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|