alba 0.5.0 → 0.10.0
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 -6
- data/Gemfile.lock +26 -5
- data/README.md +87 -2
- data/alba.gemspec +14 -14
- data/lib/alba.rb +41 -1
- 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 -20
- data/lib/alba/resources/default_resource.rb +5 -1
- data/lib/alba/serializer.rb +30 -21
- data/lib/alba/version.rb +1 -1
- data/sider.yml +1 -0
- metadata +8 -6
- data/lib/alba/attribute.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8427c3365aa48ba76f97799757e5e32ae2f746d3b63c67d58e7c7ddadd17bae
|
4
|
+
data.tar.gz: c995206962d4a041032b76113a2f053e48f50f787af12c491437ff98c55d4d2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b513dea8cfa68bf09e76114c3d6e14bd77a381f94ad9342c8692034069240c114b9eac95bf071662905de14efe269ac606a7cb2b50ec4107fa393391ed5ddf9d
|
7
|
+
data.tar.gz: e44bc0f25be1342ea9424c3919c62cd40b1917eac62f6bf612cd7979ead6db5521200eae4d7ef9a795ee373145c4fb5c846886bc1869916fd744596ac57aecbc
|
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,9 +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
|
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', platforms: :ruby # 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.0)
|
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,8 +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)
|
29
|
+
oj (3.10.12)
|
30
|
+
bigdecimal (>= 1.0, < 3)
|
19
31
|
parallel (1.19.2)
|
20
32
|
parser (2.7.1.4)
|
21
33
|
ast (~> 2.4.1)
|
@@ -23,17 +35,19 @@ GEM
|
|
23
35
|
rake (13.0.1)
|
24
36
|
regexp_parser (1.7.1)
|
25
37
|
rexml (3.2.4)
|
26
|
-
rubocop (0.
|
38
|
+
rubocop (0.89.1)
|
27
39
|
parallel (~> 1.10)
|
28
40
|
parser (>= 2.7.1.1)
|
29
41
|
rainbow (>= 2.2.2, < 4.0)
|
30
42
|
regexp_parser (>= 1.7)
|
31
43
|
rexml
|
32
|
-
rubocop-ast (>= 0.
|
44
|
+
rubocop-ast (>= 0.3.0, < 1.0)
|
33
45
|
ruby-progressbar (~> 1.7)
|
34
46
|
unicode-display_width (>= 1.4.0, < 2.0)
|
35
|
-
rubocop-ast (0.
|
36
|
-
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)
|
37
51
|
rubocop-performance (1.7.1)
|
38
52
|
rubocop (>= 0.82.0)
|
39
53
|
rubocop-sensible (0.3.0)
|
@@ -48,19 +62,26 @@ GEM
|
|
48
62
|
term-ansicolor (1.7.1)
|
49
63
|
tins (~> 1.0)
|
50
64
|
thor (1.0.1)
|
65
|
+
thread_safe (0.3.6)
|
51
66
|
tins (1.25.0)
|
52
67
|
sync
|
68
|
+
tzinfo (1.2.7)
|
69
|
+
thread_safe (~> 0.1)
|
53
70
|
unicode-display_width (1.7.0)
|
71
|
+
zeitwerk (2.4.0)
|
54
72
|
|
55
73
|
PLATFORMS
|
56
74
|
ruby
|
57
75
|
|
58
76
|
DEPENDENCIES
|
77
|
+
activesupport
|
59
78
|
alba!
|
60
79
|
coveralls
|
61
80
|
minitest (~> 5.0)
|
81
|
+
oj (~> 3.10)
|
62
82
|
rake (~> 13.0)
|
63
83
|
rubocop (>= 0.79.0)
|
84
|
+
rubocop-minitest (~> 0.10.1)
|
64
85
|
rubocop-performance (~> 1.7.1)
|
65
86
|
rubocop-sensible (~> 0.3.0)
|
66
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
|
|
@@ -24,6 +41,24 @@ Or install it yourself as:
|
|
24
41
|
|
25
42
|
## Usage
|
26
43
|
|
44
|
+
### Configuration
|
45
|
+
|
46
|
+
Alba's configuration is fairly simple.
|
47
|
+
|
48
|
+
#### Backend
|
49
|
+
|
50
|
+
Backend is the actual part serializing an object into JSON. Alba supports these backends.
|
51
|
+
|
52
|
+
* Oj, the fastest. Gem installation required.
|
53
|
+
* active_support, mostly for Rails. Gem installation required.
|
54
|
+
* default or json, with no external dependencies.
|
55
|
+
|
56
|
+
You can set a backend like this:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
Alba.backend = :oj
|
60
|
+
```
|
61
|
+
|
27
62
|
### Simple serialization with key
|
28
63
|
|
29
64
|
```ruby
|
@@ -124,15 +159,65 @@ end
|
|
124
159
|
|
125
160
|
Although this might be useful sometimes, it's generally recommended to define a class for both Resource and Serializer.
|
126
161
|
|
162
|
+
### Inheritance and Ignorance
|
163
|
+
|
164
|
+
You can `exclude` or `ignore` certain attributes using `ignoring`.
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
class Foo
|
168
|
+
attr_accessor :id, :name, :body
|
169
|
+
|
170
|
+
def initialize(id, name, body)
|
171
|
+
@id = id
|
172
|
+
@name = name
|
173
|
+
@body = body
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
class GenericFooResource
|
178
|
+
include Alba::Resource
|
179
|
+
|
180
|
+
attributes :id, :name, :body
|
181
|
+
end
|
182
|
+
|
183
|
+
class RestrictedFooResouce < GenericFooResource
|
184
|
+
ignoring :id, :body
|
185
|
+
end
|
186
|
+
|
187
|
+
RestrictedFooResouce.new(foo).serialize
|
188
|
+
# => '{"name":"my foo"}'
|
189
|
+
end
|
190
|
+
```
|
191
|
+
|
127
192
|
## Comparison
|
128
193
|
|
129
|
-
|
194
|
+
Alba is faster than alternatives.
|
130
195
|
For a performance benchmark, see https://gist.github.com/okuramasafumi/4e375525bd3a28e4ca812d2a3b3e5829.
|
131
196
|
|
197
|
+
## Rails
|
198
|
+
|
199
|
+
When you use Alba in Rails, you can create an initializer file with the line below for compatibility with Rails JSON encoder.
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
Alba.backend = :active_support
|
203
|
+
```
|
204
|
+
|
132
205
|
## Why named "Alba"?
|
133
206
|
|
134
207
|
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
208
|
|
209
|
+
## Alba internals
|
210
|
+
|
211
|
+
Alba has three component, `Serializer`, `Resource` and `Value` (`Value` is conceptual and not implemented directly).
|
212
|
+
|
213
|
+
`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`.
|
214
|
+
|
215
|
+
`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`.
|
216
|
+
|
217
|
+
`One` and `Many` are the special object fetching other resources and converting them into Hash.
|
218
|
+
|
219
|
+
The main `Alba` module holds config values and one convenience method, `.serialize`.
|
220
|
+
|
136
221
|
## Development
|
137
222
|
|
138
223
|
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.8')
|
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
@@ -7,12 +7,15 @@ require 'alba/resources/default_resource'
|
|
7
7
|
# Core module
|
8
8
|
module Alba
|
9
9
|
class Error < StandardError; end
|
10
|
+
class UnsupportedBackend < Error; end
|
10
11
|
|
11
12
|
class << self
|
12
|
-
attr_reader :backend
|
13
|
+
attr_reader :backend, :encoder
|
14
|
+
attr_accessor :default_serializer
|
13
15
|
|
14
16
|
def backend=(backend)
|
15
17
|
@backend = backend&.to_sym
|
18
|
+
set_encoder
|
16
19
|
end
|
17
20
|
|
18
21
|
def serialize(object, with: nil, &block)
|
@@ -20,13 +23,50 @@ module Alba
|
|
20
23
|
|
21
24
|
resource_class.class_eval(&block)
|
22
25
|
resource = resource_class.new(object)
|
26
|
+
with ||= @default_serializer
|
23
27
|
resource.serialize(with: with)
|
24
28
|
end
|
25
29
|
|
26
30
|
private
|
27
31
|
|
32
|
+
def set_encoder
|
33
|
+
@encoder = case @backend
|
34
|
+
when :oj
|
35
|
+
try_oj
|
36
|
+
when :active_support
|
37
|
+
try_active_support
|
38
|
+
when nil, :default, :json
|
39
|
+
default_encoder
|
40
|
+
else
|
41
|
+
raise Alba::UnsupportedBackend, "Unsupported backend, #{backend}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def try_oj
|
46
|
+
require 'oj'
|
47
|
+
->(hash) { Oj.dump(hash, mode: :strict) }
|
48
|
+
rescue LoadError
|
49
|
+
default_encoder
|
50
|
+
end
|
51
|
+
|
52
|
+
def try_active_support
|
53
|
+
require 'active_support/json'
|
54
|
+
->(hash) { ActiveSupport::JSON.encode(hash) }
|
55
|
+
rescue LoadError
|
56
|
+
default_encoder
|
57
|
+
end
|
58
|
+
|
59
|
+
def default_encoder
|
60
|
+
lambda do |hash|
|
61
|
+
require 'json'
|
62
|
+
JSON.dump(hash)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
28
66
|
def resource_class
|
29
67
|
::Alba::Resources::DefaultResource.clone
|
30
68
|
end
|
31
69
|
end
|
70
|
+
|
71
|
+
@encoder = default_encoder
|
32
72
|
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 = ::Alba::Resources::DefaultResource.dup
|
21
|
+
klass.reset
|
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,5 +1,4 @@
|
|
1
1
|
require 'alba/serializer'
|
2
|
-
require 'alba/attribute'
|
3
2
|
require 'alba/one'
|
4
3
|
require 'alba/many'
|
5
4
|
require 'alba/serializers/default_serializer'
|
@@ -7,13 +6,13 @@ require 'alba/serializers/default_serializer'
|
|
7
6
|
module Alba
|
8
7
|
# This module represents what should be serialized
|
9
8
|
module Resource
|
10
|
-
DSLS =
|
9
|
+
DSLS = {_attributes: {}, _serializer: nil, _key: nil}.freeze
|
11
10
|
def self.included(base)
|
11
|
+
super
|
12
12
|
base.class_eval do
|
13
13
|
# Initialize
|
14
|
-
DSLS.each do |name|
|
15
|
-
|
16
|
-
instance_variable_set("@#{name}", initial) unless instance_variable_defined?("@#{name}")
|
14
|
+
DSLS.each do |name, initial|
|
15
|
+
instance_variable_set("@#{name}", initial.dup) unless instance_variable_defined?("@#{name}")
|
17
16
|
end
|
18
17
|
end
|
19
18
|
base.include InstanceMethods
|
@@ -22,9 +21,12 @@ module Alba
|
|
22
21
|
|
23
22
|
# Instance methods
|
24
23
|
module InstanceMethods
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
attr_reader :object, :_key, :params
|
25
|
+
|
26
|
+
def initialize(object, params: {})
|
27
|
+
@object = object
|
28
|
+
@params = params
|
29
|
+
DSLS.each_key { |name| instance_variable_set("@#{name}", self.class.public_send(name)) }
|
28
30
|
end
|
29
31
|
|
30
32
|
def serialize(with: nil)
|
@@ -38,54 +40,89 @@ module Alba
|
|
38
40
|
else
|
39
41
|
raise ArgumentError, 'Unexpected type for with, possible types are Class or Proc'
|
40
42
|
end
|
41
|
-
serializer.new(
|
43
|
+
serializer.new(self).serialize
|
42
44
|
end
|
43
45
|
|
44
46
|
def serializable_hash
|
45
|
-
@
|
46
|
-
attribute.to_hash(@_resource)
|
47
|
-
end
|
47
|
+
collection? ? @object.map(&converter) : converter.call(@object)
|
48
48
|
end
|
49
49
|
alias to_hash serializable_hash
|
50
50
|
|
51
|
+
def key
|
52
|
+
@_key || self.class.name.delete_suffix('Resource').downcase.gsub(/:{2}/, '_').to_sym
|
53
|
+
end
|
54
|
+
|
51
55
|
private
|
52
56
|
|
57
|
+
def converter
|
58
|
+
lambda do |resource|
|
59
|
+
@_attributes.transform_values do |attribute|
|
60
|
+
case attribute
|
61
|
+
when Symbol
|
62
|
+
resource.public_send attribute
|
63
|
+
when Proc
|
64
|
+
instance_exec(resource, &attribute)
|
65
|
+
when Alba::One, Alba::Many
|
66
|
+
attribute.to_hash(resource, params: params)
|
67
|
+
else
|
68
|
+
raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
53
74
|
def inline_extended_serializer(with)
|
54
75
|
klass = ::Alba::Serializers::DefaultSerializer.clone
|
55
76
|
klass.class_eval(&with)
|
56
77
|
klass
|
57
78
|
end
|
79
|
+
|
80
|
+
def collection?
|
81
|
+
@object.is_a?(Enumerable)
|
82
|
+
end
|
58
83
|
end
|
59
84
|
|
60
85
|
# Class methods
|
61
86
|
module ClassMethods
|
62
|
-
|
87
|
+
attr_reader(*DSLS.keys)
|
63
88
|
|
64
89
|
def inherited(subclass)
|
65
|
-
|
90
|
+
super
|
91
|
+
DSLS.each_key { |name| subclass.instance_variable_set("@#{name}", instance_variable_get("@#{name}").clone) }
|
66
92
|
end
|
67
93
|
|
68
94
|
def attributes(*attrs)
|
69
|
-
attrs.each { |attr_name| @_attributes[attr_name] =
|
95
|
+
attrs.each { |attr_name| @_attributes[attr_name.to_sym] = attr_name.to_sym }
|
70
96
|
end
|
71
97
|
|
72
98
|
def attribute(name, &block)
|
73
99
|
raise ArgumentError, 'No block given in attribute method' unless block
|
74
100
|
|
75
|
-
@_attributes[name] =
|
101
|
+
@_attributes[name.to_sym] = block
|
76
102
|
end
|
77
103
|
|
78
|
-
def one(name, resource: nil, &block)
|
79
|
-
@_attributes[name.to_sym] = One.new(name: name, resource: resource, &block)
|
104
|
+
def one(name, condition = nil, resource: nil, key: nil, &block)
|
105
|
+
@_attributes[key&.to_sym || name.to_sym] = One.new(name: name, condition: condition, resource: resource, &block)
|
80
106
|
end
|
81
107
|
|
82
|
-
def many(name, resource: nil, &block)
|
83
|
-
@_attributes[name.to_sym] = Many.new(name: name, resource: resource, &block)
|
108
|
+
def many(name, condition = nil, resource: nil, key: nil, &block)
|
109
|
+
@_attributes[key&.to_sym || name.to_sym] = Many.new(name: name, condition: condition, resource: resource, &block)
|
84
110
|
end
|
85
111
|
|
86
112
|
def serializer(name)
|
87
113
|
@_serializer = name <= Alba::Serializer ? name : nil
|
88
114
|
end
|
115
|
+
|
116
|
+
def key(key)
|
117
|
+
@_key = key.to_sym
|
118
|
+
end
|
119
|
+
|
120
|
+
# Use this DSL in child class to ignore certain attributes
|
121
|
+
def ignoring(*attributes)
|
122
|
+
attributes.each do |attr_name|
|
123
|
+
@_attributes.delete(attr_name.to_sym)
|
124
|
+
end
|
125
|
+
end
|
89
126
|
end
|
90
127
|
end
|
91
128
|
end
|
data/lib/alba/serializer.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Alba
|
2
2
|
# This module represents how a resource should be serialized.
|
3
|
-
#
|
4
3
|
module Serializer
|
5
4
|
def self.included(base)
|
5
|
+
super
|
6
6
|
base.include InstanceMethods
|
7
7
|
base.extend ClassMethods
|
8
8
|
end
|
@@ -10,39 +10,48 @@ module Alba
|
|
10
10
|
# Instance methods
|
11
11
|
module InstanceMethods
|
12
12
|
def initialize(resource)
|
13
|
-
@
|
14
|
-
@
|
15
|
-
|
16
|
-
@
|
13
|
+
@resource = resource
|
14
|
+
@hash = resource.serializable_hash
|
15
|
+
@hash = {key.to_sym => @hash} if key
|
16
|
+
# @hash is either Hash or Array
|
17
|
+
@hash.is_a?(Hash) ? @hash.merge!(metadata.to_h) : @hash << metadata
|
17
18
|
end
|
18
19
|
|
19
20
|
def serialize
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
fallback
|
34
|
-
end.call
|
21
|
+
Alba.encoder.call(@hash)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def key
|
27
|
+
opts = self.class._opts || {}
|
28
|
+
opts[:key] == true ? @resource.key : opts[:key]
|
29
|
+
end
|
30
|
+
|
31
|
+
def metadata
|
32
|
+
metadata = self.class._metadata || {}
|
33
|
+
metadata.transform_values { |block| block.call(@resource.object) }
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
37
|
# Class methods
|
39
38
|
module ClassMethods
|
40
|
-
attr_reader :_opts
|
39
|
+
attr_reader :_opts, :_metadata
|
40
|
+
|
41
|
+
def inherited(subclass)
|
42
|
+
super
|
43
|
+
%w[_opts _metadata].each { |name| subclass.instance_variable_set("@#{name}", instance_variable_get("@#{name}")) }
|
44
|
+
end
|
41
45
|
|
42
46
|
def set(key: false)
|
43
47
|
@_opts ||= {}
|
44
48
|
@_opts[:key] = key
|
45
49
|
end
|
50
|
+
|
51
|
+
def metadata(name, &block)
|
52
|
+
@_metadata ||= {}
|
53
|
+
@_metadata[name] = block
|
54
|
+
end
|
46
55
|
end
|
47
56
|
end
|
48
57
|
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.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: 2020-
|
11
|
+
date: 2020-08-23 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,7 +32,7 @@ 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
|
@@ -54,7 +56,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
56
|
requirements:
|
55
57
|
- - ">="
|
56
58
|
- !ruby/object:Gem::Version
|
57
|
-
version: 2.
|
59
|
+
version: 2.5.8
|
58
60
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
61
|
requirements:
|
60
62
|
- - ">="
|
@@ -64,5 +66,5 @@ requirements: []
|
|
64
66
|
rubygems_version: 3.1.4
|
65
67
|
signing_key:
|
66
68
|
specification_version: 4
|
67
|
-
summary:
|
69
|
+
summary: Alba is the fastest JSON serializer for Ruby.
|
68
70
|
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
|