alba 0.4.0 → 0.9.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 +5 -5
- data/.travis.yml +4 -1
- data/Gemfile +3 -0
- data/Gemfile.lock +24 -5
- data/README.md +87 -2
- data/alba.gemspec +14 -14
- data/lib/alba.rb +53 -7
- data/lib/alba/association.rb +25 -0
- data/lib/alba/many.rb +3 -17
- data/lib/alba/one.rb +3 -17
- data/lib/alba/resource.rb +63 -20
- data/lib/alba/resources/default_resource.rb +13 -0
- data/lib/alba/serializer.rb +34 -20
- data/lib/alba/version.rb +1 -1
- data/sider.yml +1 -0
- metadata +9 -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: 3a92c56eee7615f823efc93ed7edb87ba6c47a4bcf8e8b11e48edfc62c380545
|
4
|
+
data.tar.gz: 310eca11a4a5a83287d3d87c1346c2436900bf1283e5642baa3878c69087812d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2fed0c44e90d2d876b2db635867741b3520a21c470acfb07a0218b7e0b627ce718edb1da964dfafdf0c79b3fe16bf7502a4fd873e998778c5307bd0c37d0c7c0
|
7
|
+
data.tar.gz: 334edc5389f1fceba2ee880a322f894ccb145533793a885777ac29c08c273b5dda9a31cf9885b493b6ec3fabcf859a1d1643ce37b848c225db66b658b36e3e34
|
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:
|
@@ -15,13 +16,12 @@ AllCops:
|
|
15
16
|
Layout/SpaceInsideHashLiteralBraces:
|
16
17
|
EnforcedStyle: no_space
|
17
18
|
|
19
|
+
Metrics/ClassLength:
|
20
|
+
Exclude:
|
21
|
+
- 'test/alba_test.rb'
|
22
|
+
|
18
23
|
Metrics/MethodLength:
|
19
24
|
Max: 20
|
20
25
|
|
21
|
-
Naming/PredicateName:
|
22
|
-
AllowedMethods:
|
23
|
-
- 'has_one'
|
24
|
-
- 'has_many'
|
25
|
-
|
26
26
|
Style/FrozenStringLiteralComment:
|
27
27
|
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 'activesupport', require: false
|
6
7
|
gem 'coveralls', require: false
|
7
8
|
gem 'minitest', '~> 5.0'
|
9
|
+
gem 'oj', '~> 3.10', platforms: :ruby
|
8
10
|
gem 'rake', '~> 13.0'
|
9
11
|
gem 'rubocop', '>= 0.79.0', require: false
|
12
|
+
gem 'rubocop-minitest', '~> 0.10.1', require: false
|
10
13
|
gem 'rubocop-performance', '~> 1.7.1', require: false
|
11
14
|
gem 'rubocop-sensible', '~> 0.3.0', require: false
|
data/Gemfile.lock
CHANGED
@@ -1,12 +1,19 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
alba (0.
|
4
|
+
alba (0.9.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
|
+
concurrent-ruby (1.1.6)
|
10
17
|
coveralls (0.8.23)
|
11
18
|
json (>= 1.8, < 3)
|
12
19
|
simplecov (~> 0.16.1)
|
@@ -14,8 +21,11 @@ GEM
|
|
14
21
|
thor (>= 0.19.4, < 2.0)
|
15
22
|
tins (~> 1.6)
|
16
23
|
docile (1.3.2)
|
24
|
+
i18n (1.8.5)
|
25
|
+
concurrent-ruby (~> 1.0)
|
17
26
|
json (2.3.1)
|
18
27
|
minitest (5.14.1)
|
28
|
+
oj (3.10.8)
|
19
29
|
parallel (1.19.2)
|
20
30
|
parser (2.7.1.4)
|
21
31
|
ast (~> 2.4.1)
|
@@ -23,17 +33,19 @@ GEM
|
|
23
33
|
rake (13.0.1)
|
24
34
|
regexp_parser (1.7.1)
|
25
35
|
rexml (3.2.4)
|
26
|
-
rubocop (0.
|
36
|
+
rubocop (0.89.1)
|
27
37
|
parallel (~> 1.10)
|
28
38
|
parser (>= 2.7.1.1)
|
29
39
|
rainbow (>= 2.2.2, < 4.0)
|
30
40
|
regexp_parser (>= 1.7)
|
31
41
|
rexml
|
32
|
-
rubocop-ast (>= 0.
|
42
|
+
rubocop-ast (>= 0.3.0, < 1.0)
|
33
43
|
ruby-progressbar (~> 1.7)
|
34
44
|
unicode-display_width (>= 1.4.0, < 2.0)
|
35
|
-
rubocop-ast (0.
|
36
|
-
parser (>= 2.7.
|
45
|
+
rubocop-ast (0.3.0)
|
46
|
+
parser (>= 2.7.1.4)
|
47
|
+
rubocop-minitest (0.10.1)
|
48
|
+
rubocop (>= 0.87)
|
37
49
|
rubocop-performance (1.7.1)
|
38
50
|
rubocop (>= 0.82.0)
|
39
51
|
rubocop-sensible (0.3.0)
|
@@ -48,19 +60,26 @@ GEM
|
|
48
60
|
term-ansicolor (1.7.1)
|
49
61
|
tins (~> 1.0)
|
50
62
|
thor (1.0.1)
|
63
|
+
thread_safe (0.3.6)
|
51
64
|
tins (1.25.0)
|
52
65
|
sync
|
66
|
+
tzinfo (1.2.7)
|
67
|
+
thread_safe (~> 0.1)
|
53
68
|
unicode-display_width (1.7.0)
|
69
|
+
zeitwerk (2.4.0)
|
54
70
|
|
55
71
|
PLATFORMS
|
56
72
|
ruby
|
57
73
|
|
58
74
|
DEPENDENCIES
|
75
|
+
activesupport
|
59
76
|
alba!
|
60
77
|
coveralls
|
61
78
|
minitest (~> 5.0)
|
79
|
+
oj (~> 3.10)
|
62
80
|
rake (~> 13.0)
|
63
81
|
rubocop (>= 0.79.0)
|
82
|
+
rubocop-minitest (~> 0.10.1)
|
64
83
|
rubocop-performance (~> 1.7.1)
|
65
84
|
rubocop-sensible (~> 0.3.0)
|
66
85
|
|
data/README.md
CHANGED
@@ -1,10 +1,11 @@
|
|
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.
|
8
9
|
|
9
10
|
## Installation
|
10
11
|
|
@@ -24,6 +25,24 @@ Or install it yourself as:
|
|
24
25
|
|
25
26
|
## Usage
|
26
27
|
|
28
|
+
### Configuration
|
29
|
+
|
30
|
+
Alba's configuration is fairly simple.
|
31
|
+
|
32
|
+
#### Backend
|
33
|
+
|
34
|
+
Backend is the actual part serializing an object into JSON. Alba supports these backends.
|
35
|
+
|
36
|
+
* Oj, the fastest. Gem installation required.
|
37
|
+
* active_support, mostly for Rails. Gem installation required.
|
38
|
+
* default or json, with no external dependencies.
|
39
|
+
|
40
|
+
You can set a backend like this:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
Alba.backend = :oj
|
44
|
+
```
|
45
|
+
|
27
46
|
### Simple serialization with key
|
28
47
|
|
29
48
|
```ruby
|
@@ -108,15 +127,81 @@ UserResource1.new(user).serialize
|
|
108
127
|
# => '{"id":1,"articles":[{"title":"Hello World!"},{"title":"Super nice"}]}'
|
109
128
|
```
|
110
129
|
|
130
|
+
### Inline definition with `Alba.serialize`
|
131
|
+
|
132
|
+
`Alba.serialize` method is a shortcut to define everything inline.
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
Alba.serialize(user, with: proc { set key: :foo }) do
|
136
|
+
attributes :id
|
137
|
+
many :articles do
|
138
|
+
attributes :title, :body
|
139
|
+
end
|
140
|
+
end
|
141
|
+
# => '{"foo":{"id":1,"articles":[{"title":"Hello World!","body":"Hello World!!!"},{"title":"Super nice","body":"Really nice!"}]}}'
|
142
|
+
```
|
143
|
+
|
144
|
+
Although this might be useful sometimes, it's generally recommended to define a class for both Resource and Serializer.
|
145
|
+
|
146
|
+
### Inheritance and Ignorance
|
147
|
+
|
148
|
+
You can `exclude` or `ignore` certain attributes using `ignoring`.
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
class Foo
|
152
|
+
attr_accessor :id, :name, :body
|
153
|
+
|
154
|
+
def initialize(id, name, body)
|
155
|
+
@id = id
|
156
|
+
@name = name
|
157
|
+
@body = body
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class GenericFooResource
|
162
|
+
include Alba::Resource
|
163
|
+
|
164
|
+
attributes :id, :name, :body
|
165
|
+
end
|
166
|
+
|
167
|
+
class RestrictedFooResouce < GenericFooResource
|
168
|
+
ignoring :id, :body
|
169
|
+
end
|
170
|
+
|
171
|
+
RestrictedFooResouce.new(foo).serialize
|
172
|
+
# => '{"name":"my foo"}'
|
173
|
+
end
|
174
|
+
```
|
175
|
+
|
111
176
|
## Comparison
|
112
177
|
|
113
|
-
|
178
|
+
Alba is faster than alternatives.
|
114
179
|
For a performance benchmark, see https://gist.github.com/okuramasafumi/4e375525bd3a28e4ca812d2a3b3e5829.
|
115
180
|
|
181
|
+
## Rails
|
182
|
+
|
183
|
+
When you use Alba in Rails, you can create an initializer file with the line below for compatibility with Rails JSON encoder.
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
Alba.backend = :active_support
|
187
|
+
```
|
188
|
+
|
116
189
|
## Why named "Alba"?
|
117
190
|
|
118
191
|
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.
|
119
192
|
|
193
|
+
## Alba internals
|
194
|
+
|
195
|
+
Alba has three component, `Serializer`, `Resource` and `Value` (`Value` is conceptual and not implemented directly).
|
196
|
+
|
197
|
+
`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`.
|
198
|
+
|
199
|
+
`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`.
|
200
|
+
|
201
|
+
`One` and `Many` are the special object fetching other resources and converting them into Hash.
|
202
|
+
|
203
|
+
The main `Alba` module holds config values and one convenience method, `.serialize`.
|
204
|
+
|
120
205
|
## Development
|
121
206
|
|
122
207
|
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
@@ -2,20 +2,66 @@ require 'alba/version'
|
|
2
2
|
require 'alba/serializers/default_serializer'
|
3
3
|
require 'alba/serializer'
|
4
4
|
require 'alba/resource'
|
5
|
+
require 'alba/resources/default_resource'
|
5
6
|
|
6
7
|
# Core module
|
7
8
|
module Alba
|
8
9
|
class Error < StandardError; end
|
9
10
|
|
10
11
|
class << self
|
11
|
-
attr_reader :backend
|
12
|
-
|
12
|
+
attr_reader :backend, :encoder
|
13
|
+
attr_accessor :default_serializer
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
def backend=(backend)
|
16
|
+
@backend = backend&.to_sym
|
17
|
+
set_encoder
|
18
|
+
end
|
19
|
+
|
20
|
+
def serialize(object, with: nil, &block)
|
21
|
+
raise ArgumentError, 'Block required' unless block
|
22
|
+
|
23
|
+
resource_class.class_eval(&block)
|
24
|
+
resource = resource_class.new(object)
|
25
|
+
with ||= @default_serializer
|
26
|
+
resource.serialize(with: with)
|
27
|
+
end
|
17
28
|
|
18
|
-
|
19
|
-
|
29
|
+
private
|
30
|
+
|
31
|
+
def set_encoder
|
32
|
+
@encoder = case @backend
|
33
|
+
when :oj
|
34
|
+
begin
|
35
|
+
require 'oj'
|
36
|
+
->(hash) { Oj.dump(hash, mode: :strict) }
|
37
|
+
rescue LoadError
|
38
|
+
default_encoder
|
39
|
+
end
|
40
|
+
when :active_support
|
41
|
+
begin
|
42
|
+
require 'active_support/json'
|
43
|
+
->(hash) { ActiveSupport::JSON.encode(hash) }
|
44
|
+
rescue LoadError
|
45
|
+
default_encoder
|
46
|
+
end
|
47
|
+
when nil, :default, :json
|
48
|
+
default_encoder
|
49
|
+
else
|
50
|
+
raise Alba::Error, "Unsupported backend, #{backend}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_encoder
|
55
|
+
lambda do |hash|
|
56
|
+
require 'json'
|
57
|
+
JSON.dump(hash)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def resource_class
|
62
|
+
::Alba::Resources::DefaultResource.clone
|
63
|
+
end
|
20
64
|
end
|
65
|
+
|
66
|
+
@encoder = default_encoder
|
21
67
|
end
|
@@ -0,0 +1,25 @@
|
|
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:, resource: nil, &block)
|
6
|
+
@name = name
|
7
|
+
@resource = resource
|
8
|
+
@block = block
|
9
|
+
raise ArgumentError, 'resource or block is required' if @resource.nil? && @block.nil?
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_hash
|
13
|
+
:not_implemented
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def resource_class
|
19
|
+
klass = ::Alba::Resources::DefaultResource.dup
|
20
|
+
klass.reset
|
21
|
+
klass.class_eval(&@block)
|
22
|
+
klass
|
23
|
+
end
|
24
|
+
end
|
25
|
+
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 initialize(name:, resource: nil, &block)
|
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
|
-
|
5
|
+
class Many < Association
|
11
6
|
def to_hash(target)
|
12
7
|
objects = target.public_send(@name)
|
13
8
|
@resource ||= resource_class
|
14
9
|
objects.map { |o| @resource.new(o).to_hash }
|
15
10
|
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
|
24
|
-
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 initialize(name:, resource: nil, &block)
|
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
|
-
|
5
|
+
class One < Association
|
11
6
|
def to_hash(target)
|
12
7
|
object = target.public_send(@name)
|
13
8
|
@resource ||= resource_class
|
14
9
|
@resource.new(object).to_hash
|
15
10
|
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
|
24
|
-
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)
|
@@ -33,38 +35,68 @@ module Alba
|
|
33
35
|
@_serializer || Alba::Serializers::DefaultSerializer
|
34
36
|
when ->(obj) { obj.is_a?(Class) && obj <= Alba::Serializer }
|
35
37
|
with
|
36
|
-
when
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
when Proc
|
39
|
+
inline_extended_serializer(with)
|
40
|
+
else
|
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
|
+
|
51
|
+
def key
|
52
|
+
@_key || self.class.name.delete_suffix('Resource').downcase.gsub(/:{2}/, '_').to_sym
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
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)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def inline_extended_serializer(with)
|
73
|
+
klass = ::Alba::Serializers::DefaultSerializer.clone
|
74
|
+
klass.class_eval(&with)
|
75
|
+
klass
|
76
|
+
end
|
77
|
+
|
78
|
+
def collection?
|
79
|
+
@object.is_a?(Enumerable)
|
80
|
+
end
|
50
81
|
end
|
51
82
|
|
52
83
|
# Class methods
|
53
84
|
module ClassMethods
|
54
|
-
|
85
|
+
attr_reader(*DSLS.keys)
|
55
86
|
|
56
87
|
def inherited(subclass)
|
57
|
-
|
88
|
+
super
|
89
|
+
DSLS.each_key { |name| subclass.instance_variable_set("@#{name}", instance_variable_get("@#{name}").clone) }
|
58
90
|
end
|
59
91
|
|
60
92
|
def attributes(*attrs)
|
61
|
-
attrs.each { |attr_name| @_attributes[attr_name] =
|
93
|
+
attrs.each { |attr_name| @_attributes[attr_name] = attr_name }
|
62
94
|
end
|
63
95
|
|
64
96
|
def attribute(name, &block)
|
65
97
|
raise ArgumentError, 'No block given in attribute method' unless block
|
66
98
|
|
67
|
-
@_attributes[name] =
|
99
|
+
@_attributes[name] = block
|
68
100
|
end
|
69
101
|
|
70
102
|
def one(name, resource: nil, &block)
|
@@ -78,6 +110,17 @@ module Alba
|
|
78
110
|
def serializer(name)
|
79
111
|
@_serializer = name <= Alba::Serializer ? name : nil
|
80
112
|
end
|
113
|
+
|
114
|
+
def key(key)
|
115
|
+
@_key = key.to_sym
|
116
|
+
end
|
117
|
+
|
118
|
+
# Use this DSL in child class to ignore certain attributes
|
119
|
+
def ignoring(*attributes)
|
120
|
+
attributes.each do |attr_name|
|
121
|
+
@_attributes.delete(attr_name)
|
122
|
+
end
|
123
|
+
end
|
81
124
|
end
|
82
125
|
end
|
83
126
|
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,53 @@ 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
|
-
fallback
|
31
|
-
end
|
21
|
+
Alba.encoder.call(@hash)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def key
|
27
|
+
opts = self.class._opts || {}
|
28
|
+
case opts[:key]
|
29
|
+
when true
|
30
|
+
@resource.key
|
32
31
|
else
|
33
|
-
|
34
|
-
end
|
32
|
+
opts[:key]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def metadata
|
37
|
+
metadata = self.class._metadata || {}
|
38
|
+
metadata.transform_values { |block| block.call(@resource.object) }
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
38
42
|
# Class methods
|
39
43
|
module ClassMethods
|
40
|
-
attr_reader :_opts
|
44
|
+
attr_reader :_opts, :_metadata
|
45
|
+
|
46
|
+
def inherited(subclass)
|
47
|
+
super
|
48
|
+
%w[_opts _metadata].each { |name| subclass.instance_variable_set("@#{name}", instance_variable_get("@#{name}")) }
|
49
|
+
end
|
41
50
|
|
42
51
|
def set(key: false)
|
43
52
|
@_opts ||= {}
|
44
53
|
@_opts[:key] = key
|
45
54
|
end
|
55
|
+
|
56
|
+
def metadata(name, &block)
|
57
|
+
@_metadata ||= {}
|
58
|
+
@_metadata[name] = block
|
59
|
+
end
|
46
60
|
end
|
47
61
|
end
|
48
62
|
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.9.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-11 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,10 +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
|
39
|
+
- lib/alba/resources/default_resource.rb
|
37
40
|
- lib/alba/serializer.rb
|
38
41
|
- lib/alba/serializers/default_serializer.rb
|
39
42
|
- lib/alba/version.rb
|
@@ -53,7 +56,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
53
56
|
requirements:
|
54
57
|
- - ">="
|
55
58
|
- !ruby/object:Gem::Version
|
56
|
-
version: 2.
|
59
|
+
version: 2.5.8
|
57
60
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
61
|
requirements:
|
59
62
|
- - ">="
|
@@ -63,5 +66,5 @@ requirements: []
|
|
63
66
|
rubygems_version: 3.1.4
|
64
67
|
signing_key:
|
65
68
|
specification_version: 4
|
66
|
-
summary:
|
69
|
+
summary: Alba is the fastest JSON serializer for Ruby.
|
67
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
|