mutils 0.2.35 → 0.2.36
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/.rubocop.yml +1 -5
- data/.rubocop_todo.yml +8 -2
- data/.travis.yml +16 -3
- data/Gemfile.lock +8 -71
- data/README.md +52 -26
- data/lib/mutils.rb +2 -3
- data/lib/mutils/lib/helper.rb +32 -0
- data/lib/mutils/serialization/serialization_includes.rb +8 -7
- data/lib/mutils/serialization/serialization_methods.rb +11 -7
- data/lib/mutils/serialization/serialization_results.rb +7 -10
- data/lib/mutils/version.rb +1 -1
- data/mutils.gemspec +2 -3
- metadata +9 -24
- data/BENCHMARK-SERIALIZER-JSON.md +0 -82
- data/benchmark/benchmark-serializer-json.rb +0 -252
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1331c714748c7ecdc92258a4b37ad2ebddb23bff4a5a9858eab6bcc9a08fee0f
|
4
|
+
data.tar.gz: 6a9850b4e1602f656c90ce2b3fa65bd1dc15639f4aad115e8295668a5ea0f305
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2af97f7e2f52f822568edf377dfa135347bd506374c27ece2c86c3b82c96780e6111e6723532192175e979cfcb8885219018d7851acb12f35744a35777513b65
|
7
|
+
data.tar.gz: ffd8ded7613308b8a736ed8fe6eee83de98c183c34854d22fc30b03f438dc6e1cc71cc42df9f1a3de66d3a2e1d57dde75a01678e0214df9467a3077ca09fd522
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
@@ -33,9 +33,15 @@ Style/RescueModifier:
|
|
33
33
|
# Cop supports --auto-correct.
|
34
34
|
# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
35
35
|
# URISchemes: http, https
|
36
|
-
|
36
|
+
Layout/LineLength:
|
37
37
|
Max: 608
|
38
38
|
Metrics/MethodLength:
|
39
39
|
Max: 20
|
40
40
|
Metrics/AbcSize:
|
41
|
-
Max:
|
41
|
+
Max: 22
|
42
|
+
Style/HashEachMethods:
|
43
|
+
Enabled: false
|
44
|
+
Style/HashTransformKeys:
|
45
|
+
Enabled: false
|
46
|
+
Style/HashTransformValues:
|
47
|
+
Enabled: false
|
data/.travis.yml
CHANGED
@@ -1,7 +1,20 @@
|
|
1
|
-
|
1
|
+
os:
|
2
|
+
- linux
|
3
|
+
- osx
|
4
|
+
rvm:
|
5
|
+
- 2.5
|
6
|
+
- 2.6.3
|
7
|
+
- 2.6.5
|
8
|
+
- 2.7.0
|
9
|
+
- 2.7.1
|
10
|
+
- jruby-9.2
|
2
11
|
sudo: false
|
3
12
|
language: ruby
|
4
13
|
cache: bundler
|
5
|
-
rvm:
|
6
|
-
- 2.7.0
|
7
14
|
before_install: gem install bundler -v 2.0.1
|
15
|
+
branches:
|
16
|
+
only: master
|
17
|
+
matrix:
|
18
|
+
allow_failures:
|
19
|
+
- rvm: jruby-9.2
|
20
|
+
fast_finish: true
|
data/Gemfile.lock
CHANGED
@@ -1,73 +1,27 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mutils (0.2.
|
5
|
-
|
4
|
+
mutils (0.2.36)
|
5
|
+
dry-inflector
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
actionpack (6.0.2.2)
|
11
|
-
actionview (= 6.0.2.2)
|
12
|
-
activesupport (= 6.0.2.2)
|
13
|
-
rack (~> 2.0, >= 2.0.8)
|
14
|
-
rack-test (>= 0.6.3)
|
15
|
-
rails-dom-testing (~> 2.0)
|
16
|
-
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
17
|
-
actionview (6.0.2.2)
|
18
|
-
activesupport (= 6.0.2.2)
|
19
|
-
builder (~> 3.1)
|
20
|
-
erubi (~> 1.4)
|
21
|
-
rails-dom-testing (~> 2.0)
|
22
|
-
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
23
|
-
activesupport (6.0.2.2)
|
24
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
25
|
-
i18n (>= 0.7, < 2)
|
26
|
-
minitest (~> 5.1)
|
27
|
-
tzinfo (~> 1.1)
|
28
|
-
zeitwerk (~> 2.2)
|
29
|
-
builder (3.2.4)
|
30
|
-
concurrent-ruby (1.1.6)
|
31
10
|
coveralls (0.8.23)
|
32
11
|
json (>= 1.8, < 3)
|
33
12
|
simplecov (~> 0.16.1)
|
34
13
|
term-ansicolor (~> 1.3)
|
35
14
|
thor (>= 0.19.4, < 2.0)
|
36
15
|
tins (~> 1.6)
|
37
|
-
crass (1.0.6)
|
38
16
|
diff-lcs (1.3)
|
39
|
-
diffy (3.3.0)
|
40
17
|
docile (1.3.2)
|
41
|
-
|
42
|
-
i18n (1.8.2)
|
43
|
-
concurrent-ruby (~> 1.0)
|
18
|
+
dry-inflector (0.2.0)
|
44
19
|
json (2.3.0)
|
45
|
-
loofah (2.4.0)
|
46
|
-
crass (~> 1.0.2)
|
47
|
-
nokogiri (>= 1.5.9)
|
48
|
-
method_source (1.0.0)
|
49
|
-
mini_portile2 (2.4.0)
|
50
|
-
minitest (5.14.0)
|
51
|
-
naws_xml (0.1.1.pre)
|
52
|
-
ox (~> 2)
|
53
|
-
nokogiri (1.10.9)
|
54
|
-
mini_portile2 (~> 2.4.0)
|
55
|
-
ox (2.13.2)
|
56
|
-
rack (2.2.2)
|
57
|
-
rack-test (1.1.0)
|
58
|
-
rack (>= 1.0, < 3)
|
59
|
-
rails-dom-testing (2.0.3)
|
60
|
-
activesupport (>= 4.2.0)
|
61
|
-
nokogiri (>= 1.6)
|
62
|
-
rails-html-sanitizer (1.3.0)
|
63
|
-
loofah (~> 2.3)
|
64
|
-
railties (6.0.2.2)
|
65
|
-
actionpack (= 6.0.2.2)
|
66
|
-
activesupport (= 6.0.2.2)
|
67
|
-
method_source
|
68
|
-
rake (>= 0.8.7)
|
69
|
-
thor (>= 0.20.3, < 2.0)
|
70
20
|
rake (13.0.1)
|
21
|
+
rspec (3.9.0)
|
22
|
+
rspec-core (~> 3.9.0)
|
23
|
+
rspec-expectations (~> 3.9.0)
|
24
|
+
rspec-mocks (~> 3.9.0)
|
71
25
|
rspec-core (3.9.1)
|
72
26
|
rspec-support (~> 3.9.1)
|
73
27
|
rspec-expectations (3.9.1)
|
@@ -77,19 +31,7 @@ GEM
|
|
77
31
|
rspec-mocks (3.9.1)
|
78
32
|
diff-lcs (>= 1.2.0, < 2.0)
|
79
33
|
rspec-support (~> 3.9.0)
|
80
|
-
rspec-rails (3.9.1)
|
81
|
-
actionpack (>= 3.0)
|
82
|
-
activesupport (>= 3.0)
|
83
|
-
railties (>= 3.0)
|
84
|
-
rspec-core (~> 3.9.0)
|
85
|
-
rspec-expectations (~> 3.9.0)
|
86
|
-
rspec-mocks (~> 3.9.0)
|
87
|
-
rspec-support (~> 3.9.0)
|
88
34
|
rspec-support (3.9.2)
|
89
|
-
rspec-xml_helpers (1.0.5)
|
90
|
-
diff-lcs (~> 1.3)
|
91
|
-
diffy (~> 3.2)
|
92
|
-
naws_xml (= 0.1.1.pre)
|
93
35
|
simplecov (0.16.1)
|
94
36
|
docile (~> 1.1)
|
95
37
|
json (>= 1.8, < 3)
|
@@ -99,12 +41,8 @@ GEM
|
|
99
41
|
term-ansicolor (1.7.1)
|
100
42
|
tins (~> 1.0)
|
101
43
|
thor (1.0.1)
|
102
|
-
thread_safe (0.3.6)
|
103
44
|
tins (1.24.1)
|
104
45
|
sync
|
105
|
-
tzinfo (1.2.6)
|
106
|
-
thread_safe (~> 0.1)
|
107
|
-
zeitwerk (2.3.0)
|
108
46
|
|
109
47
|
PLATFORMS
|
110
48
|
ruby
|
@@ -114,9 +52,8 @@ DEPENDENCIES
|
|
114
52
|
coveralls
|
115
53
|
mutils!
|
116
54
|
rake (~> 13.0)
|
55
|
+
rspec
|
117
56
|
rspec-json_expectations
|
118
|
-
rspec-rails
|
119
|
-
rspec-xml_helpers
|
120
57
|
|
121
58
|
BUNDLED WITH
|
122
59
|
2.1.4
|
data/README.md
CHANGED
@@ -26,7 +26,6 @@ Or install it yourself as:
|
|
26
26
|
| Sno | Name | Status |
|
27
27
|
|:---: |:-----------------: |:------: |
|
28
28
|
| 1 | Serializer - JSON | Done |
|
29
|
-
| 2 | Serializer - XML | Done |
|
30
29
|
|
31
30
|
## Usage
|
32
31
|
### Serializer - JSON
|
@@ -52,9 +51,11 @@ end
|
|
52
51
|
|
53
52
|
#### Decorations Available
|
54
53
|
1. Attributes
|
55
|
-
2.
|
56
|
-
3.
|
57
|
-
|
54
|
+
2. Relations
|
55
|
+
3. Conditional Attributes
|
56
|
+
4. Conditional Relations
|
57
|
+
5. Custom Methods
|
58
|
+
6. name_tag
|
58
59
|
|
59
60
|
##### Attributes
|
60
61
|
Attributes are fields in the model itself. You can reference them by below example
|
@@ -68,27 +69,6 @@ class UserSerializer < Mutils::Serialization::BaseSerializer
|
|
68
69
|
attribute :email, {always_include: true} ## this will allow to selectively include email
|
69
70
|
end
|
70
71
|
```
|
71
|
-
##### Custom Methods
|
72
|
-
Custom methods used in Serializer can be useful for cases as below.
|
73
|
-
`scope` will be available to reference object in Serializer in below case its `user`
|
74
|
-
|
75
|
-
```ruby
|
76
|
-
# frozen_string_literal: true
|
77
|
-
|
78
|
-
# User Serializer
|
79
|
-
class UserSerializer < Mutils::Serialization::BaseSerializer
|
80
|
-
attributes :id, :first_name, :last_name, :email
|
81
|
-
###
|
82
|
-
custom_methods :full_name
|
83
|
-
## OR
|
84
|
-
custom_method :full_name, {always_include: true} ## this will allow to selectively include full_name
|
85
|
-
###
|
86
|
-
|
87
|
-
def full_name
|
88
|
-
"#{scope.first_name} #{scope.last_name}"
|
89
|
-
end
|
90
|
-
end
|
91
|
-
```
|
92
72
|
##### Relations
|
93
73
|
Relations such as `has_many`, `belongs_to`, `has_one` can be used as follows
|
94
74
|
1. Every relation must be provided with their own serializer
|
@@ -114,8 +94,54 @@ class UserSerializer < Mutils::Serialization::BaseSerializer
|
|
114
94
|
end
|
115
95
|
end
|
116
96
|
```
|
97
|
+
##### Conditional Attributes
|
98
|
+
Attributes are fields in the model itself. You can reference them by below example
|
99
|
+
```ruby
|
100
|
+
# frozen_string_literal: true
|
101
|
+
|
102
|
+
# User Serializer
|
103
|
+
class UserSerializer < Mutils::Serialization::BaseSerializer
|
104
|
+
attributes :id, :first_name, :last_name
|
105
|
+
attribute :email, if: proc { |scope| scope.name == 'mutils' } ## Email will only serialize if user's name is 'mutils'
|
106
|
+
end
|
107
|
+
```
|
108
|
+
in proc {|scope|}, scope is object which is being serialized
|
109
|
+
##### Conditional Relations
|
110
|
+
Attributes are fields in the model itself. You can reference them by below example
|
111
|
+
```ruby
|
112
|
+
# frozen_string_literal: true
|
113
|
+
|
114
|
+
# User Serializer
|
115
|
+
class UserSerializer < Mutils::Serialization::BaseSerializer
|
116
|
+
attributes :id, :first_name, :last_name
|
117
|
+
has_many :comments, serializer: CommentSerializer, if: proc { |scope| scope.name == 'mutils' } ## comments will only serialize if user's name is 'mutils'
|
118
|
+
belongs_to :account, serializer: AccountSerializer, if: proc { |scope| scope.name != 'mutils' } ## account will only serialize if user's name is not 'mutils'
|
119
|
+
end
|
120
|
+
```
|
121
|
+
in proc {|scope|}, scope is object which is being serialized
|
122
|
+
##### Custom Methods
|
123
|
+
Custom methods used in Serializer can be useful for cases as below.
|
124
|
+
`scope` will be available to reference object in Serializer in below case its `user`
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
# frozen_string_literal: true
|
128
|
+
|
129
|
+
# User Serializer
|
130
|
+
class UserSerializer < Mutils::Serialization::BaseSerializer
|
131
|
+
attributes :id, :first_name, :last_name, :email
|
132
|
+
###
|
133
|
+
custom_methods :full_name
|
134
|
+
## OR
|
135
|
+
custom_method :full_name, {always_include: true} ## this will allow to selectively include full_name
|
136
|
+
###
|
137
|
+
|
138
|
+
def full_name
|
139
|
+
"#{scope.first_name} #{scope.last_name}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
```
|
117
143
|
##### name_tag
|
118
|
-
name_tag is used to provide custom name to serializer output keys for json
|
144
|
+
name_tag is used to provide custom name to serializer output keys for json
|
119
145
|
|
120
146
|
**Options**
|
121
147
|
- ``name_tag 'Person', true`` # Include Person or People in JSON serialization as root, true|false this only implies to root serializer
|
data/lib/mutils.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'dry/inflector'
|
3
4
|
require_relative 'mutils/version'
|
4
|
-
|
5
|
-
require 'active_support/inflector'
|
6
|
-
require 'active_support/core_ext/hash'
|
5
|
+
require_relative 'mutils/lib/helper'
|
7
6
|
require_relative 'mutils/serialization/serialization_results'
|
8
7
|
require_relative 'mutils/serialization/serialization_includes'
|
9
8
|
require_relative 'mutils/serialization/serialization_methods'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
# module Mutils
|
5
|
+
module Mutils
|
6
|
+
module Lib
|
7
|
+
# BaseSerializer: inherit this class to get Serializer functionality
|
8
|
+
class Helper
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
self.inflector_object = Dry::Inflector.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def underscore(string)
|
16
|
+
inflector_object.underscore string
|
17
|
+
end
|
18
|
+
|
19
|
+
def pluralize(string)
|
20
|
+
inflector_object.pluralize string
|
21
|
+
end
|
22
|
+
|
23
|
+
def collection?(object)
|
24
|
+
object.respond_to?(:size) && !object.respond_to?(:each_pair)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_accessor :inflector_object
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -5,13 +5,14 @@ module Mutils
|
|
5
5
|
module Serialization
|
6
6
|
# Module SerializationIncludes
|
7
7
|
module SerializationIncludes
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
def self.included(base)
|
9
|
+
base.class_eval do
|
10
|
+
class << self
|
11
|
+
attr_accessor :serializer_name,
|
12
|
+
:include_root,
|
13
|
+
:relationships,
|
14
|
+
:attributes_to_serialize
|
15
|
+
end
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
@@ -5,7 +5,9 @@ module Mutils
|
|
5
5
|
module Serialization
|
6
6
|
# Module SerializationCore
|
7
7
|
module SerializationMethods
|
8
|
-
|
8
|
+
def self.included(base)
|
9
|
+
base.extend ClassMethods
|
10
|
+
end
|
9
11
|
# Module ClassMethods
|
10
12
|
module ClassMethods
|
11
13
|
def name_tag(name_tag, root = nil)
|
@@ -30,6 +32,8 @@ module Mutils
|
|
30
32
|
end
|
31
33
|
|
32
34
|
def attribute(method_name, options = {})
|
35
|
+
raise "if: should be a Proc object for attribute #{method_name}" if options[:if] && (options[:if].class.to_s != 'Proc')
|
36
|
+
|
33
37
|
add_single_attribute(method_name, options, 'attribute')
|
34
38
|
end
|
35
39
|
|
@@ -40,12 +44,12 @@ module Mutils
|
|
40
44
|
def add_single_attribute(method_name, options, type)
|
41
45
|
self.attributes_to_serialize = {} if attributes_to_serialize.nil?
|
42
46
|
always_include = options[:always_include].nil? ? false : options[:always_include]
|
43
|
-
value = { method: type == 'method', always_include: always_include }
|
47
|
+
value = { method: type == 'method', always_include: always_include, if: options[:if] }
|
44
48
|
attributes_to_serialize[method_name] = value
|
45
49
|
end
|
46
50
|
|
47
|
-
def relationship(relationship_name, options = {}
|
48
|
-
options = prepare_options(relationship_name, options,
|
51
|
+
def relationship(relationship_name, options = {})
|
52
|
+
options = prepare_options(relationship_name, options, __callee__)
|
49
53
|
self.relationships = {} if relationships.nil?
|
50
54
|
relationships[relationship_name] = options
|
51
55
|
end
|
@@ -62,18 +66,18 @@ module Mutils
|
|
62
66
|
'serializer: SERIALIZER_CLASS'
|
63
67
|
end
|
64
68
|
raise "Serializer class not defined for relationship: #{relationship_name}" unless class_exists? class_name
|
69
|
+
raise "if: should be a Proc object for attribute #{relationship_name}" if options[:if] && (options[:if].class.to_s != 'Proc')
|
65
70
|
|
66
|
-
options[:serializer] = class_name.to_s
|
71
|
+
options[:serializer] = Object.const_get class_name.to_s
|
67
72
|
options[:option_name] = option_name
|
68
73
|
options[:label] = options[:label]
|
69
74
|
options
|
70
75
|
end
|
71
76
|
|
72
77
|
def class_exists?(class_name)
|
73
|
-
klass = class_name.to_s
|
78
|
+
klass = Object.const_get class_name.to_s rescue nil
|
74
79
|
klass && defined?(klass) && klass.is_a?(Class)
|
75
80
|
end
|
76
|
-
|
77
81
|
end
|
78
82
|
end
|
79
83
|
end
|
@@ -36,11 +36,10 @@ module Mutils
|
|
36
36
|
hash = {}
|
37
37
|
relationships&.keys&.each do |key|
|
38
38
|
object = scope.send(key)
|
39
|
-
label = relationships[key][:label]
|
40
39
|
name = key
|
41
|
-
if label
|
42
|
-
name =
|
43
|
-
name =
|
40
|
+
if (label = relationships[key][:label])
|
41
|
+
name = Lib::Helper.instance.underscore label
|
42
|
+
Lib::Helper.instance.collection?(object) && (name = Lib::Helper.instance.pluralize(name))
|
44
43
|
name = name.to_sym
|
45
44
|
end
|
46
45
|
check_if_included(relationships, key) && (hash[name] = relationships[key][:serializer].new(object).to_h)
|
@@ -49,21 +48,19 @@ module Mutils
|
|
49
48
|
end
|
50
49
|
|
51
50
|
def check_if_included(relationships, key)
|
51
|
+
return relationships[key][:if].call(scope) unless relationships[key][:if].nil? || scope_is_collection?
|
52
|
+
|
52
53
|
always_include = relationships[key][:always_include] == true
|
53
54
|
always_include || options[:includes]&.include?(key)
|
54
55
|
end
|
55
56
|
|
56
57
|
def scope_is_collection?
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
def collection?(object)
|
61
|
-
object.respond_to?(:size) && !object.respond_to?(:each_pair)
|
58
|
+
Lib::Helper.instance.collection? scope
|
62
59
|
end
|
63
60
|
|
64
61
|
def class_name
|
65
62
|
if scope_is_collection?
|
66
|
-
format_class_name(scope[0])
|
63
|
+
Lib::Helper.name.pluralize(format_class_name(scope[0]))
|
67
64
|
else
|
68
65
|
format_class_name(scope)
|
69
66
|
end
|
data/lib/mutils/version.rb
CHANGED
data/mutils.gemspec
CHANGED
@@ -22,13 +22,12 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.require_paths = ['lib']
|
23
23
|
spec.required_ruby_version = '>= 2.5.0'
|
24
24
|
spec.required_rubygems_version = '>= 1.8.11'
|
25
|
-
spec.add_runtime_dependency('
|
25
|
+
spec.add_runtime_dependency('dry-inflector')
|
26
26
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
27
27
|
spec.add_development_dependency 'coveralls'
|
28
28
|
spec.add_development_dependency 'rake', '~> 13.0'
|
29
|
+
spec.add_development_dependency 'rspec'
|
29
30
|
spec.add_development_dependency 'rspec-json_expectations'
|
30
|
-
spec.add_development_dependency 'rspec-rails'
|
31
|
-
spec.add_development_dependency 'rspec-xml_helpers'
|
32
31
|
|
33
32
|
spec.metadata = {
|
34
33
|
'bug_tracker_uri' => 'https://github.com/niteshpurohit/mutils/issues',
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mutils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.36
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nitesh Purohit
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-04-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: dry-inflector
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '13.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name: rspec
|
70
|
+
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -81,21 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name: rspec-
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: rspec-xml_helpers
|
84
|
+
name: rspec-json_expectations
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
100
86
|
requirements:
|
101
87
|
- - ">="
|
@@ -129,7 +115,6 @@ files:
|
|
129
115
|
- ".rubocop_todo.yml"
|
130
116
|
- ".ruby-version"
|
131
117
|
- ".travis.yml"
|
132
|
-
- BENCHMARK-SERIALIZER-JSON.md
|
133
118
|
- CHANGELOG.md
|
134
119
|
- CODE_OF_CONDUCT.md
|
135
120
|
- Gemfile
|
@@ -138,13 +123,13 @@ files:
|
|
138
123
|
- Makefile
|
139
124
|
- README.md
|
140
125
|
- Rakefile
|
141
|
-
- benchmark/benchmark-serializer-json.rb
|
142
126
|
- bin/console
|
143
127
|
- bin/setup
|
144
128
|
- lib/generators/mutils/USAGE
|
145
129
|
- lib/generators/mutils/serializer_generator.rb
|
146
130
|
- lib/generators/mutils/templates/serializer.rb.tt
|
147
131
|
- lib/mutils.rb
|
132
|
+
- lib/mutils/lib/helper.rb
|
148
133
|
- lib/mutils/serialization/base_serializer.rb
|
149
134
|
- lib/mutils/serialization/serialization_includes.rb
|
150
135
|
- lib/mutils/serialization/serialization_methods.rb
|
@@ -156,7 +141,7 @@ licenses:
|
|
156
141
|
- MIT
|
157
142
|
metadata:
|
158
143
|
bug_tracker_uri: https://github.com/niteshpurohit/mutils/issues
|
159
|
-
source_code_uri: https://github.com/niteshpurohit/mutils/tree/v0.2.
|
144
|
+
source_code_uri: https://github.com/niteshpurohit/mutils/tree/v0.2.36
|
160
145
|
post_install_message:
|
161
146
|
rdoc_options: []
|
162
147
|
require_paths:
|
@@ -1,82 +0,0 @@
|
|
1
|
-
```
|
2
|
-
ruby benchmark/benchmark-serializer-json.rb
|
3
|
-
|
4
|
-
Rehearsal ------------------------------------------------
|
5
|
-
fast_jsonapi 0.469146 0.003692 0.472838 ( 0.482972)
|
6
|
-
==>mutils 0.343414 0.002338 0.345752 ( 0.350116)
|
7
|
-
as_json 0.349795 0.002601 0.352396 ( 0.355537)
|
8
|
-
grape_entity 2.123932 0.008031 2.131963 ( 2.142096)
|
9
|
-
blueprinter 0.729144 0.005669 0.734813 ( 0.737173)
|
10
|
-
roar 1.815007 0.015412 1.830419 ( 1.831867)
|
11
|
-
panko 0.324755 0.000970 0.325725 ( 0.325953)
|
12
|
-
--------------------------------------- total: 6.193906sec
|
13
|
-
|
14
|
-
user system total real
|
15
|
-
fast_jsonapi 0.326813 0.000479 0.327292 ( 0.328071)
|
16
|
-
==>mutils 0.228319 0.000145 0.228464 ( 0.228649)
|
17
|
-
as_json 0.252139 0.000242 0.252381 ( 0.252570)
|
18
|
-
grape_entity 1.820288 0.008052 1.828340 ( 1.837977)
|
19
|
-
blueprinter 0.656481 0.001270 0.657751 ( 0.659753)
|
20
|
-
roar 1.592949 0.008122 1.601071 ( 1.604941)
|
21
|
-
panko 0.260401 0.000433 0.260834 ( 0.261211)
|
22
|
-
|
23
|
-
Warming up --------------------------------------
|
24
|
-
fast_jsonapi 1.000 i/100ms
|
25
|
-
==>mutils 1.000 i/100ms
|
26
|
-
as_json 1.000 i/100ms
|
27
|
-
grape_entity 1.000 i/100ms
|
28
|
-
blueprinter 1.000 i/100ms
|
29
|
-
roar 1.000 i/100ms
|
30
|
-
panko 1.000 i/100ms
|
31
|
-
Calculating -------------------------------------
|
32
|
-
fast_jsonapi 2.215 (± 5.1%) i/s - 22.000 in 10.107915s
|
33
|
-
==>mutils 3.136 (± 3.0%) i/s - 32.000 in 10.281530s
|
34
|
-
as_json 3.455 (± 3.1%) i/s - 35.000 in 10.229037s
|
35
|
-
grape_entity 0.509 (± 7.2%) i/s - 6.000 in 11.844870s
|
36
|
-
blueprinter 1.337 (± 3.9%) i/s - 14.000 in 10.537541s
|
37
|
-
roar 0.613 (± 2.2%) i/s - 7.000 in 11.441661s
|
38
|
-
panko 3.527 (± 2.9%) i/s - 36.000 in 10.292679s
|
39
|
-
with 95.0% confidence
|
40
|
-
|
41
|
-
Comparison:
|
42
|
-
panko: 3.5 i/s
|
43
|
-
as_json: 3.5 i/s - same-ish: difference falls within error
|
44
|
-
==>mutils: 3.1 i/s - 1.13x (± 0.05) slower
|
45
|
-
fast_jsonapi: 2.2 i/s - 1.59x (± 0.09) slower
|
46
|
-
blueprinter: 1.3 i/s - 2.64x (± 0.13) slower
|
47
|
-
roar: 0.6 i/s - 5.76x (± 0.21) slower
|
48
|
-
grape_entity: 0.5 i/s - 6.93x (± 0.53) slower
|
49
|
-
with 95.0% confidence
|
50
|
-
|
51
|
-
Calculating -------------------------------------
|
52
|
-
fast_jsonapi 62.946M memsize ( 0.000 retained)
|
53
|
-
981.039k objects ( 0.000 retained)
|
54
|
-
50.000 strings ( 0.000 retained)
|
55
|
-
==>mutils 65.112M memsize ( 0.000 retained)
|
56
|
-
721.156k objects ( 0.000 retained)
|
57
|
-
0.000 strings ( 0.000 retained)
|
58
|
-
as_json 98.148M memsize ( 0.000 retained)
|
59
|
-
1.683M objects ( 0.000 retained)
|
60
|
-
8.000 strings ( 0.000 retained)
|
61
|
-
grape_entity 245.776M memsize ( 0.000 retained)
|
62
|
-
2.524M objects ( 0.000 retained)
|
63
|
-
4.000 strings ( 0.000 retained)
|
64
|
-
blueprinter 71.856M memsize ( 0.000 retained)
|
65
|
-
661.154k objects ( 0.000 retained)
|
66
|
-
0.000 strings ( 0.000 retained)
|
67
|
-
roar 221.022M memsize ( 0.000 retained)
|
68
|
-
1.823M objects ( 0.000 retained)
|
69
|
-
1.000 strings ( 0.000 retained)
|
70
|
-
panko 98.153M memsize ( 0.000 retained)
|
71
|
-
1.683M objects ( 0.000 retained)
|
72
|
-
13.000 strings ( 0.000 retained)
|
73
|
-
|
74
|
-
Comparison:
|
75
|
-
fast_jsonapi: 62945864 allocated
|
76
|
-
=>>mutils: 65111936 allocated - 1.03x more
|
77
|
-
blueprinter: 71856304 allocated - 1.14x more
|
78
|
-
as_json: 98148488 allocated - 1.56x more
|
79
|
-
panko: 98153072 allocated - 1.56x more
|
80
|
-
roar: 221022344 allocated - 3.51x more
|
81
|
-
grape_entity: 245775576 allocated - 3.90x morre
|
82
|
-
```
|
@@ -1,252 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'bundler/inline'
|
4
|
-
|
5
|
-
require_relative '../lib//mutils'
|
6
|
-
|
7
|
-
gemfile do
|
8
|
-
source 'https://rubygems.org'
|
9
|
-
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
10
|
-
gem 'oj'
|
11
|
-
gem 'benchmark-ips', require: 'benchmark/ips'
|
12
|
-
gem 'kalibera', :github => 'softdevteam/libkalibera', glob: 'ruby/*.gemspec'
|
13
|
-
# gem 'kalibera'
|
14
|
-
gem 'benchmark-memory', require: 'benchmark/memory'
|
15
|
-
|
16
|
-
gem 'activesupport'
|
17
|
-
|
18
|
-
# https://github.com/Netflix/fast_jsonapi
|
19
|
-
gem 'fast_jsonapi'
|
20
|
-
|
21
|
-
# https://github.com/ruby-grape/grape-entity
|
22
|
-
gem 'grape-entity'
|
23
|
-
|
24
|
-
# https://github.com/procore/blueprinter
|
25
|
-
gem 'blueprinter'
|
26
|
-
|
27
|
-
# https://github.com/trailblazer/roar
|
28
|
-
# https://github.com/trailblazer/representable
|
29
|
-
gem 'roar'
|
30
|
-
gem 'multi_json'
|
31
|
-
|
32
|
-
# https://github.com/yosiat/panko_serializer
|
33
|
-
gem 'panko_serializer'
|
34
|
-
end
|
35
|
-
|
36
|
-
require 'active_support'
|
37
|
-
require 'active_support/core_ext/object' # For Hash#deep_dup
|
38
|
-
|
39
|
-
# Define models
|
40
|
-
Issue = Struct.new(:id, :number, :title, :user, :labels) do
|
41
|
-
alias_method :read_attribute_for_serialization, :send
|
42
|
-
|
43
|
-
def label_ids
|
44
|
-
labels.map(&:id)
|
45
|
-
end
|
46
|
-
|
47
|
-
def user_id
|
48
|
-
user.id
|
49
|
-
end
|
50
|
-
end
|
51
|
-
User = Struct.new(:id, :login) do
|
52
|
-
alias_method :read_attribute_for_serialization, :send
|
53
|
-
end
|
54
|
-
Label = Struct.new(:id, :name, :color) do
|
55
|
-
alias_method :read_attribute_for_serialization, :send
|
56
|
-
end
|
57
|
-
|
58
|
-
# Define serializers
|
59
|
-
module FastJsonApi
|
60
|
-
class IssueSerializer
|
61
|
-
include FastJsonapi::ObjectSerializer
|
62
|
-
|
63
|
-
attributes :number, :title
|
64
|
-
has_many :labels
|
65
|
-
belongs_to :user
|
66
|
-
end
|
67
|
-
|
68
|
-
class LabelSerializer
|
69
|
-
include FastJsonapi::ObjectSerializer
|
70
|
-
|
71
|
-
attributes :name, :color
|
72
|
-
end
|
73
|
-
|
74
|
-
class UserSerializer
|
75
|
-
include FastJsonapi::ObjectSerializer
|
76
|
-
|
77
|
-
attributes :login
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
module GrapeEntity
|
82
|
-
class Label < Grape::Entity
|
83
|
-
expose :id
|
84
|
-
expose :name
|
85
|
-
expose :color
|
86
|
-
end
|
87
|
-
|
88
|
-
class User < Grape::Entity
|
89
|
-
expose :id
|
90
|
-
expose :login
|
91
|
-
end
|
92
|
-
|
93
|
-
class Issue < Grape::Entity
|
94
|
-
expose :id
|
95
|
-
expose :number
|
96
|
-
expose :title
|
97
|
-
expose :labels, using: Label
|
98
|
-
expose :user, using: User
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
Blueprinter.configure do |config|
|
103
|
-
config.generator = Oj
|
104
|
-
config.sort_fields_by = :definition
|
105
|
-
end
|
106
|
-
|
107
|
-
module BluePrint
|
108
|
-
class Label < Blueprinter::Base
|
109
|
-
identifier :id
|
110
|
-
fields :name, :color
|
111
|
-
end
|
112
|
-
|
113
|
-
class User < Blueprinter::Base
|
114
|
-
identifier :id
|
115
|
-
field :login
|
116
|
-
end
|
117
|
-
|
118
|
-
class Issue < Blueprinter::Base
|
119
|
-
identifier :id
|
120
|
-
fields :number, :title
|
121
|
-
association :labels, blueprint: Label
|
122
|
-
association :user, blueprint: User
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
module Mutils
|
127
|
-
class Label < Mutils::Serialization::BaseSerializer
|
128
|
-
attributes :id, :name, :color
|
129
|
-
end
|
130
|
-
|
131
|
-
class User < Mutils::Serialization::BaseSerializer
|
132
|
-
attributes :id, :login
|
133
|
-
end
|
134
|
-
|
135
|
-
class Issue < Mutils::Serialization::BaseSerializer
|
136
|
-
attributes :id, :number, :title
|
137
|
-
has_many :labels, serializer: Mutils::Label, always_include: true
|
138
|
-
belongs_to :user, serializer: Mutils::User, always_include: true
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
require 'roar/decorator'
|
143
|
-
require 'roar/json'
|
144
|
-
module ROAR
|
145
|
-
class IssueRepresenter < Roar::Decorator
|
146
|
-
include Roar::JSON
|
147
|
-
|
148
|
-
property :id
|
149
|
-
property :number
|
150
|
-
property :title
|
151
|
-
|
152
|
-
collection :labels do
|
153
|
-
property :id
|
154
|
-
property :name
|
155
|
-
property :color
|
156
|
-
end
|
157
|
-
|
158
|
-
property :user do
|
159
|
-
property :id
|
160
|
-
property :login
|
161
|
-
end
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
module PANKO
|
166
|
-
class LabelSerializer < Panko::Serializer
|
167
|
-
attributes :id, :name, :color
|
168
|
-
end
|
169
|
-
|
170
|
-
class UserSerializer < Panko::Serializer
|
171
|
-
attributes :id, :login
|
172
|
-
end
|
173
|
-
|
174
|
-
class IssueSerializer < Panko::Serializer
|
175
|
-
attributes :id, :number, :title
|
176
|
-
has_many :labels, serializer: LabelSerializer
|
177
|
-
has_one :user, serializer: UserSerializer
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
# Generate data
|
182
|
-
users = Array.new(10) { |i| User.new(i, "User #{i}") }
|
183
|
-
labels = Array.new(4) { |i| Label.new(i, "Label #{i}", 'ffffff') }
|
184
|
-
issues = Array.new(20_000) { |i| Issue.new(i, i, "Issue #{i}", users.sample, labels.sample(rand(2..4))) }
|
185
|
-
|
186
|
-
serializers = [
|
187
|
-
{
|
188
|
-
name: :fast_jsonapi,
|
189
|
-
serializer: -> { FastJsonApi::IssueSerializer.new(issues, include: %i[labels user]).serializable_hash },
|
190
|
-
output_inspector: ->(output) { output[:data].first }
|
191
|
-
},
|
192
|
-
{
|
193
|
-
name: :mutils,
|
194
|
-
serializer: -> { Mutils::Issue.new(issues).as_json },
|
195
|
-
output_inspector: ->(output) { output.first }
|
196
|
-
},
|
197
|
-
{
|
198
|
-
name: :as_json,
|
199
|
-
serializer: -> { issues.as_json },
|
200
|
-
output_inspector: ->(output) { output.first }
|
201
|
-
},
|
202
|
-
{
|
203
|
-
name: :grape_entity,
|
204
|
-
serializer: -> { GrapeEntity::Issue.represent(issues).as_json },
|
205
|
-
output_inspector: ->(output) { output.first }
|
206
|
-
},
|
207
|
-
{
|
208
|
-
name: :blueprinter,
|
209
|
-
serializer: -> { BluePrint::Issue.render_as_hash(issues) },
|
210
|
-
output_inspector: ->(output) { output.first }
|
211
|
-
},
|
212
|
-
{
|
213
|
-
name: :roar,
|
214
|
-
serializer: -> { ROAR::IssueRepresenter.for_collection.new(issues).as_json },
|
215
|
-
output_inspector: ->(output) { output.first }
|
216
|
-
},
|
217
|
-
{
|
218
|
-
name: :panko,
|
219
|
-
serializer: -> { Panko::ArraySerializer.new(issues, each_serializer: PANKO::IssueSerializer).as_json },
|
220
|
-
output_inspector: ->(output) { output['subjects'].first }
|
221
|
-
}
|
222
|
-
]
|
223
|
-
|
224
|
-
# Display output
|
225
|
-
serializers.each do |name:, serializer:, output_inspector:|
|
226
|
-
puts "\n#{name}:\n"
|
227
|
-
puts output_inspector.call(serializer.call).inspect
|
228
|
-
puts
|
229
|
-
end
|
230
|
-
|
231
|
-
# Run benchmarks
|
232
|
-
require 'benchmark'
|
233
|
-
Benchmark.bmbm do |b|
|
234
|
-
serializers.each do |name:, serializer:, **_other|
|
235
|
-
b.report(name, &serializer)
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
%i[ips memory].each do |bench|
|
240
|
-
puts '##################################################'
|
241
|
-
puts "START #{bench}"
|
242
|
-
puts '##################################################'
|
243
|
-
Benchmark.send(bench) do |b|
|
244
|
-
b.config(time: 10, warmup: 5, stats: :bootstrap, confidence: 95) if b.respond_to?(:config)
|
245
|
-
|
246
|
-
serializers.each do |name:, serializer:, **_other|
|
247
|
-
b.report(name, &serializer)
|
248
|
-
end
|
249
|
-
|
250
|
-
b.compare!
|
251
|
-
end
|
252
|
-
end
|