mutils 0.2.35 → 0.2.36

Sign up to get free protection for your applications and to get access to all the features.
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