alba 0.9.0 → 0.12.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 +26 -1
- data/.travis.yml +1 -0
- data/.yardopts +2 -0
- data/Gemfile +11 -9
- data/Gemfile.lock +41 -36
- data/README.md +50 -2
- data/alba.gemspec +1 -1
- data/lib/alba.rb +41 -19
- data/lib/alba/association.rb +10 -4
- data/lib/alba/many.rb +9 -4
- data/lib/alba/one.rb +9 -4
- data/lib/alba/resource.rb +79 -21
- data/lib/alba/serializer.rb +28 -13
- data/lib/alba/version.rb +1 -1
- data/sider.yml +1 -0
- metadata +5 -6
- data/lib/alba/resources/default_resource.rb +0 -13
- 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: ee2f8d482fedb98083c2acab37b425c7ecedb429ab7bae7698b4eea7949635d9
|
4
|
+
data.tar.gz: 1a44f23d425072253ba6743e18c6da9d8fa81de448b58720848c4e9667b12bfb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9bf421fcd99f06cb56499ee31c88dda019e004c58a1880c03326f2a1ce395f7dc4b64be7cee012169c7039530194e85a312b3c53d964b1aaf5288cdf8cb78ae4
|
7
|
+
data.tar.gz: 02f20dd839f72f9d2c1859b48470595fff263939f41421e240d74452677edae2dc0569078823984144f630cbc2e6000b6ac3bd0d4161a9ef65bd95dbf311294f
|
data/.rubocop.yml
CHANGED
@@ -6,22 +6,47 @@ inherit_gem:
|
|
6
6
|
require:
|
7
7
|
- rubocop-minitest
|
8
8
|
- rubocop-performance
|
9
|
+
- rubocop-rake
|
9
10
|
|
10
11
|
AllCops:
|
11
12
|
Exclude:
|
12
13
|
- 'Rakefile'
|
13
14
|
- 'alba.gemspec'
|
14
15
|
NewCops: enable
|
16
|
+
EnabledByDefault: true
|
17
|
+
|
18
|
+
# Oneline comment is not valid so until it gets valid, we disable it
|
19
|
+
Bundler/GemComment:
|
20
|
+
Enabled: false
|
15
21
|
|
16
22
|
Layout/SpaceInsideHashLiteralBraces:
|
17
23
|
EnforcedStyle: no_space
|
18
24
|
|
25
|
+
Layout/MultilineAssignmentLayout:
|
26
|
+
EnforcedStyle: same_line
|
27
|
+
|
28
|
+
Lint/ConstantResolution:
|
29
|
+
Enabled: false
|
30
|
+
|
19
31
|
Metrics/ClassLength:
|
20
32
|
Exclude:
|
21
33
|
- 'test/alba_test.rb'
|
22
34
|
|
23
35
|
Metrics/MethodLength:
|
24
|
-
Max:
|
36
|
+
Max: 15
|
37
|
+
|
38
|
+
Style/ConstantVisibility:
|
39
|
+
Exclude:
|
40
|
+
- 'lib/alba/version.rb'
|
41
|
+
|
42
|
+
Style/Copyright:
|
43
|
+
Enabled: false
|
25
44
|
|
26
45
|
Style/FrozenStringLiteralComment:
|
27
46
|
Enabled: false
|
47
|
+
|
48
|
+
Style/InlineComment:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
Style/MethodCallWithArgsParentheses:
|
52
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/.yardopts
ADDED
data/Gemfile
CHANGED
@@ -3,12 +3,14 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in alba.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
gem 'activesupport', require: false
|
7
|
-
gem 'coveralls', require: false
|
8
|
-
gem 'minitest', '~> 5.
|
9
|
-
gem 'oj', '~> 3.
|
10
|
-
gem 'rake', '~> 13.0'
|
11
|
-
gem 'rubocop', '>= 0.79.0', require: false
|
12
|
-
gem 'rubocop-minitest', '~> 0.10.
|
13
|
-
gem 'rubocop-performance', '~> 1.
|
14
|
-
gem 'rubocop-
|
6
|
+
gem 'activesupport', require: false # For backend
|
7
|
+
gem 'coveralls', require: false # For test coverage
|
8
|
+
gem 'minitest', '~> 5.14' # For test
|
9
|
+
gem 'oj', '~> 3.11', 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.3', require: false # For lint
|
13
|
+
gem 'rubocop-performance', '~> 1.9.2', require: false # For lint
|
14
|
+
gem 'rubocop-rake', '>= 0.5.1', require: false # For lint
|
15
|
+
gem 'rubocop-sensible', '~> 0.3.0', require: false # For lint
|
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.
|
4
|
+
alba (0.12.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
activesupport (6.
|
9
|
+
activesupport (6.1.1)
|
10
10
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
-
i18n (>=
|
12
|
-
minitest (
|
13
|
-
tzinfo (~>
|
14
|
-
zeitwerk (~> 2.
|
11
|
+
i18n (>= 1.6, < 2)
|
12
|
+
minitest (>= 5.1)
|
13
|
+
tzinfo (~> 2.0)
|
14
|
+
zeitwerk (~> 2.3)
|
15
15
|
ast (2.4.1)
|
16
|
-
concurrent-ruby (1.1.
|
16
|
+
concurrent-ruby (1.1.7)
|
17
17
|
coveralls (0.8.23)
|
18
18
|
json (>= 1.8, < 3)
|
19
19
|
simplecov (~> 0.16.1)
|
@@ -21,36 +21,39 @@ GEM
|
|
21
21
|
thor (>= 0.19.4, < 2.0)
|
22
22
|
tins (~> 1.6)
|
23
23
|
docile (1.3.2)
|
24
|
-
i18n (1.8.
|
24
|
+
i18n (1.8.7)
|
25
25
|
concurrent-ruby (~> 1.0)
|
26
26
|
json (2.3.1)
|
27
|
-
minitest (5.14.
|
28
|
-
oj (3.
|
29
|
-
parallel (1.
|
30
|
-
parser (
|
27
|
+
minitest (5.14.3)
|
28
|
+
oj (3.11.0)
|
29
|
+
parallel (1.20.1)
|
30
|
+
parser (3.0.0.0)
|
31
31
|
ast (~> 2.4.1)
|
32
32
|
rainbow (3.0.0)
|
33
|
-
rake (13.0.
|
34
|
-
regexp_parser (
|
33
|
+
rake (13.0.3)
|
34
|
+
regexp_parser (2.0.3)
|
35
35
|
rexml (3.2.4)
|
36
|
-
rubocop (
|
36
|
+
rubocop (1.8.1)
|
37
37
|
parallel (~> 1.10)
|
38
|
-
parser (>=
|
38
|
+
parser (>= 3.0.0.0)
|
39
39
|
rainbow (>= 2.2.2, < 4.0)
|
40
|
-
regexp_parser (>= 1.
|
40
|
+
regexp_parser (>= 1.8, < 3.0)
|
41
41
|
rexml
|
42
|
-
rubocop-ast (>=
|
42
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
43
43
|
ruby-progressbar (~> 1.7)
|
44
|
-
unicode-display_width (>= 1.4.0, <
|
45
|
-
rubocop-ast (
|
46
|
-
parser (>= 2.7.1.
|
47
|
-
rubocop-minitest (0.10.
|
48
|
-
rubocop (>= 0.87)
|
49
|
-
rubocop-performance (1.
|
50
|
-
rubocop (>= 0.
|
44
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
45
|
+
rubocop-ast (1.4.0)
|
46
|
+
parser (>= 2.7.1.5)
|
47
|
+
rubocop-minitest (0.10.3)
|
48
|
+
rubocop (>= 0.87, < 2.0)
|
49
|
+
rubocop-performance (1.9.2)
|
50
|
+
rubocop (>= 0.90.0, < 2.0)
|
51
|
+
rubocop-ast (>= 0.4.0)
|
52
|
+
rubocop-rake (0.5.1)
|
53
|
+
rubocop
|
51
54
|
rubocop-sensible (0.3.0)
|
52
55
|
rubocop (>= 0.60.0)
|
53
|
-
ruby-progressbar (1.
|
56
|
+
ruby-progressbar (1.11.0)
|
54
57
|
simplecov (0.16.1)
|
55
58
|
docile (~> 1.1)
|
56
59
|
json (>= 1.8, < 3)
|
@@ -60,13 +63,13 @@ GEM
|
|
60
63
|
term-ansicolor (1.7.1)
|
61
64
|
tins (~> 1.0)
|
62
65
|
thor (1.0.1)
|
63
|
-
thread_safe (0.3.6)
|
64
66
|
tins (1.25.0)
|
65
67
|
sync
|
66
|
-
tzinfo (
|
67
|
-
|
68
|
-
unicode-display_width (
|
69
|
-
|
68
|
+
tzinfo (2.0.4)
|
69
|
+
concurrent-ruby (~> 1.0)
|
70
|
+
unicode-display_width (2.0.0)
|
71
|
+
yard (0.9.26)
|
72
|
+
zeitwerk (2.4.2)
|
70
73
|
|
71
74
|
PLATFORMS
|
72
75
|
ruby
|
@@ -75,13 +78,15 @@ DEPENDENCIES
|
|
75
78
|
activesupport
|
76
79
|
alba!
|
77
80
|
coveralls
|
78
|
-
minitest (~> 5.
|
79
|
-
oj (~> 3.
|
81
|
+
minitest (~> 5.14)
|
82
|
+
oj (~> 3.11)
|
80
83
|
rake (~> 13.0)
|
81
84
|
rubocop (>= 0.79.0)
|
82
|
-
rubocop-minitest (~> 0.10.
|
83
|
-
rubocop-performance (~> 1.
|
85
|
+
rubocop-minitest (~> 0.10.3)
|
86
|
+
rubocop-performance (~> 1.9.2)
|
87
|
+
rubocop-rake (>= 0.5.1)
|
84
88
|
rubocop-sensible (~> 0.3.0)
|
89
|
+
yard
|
85
90
|
|
86
91
|
BUNDLED WITH
|
87
|
-
2.
|
92
|
+
2.2.6
|
data/README.md
CHANGED
@@ -2,11 +2,29 @@
|
|
2
2
|
[![Build Status](https://travis-ci.com/okuramasafumi/alba.svg?branch=master)](https://travis-ci.com/okuramasafumi/alba)
|
3
3
|
[![Coverage Status](https://coveralls.io/repos/github/okuramasafumi/alba/badge.svg?branch=master)](https://coveralls.io/github/okuramasafumi/alba?branch=master)
|
4
4
|
[![Maintainability](https://api.codeclimate.com/v1/badges/fdab4cc0de0b9addcfe8/maintainability)](https://codeclimate.com/github/okuramasafumi/alba/maintainability)
|
5
|
+
![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/okuramasafumi/alba)
|
6
|
+
![GitHub](https://img.shields.io/github/license/okuramasafumi/alba)
|
5
7
|
|
6
8
|
# Alba
|
7
9
|
|
8
10
|
`Alba` is the fastest JSON serializer for Ruby.
|
9
11
|
|
12
|
+
## Why yet another JSON serializer?
|
13
|
+
|
14
|
+
We know that there are several other JSON serializers for Ruby around, but none of them made us satisfied.
|
15
|
+
|
16
|
+
Alba has some advantages over other JSON serializers which we've wanted to have.
|
17
|
+
|
18
|
+
### Easy to understand
|
19
|
+
|
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
|
+
|
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!
|
23
|
+
|
24
|
+
### Performance
|
25
|
+
|
26
|
+
Alba is faster than most of the alternatives. We have a [benchmark](https://gist.github.com/okuramasafumi/4e375525bd3a28e4ca812d2a3b3e5829).
|
27
|
+
|
10
28
|
## Installation
|
11
29
|
|
12
30
|
Add this line to your application's Gemfile:
|
@@ -23,6 +41,36 @@ Or install it yourself as:
|
|
23
41
|
|
24
42
|
$ gem install alba
|
25
43
|
|
44
|
+
## Supported Ruby versions
|
45
|
+
|
46
|
+
Alba supports CRuby 2.5.7 and higher and latest TruffleRuby.
|
47
|
+
|
48
|
+
## Documentation
|
49
|
+
|
50
|
+
You can find the documentation on [RubyDoc](https://rubydoc.info/gems/alba).
|
51
|
+
|
52
|
+
## Features
|
53
|
+
|
54
|
+
* Resource-based serialization
|
55
|
+
* Arbitrary attribute definition
|
56
|
+
* One and many association with the ability to define them inline
|
57
|
+
* Adding condition and filter to association
|
58
|
+
* Parameters can be injected and used in attributes and associations
|
59
|
+
* Setting root key separately in Serializer
|
60
|
+
* Adding metadata
|
61
|
+
* Selectable backend
|
62
|
+
* No runtime dependencies
|
63
|
+
|
64
|
+
## Anti features
|
65
|
+
|
66
|
+
* Sorting keys
|
67
|
+
* Class level support of parameters
|
68
|
+
* Supporting all existing JSON encoder/decoder
|
69
|
+
* Cache
|
70
|
+
* [JSON:API](https://jsonapi.org) support
|
71
|
+
* Association name inflection
|
72
|
+
* And many others
|
73
|
+
|
26
74
|
## Usage
|
27
75
|
|
28
76
|
### Configuration
|
@@ -109,7 +157,7 @@ class ArticleResource
|
|
109
157
|
attributes :title
|
110
158
|
end
|
111
159
|
|
112
|
-
class
|
160
|
+
class UserResource
|
113
161
|
include Alba::Resource
|
114
162
|
|
115
163
|
attributes :id
|
@@ -123,7 +171,7 @@ user.articles << article1
|
|
123
171
|
article2 = Article.new(2, 'Super nice', 'Really nice!')
|
124
172
|
user.articles << article2
|
125
173
|
|
126
|
-
|
174
|
+
UserResource.new(user).serialize
|
127
175
|
# => '{"id":1,"articles":[{"title":"Hello World!"},{"title":"Super nice"}]}'
|
128
176
|
```
|
129
177
|
|
data/alba.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
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
11
|
spec.homepage = 'https://github.com/okuramasafumi/alba'
|
12
12
|
spec.license = 'MIT'
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new('>= 2.5.
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.5.7')
|
14
14
|
|
15
15
|
spec.metadata['homepage_uri'] = spec.homepage
|
16
16
|
spec.metadata['source_code_uri'] = 'https://github.com/okuramasafumi/alba'
|
data/lib/alba.rb
CHANGED
@@ -1,22 +1,37 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require 'alba/resource'
|
5
|
-
require 'alba/resources/default_resource'
|
1
|
+
require_relative 'alba/version'
|
2
|
+
require_relative 'alba/serializer'
|
3
|
+
require_relative 'alba/resource'
|
6
4
|
|
7
5
|
# Core module
|
8
6
|
module Alba
|
7
|
+
# Base class for Errors
|
9
8
|
class Error < StandardError; end
|
10
9
|
|
10
|
+
# Error class for backend which is not supported
|
11
|
+
class UnsupportedBackend < Error; end
|
12
|
+
|
11
13
|
class << self
|
12
14
|
attr_reader :backend, :encoder
|
13
15
|
attr_accessor :default_serializer
|
14
16
|
|
17
|
+
# Set the backend, which actually serializes object into JSON
|
18
|
+
#
|
19
|
+
# @param backend [#to_sym, nil] the name of the backend
|
20
|
+
# Possible values are `oj`, `active_support`, `default`, `json` and nil
|
21
|
+
# @return [Proc] the proc to encode object into JSON
|
22
|
+
# @raise [Alba::UnsupportedBackend] if backend is not supported
|
15
23
|
def backend=(backend)
|
16
24
|
@backend = backend&.to_sym
|
17
25
|
set_encoder
|
18
26
|
end
|
19
27
|
|
28
|
+
# Serialize the object with inline definitions
|
29
|
+
#
|
30
|
+
# @param object [Object] the object to be serialized
|
31
|
+
# @param with [nil, Proc, Alba::Serializer] selializer
|
32
|
+
# @param block [Block] resource block
|
33
|
+
# @return [String] serialized JSON string
|
34
|
+
# @raise [ArgumentError] if block is absent or `with` argument's type is wrong
|
20
35
|
def serialize(object, with: nil, &block)
|
21
36
|
raise ArgumentError, 'Block required' unless block
|
22
37
|
|
@@ -31,26 +46,30 @@ module Alba
|
|
31
46
|
def set_encoder
|
32
47
|
@encoder = case @backend
|
33
48
|
when :oj
|
34
|
-
|
35
|
-
require 'oj'
|
36
|
-
->(hash) { Oj.dump(hash, mode: :strict) }
|
37
|
-
rescue LoadError
|
38
|
-
default_encoder
|
39
|
-
end
|
49
|
+
try_oj
|
40
50
|
when :active_support
|
41
|
-
|
42
|
-
require 'active_support/json'
|
43
|
-
->(hash) { ActiveSupport::JSON.encode(hash) }
|
44
|
-
rescue LoadError
|
45
|
-
default_encoder
|
46
|
-
end
|
51
|
+
try_active_support
|
47
52
|
when nil, :default, :json
|
48
53
|
default_encoder
|
49
54
|
else
|
50
|
-
raise Alba::
|
55
|
+
raise Alba::UnsupportedBackend, "Unsupported backend, #{backend}"
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
59
|
+
def try_oj
|
60
|
+
require 'oj'
|
61
|
+
->(hash) { Oj.dump(hash, mode: :strict) }
|
62
|
+
rescue LoadError
|
63
|
+
default_encoder
|
64
|
+
end
|
65
|
+
|
66
|
+
def try_active_support
|
67
|
+
require 'active_support/json'
|
68
|
+
->(hash) { ActiveSupport::JSON.encode(hash) }
|
69
|
+
rescue LoadError
|
70
|
+
default_encoder
|
71
|
+
end
|
72
|
+
|
54
73
|
def default_encoder
|
55
74
|
lambda do |hash|
|
56
75
|
require 'json'
|
@@ -59,7 +78,10 @@ module Alba
|
|
59
78
|
end
|
60
79
|
|
61
80
|
def resource_class
|
62
|
-
|
81
|
+
@resource_class ||= begin
|
82
|
+
klass = Class.new
|
83
|
+
klass.include(Alba::Resource)
|
84
|
+
end
|
63
85
|
end
|
64
86
|
end
|
65
87
|
|
data/lib/alba/association.rb
CHANGED
@@ -2,13 +2,19 @@ module Alba
|
|
2
2
|
# Base class for `One` and `Many`
|
3
3
|
# Child class should implement `to_hash` method
|
4
4
|
class Association
|
5
|
-
|
5
|
+
# @param name [Symbol] name of the method to fetch association
|
6
|
+
# @param condition [Proc] a proc filtering data
|
7
|
+
# @param resource [Class<Alba::Resource>] a resource class for the association
|
8
|
+
# @param block [Block] used to define resource when resource arg is absent
|
9
|
+
def initialize(name:, condition: nil, resource: nil, &block)
|
6
10
|
@name = name
|
7
|
-
@
|
11
|
+
@condition = condition
|
8
12
|
@block = block
|
13
|
+
@resource = resource || resource_class
|
9
14
|
raise ArgumentError, 'resource or block is required' if @resource.nil? && @block.nil?
|
10
15
|
end
|
11
16
|
|
17
|
+
# @abstract
|
12
18
|
def to_hash
|
13
19
|
:not_implemented
|
14
20
|
end
|
@@ -16,8 +22,8 @@ module Alba
|
|
16
22
|
private
|
17
23
|
|
18
24
|
def resource_class
|
19
|
-
klass =
|
20
|
-
klass.
|
25
|
+
klass = Class.new
|
26
|
+
klass.include(Alba::Resource)
|
21
27
|
klass.class_eval(&@block)
|
22
28
|
klass
|
23
29
|
end
|
data/lib/alba/many.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
|
-
|
1
|
+
require_relative 'association'
|
2
2
|
|
3
3
|
module Alba
|
4
4
|
# Representing many association
|
5
5
|
class Many < Association
|
6
|
-
|
6
|
+
# Recursively converts objects into an Array of Hashes
|
7
|
+
#
|
8
|
+
# @param target [Object] the object having an association method
|
9
|
+
# @param params [Hash] user-given Hash for arbitrary data
|
10
|
+
# @return [Array<Hash>]
|
11
|
+
def to_hash(target, params: {})
|
7
12
|
objects = target.public_send(@name)
|
8
|
-
@
|
9
|
-
objects.map { |o| @resource.new(o).to_hash }
|
13
|
+
objects = @condition.call(objects, params) if @condition
|
14
|
+
objects.map { |o| @resource.new(o, params: params).to_hash }
|
10
15
|
end
|
11
16
|
end
|
12
17
|
end
|
data/lib/alba/one.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
|
-
|
1
|
+
require_relative 'association'
|
2
2
|
|
3
3
|
module Alba
|
4
4
|
# Representing one association
|
5
5
|
class One < Association
|
6
|
-
|
6
|
+
# Recursively converts an object into a Hash
|
7
|
+
#
|
8
|
+
# @param target [Object] the object having an association method
|
9
|
+
# @param params [Hash] user-given Hash for arbitrary data
|
10
|
+
# @return [Hash]
|
11
|
+
def to_hash(target, params: {})
|
7
12
|
object = target.public_send(@name)
|
8
|
-
@
|
9
|
-
@resource.new(object).to_hash
|
13
|
+
object = @condition.call(object, params) if @condition
|
14
|
+
@resource.new(object, params: params).to_hash
|
10
15
|
end
|
11
16
|
end
|
12
17
|
end
|
data/lib/alba/resource.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require 'alba/serializers/default_serializer'
|
1
|
+
require_relative 'serializer'
|
2
|
+
require_relative 'one'
|
3
|
+
require_relative 'many'
|
5
4
|
|
6
5
|
module Alba
|
7
6
|
# This module represents what should be serialized
|
8
7
|
module Resource
|
8
|
+
# @!parse include InstanceMethods
|
9
|
+
# @!parse extend ClassMethods
|
9
10
|
DSLS = {_attributes: {}, _serializer: nil, _key: nil}.freeze
|
11
|
+
private_constant :DSLS
|
12
|
+
|
13
|
+
# @private
|
10
14
|
def self.included(base)
|
11
15
|
super
|
12
16
|
base.class_eval do
|
@@ -23,16 +27,22 @@ module Alba
|
|
23
27
|
module InstanceMethods
|
24
28
|
attr_reader :object, :_key, :params
|
25
29
|
|
30
|
+
# @param object [Object] the object to be serialized
|
31
|
+
# @param params [Hash] user-given Hash for arbitrary data
|
26
32
|
def initialize(object, params: {})
|
27
33
|
@object = object
|
28
|
-
@params = params
|
34
|
+
@params = params.freeze
|
29
35
|
DSLS.each_key { |name| instance_variable_set("@#{name}", self.class.public_send(name)) }
|
30
36
|
end
|
31
37
|
|
38
|
+
# Get serializer with `with` argument and serialize self with it
|
39
|
+
#
|
40
|
+
# @param with [nil, Proc, Alba::Serializer] selializer
|
41
|
+
# @return [String] serialized JSON string
|
32
42
|
def serialize(with: nil)
|
33
43
|
serializer = case with
|
34
44
|
when nil
|
35
|
-
@_serializer ||
|
45
|
+
@_serializer || empty_serializer
|
36
46
|
when ->(obj) { obj.is_a?(Class) && obj <= Alba::Serializer }
|
37
47
|
with
|
38
48
|
when Proc
|
@@ -43,11 +53,15 @@ module Alba
|
|
43
53
|
serializer.new(self).serialize
|
44
54
|
end
|
45
55
|
|
56
|
+
# A Hash for serialization
|
57
|
+
#
|
58
|
+
# @return [Hash]
|
46
59
|
def serializable_hash
|
47
60
|
collection? ? @object.map(&converter) : converter.call(@object)
|
48
61
|
end
|
49
62
|
alias to_hash serializable_hash
|
50
63
|
|
64
|
+
# @return [Symbol]
|
51
65
|
def key
|
52
66
|
@_key || self.class.name.delete_suffix('Resource').downcase.gsub(/:{2}/, '_').to_sym
|
53
67
|
end
|
@@ -63,14 +77,22 @@ module Alba
|
|
63
77
|
when Proc
|
64
78
|
instance_exec(resource, &attribute)
|
65
79
|
when Alba::One, Alba::Many
|
66
|
-
attribute.to_hash(resource)
|
80
|
+
attribute.to_hash(resource, params: params)
|
81
|
+
else
|
82
|
+
raise ::Alba::Error, "Unsupported type of attribute: #{attribute.class}"
|
67
83
|
end
|
68
84
|
end
|
69
85
|
end
|
70
86
|
end
|
71
87
|
|
88
|
+
def empty_serializer
|
89
|
+
klass = Class.new
|
90
|
+
klass.include Alba::Serializer
|
91
|
+
klass
|
92
|
+
end
|
93
|
+
|
72
94
|
def inline_extended_serializer(with)
|
73
|
-
klass =
|
95
|
+
klass = empty_serializer
|
74
96
|
klass.class_eval(&with)
|
75
97
|
klass
|
76
98
|
end
|
@@ -84,41 +106,77 @@ module Alba
|
|
84
106
|
module ClassMethods
|
85
107
|
attr_reader(*DSLS.keys)
|
86
108
|
|
109
|
+
# @private
|
87
110
|
def inherited(subclass)
|
88
111
|
super
|
89
112
|
DSLS.each_key { |name| subclass.instance_variable_set("@#{name}", instance_variable_get("@#{name}").clone) }
|
90
113
|
end
|
91
114
|
|
115
|
+
# Set multiple attributes at once
|
116
|
+
#
|
117
|
+
# @param attrs [Array<String, Symbol>]
|
92
118
|
def attributes(*attrs)
|
93
|
-
attrs.each { |attr_name| @_attributes[attr_name] = attr_name }
|
119
|
+
attrs.each { |attr_name| @_attributes[attr_name.to_sym] = attr_name.to_sym }
|
94
120
|
end
|
95
121
|
|
122
|
+
# Set an attribute with the given block
|
123
|
+
#
|
124
|
+
# @param name [String, Symbol] key name
|
125
|
+
# @param block [Block] the block called during serialization
|
126
|
+
# @raise [ArgumentError] if block is absent
|
96
127
|
def attribute(name, &block)
|
97
128
|
raise ArgumentError, 'No block given in attribute method' unless block
|
98
129
|
|
99
|
-
@_attributes[name] = block
|
100
|
-
end
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
130
|
+
@_attributes[name.to_sym] = block
|
131
|
+
end
|
132
|
+
|
133
|
+
# Set One association
|
134
|
+
#
|
135
|
+
# @param name [String, Symbol]
|
136
|
+
# @param condition [Proc]
|
137
|
+
# @param resource [Class<Alba::Resource>]
|
138
|
+
# @param key [String, Symbol] used as key when given
|
139
|
+
# @param block [Block]
|
140
|
+
# @see Alba::One#initialize
|
141
|
+
def one(name, condition = nil, resource: nil, key: nil, &block)
|
142
|
+
@_attributes[key&.to_sym || name.to_sym] = One.new(name: name, condition: condition, resource: resource, &block)
|
143
|
+
end
|
144
|
+
alias has_one one
|
145
|
+
|
146
|
+
# Set Many association
|
147
|
+
#
|
148
|
+
# @param name [String, Symbol]
|
149
|
+
# @param condition [Proc]
|
150
|
+
# @param resource [Class<Alba::Resource>]
|
151
|
+
# @param key [String, Symbol] used as key when given
|
152
|
+
# @param block [Block]
|
153
|
+
# @see Alba::Many#initialize
|
154
|
+
def many(name, condition = nil, resource: nil, key: nil, &block)
|
155
|
+
@_attributes[key&.to_sym || name.to_sym] = Many.new(name: name, condition: condition, resource: resource, &block)
|
156
|
+
end
|
157
|
+
alias has_many many
|
158
|
+
|
159
|
+
# Set serializer for the resource
|
160
|
+
#
|
161
|
+
# @param name [Alba::Serializer]
|
110
162
|
def serializer(name)
|
111
163
|
@_serializer = name <= Alba::Serializer ? name : nil
|
112
164
|
end
|
113
165
|
|
166
|
+
# Set key
|
167
|
+
#
|
168
|
+
# @param key [String, Symbol]
|
114
169
|
def key(key)
|
115
170
|
@_key = key.to_sym
|
116
171
|
end
|
117
172
|
|
173
|
+
# Delete attributes
|
118
174
|
# Use this DSL in child class to ignore certain attributes
|
175
|
+
#
|
176
|
+
# @param attributes [Array<String, Symbol>]
|
119
177
|
def ignoring(*attributes)
|
120
178
|
attributes.each do |attr_name|
|
121
|
-
@_attributes.delete(attr_name)
|
179
|
+
@_attributes.delete(attr_name.to_sym)
|
122
180
|
end
|
123
181
|
end
|
124
182
|
end
|
data/lib/alba/serializer.rb
CHANGED
@@ -1,22 +1,36 @@
|
|
1
1
|
module Alba
|
2
2
|
# This module represents how a resource should be serialized.
|
3
3
|
module Serializer
|
4
|
+
# @!parse include InstanceMethods
|
5
|
+
# @!parse extend ClassMethods
|
6
|
+
|
7
|
+
# @private
|
4
8
|
def self.included(base)
|
5
9
|
super
|
10
|
+
base.class_eval do
|
11
|
+
@_opts = {} unless instance_variable_defined?('@_opts')
|
12
|
+
@_metadata = {} unless instance_variable_defined?('@_metadata')
|
13
|
+
end
|
6
14
|
base.include InstanceMethods
|
7
15
|
base.extend ClassMethods
|
8
16
|
end
|
9
17
|
|
10
18
|
# Instance methods
|
11
19
|
module InstanceMethods
|
20
|
+
# @param resource [Alba::Resource]
|
12
21
|
def initialize(resource)
|
13
22
|
@resource = resource
|
14
23
|
@hash = resource.serializable_hash
|
15
24
|
@hash = {key.to_sym => @hash} if key
|
16
25
|
# @hash is either Hash or Array
|
17
|
-
|
26
|
+
unless metadata.empty?
|
27
|
+
@hash.is_a?(Hash) ? @hash.merge!(metadata.to_h) : @hash << metadata
|
28
|
+
end
|
18
29
|
end
|
19
30
|
|
31
|
+
# Use real encoder to actually serialize to JSON
|
32
|
+
#
|
33
|
+
# @return [String] JSON string
|
20
34
|
def serialize
|
21
35
|
Alba.encoder.call(@hash)
|
22
36
|
end
|
@@ -24,17 +38,12 @@ module Alba
|
|
24
38
|
private
|
25
39
|
|
26
40
|
def key
|
27
|
-
opts = self.class._opts
|
28
|
-
|
29
|
-
when true
|
30
|
-
@resource.key
|
31
|
-
else
|
32
|
-
opts[:key]
|
33
|
-
end
|
41
|
+
opts = self.class._opts
|
42
|
+
opts[:key] == true ? @resource.key : opts[:key]
|
34
43
|
end
|
35
44
|
|
36
45
|
def metadata
|
37
|
-
metadata = self.class._metadata
|
46
|
+
metadata = self.class._metadata
|
38
47
|
metadata.transform_values { |block| block.call(@resource.object) }
|
39
48
|
end
|
40
49
|
end
|
@@ -43,19 +52,25 @@ module Alba
|
|
43
52
|
module ClassMethods
|
44
53
|
attr_reader :_opts, :_metadata
|
45
54
|
|
55
|
+
# @private
|
46
56
|
def inherited(subclass)
|
47
57
|
super
|
48
|
-
%w[_opts _metadata].each { |name| subclass.instance_variable_set("@#{name}",
|
58
|
+
%w[_opts _metadata].each { |name| subclass.instance_variable_set("@#{name}", public_send(name).clone) }
|
49
59
|
end
|
50
60
|
|
61
|
+
# Set options, currently key only
|
62
|
+
#
|
63
|
+
# @param key [Boolean, Symbol]
|
51
64
|
def set(key: false)
|
52
|
-
@_opts ||= {}
|
53
65
|
@_opts[:key] = key
|
54
66
|
end
|
55
67
|
|
68
|
+
# Set metadata
|
69
|
+
#
|
70
|
+
# @param name [String, Symbol] key for the metadata
|
71
|
+
# @param block [Block] the content of the metadata
|
56
72
|
def metadata(name, &block)
|
57
|
-
@_metadata
|
58
|
-
@_metadata[name] = block
|
73
|
+
@_metadata[name.to_sym] = block
|
59
74
|
end
|
60
75
|
end
|
61
76
|
end
|
data/lib/alba/version.rb
CHANGED
data/sider.yml
CHANGED
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.
|
4
|
+
version: 0.12.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:
|
11
|
+
date: 2021-01-20 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
|
@@ -22,6 +22,7 @@ files:
|
|
22
22
|
- ".gitignore"
|
23
23
|
- ".rubocop.yml"
|
24
24
|
- ".travis.yml"
|
25
|
+
- ".yardopts"
|
25
26
|
- CODE_OF_CONDUCT.md
|
26
27
|
- Gemfile
|
27
28
|
- Gemfile.lock
|
@@ -36,9 +37,7 @@ files:
|
|
36
37
|
- lib/alba/many.rb
|
37
38
|
- lib/alba/one.rb
|
38
39
|
- lib/alba/resource.rb
|
39
|
-
- lib/alba/resources/default_resource.rb
|
40
40
|
- lib/alba/serializer.rb
|
41
|
-
- lib/alba/serializers/default_serializer.rb
|
42
41
|
- lib/alba/version.rb
|
43
42
|
- sider.yml
|
44
43
|
homepage: https://github.com/okuramasafumi/alba
|
@@ -56,14 +55,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
56
55
|
requirements:
|
57
56
|
- - ">="
|
58
57
|
- !ruby/object:Gem::Version
|
59
|
-
version: 2.5.
|
58
|
+
version: 2.5.7
|
60
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
60
|
requirements:
|
62
61
|
- - ">="
|
63
62
|
- !ruby/object:Gem::Version
|
64
63
|
version: '0'
|
65
64
|
requirements: []
|
66
|
-
rubygems_version: 3.
|
65
|
+
rubygems_version: 3.0.3
|
67
66
|
signing_key:
|
68
67
|
specification_version: 4
|
69
68
|
summary: Alba is the fastest JSON serializer for Ruby.
|
@@ -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
|