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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29ea440032b0c3a5961c65970f1e4d9654b19f44d5549c62b178a3401799aae5
4
- data.tar.gz: 99d62ab7cc81e88b58644b47ebe607372fb74df7c376adef70f180f9dec6b771
3
+ metadata.gz: 1331c714748c7ecdc92258a4b37ad2ebddb23bff4a5a9858eab6bcc9a08fee0f
4
+ data.tar.gz: 6a9850b4e1602f656c90ce2b3fa65bd1dc15639f4aad115e8295668a5ea0f305
5
5
  SHA512:
6
- metadata.gz: '0278f224aad256658b8b862135e0afcd29ef05873e7b392bc8c8ca5af67e38b1bc31aaf9e500c3349b7674908e3f6821c16ddee8db5b845b867e84718069d35c'
7
- data.tar.gz: 18ee155fbc162d27b78056468dc064d755ed2339fd65c0fe677a75cfea73043999ca7244ad28671e076f71e54252b278ab8add538b289b1b82c413934b8a6feb
6
+ metadata.gz: 2af97f7e2f52f822568edf377dfa135347bd506374c27ece2c86c3b82c96780e6111e6723532192175e979cfcb8885219018d7851acb12f35744a35777513b65
7
+ data.tar.gz: ffd8ded7613308b8a736ed8fe6eee83de98c183c34854d22fc30b03f438dc6e1cc71cc42df9f1a3de66d3a2e1d57dde75a01678e0214df9467a3077ca09fd522
data/.rubocop.yml CHANGED
@@ -1,11 +1,7 @@
1
1
  inherit_from: .rubocop_todo.yml
2
2
 
3
3
  AllCops:
4
- TargetRubyVersion: "2.7.0"
5
- Naming/FileName:
6
- Exclude:
7
- - 'benchmark/benchmark-serializer-json.rb'
8
- Style/Documentation:
4
+ TargetRubyVersion: "2.5.0"
9
5
  Exclude:
10
6
  - 'spec/**/*'
11
7
  - 'test/**/*'
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
- Metrics/LineLength:
36
+ Layout/LineLength:
37
37
  Max: 608
38
38
  Metrics/MethodLength:
39
39
  Max: 20
40
40
  Metrics/AbcSize:
41
- Max: 20
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.35)
5
- activesupport (>= 4.2)
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
- erubi (1.9.0)
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. Custom Methods
56
- 3. Relations
57
- 3. name_tag
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 or tags for xml
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
- require 'active_support/concern'
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
- extend ActiveSupport::Concern
9
- included do
10
- class << self
11
- attr_accessor :serializer_name,
12
- :include_root,
13
- :relationships,
14
- :attributes_to_serialize
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
- extend ActiveSupport::Concern
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 = {}, option_name = 'belongs_to')
48
- options = prepare_options(relationship_name, options, option_name)
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.constantize
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.constantize rescue nil
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 = label.underscore
43
- name = name.pluralize if collection? object
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
- scope.respond_to?(:size) && !scope.respond_to?(:each_pair)
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]).pluralize
63
+ Lib::Helper.name.pluralize(format_class_name(scope[0]))
67
64
  else
68
65
  format_class_name(scope)
69
66
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutils
4
- VERSION = '0.2.35'
4
+ VERSION = '0.2.36'
5
5
  end
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('activesupport', ['>= 4.2'])
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.35
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-03-30 00:00:00.000000000 Z
11
+ date: 2020-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activesupport
14
+ name: dry-inflector
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.2'
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: '4.2'
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-json_expectations
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-rails
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.35
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