mutils 0.2.25

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.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Nitesh Purohit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,6 @@
1
+ build:
2
+ bundle exec rake build
3
+ release: build
4
+ git add .
5
+ git commit -am '$(MESSAGE)'
6
+ bundle exec rake release
data/README.md ADDED
@@ -0,0 +1,126 @@
1
+
2
+ [![Gem Version](https://badge.fury.io/rb/mutils.svg)](https://badge.fury.io/rb/mutils)
3
+
4
+ # Mutils
5
+ ## Introduction
6
+ `mutils` is collection of useful modules for `ruby on rails` which is tested and benchmarked against high load.
7
+
8
+ These collection of modules are built by developer for developers :-)
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+ ```ruby
13
+ gem 'mutils'
14
+ ```
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install mutils
22
+
23
+ ## Modules
24
+ | Sno | Name | Status |
25
+ |:---: |:-----------------: |:------: |
26
+ | 1 | Serializer - JSON | Beta |
27
+ | 2 | Serializer - XML | In-Dev |
28
+ | 3 | Active Storage Helpers | In-Dev |
29
+ ## Usage
30
+ ### Serializer - JSON
31
+ JSON Serializer for Active Models
32
+
33
+ #### Generate Serializer by command
34
+ ```shell script
35
+ rails g serializer User id first_name last_name email
36
+
37
+ OUTPUT
38
+ Running via Spring preloader in process xxxxx
39
+ create app/serializers/user_serializer.rb
40
+ ```
41
+ You will get serializer in app/serializers/user_serializer.rb
42
+ ```ruby
43
+ # frozen_string_literal: true
44
+
45
+ # User Serializer
46
+ class UserSerializer < Mutils::Serialization::BaseSerializer
47
+ attributes :id, :first_name, :last_name, :email
48
+ end
49
+ ```
50
+
51
+ #### Decorations Available
52
+ 1. Attributes
53
+ 2. Custom Methods
54
+ 3. Relations
55
+
56
+ ##### Attributes
57
+ Attributes are fields in the model itself. You can reference them by below example
58
+ ```ruby
59
+ # frozen_string_literal: true
60
+
61
+ # User Serializer
62
+ class UserSerializer < Mutils::Serialization::BaseSerializer
63
+ attributes :id, :first_name, :last_name, :email
64
+ end
65
+ ```
66
+ ##### Custom Methods
67
+ Custom methods used in Serializer can be useful for cases as below.
68
+ `scope` will be available to reference object in Serializer in below case its `user`
69
+
70
+ ```ruby
71
+ # frozen_string_literal: true
72
+
73
+ # User Serializer
74
+ class UserSerializer < Mutils::Serialization::BaseSerializer
75
+ attributes :id, :first_name, :last_name, :email
76
+ custom_methods :full_name
77
+
78
+ def full_name
79
+ "#{scope.first_name} #{scope.last_name}"
80
+ end
81
+ end
82
+ ```
83
+ ##### Relations
84
+ Relations such as `has_many`, `belongs_to`, `has_one` can be used as follows
85
+ 1. Every relation must be provided with their own serializer
86
+ 2. `always_include` option can be used to instruct `Serializer` to always include this relation
87
+ 3. `always_include` by default is disabled, relations which are not `always_include` can be included while using the serializer. Refer to next section for this usage
88
+
89
+ ```ruby
90
+ # frozen_string_literal: true
91
+
92
+ # User Serializer
93
+ class UserSerializer < Mutils::Serialization::BaseSerializer
94
+ attributes :id, :first_name, :last_name, :email
95
+ belongs_to :company, serializer: CompanySerializer, always_include: true
96
+ has_many :comments, serializer: CommentSerializer
97
+ has_one :account, serializer: AccountSerializer
98
+
99
+ def full_name
100
+ "#{scope.first_name} #{scope.last_name}"
101
+ end
102
+ end
103
+ ```
104
+ Usage: Use anywhere by
105
+
106
+ ```ruby
107
+ user = User.first
108
+ options = {includes: [:comments,:account]}
109
+ UserSerializer.new(user,options).to_h
110
+ # or
111
+ users = User.all
112
+ options = {includes: [:account]}
113
+ UserSerializer.new(users,options).to_json
114
+ ```
115
+
116
+ ## Contributing
117
+
118
+ Bug Reports and PR's are welcomed in this repository kindly follow guidelines from `.github` directory.
119
+
120
+ ## License
121
+
122
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
123
+
124
+ ## Code of Conduct
125
+
126
+ Everyone interacting in the Mutils project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/niteshpurohit/mutils/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,248 @@
1
+ require 'bundler/inline'
2
+
3
+ require_relative '../lib//mutils'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+ gem 'oj'
8
+ gem 'benchmark-ips', require: 'benchmark/ips'
9
+ gem 'kalibera'
10
+ gem 'benchmark-memory', require: 'benchmark/memory'
11
+
12
+ gem 'activesupport'
13
+
14
+ # https://github.com/Netflix/fast_jsonapi
15
+ gem 'fast_jsonapi'
16
+
17
+ # https://github.com/ruby-grape/grape-entity
18
+ gem 'grape-entity'
19
+
20
+ # https://github.com/procore/blueprinter
21
+ gem 'blueprinter'
22
+
23
+ # https://github.com/trailblazer/roar
24
+ # https://github.com/trailblazer/representable
25
+ gem 'roar'
26
+ gem 'multi_json'
27
+
28
+ # https://github.com/yosiat/panko_serializer
29
+ gem 'panko_serializer'
30
+ end
31
+
32
+ require 'active_support'
33
+ require 'active_support/core_ext/object' # For Hash#deep_dup
34
+
35
+ # Define models
36
+ Issue = Struct.new(:id, :number, :title, :user, :labels) do
37
+ alias_method :read_attribute_for_serialization, :send
38
+
39
+ def label_ids
40
+ labels.map(&:id)
41
+ end
42
+
43
+ def user_id
44
+ user.id
45
+ end
46
+ end
47
+ User = Struct.new(:id, :login) do
48
+ alias_method :read_attribute_for_serialization, :send
49
+ end
50
+ Label = Struct.new(:id, :name, :color) do
51
+ alias_method :read_attribute_for_serialization, :send
52
+ end
53
+
54
+ # Define serializers
55
+ module FastJsonApi
56
+ class IssueSerializer
57
+ include FastJsonapi::ObjectSerializer
58
+
59
+ attributes :number, :title
60
+ has_many :labels
61
+ belongs_to :user
62
+ end
63
+
64
+ class LabelSerializer
65
+ include FastJsonapi::ObjectSerializer
66
+
67
+ attributes :name, :color
68
+ end
69
+
70
+ class UserSerializer
71
+ include FastJsonapi::ObjectSerializer
72
+
73
+ attributes :login
74
+ end
75
+ end
76
+
77
+ module GrapeEntity
78
+ class Label < Grape::Entity
79
+ expose :id
80
+ expose :name
81
+ expose :color
82
+ end
83
+
84
+ class User < Grape::Entity
85
+ expose :id
86
+ expose :login
87
+ end
88
+
89
+ class Issue < Grape::Entity
90
+ expose :id
91
+ expose :number
92
+ expose :title
93
+ expose :labels, using: Label
94
+ expose :user, using: User
95
+ end
96
+ end
97
+
98
+ Blueprinter.configure do |config|
99
+ config.generator = Oj
100
+ config.sort_fields_by = :definition
101
+ end
102
+
103
+ module BluePrint
104
+ class Label < Blueprinter::Base
105
+ identifier :id
106
+ fields :name, :color
107
+ end
108
+
109
+ class User < Blueprinter::Base
110
+ identifier :id
111
+ field :login
112
+ end
113
+
114
+ class Issue < Blueprinter::Base
115
+ identifier :id
116
+ fields :number, :title
117
+ association :labels, blueprint: Label
118
+ association :user, blueprint: User
119
+ end
120
+ end
121
+
122
+ module Mutils
123
+ class Label < Mutils::Serialization::BaseSerializer
124
+ attributes :id, :name, :color
125
+ end
126
+
127
+ class User < Mutils::Serialization::BaseSerializer
128
+ attributes :id, :login
129
+ end
130
+
131
+ class Issue < Mutils::Serialization::BaseSerializer
132
+ attributes :id, :number, :title
133
+ has_many :labels, serializer: Mutils::Label, always_include: true
134
+ belongs_to :user, serializer: Mutils::User, always_include: true
135
+ end
136
+ end
137
+
138
+ require 'roar/decorator'
139
+ require 'roar/json'
140
+ module ROAR
141
+ class IssueRepresenter < Roar::Decorator
142
+ include Roar::JSON
143
+
144
+ property :id
145
+ property :number
146
+ property :title
147
+
148
+ collection :labels do
149
+ property :id
150
+ property :name
151
+ property :color
152
+ end
153
+
154
+ property :user do
155
+ property :id
156
+ property :login
157
+ end
158
+ end
159
+ end
160
+
161
+ module PANKO
162
+ class LabelSerializer < Panko::Serializer
163
+ attributes :id, :name, :color
164
+ end
165
+
166
+ class UserSerializer < Panko::Serializer
167
+ attributes :id, :login
168
+ end
169
+
170
+ class IssueSerializer < Panko::Serializer
171
+ attributes :id, :number, :title
172
+ has_many :labels, serializer: LabelSerializer
173
+ has_one :user, serializer: UserSerializer
174
+ end
175
+ end
176
+
177
+ # Generate data
178
+ users = Array.new(10) { |i| User.new(i, "User #{i}") }
179
+ labels = Array.new(4) { |i| Label.new(i, "Label #{i}", 'ffffff') }
180
+ issues = Array.new(10_000) { |i| Issue.new(i, i, "Issue #{i}", users.sample, labels.sample(rand(2..4))) }
181
+
182
+ serializers = [
183
+ {
184
+ name: :as_json,
185
+ serializer: -> { issues.as_json },
186
+ output_inspector: ->(output) { output.first }
187
+ },
188
+ {
189
+ name: :fast_jsonapi,
190
+ serializer: -> { FastJsonApi::IssueSerializer.new(issues, include: [:labels, :user]).serializable_hash },
191
+ output_inspector: ->(output) { output[:data].first }
192
+ },
193
+ {
194
+ name: :grape_entity,
195
+ serializer: -> { GrapeEntity::Issue.represent(issues).as_json },
196
+ output_inspector: ->(output) { output.first }
197
+ },
198
+ {
199
+ name: :blueprinter,
200
+ serializer: -> { BluePrint::Issue.render_as_hash(issues) },
201
+ output_inspector: ->(output) { output.first }
202
+ },
203
+ {
204
+ name: :mutils,
205
+ serializer: -> { Mutils::Issue.new(issues).as_json },
206
+ output_inspector: ->(output) { output.first }
207
+ },
208
+ {
209
+ name: :roar,
210
+ serializer: -> { ROAR::IssueRepresenter.for_collection.new(issues).as_json },
211
+ output_inspector: ->(output) { output.first }
212
+ },
213
+ {
214
+ name: :panko,
215
+ serializer: -> { Panko::ArraySerializer.new(issues, each_serializer: PANKO::IssueSerializer).as_json },
216
+ output_inspector: ->(output) { output['subjects'].first }
217
+ }
218
+ ]
219
+
220
+ # Display output
221
+ serializers.each do |name:, serializer:, output_inspector:|
222
+ puts "\n#{name}:\n"
223
+ puts output_inspector.call(serializer.call).inspect
224
+ puts
225
+ end
226
+
227
+ # Run benchmarks
228
+ require 'benchmark'
229
+ Benchmark.bmbm do |b|
230
+ serializers.each do |name:, serializer:, **_other|
231
+ b.report(name, &serializer)
232
+ end
233
+ end
234
+
235
+ %i[ips memory].each do |bench|
236
+ puts '##################################################'
237
+ puts "START #{bench}"
238
+ puts '##################################################'
239
+ Benchmark.send(bench) do |b|
240
+ b.config(time: 10, warmup: 5, stats: :bootstrap, confidence: 95) if b.respond_to?(:config)
241
+
242
+ serializers.each do |name:, serializer:, **_other|
243
+ b.report(name, &serializer)
244
+ end
245
+
246
+ b.compare!
247
+ end
248
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "mutils"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generates a serializer for the given model.
3
+
4
+ Example:
5
+ rails generate serializer User
6
+
7
+ This will create:
8
+ app/serializers/user_serializer.rb