juso 0.1.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +29 -1
- data/.gitignore +4 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +134 -1
- data/README.md +67 -8
- data/Rakefile +11 -5
- data/benchmark/collection.rb +472 -0
- data/benchmark/single_resource.rb +28 -32
- data/juso.gemspec +3 -1
- data/lib/juso/version.rb +1 -1
- data/lib/juso.rb +41 -27
- metadata +19 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be611b823c4dbebdbd7882f6d9d71c1bf05fbd38c72a6e57a515560fb5efc6b3
|
|
4
|
+
data.tar.gz: da19722184dea68868395b0db2f7bbbafe093abf2f55d6c64abc3fd2faf5c339
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6937d6359d6ee9589a7d88e605d873d743769f9161a66277027b962d1a96342334f653d0ab8c0dcd234ec9617570723f8826e53753bf9e2acace75cd90110171
|
|
7
|
+
data.tar.gz: b431598fde992ec3da065898c6a42a8e4c874c2f9d01efd5a0c76dff8767636b27f411acf0051504cbc407109ecd26228ec70d9f3870e22374edc86449e7314d
|
data/.github/workflows/main.yml
CHANGED
|
@@ -8,8 +8,10 @@ jobs:
|
|
|
8
8
|
timeout-minutes: 10
|
|
9
9
|
|
|
10
10
|
strategy:
|
|
11
|
+
fail-fast: false
|
|
11
12
|
matrix:
|
|
12
|
-
ruby-version: [3.1.0-preview1, 3.0.2, 2.7.4, 2.6.8]
|
|
13
|
+
# ruby-version: [3.1.0-preview1, 3.0.2, 2.7.4, 2.6.8]
|
|
14
|
+
ruby-version: [3.0.2, 2.7.4, 2.6.8]
|
|
13
15
|
|
|
14
16
|
steps:
|
|
15
17
|
- uses: actions/checkout@v2
|
|
@@ -22,3 +24,29 @@ jobs:
|
|
|
22
24
|
|
|
23
25
|
- name: Run test
|
|
24
26
|
run: bundle exec rake test
|
|
27
|
+
|
|
28
|
+
- name: Run test (rails)
|
|
29
|
+
env:
|
|
30
|
+
RAILS_TEST: true
|
|
31
|
+
run: |
|
|
32
|
+
bundle exec rails db:setup
|
|
33
|
+
bundle exec rake test
|
|
34
|
+
|
|
35
|
+
benchmark:
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
timeout-minutes: 10
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v2
|
|
41
|
+
|
|
42
|
+
- name: Set up Ruby
|
|
43
|
+
uses: ruby/setup-ruby@v1
|
|
44
|
+
with:
|
|
45
|
+
ruby-version: 3.0.2
|
|
46
|
+
bundler-cache: true
|
|
47
|
+
|
|
48
|
+
- name: Run benchmark (collection)
|
|
49
|
+
run: ruby benchmark/collection.rb
|
|
50
|
+
|
|
51
|
+
- name: Run benchmark (single)
|
|
52
|
+
run: ruby benchmark/single_resource.rb
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,16 +1,131 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
juso (
|
|
4
|
+
juso (1.0.0)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
|
+
actioncable (6.1.4.1)
|
|
10
|
+
actionpack (= 6.1.4.1)
|
|
11
|
+
activesupport (= 6.1.4.1)
|
|
12
|
+
nio4r (~> 2.0)
|
|
13
|
+
websocket-driver (>= 0.6.1)
|
|
14
|
+
actionmailbox (6.1.4.1)
|
|
15
|
+
actionpack (= 6.1.4.1)
|
|
16
|
+
activejob (= 6.1.4.1)
|
|
17
|
+
activerecord (= 6.1.4.1)
|
|
18
|
+
activestorage (= 6.1.4.1)
|
|
19
|
+
activesupport (= 6.1.4.1)
|
|
20
|
+
mail (>= 2.7.1)
|
|
21
|
+
actionmailer (6.1.4.1)
|
|
22
|
+
actionpack (= 6.1.4.1)
|
|
23
|
+
actionview (= 6.1.4.1)
|
|
24
|
+
activejob (= 6.1.4.1)
|
|
25
|
+
activesupport (= 6.1.4.1)
|
|
26
|
+
mail (~> 2.5, >= 2.5.4)
|
|
27
|
+
rails-dom-testing (~> 2.0)
|
|
28
|
+
actionpack (6.1.4.1)
|
|
29
|
+
actionview (= 6.1.4.1)
|
|
30
|
+
activesupport (= 6.1.4.1)
|
|
31
|
+
rack (~> 2.0, >= 2.0.9)
|
|
32
|
+
rack-test (>= 0.6.3)
|
|
33
|
+
rails-dom-testing (~> 2.0)
|
|
34
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
35
|
+
actiontext (6.1.4.1)
|
|
36
|
+
actionpack (= 6.1.4.1)
|
|
37
|
+
activerecord (= 6.1.4.1)
|
|
38
|
+
activestorage (= 6.1.4.1)
|
|
39
|
+
activesupport (= 6.1.4.1)
|
|
40
|
+
nokogiri (>= 1.8.5)
|
|
41
|
+
actionview (6.1.4.1)
|
|
42
|
+
activesupport (= 6.1.4.1)
|
|
43
|
+
builder (~> 3.1)
|
|
44
|
+
erubi (~> 1.4)
|
|
45
|
+
rails-dom-testing (~> 2.0)
|
|
46
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
47
|
+
activejob (6.1.4.1)
|
|
48
|
+
activesupport (= 6.1.4.1)
|
|
49
|
+
globalid (>= 0.3.6)
|
|
50
|
+
activemodel (6.1.4.1)
|
|
51
|
+
activesupport (= 6.1.4.1)
|
|
52
|
+
activerecord (6.1.4.1)
|
|
53
|
+
activemodel (= 6.1.4.1)
|
|
54
|
+
activesupport (= 6.1.4.1)
|
|
55
|
+
activestorage (6.1.4.1)
|
|
56
|
+
actionpack (= 6.1.4.1)
|
|
57
|
+
activejob (= 6.1.4.1)
|
|
58
|
+
activerecord (= 6.1.4.1)
|
|
59
|
+
activesupport (= 6.1.4.1)
|
|
60
|
+
marcel (~> 1.0.0)
|
|
61
|
+
mini_mime (>= 1.1.0)
|
|
62
|
+
activesupport (6.1.4.1)
|
|
63
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
64
|
+
i18n (>= 1.6, < 2)
|
|
65
|
+
minitest (>= 5.1)
|
|
66
|
+
tzinfo (~> 2.0)
|
|
67
|
+
zeitwerk (~> 2.3)
|
|
9
68
|
ast (2.4.2)
|
|
69
|
+
builder (3.2.4)
|
|
70
|
+
concurrent-ruby (1.1.9)
|
|
71
|
+
crass (1.0.6)
|
|
72
|
+
erubi (1.10.0)
|
|
73
|
+
globalid (1.0.0)
|
|
74
|
+
activesupport (>= 5.0)
|
|
75
|
+
i18n (1.8.11)
|
|
76
|
+
concurrent-ruby (~> 1.0)
|
|
77
|
+
json_expressions (0.9.0)
|
|
78
|
+
loofah (2.12.0)
|
|
79
|
+
crass (~> 1.0.2)
|
|
80
|
+
nokogiri (>= 1.5.9)
|
|
81
|
+
mail (2.7.1)
|
|
82
|
+
mini_mime (>= 0.1.1)
|
|
83
|
+
marcel (1.0.2)
|
|
84
|
+
method_source (1.0.0)
|
|
85
|
+
mini_mime (1.1.2)
|
|
86
|
+
mini_portile2 (2.6.1)
|
|
10
87
|
minitest (5.14.4)
|
|
88
|
+
nio4r (2.5.8)
|
|
89
|
+
nokogiri (1.12.5)
|
|
90
|
+
mini_portile2 (~> 2.6.1)
|
|
91
|
+
racc (~> 1.4)
|
|
92
|
+
nokogiri (1.12.5-arm64-darwin)
|
|
93
|
+
racc (~> 1.4)
|
|
94
|
+
nokogiri (1.12.5-x86_64-linux)
|
|
95
|
+
racc (~> 1.4)
|
|
11
96
|
parallel (1.21.0)
|
|
12
97
|
parser (3.0.2.0)
|
|
13
98
|
ast (~> 2.4.1)
|
|
99
|
+
racc (1.6.0)
|
|
100
|
+
rack (2.2.3)
|
|
101
|
+
rack-test (1.1.0)
|
|
102
|
+
rack (>= 1.0, < 3)
|
|
103
|
+
rails (6.1.4.1)
|
|
104
|
+
actioncable (= 6.1.4.1)
|
|
105
|
+
actionmailbox (= 6.1.4.1)
|
|
106
|
+
actionmailer (= 6.1.4.1)
|
|
107
|
+
actionpack (= 6.1.4.1)
|
|
108
|
+
actiontext (= 6.1.4.1)
|
|
109
|
+
actionview (= 6.1.4.1)
|
|
110
|
+
activejob (= 6.1.4.1)
|
|
111
|
+
activemodel (= 6.1.4.1)
|
|
112
|
+
activerecord (= 6.1.4.1)
|
|
113
|
+
activestorage (= 6.1.4.1)
|
|
114
|
+
activesupport (= 6.1.4.1)
|
|
115
|
+
bundler (>= 1.15.0)
|
|
116
|
+
railties (= 6.1.4.1)
|
|
117
|
+
sprockets-rails (>= 2.0.0)
|
|
118
|
+
rails-dom-testing (2.0.3)
|
|
119
|
+
activesupport (>= 4.2.0)
|
|
120
|
+
nokogiri (>= 1.6)
|
|
121
|
+
rails-html-sanitizer (1.4.2)
|
|
122
|
+
loofah (~> 2.3)
|
|
123
|
+
railties (6.1.4.1)
|
|
124
|
+
actionpack (= 6.1.4.1)
|
|
125
|
+
activesupport (= 6.1.4.1)
|
|
126
|
+
method_source
|
|
127
|
+
rake (>= 0.13)
|
|
128
|
+
thor (~> 1.0)
|
|
14
129
|
rainbow (3.0.0)
|
|
15
130
|
rake (13.0.6)
|
|
16
131
|
regexp_parser (2.1.1)
|
|
@@ -27,7 +142,22 @@ GEM
|
|
|
27
142
|
rubocop-ast (1.13.0)
|
|
28
143
|
parser (>= 3.0.1.1)
|
|
29
144
|
ruby-progressbar (1.11.0)
|
|
145
|
+
sprockets (4.0.2)
|
|
146
|
+
concurrent-ruby (~> 1.0)
|
|
147
|
+
rack (> 1, < 3)
|
|
148
|
+
sprockets-rails (3.4.1)
|
|
149
|
+
actionpack (>= 5.2)
|
|
150
|
+
activesupport (>= 5.2)
|
|
151
|
+
sprockets (>= 3.0.0)
|
|
152
|
+
sqlite3 (1.4.2)
|
|
153
|
+
thor (1.1.0)
|
|
154
|
+
tzinfo (2.0.4)
|
|
155
|
+
concurrent-ruby (~> 1.0)
|
|
30
156
|
unicode-display_width (2.1.0)
|
|
157
|
+
websocket-driver (0.7.5)
|
|
158
|
+
websocket-extensions (>= 0.1.0)
|
|
159
|
+
websocket-extensions (0.1.5)
|
|
160
|
+
zeitwerk (2.5.1)
|
|
31
161
|
|
|
32
162
|
PLATFORMS
|
|
33
163
|
arm64-darwin-20
|
|
@@ -35,10 +165,13 @@ PLATFORMS
|
|
|
35
165
|
x86_64-linux
|
|
36
166
|
|
|
37
167
|
DEPENDENCIES
|
|
168
|
+
json_expressions
|
|
38
169
|
juso!
|
|
39
170
|
minitest (~> 5.0)
|
|
171
|
+
rails (~> 6.1.4)
|
|
40
172
|
rake (~> 13.0)
|
|
41
173
|
rubocop (~> 1.7)
|
|
174
|
+
sqlite3
|
|
42
175
|
|
|
43
176
|
BUNDLED WITH
|
|
44
177
|
2.2.22
|
data/README.md
CHANGED
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
Juso is simple, fast and explicit JSON Serializer.
|
|
8
8
|
Juso means 13 (thirteen) in Japanese.
|
|
9
9
|
|
|
10
|
+
## Motivation
|
|
11
|
+
|
|
12
|
+
#### Japanese
|
|
13
|
+
|
|
14
|
+
Juso は juso というメソッドを定義することで JSON 化が可能になります。Ruby の Hash や Array を用いて定義すれば良いので、覚えることが非常に少ないことが特徴です。また、暗黙的な挙動で非公開にすべき属性が公開されることを防ぎます。
|
|
15
|
+
|
|
16
|
+
Ruby on Rails においては Model のクラスにそのまま定義することができるため、初期の導入としてはシンプルでわかりやすいです。[^1]
|
|
17
|
+
|
|
18
|
+
[^1]: as_json メソッドで頑張ることもできますが、より宣言的で分かりやすいはずです
|
|
19
|
+
|
|
10
20
|
## Installation
|
|
11
21
|
|
|
12
22
|
Add this line to your application's Gemfile:
|
|
@@ -26,7 +36,7 @@ Or install it yourself as:
|
|
|
26
36
|
## Usage
|
|
27
37
|
|
|
28
38
|
1. Include `Juso::Serializable` to your class.
|
|
29
|
-
2. Define
|
|
39
|
+
2. Define juso(context) method.
|
|
30
40
|
3. Use Juso.generate(object) method to generate json.
|
|
31
41
|
|
|
32
42
|
```ruby
|
|
@@ -35,7 +45,7 @@ class User < ApplicationRecord
|
|
|
35
45
|
|
|
36
46
|
# ...
|
|
37
47
|
|
|
38
|
-
def
|
|
48
|
+
def juso(context)
|
|
39
49
|
{
|
|
40
50
|
id: id,
|
|
41
51
|
nickname: nickname,
|
|
@@ -50,7 +60,7 @@ class Team < ApplicationRecord
|
|
|
50
60
|
|
|
51
61
|
# ...
|
|
52
62
|
|
|
53
|
-
def
|
|
63
|
+
def juso(context)
|
|
54
64
|
{
|
|
55
65
|
id: id,
|
|
56
66
|
name: name,
|
|
@@ -70,17 +80,66 @@ Juso.generate(team)
|
|
|
70
80
|
|
|
71
81
|
#### Japanese
|
|
72
82
|
|
|
73
|
-
|
|
83
|
+
juso メソッドは以下のインスタンスしか返してはいけません
|
|
74
84
|
|
|
75
85
|
- Numeric Class
|
|
76
86
|
- String Class
|
|
77
|
-
-
|
|
87
|
+
- Nil Class
|
|
88
|
+
- True Class
|
|
89
|
+
- False Class
|
|
78
90
|
- Hash Class
|
|
79
91
|
- Array Class
|
|
80
|
-
-
|
|
81
|
-
-
|
|
92
|
+
- - ActiveRecord::Relation
|
|
93
|
+
- Juso::Serializable を include したクラス
|
|
94
|
+
- Date / DateTime
|
|
95
|
+
- - ActiveSupport::TimeWithZone
|
|
96
|
+
|
|
97
|
+
再帰的に juso の処理が適用されるため、Array の要素や Hash の value も同様のルールが適用されます
|
|
98
|
+
|
|
99
|
+
### Juso::Context
|
|
100
|
+
|
|
101
|
+
#### Japanese
|
|
102
|
+
|
|
103
|
+
juso メソッドには Context オブジェクトが渡されます。これによって、Juso.generate から各 juso メソッドにシリアライズのオプションを伝播させることができます
|
|
104
|
+
|
|
105
|
+
### Juso.wrap
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
class UserSerializer
|
|
109
|
+
include Juso::Serializable
|
|
110
|
+
|
|
111
|
+
# ...
|
|
112
|
+
|
|
113
|
+
def juso(context)
|
|
114
|
+
{
|
|
115
|
+
id: @user.id,
|
|
116
|
+
|
|
117
|
+
# use PostSerializer#juso method. Each post passes into PostSerializer object.
|
|
118
|
+
posts: Juso.wrap(@user.posts, PostSerializer),
|
|
119
|
+
|
|
120
|
+
# use Team#juso method
|
|
121
|
+
team: @user.team,
|
|
122
|
+
}
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class PostSerializer
|
|
127
|
+
include Juso::Serializable
|
|
128
|
+
|
|
129
|
+
def initialize(post)
|
|
130
|
+
@post = post
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def juso(context)
|
|
134
|
+
# do something with @post...
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### Japanese
|
|
82
140
|
|
|
83
|
-
|
|
141
|
+
Juso.wrap(object, serializable_class) ユーティリティを使うことで、特定のクラスに処理を委譲できます。
|
|
142
|
+
コード例だと、 @user.posts は Post の ActiveRecord::Relation を返しますが、通常であれば Post インスタンスの juso メソッドが使われるのに対して、各 Post インスタンスを PostSerializer でラップします。PostSerializer#juso メソッドが呼ばれることになります。
|
|
84
143
|
|
|
85
144
|
## Development
|
|
86
145
|
|
data/Rakefile
CHANGED
|
@@ -6,11 +6,17 @@ require "rake/testtask"
|
|
|
6
6
|
Rake::TestTask.new(:test) do |t|
|
|
7
7
|
t.libs << "test"
|
|
8
8
|
t.libs << "lib"
|
|
9
|
-
t.test_files = FileList["test/**/*_test.rb"]
|
|
10
|
-
end
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
files = FileList["test/juso_test.rb"]
|
|
11
|
+
|
|
12
|
+
if ENV['RAILS_TEST']
|
|
13
|
+
files << 'test/rails_test.rb'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
t.test_files = files
|
|
17
|
+
end
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
# require "rubocop/rake_task"
|
|
20
|
+
# RuboCop::RakeTask.new
|
|
15
21
|
|
|
16
|
-
task default: %i[test
|
|
22
|
+
task default: %i[test]
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
# original: https://github.com/okuramasafumi/alba/blob/main/benchmark/collection.rb
|
|
2
|
+
|
|
3
|
+
# Benchmark script to run varieties of JSON serializers
|
|
4
|
+
# Fetch juso from local, otherwise fetch latest from RubyGems
|
|
5
|
+
|
|
6
|
+
# --- Bundle dependencies ---
|
|
7
|
+
|
|
8
|
+
require "bundler/inline"
|
|
9
|
+
|
|
10
|
+
gemfile(true) do
|
|
11
|
+
source "https://rubygems.org"
|
|
12
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
|
13
|
+
|
|
14
|
+
gem "active_model_serializers"
|
|
15
|
+
gem "activerecord", "6.1.3"
|
|
16
|
+
gem "alba"
|
|
17
|
+
gem "juso", path: '../'
|
|
18
|
+
gem "benchmark-ips"
|
|
19
|
+
gem "benchmark-memory"
|
|
20
|
+
gem "blueprinter"
|
|
21
|
+
gem "jbuilder"
|
|
22
|
+
gem "jserializer"
|
|
23
|
+
gem "jsonapi-serializer" # successor of fast_jsonapi
|
|
24
|
+
gem "multi_json"
|
|
25
|
+
gem "panko_serializer"
|
|
26
|
+
gem "pg"
|
|
27
|
+
gem "primalize"
|
|
28
|
+
gem "oj"
|
|
29
|
+
gem "representable"
|
|
30
|
+
gem "simple_ams"
|
|
31
|
+
gem "sqlite3"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# --- Test data model setup ---
|
|
35
|
+
|
|
36
|
+
require "pg"
|
|
37
|
+
require "active_record"
|
|
38
|
+
require "active_record/connection_adapters/postgresql_adapter"
|
|
39
|
+
require "logger"
|
|
40
|
+
require "oj"
|
|
41
|
+
require "sqlite3"
|
|
42
|
+
Oj.optimize_rails
|
|
43
|
+
|
|
44
|
+
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
|
|
45
|
+
# ActiveRecord::Base.logger = Logger.new($stdout)
|
|
46
|
+
|
|
47
|
+
ActiveRecord::Schema.define do
|
|
48
|
+
create_table :posts, force: true do |t|
|
|
49
|
+
t.string :body
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
create_table :comments, force: true do |t|
|
|
53
|
+
t.integer :post_id
|
|
54
|
+
t.string :body
|
|
55
|
+
t.integer :commenter_id
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
create_table :users, force: true do |t|
|
|
59
|
+
t.string :name
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
class Post < ActiveRecord::Base
|
|
64
|
+
has_many :comments
|
|
65
|
+
has_many :commenters, through: :comments, class_name: 'User', source: :commenter
|
|
66
|
+
|
|
67
|
+
def attributes
|
|
68
|
+
{id: nil, body: nil, commenter_names: commenter_names}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def commenter_names
|
|
72
|
+
commenters.pluck(:name)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class Comment < ActiveRecord::Base
|
|
77
|
+
belongs_to :post
|
|
78
|
+
belongs_to :commenter, class_name: 'User'
|
|
79
|
+
|
|
80
|
+
def attributes
|
|
81
|
+
{id: nil, body: nil}
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class User < ActiveRecord::Base
|
|
86
|
+
has_many :comments
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# --- Juso serializers ---
|
|
90
|
+
|
|
91
|
+
require "juso"
|
|
92
|
+
|
|
93
|
+
class Comment
|
|
94
|
+
include ::Juso::Serializable
|
|
95
|
+
|
|
96
|
+
def juso(context)
|
|
97
|
+
{id: id, body: body}
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class Post
|
|
102
|
+
include ::Juso::Serializable
|
|
103
|
+
|
|
104
|
+
def juso(context)
|
|
105
|
+
{id: id, body: body, commenter_names: commenter_names, comments: comments}
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# --- Alba serializers ---
|
|
110
|
+
|
|
111
|
+
require "alba"
|
|
112
|
+
|
|
113
|
+
class AlbaCommentResource
|
|
114
|
+
include ::Alba::Resource
|
|
115
|
+
attributes :id, :body
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
class AlbaPostResource
|
|
119
|
+
include ::Alba::Resource
|
|
120
|
+
attributes :id, :body
|
|
121
|
+
attribute :commenter_names do |post|
|
|
122
|
+
post.commenters.pluck(:name)
|
|
123
|
+
end
|
|
124
|
+
many :comments, resource: AlbaCommentResource
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# --- ActiveModelSerializer serializers ---
|
|
128
|
+
|
|
129
|
+
require "active_model_serializers"
|
|
130
|
+
|
|
131
|
+
ActiveModelSerializers.logger = Logger.new(nil)
|
|
132
|
+
|
|
133
|
+
class AMSCommentSerializer < ActiveModel::Serializer
|
|
134
|
+
attributes :id, :body
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
class AMSPostSerializer < ActiveModel::Serializer
|
|
138
|
+
attributes :id, :body
|
|
139
|
+
attribute :commenter_names
|
|
140
|
+
has_many :comments, serializer: AMSCommentSerializer
|
|
141
|
+
|
|
142
|
+
def commenter_names
|
|
143
|
+
object.commenters.pluck(:name)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# --- Blueprint serializers ---
|
|
148
|
+
|
|
149
|
+
require "blueprinter"
|
|
150
|
+
|
|
151
|
+
class CommentBlueprint < Blueprinter::Base
|
|
152
|
+
fields :id, :body
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
class PostBlueprint < Blueprinter::Base
|
|
156
|
+
fields :id, :body, :commenter_names
|
|
157
|
+
association :comments, blueprint: CommentBlueprint
|
|
158
|
+
|
|
159
|
+
def commenter_names
|
|
160
|
+
commenters.pluck(:name)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# --- JBuilder serializers ---
|
|
165
|
+
|
|
166
|
+
require "jbuilder"
|
|
167
|
+
|
|
168
|
+
class Post
|
|
169
|
+
def to_builder
|
|
170
|
+
Jbuilder.new do |post|
|
|
171
|
+
post.call(self, :id, :body, :commenter_names, :comments)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def commenter_names
|
|
176
|
+
commenters.pluck(:name)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
class Comment
|
|
181
|
+
def to_builder
|
|
182
|
+
Jbuilder.new do |comment|
|
|
183
|
+
comment.call(self, :id, :body)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# --- Jserializer serializers ---
|
|
189
|
+
|
|
190
|
+
require 'jserializer'
|
|
191
|
+
|
|
192
|
+
class JserializerCommentSerializer < Jserializer::Base
|
|
193
|
+
attributes :id, :body
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
class JserializerPostSerializer < Jserializer::Base
|
|
197
|
+
attributes :id, :body, :commenter_names
|
|
198
|
+
has_many :comments, serializer: JserializerCommentSerializer
|
|
199
|
+
def commenter_names
|
|
200
|
+
object.commenters.pluck(:name)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# --- JSONAPI:Serializer serializers / (successor of fast_jsonapi) ---
|
|
205
|
+
|
|
206
|
+
class JsonApiStandardCommentSerializer
|
|
207
|
+
include JSONAPI::Serializer
|
|
208
|
+
|
|
209
|
+
attribute :id
|
|
210
|
+
attribute :body
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
class JsonApiStandardPostSerializer
|
|
214
|
+
include JSONAPI::Serializer
|
|
215
|
+
|
|
216
|
+
# set_type :post # optional
|
|
217
|
+
attribute :id
|
|
218
|
+
attribute :body
|
|
219
|
+
attribute :commenter_names
|
|
220
|
+
|
|
221
|
+
attribute :comments do |post|
|
|
222
|
+
post.comments.map { |comment| JsonApiSameFormatCommentSerializer.new(comment) }
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# --- JSONAPI:Serializer serializers that format the code the same flat way as the other gems here ---
|
|
227
|
+
|
|
228
|
+
# code to convert from JSON:API output to "flat" JSON, like the other serializers build
|
|
229
|
+
class JsonApiSameFormatSerializer
|
|
230
|
+
include JSONAPI::Serializer
|
|
231
|
+
|
|
232
|
+
def as_json(*_options)
|
|
233
|
+
hash = serializable_hash
|
|
234
|
+
|
|
235
|
+
if hash[:data].is_a? Hash
|
|
236
|
+
hash[:data][:attributes]
|
|
237
|
+
|
|
238
|
+
elsif hash[:data].is_a? Array
|
|
239
|
+
hash[:data].pluck(:attributes)
|
|
240
|
+
|
|
241
|
+
elsif hash[:data].nil?
|
|
242
|
+
{ }
|
|
243
|
+
|
|
244
|
+
else
|
|
245
|
+
raise "unexpected data type #{hash[:data].class}"
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
class JsonApiSameFormatCommentSerializer < JsonApiSameFormatSerializer
|
|
251
|
+
attribute :id
|
|
252
|
+
attribute :body
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
class JsonApiSameFormatPostSerializer < JsonApiSameFormatSerializer
|
|
256
|
+
attribute :id
|
|
257
|
+
attribute :body
|
|
258
|
+
attribute :commenter_names
|
|
259
|
+
|
|
260
|
+
attribute :comments do |post|
|
|
261
|
+
post.comments.map { |comment| JsonApiSameFormatCommentSerializer.new(comment) }
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# --- Panko serializers ---
|
|
266
|
+
#
|
|
267
|
+
|
|
268
|
+
require "panko_serializer"
|
|
269
|
+
|
|
270
|
+
class PankoCommentSerializer < Panko::Serializer
|
|
271
|
+
attributes :id, :body
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class PankoPostSerializer < Panko::Serializer
|
|
276
|
+
attributes :id, :body, :commenter_names
|
|
277
|
+
|
|
278
|
+
has_many :comments, serializer: PankoCommentSerializer
|
|
279
|
+
|
|
280
|
+
def commenter_names
|
|
281
|
+
object.comments.pluck(:name)
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# --- Primalize serializers ---
|
|
286
|
+
#
|
|
287
|
+
class PrimalizeCommentResource < Primalize::Single
|
|
288
|
+
attributes id: integer, body: string
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
class PrimalizePostResource < Primalize::Single
|
|
292
|
+
alias post object
|
|
293
|
+
|
|
294
|
+
attributes(
|
|
295
|
+
id: integer,
|
|
296
|
+
body: string,
|
|
297
|
+
comments: array(primalize(PrimalizeCommentResource)),
|
|
298
|
+
commenter_names: array(string),
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
def commenter_names
|
|
302
|
+
post.commenters.pluck(:name)
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
class PrimalizePostsResource < Primalize::Many
|
|
307
|
+
attributes posts: enumerable(PrimalizePostResource)
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# --- Representable serializers ---
|
|
311
|
+
|
|
312
|
+
require "representable"
|
|
313
|
+
|
|
314
|
+
class CommentRepresenter < Representable::Decorator
|
|
315
|
+
include Representable::JSON
|
|
316
|
+
|
|
317
|
+
property :id
|
|
318
|
+
property :body
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
class PostsRepresenter < Representable::Decorator
|
|
322
|
+
include Representable::JSON::Collection
|
|
323
|
+
|
|
324
|
+
items class: Post do
|
|
325
|
+
property :id
|
|
326
|
+
property :body
|
|
327
|
+
property :commenter_names
|
|
328
|
+
collection :comments
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def commenter_names
|
|
332
|
+
commenters.pluck(:name)
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# --- SimpleAMS serializers ---
|
|
337
|
+
|
|
338
|
+
require "simple_ams"
|
|
339
|
+
|
|
340
|
+
class SimpleAMSCommentSerializer
|
|
341
|
+
include SimpleAMS::DSL
|
|
342
|
+
|
|
343
|
+
attributes :id, :body
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
class SimpleAMSPostSerializer
|
|
347
|
+
include SimpleAMS::DSL
|
|
348
|
+
|
|
349
|
+
attributes :id, :body
|
|
350
|
+
attribute :commenter_names
|
|
351
|
+
has_many :comments, serializer: SimpleAMSCommentSerializer
|
|
352
|
+
|
|
353
|
+
def commenter_names
|
|
354
|
+
object.commenters.pluck(:name)
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# --- Test data creation ---
|
|
359
|
+
|
|
360
|
+
100.times do |i|
|
|
361
|
+
post = Post.create!(body: "post#{i}")
|
|
362
|
+
user1 = User.create!(name: "John#{i}")
|
|
363
|
+
user2 = User.create!(name: "Jane#{i}")
|
|
364
|
+
10.times do |n|
|
|
365
|
+
post.comments.create!(commenter: user1, body: "Comment1_#{i}_#{n}")
|
|
366
|
+
post.comments.create!(commenter: user2, body: "Comment2_#{i}_#{n}")
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
posts = Post.all.to_a
|
|
371
|
+
|
|
372
|
+
# --- Store the serializers in procs ---
|
|
373
|
+
|
|
374
|
+
alba = Proc.new { AlbaPostResource.new(posts).serialize }
|
|
375
|
+
alba_inline = Proc.new do
|
|
376
|
+
Alba.serialize(posts) do
|
|
377
|
+
attributes :id, :body
|
|
378
|
+
attribute :commenter_names do |post|
|
|
379
|
+
post.commenters.pluck(:name)
|
|
380
|
+
end
|
|
381
|
+
many :comments do
|
|
382
|
+
attributes :id, :body
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
juso = Proc.new do
|
|
388
|
+
Juso.generate(posts)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
ams = Proc.new { ActiveModelSerializers::SerializableResource.new(posts, {}).as_json }
|
|
392
|
+
blueprinter = Proc.new { PostBlueprint.render(posts) }
|
|
393
|
+
jbuilder = Proc.new do
|
|
394
|
+
Jbuilder.new do |json|
|
|
395
|
+
json.array!(posts) do |post|
|
|
396
|
+
json.post post.to_builder
|
|
397
|
+
end
|
|
398
|
+
end.target!
|
|
399
|
+
end
|
|
400
|
+
jserializer = Proc.new { JserializerPostSerializer.new(posts, is_collection: true).to_json }
|
|
401
|
+
jsonapi = proc { JsonApiStandardPostSerializer.new(posts).to_json }
|
|
402
|
+
jsonapi_same_format = proc { JsonApiSameFormatPostSerializer.new(posts).to_json }
|
|
403
|
+
panko = proc { Panko::ArraySerializer.new(posts, each_serializer: PankoPostSerializer).to_json }
|
|
404
|
+
primalize = proc { PrimalizePostsResource.new(posts: posts).to_json }
|
|
405
|
+
rails = Proc.new do
|
|
406
|
+
ActiveSupport::JSON.encode(posts.map{ |post| post.serializable_hash(include: :comments) })
|
|
407
|
+
end
|
|
408
|
+
representable = Proc.new { PostsRepresenter.new(posts).to_json }
|
|
409
|
+
simple_ams = Proc.new { SimpleAMS::Renderer::Collection.new(posts, serializer: SimpleAMSPostSerializer).to_json }
|
|
410
|
+
|
|
411
|
+
# --- Execute the serializers to check their output ---
|
|
412
|
+
|
|
413
|
+
puts "Serializer outputs ----------------------------------"
|
|
414
|
+
{
|
|
415
|
+
alba: alba,
|
|
416
|
+
alba_inline: alba_inline,
|
|
417
|
+
juso: juso,
|
|
418
|
+
ams: ams,
|
|
419
|
+
blueprinter: blueprinter,
|
|
420
|
+
jbuilder: jbuilder, # different order
|
|
421
|
+
jserializer: jserializer,
|
|
422
|
+
jsonapi: jsonapi, # nested JSON:API format
|
|
423
|
+
jsonapi_same_format: jsonapi_same_format,
|
|
424
|
+
panko: panko,
|
|
425
|
+
primalize: primalize,
|
|
426
|
+
rails: rails,
|
|
427
|
+
representable: representable,
|
|
428
|
+
simple_ams: simple_ams,
|
|
429
|
+
}.each { |name, serializer| puts "#{name.to_s.ljust(24, ' ')} #{serializer.call}" }
|
|
430
|
+
|
|
431
|
+
# --- Run the benchmarks ---
|
|
432
|
+
|
|
433
|
+
require 'benchmark/ips'
|
|
434
|
+
Benchmark.ips do |x|
|
|
435
|
+
x.report(:alba, &alba)
|
|
436
|
+
x.report(:alba_inline, &alba_inline)
|
|
437
|
+
x.report(:juso, &juso)
|
|
438
|
+
x.report(:ams, &ams)
|
|
439
|
+
x.report(:blueprinter, &blueprinter)
|
|
440
|
+
x.report(:jbuilder, &jbuilder)
|
|
441
|
+
x.report(:jserializer, &jserializer)
|
|
442
|
+
x.report(:jsonapi, &jsonapi)
|
|
443
|
+
x.report(:jsonapi_same_format, &jsonapi_same_format)
|
|
444
|
+
x.report(:panko, &panko)
|
|
445
|
+
x.report(:primalize, &primalize)
|
|
446
|
+
x.report(:rails, &rails)
|
|
447
|
+
x.report(:representable, &representable)
|
|
448
|
+
x.report(:simple_ams, &simple_ams)
|
|
449
|
+
|
|
450
|
+
x.compare!
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
require 'benchmark/memory'
|
|
455
|
+
Benchmark.memory do |x|
|
|
456
|
+
x.report(:alba, &alba)
|
|
457
|
+
x.report(:alba_inline, &alba_inline)
|
|
458
|
+
x.report(:juso, &juso)
|
|
459
|
+
x.report(:ams, &ams)
|
|
460
|
+
x.report(:blueprinter, &blueprinter)
|
|
461
|
+
x.report(:jbuilder, &jbuilder)
|
|
462
|
+
x.report(:jserializer, &jserializer)
|
|
463
|
+
x.report(:jsonapi, &jsonapi)
|
|
464
|
+
x.report(:jsonapi_same_format, &jsonapi_same_format)
|
|
465
|
+
x.report(:panko, &panko)
|
|
466
|
+
x.report(:primalize, &primalize)
|
|
467
|
+
x.report(:rails, &rails)
|
|
468
|
+
x.report(:representable, &representable)
|
|
469
|
+
x.report(:simple_ams, &simple_ams)
|
|
470
|
+
|
|
471
|
+
x.compare!
|
|
472
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# original from https://github.com/okuramasafumi/alba/blob/main/benchmark/single_resource.rb
|
|
2
2
|
|
|
3
3
|
# Benchmark script to run varieties of JSON serializers
|
|
4
|
-
# Fetch
|
|
4
|
+
# Fetch juso from local, otherwise fetch latest from RubyGems
|
|
5
5
|
|
|
6
6
|
# --- Bundle dependencies ---
|
|
7
7
|
|
|
@@ -22,10 +22,10 @@ gemfile(true) do
|
|
|
22
22
|
gem "jserializer"
|
|
23
23
|
gem "jsonapi-serializer" # successor of fast_jsonapi
|
|
24
24
|
gem "multi_json"
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
gem "panko_serializer"
|
|
26
|
+
gem "pg"
|
|
27
27
|
gem "primalize"
|
|
28
|
-
|
|
28
|
+
gem "oj"
|
|
29
29
|
gem "representable"
|
|
30
30
|
gem "simple_ams"
|
|
31
31
|
gem "sqlite3"
|
|
@@ -33,14 +33,14 @@ end
|
|
|
33
33
|
|
|
34
34
|
# --- Test data model setup ---
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
require "pg"
|
|
37
37
|
require "active_record"
|
|
38
|
-
|
|
38
|
+
require "active_record/connection_adapters/postgresql_adapter"
|
|
39
39
|
require "active_record/connection_adapters/sqlite3_adapter"
|
|
40
40
|
require "logger"
|
|
41
|
-
|
|
41
|
+
require "oj"
|
|
42
42
|
require "sqlite3"
|
|
43
|
-
|
|
43
|
+
Oj.optimize_rails
|
|
44
44
|
|
|
45
45
|
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
|
|
46
46
|
# ActiveRecord::Base.logger = Logger.new($stdout)
|
|
@@ -90,13 +90,11 @@ end
|
|
|
90
90
|
# --- Juso serializers ---
|
|
91
91
|
|
|
92
92
|
require "juso"
|
|
93
|
-
require 'active_record' # hack for CollectionProxy
|
|
94
|
-
Juso.reset_collection_classes
|
|
95
93
|
|
|
96
94
|
class Comment
|
|
97
95
|
include ::Juso::Serializable
|
|
98
96
|
|
|
99
|
-
def
|
|
97
|
+
def juso(context)
|
|
100
98
|
{id: id, body: body}
|
|
101
99
|
end
|
|
102
100
|
end
|
|
@@ -104,7 +102,7 @@ end
|
|
|
104
102
|
class Post
|
|
105
103
|
include ::Juso::Serializable
|
|
106
104
|
|
|
107
|
-
def
|
|
105
|
+
def juso(context)
|
|
108
106
|
{id: id, body: body, commenter_names: commenter_names, comments: comments}
|
|
109
107
|
end
|
|
110
108
|
end
|
|
@@ -266,22 +264,22 @@ end
|
|
|
266
264
|
|
|
267
265
|
# --- Panko serializers ---
|
|
268
266
|
#
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
267
|
+
require "panko_serializer"
|
|
268
|
+
|
|
269
|
+
class PankoCommentSerializer < Panko::Serializer
|
|
270
|
+
attributes :id, :body
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
class PankoPostSerializer < Panko::Serializer
|
|
275
|
+
attributes :id, :body, :commenter_names
|
|
276
|
+
|
|
277
|
+
has_many :comments, serializer: PankoCommentSerializer
|
|
278
|
+
|
|
279
|
+
def commenter_names
|
|
280
|
+
object.comments.pluck(:name)
|
|
281
|
+
end
|
|
282
|
+
end
|
|
285
283
|
|
|
286
284
|
# --- Primalize serializers ---
|
|
287
285
|
#
|
|
@@ -363,8 +361,6 @@ post.reload
|
|
|
363
361
|
|
|
364
362
|
juso = Proc.new do
|
|
365
363
|
Juso.generate(post)
|
|
366
|
-
rescue
|
|
367
|
-
binding.irb
|
|
368
364
|
end
|
|
369
365
|
|
|
370
366
|
alba = Proc.new { AlbaPostResource.new(post).serialize }
|
|
@@ -385,8 +381,8 @@ jbuilder = Proc.new { post.to_builder.target! }
|
|
|
385
381
|
jserializer = Proc.new { JserializerPostSerializer.new(post).to_json }
|
|
386
382
|
jsonapi = proc { JsonApiStandardPostSerializer.new(post).to_json }
|
|
387
383
|
jsonapi_same_format = proc { JsonApiSameFormatPostSerializer.new(post).to_json }
|
|
388
|
-
|
|
389
|
-
panko = proc { 'nop' }
|
|
384
|
+
panko = proc { PankoPostSerializer.new.serialize_to_json(post) }
|
|
385
|
+
# panko = proc { 'nop' }
|
|
390
386
|
primalize = proc { PrimalizePostResource.new(post).to_json }
|
|
391
387
|
rails = Proc.new { ActiveSupport::JSON.encode(post.serializable_hash(include: :comments)) }
|
|
392
388
|
representable = Proc.new { PostRepresenter.new(post).to_json }
|
data/juso.gemspec
CHANGED
|
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
|
12
12
|
spec.description = "juso is simple json serializer for web application"
|
|
13
13
|
spec.homepage = "https://github.com/ykpythemind/juso"
|
|
14
14
|
spec.license = "MIT"
|
|
15
|
-
spec.required_ruby_version = ">= 2.
|
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
|
16
16
|
|
|
17
17
|
# spec.metadata["allowed_push_host"] = "TODO: Set to 'https://mygemserver.com'"
|
|
18
18
|
|
|
@@ -34,4 +34,6 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
|
|
35
35
|
# For more information and examples about making a new gem, checkout our
|
|
36
36
|
# guide at: https://bundler.io/guides/creating_gem.html
|
|
37
|
+
|
|
38
|
+
spec.add_development_dependency "rails", "~> 6.1.4"
|
|
37
39
|
end
|
data/lib/juso/version.rb
CHANGED
data/lib/juso.rb
CHANGED
|
@@ -9,63 +9,77 @@ module Juso
|
|
|
9
9
|
class Error < StandardError; end
|
|
10
10
|
|
|
11
11
|
module Serializable
|
|
12
|
-
def
|
|
12
|
+
def juso(_)
|
|
13
13
|
nil
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
# Juso
|
|
18
|
-
# xxxxx
|
|
17
|
+
# Juso::Context is serializer context
|
|
19
18
|
class Context
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
DEFAULT_OPTS = {}.freeze
|
|
20
|
+
|
|
21
|
+
def initialize(serializer: :default, options: DEFAULT_OPTS)
|
|
22
|
+
@serializer = serializer
|
|
23
|
+
@options = options
|
|
22
24
|
end
|
|
23
25
|
|
|
24
|
-
attr_reader :
|
|
26
|
+
attr_reader :serializer, :options
|
|
25
27
|
end
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
# Juso.generate generates json string
|
|
30
|
+
def self.generate(object, context = Context.new)
|
|
31
|
+
JSON.fast_generate(_g(object, context))
|
|
29
32
|
end
|
|
30
33
|
|
|
31
|
-
# generate returns
|
|
32
|
-
def self.
|
|
34
|
+
# generate returns object (as json)
|
|
35
|
+
def self._g(object, context)
|
|
33
36
|
case object
|
|
34
|
-
when nil, Numeric, String
|
|
37
|
+
when nil, Numeric, String, true, false
|
|
35
38
|
return object
|
|
36
39
|
when Hash
|
|
37
40
|
return object.each_with_object({}) do |(k, v), acc|
|
|
38
|
-
acc[k] =
|
|
41
|
+
acc[k] = _g(v, context)
|
|
39
42
|
end
|
|
40
43
|
when Serializable
|
|
41
|
-
# respond_to?(:
|
|
42
|
-
return
|
|
44
|
+
# respond_to?(:juso) のほうが良い可能性ある?
|
|
45
|
+
return _g(object.juso(context), context)
|
|
43
46
|
when *collection_classes
|
|
44
|
-
return object.to_a.map { |o|
|
|
47
|
+
return object.to_a.map { |o| _g(o, context) }
|
|
45
48
|
when *date_classes
|
|
46
|
-
return object.iso8601
|
|
49
|
+
return object.iso8601(context.options[:juso_time_n_digits] || 0)
|
|
47
50
|
else
|
|
48
|
-
# TODO: fallback to respond_to?(:
|
|
51
|
+
# TODO: fallback to respond_to?(:juso) and warn?
|
|
49
52
|
|
|
50
53
|
raise Error.new("cannot serialize object: #{object}. you must include Juso::Serializable")
|
|
51
54
|
end
|
|
52
55
|
end
|
|
53
56
|
|
|
57
|
+
# Juso.wrap is utility for wrapping object with Juso::Serializable class
|
|
58
|
+
def self.wrap(object, klass)
|
|
59
|
+
if collection_classes.any? { |arrayish| object.is_a?(arrayish) }
|
|
60
|
+
object.to_a.map { |o| klass.new(o) }
|
|
61
|
+
else
|
|
62
|
+
klass.new(object)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
54
66
|
def self.collection_classes
|
|
55
|
-
@collection_classes
|
|
67
|
+
@collection_classes ||= default_collection_classes
|
|
56
68
|
end
|
|
57
69
|
|
|
58
|
-
def self.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
end
|
|
70
|
+
def self.default_collection_classes
|
|
71
|
+
if defined?(ActiveRecord)
|
|
72
|
+
[Array, ActiveRecord::Relation]
|
|
73
|
+
else
|
|
74
|
+
[Array]
|
|
75
|
+
end
|
|
65
76
|
end
|
|
66
77
|
|
|
67
78
|
def self.date_classes
|
|
68
|
-
|
|
79
|
+
@date_classes ||= default_date_classes
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def self.default_date_classes
|
|
69
83
|
if defined?(ActiveSupport::TimeWithZone)
|
|
70
84
|
[Date, DateTime, ActiveSupport::TimeWithZone]
|
|
71
85
|
else
|
|
@@ -73,5 +87,5 @@ module Juso
|
|
|
73
87
|
end
|
|
74
88
|
end
|
|
75
89
|
|
|
76
|
-
|
|
90
|
+
private_class_method :default_collection_classes, :default_date_classes
|
|
77
91
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: juso
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ykpythemind
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
12
|
-
dependencies:
|
|
11
|
+
date: 2021-12-01 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 6.1.4
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 6.1.4
|
|
13
27
|
description: juso is simple json serializer for web application
|
|
14
28
|
email:
|
|
15
29
|
- yukibukiyou@gmail.com
|
|
@@ -26,6 +40,7 @@ files:
|
|
|
26
40
|
- LICENSE.txt
|
|
27
41
|
- README.md
|
|
28
42
|
- Rakefile
|
|
43
|
+
- benchmark/collection.rb
|
|
29
44
|
- benchmark/single_resource.rb
|
|
30
45
|
- bin/console
|
|
31
46
|
- bin/setup
|
|
@@ -48,7 +63,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
48
63
|
requirements:
|
|
49
64
|
- - ">="
|
|
50
65
|
- !ruby/object:Gem::Version
|
|
51
|
-
version: 2.
|
|
66
|
+
version: 2.6.0
|
|
52
67
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
68
|
requirements:
|
|
54
69
|
- - ">="
|