mutils 0.2.34 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/CONTRIBUTING.md +3 -3
- data/.github/dependabot.yml +11 -0
- data/.gitignore +2 -0
- data/.huskyrc +7 -0
- data/.rspec +0 -1
- data/.rubocop.yml +2 -7
- data/.rubocop_todo.yml +13 -1
- data/.travis.yml +26 -4
- data/CHANGELOG.md +88 -37
- data/Gemfile +6 -0
- data/Gemfile.lock +44 -71
- data/README.md +118 -39
- data/SECURITY.md +13 -0
- data/Version +1 -0
- data/commitlint.config.js +1 -0
- data/gemdeploy.sh +10 -0
- data/lib/mutils.rb +3 -3
- data/lib/mutils/lib/helper.rb +42 -0
- data/lib/mutils/lib/result_hash.rb +25 -0
- data/lib/mutils/serialization/base_serializer.rb +0 -8
- data/lib/mutils/serialization/methods/attributes.rb +52 -0
- data/lib/mutils/serialization/methods/main.rb +27 -0
- data/lib/mutils/serialization/methods/relations.rb +40 -0
- data/lib/mutils/serialization/results/attributes.rb +24 -0
- data/lib/mutils/serialization/results/main.rb +59 -0
- data/lib/mutils/serialization/results/relations.rb +23 -0
- data/lib/mutils/serialization/serialization_includes.rb +9 -7
- data/lib/mutils/serialization/serialization_methods.rb +7 -67
- data/lib/mutils/serialization/serialization_results.rb +6 -57
- data/lib/mutils/version.rb +1 -1
- data/mutils.gemspec +5 -8
- data/package-lock.json +7157 -0
- data/package.json +94 -0
- metadata +25 -71
- data/.github/workflows/gempush.yml +0 -28
- data/.mergify.yml +0 -8
- data/.ruby-version +0 -1
- data/BENCHMARK-SERIALIZER-JSON.md +0 -82
- data/Makefile +0 -8
- data/benchmark/benchmark-serializer-json.rb +0 -252
data/README.md
CHANGED
@@ -1,13 +1,34 @@
|
|
1
|
-
[](https://codeclimate.com/github/code-vedas/mutils/maintainability)
|
2
2
|

|
3
3
|
[](https://badge.fury.io/rb/mutils)
|
4
|
-
[](https://coveralls.io/github/Code-Vedas/mutils?branch=master)
|
5
|
+
[](https://travis-ci.com/code-vedas/mutils)
|
6
6
|
# Mutils
|
7
7
|
## Introduction
|
8
8
|
`mutils` is collection of useful modules for `ruby on rails` which is tested and benchmarked against high load.
|
9
9
|
|
10
10
|
These collection of modules are built by developer for developers :-)
|
11
|
+
# Table of Contents
|
12
|
+
|
13
|
+
* [Features](#features)
|
14
|
+
* [Installation](#installation)
|
15
|
+
* [Usage](#usage)
|
16
|
+
* [Rails Generator](#rails-generator)
|
17
|
+
* [Attributes](#attributes)
|
18
|
+
* [Relations](#relations)
|
19
|
+
* [Conditional Attributes](#conditional-attributes)
|
20
|
+
* [Conditional Relations](#conditional-relations)
|
21
|
+
* [Attributes Block](#attributes-blocks)
|
22
|
+
* [Attributes Block with Params](#attributes-blocks-with-params)
|
23
|
+
* [Custom Methods](#custom-methods)
|
24
|
+
* [Name Tag](#name-tag)
|
25
|
+
* [Sample Usage](#sample-usage)
|
26
|
+
|
27
|
+
## Features
|
28
|
+
* Simple declaration syntax similar to Active Model Serializer
|
29
|
+
* Realtionships support `belongs_to`, `has_many`, `has_one`
|
30
|
+
* Block style attributes with params
|
31
|
+
|
11
32
|
## Installation
|
12
33
|
|
13
34
|
Add this line to your application's Gemfile:
|
@@ -22,17 +43,9 @@ Or install it yourself as:
|
|
22
43
|
|
23
44
|
$ gem install mutils
|
24
45
|
|
25
|
-
##
|
26
|
-
| Sno | Name | Status |
|
27
|
-
|:---: |:-----------------: |:------: |
|
28
|
-
| 1 | Serializer - JSON | Done |
|
29
|
-
| 2 | Serializer - XML | Done |
|
30
|
-
|
31
|
-
## Usage
|
32
|
-
### Serializer - JSON
|
33
|
-
JSON Serializer for Active Models
|
46
|
+
## Usage
|
34
47
|
|
35
|
-
|
48
|
+
### Rails Generator
|
36
49
|
```shell script
|
37
50
|
rails g mutils:serializer User id first_name last_name email
|
38
51
|
|
@@ -50,13 +63,7 @@ class UserSerializer < Mutils::Serialization::BaseSerializer
|
|
50
63
|
end
|
51
64
|
```
|
52
65
|
|
53
|
-
|
54
|
-
1. Attributes
|
55
|
-
2. Custom Methods
|
56
|
-
3. Relations
|
57
|
-
3. name_tag
|
58
|
-
|
59
|
-
##### Attributes
|
66
|
+
### Attributes
|
60
67
|
Attributes are fields in the model itself. You can reference them by below example
|
61
68
|
```ruby
|
62
69
|
# frozen_string_literal: true
|
@@ -64,48 +71,116 @@ Attributes are fields in the model itself. You can reference them by below examp
|
|
64
71
|
# User Serializer
|
65
72
|
class UserSerializer < Mutils::Serialization::BaseSerializer
|
66
73
|
attributes :id, :first_name, :last_name, :email
|
74
|
+
## OR
|
75
|
+
attribute :email, {always_include: true} ## this will allow to selectively include email
|
67
76
|
end
|
68
77
|
```
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
78
|
+
### Relations
|
79
|
+
Relations such as `has_many`, `belongs_to`, `has_one` can be used as follows
|
80
|
+
1. Every relation must be provided with their own serializer
|
81
|
+
2. `always_include` option can be used to instruct `Serializer` to always include this relation
|
82
|
+
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
|
83
|
+
4. `label` option can be used to override model class name while serializing
|
73
84
|
```ruby
|
74
85
|
# frozen_string_literal: true
|
75
86
|
|
76
87
|
# User Serializer
|
77
88
|
class UserSerializer < Mutils::Serialization::BaseSerializer
|
78
89
|
attributes :id, :first_name, :last_name, :email
|
79
|
-
|
90
|
+
|
91
|
+
belongs_to :company, serializer: CompanySerializer, always_include: true
|
92
|
+
## OR
|
93
|
+
belongs_to :company, serializer: CompanySerializer, always_include: true, label: 'organization' ##<== important to give singular name
|
94
|
+
|
95
|
+
has_many :comments, serializer: CommentSerializer
|
96
|
+
has_one :account, serializer: AccountSerializer
|
80
97
|
|
81
98
|
def full_name
|
82
99
|
"#{scope.first_name} #{scope.last_name}"
|
83
100
|
end
|
84
101
|
end
|
85
102
|
```
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
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
|
103
|
+
### Conditional Attributes
|
104
|
+
Attributes are fields in the model itself. You can reference them by below example
|
105
|
+
```ruby
|
106
|
+
# frozen_string_literal: true
|
91
107
|
|
108
|
+
# User Serializer
|
109
|
+
class UserSerializer < Mutils::Serialization::BaseSerializer
|
110
|
+
attributes :id, :first_name, :last_name
|
111
|
+
attribute :email, if: proc { |scope| scope.name == 'mutils' } ## Email will only serialize if user's name is 'mutils'
|
112
|
+
end
|
113
|
+
```
|
114
|
+
in proc {|scope|}, scope is object which is being serialized
|
115
|
+
### Conditional Relations
|
116
|
+
Attributes are fields in the model itself. You can reference them by below example
|
117
|
+
```ruby
|
118
|
+
# frozen_string_literal: true
|
119
|
+
|
120
|
+
# User Serializer
|
121
|
+
class UserSerializer < Mutils::Serialization::BaseSerializer
|
122
|
+
attributes :id, :first_name, :last_name
|
123
|
+
has_many :comments, serializer: CommentSerializer, if: proc { |scope| scope.name == 'mutils' } ## comments will only serialize if user's name is 'mutils'
|
124
|
+
belongs_to :account, serializer: AccountSerializer, if: proc { |scope| scope.name != 'mutils' } ## account will only serialize if user's name is not 'mutils'
|
125
|
+
end
|
126
|
+
```
|
127
|
+
in proc {|scope|}, scope is object which is being serialized
|
128
|
+
### Attributes Blocks
|
129
|
+
While writting attribute a block can be provided for useful transformations like `full_name` as shown below
|
92
130
|
```ruby
|
93
131
|
# frozen_string_literal: true
|
94
132
|
|
95
133
|
# User Serializer
|
96
134
|
class UserSerializer < Mutils::Serialization::BaseSerializer
|
97
135
|
attributes :id, :first_name, :last_name, :email
|
98
|
-
|
99
|
-
|
100
|
-
|
136
|
+
attribute :full_name do |object|
|
137
|
+
"#{object.first_name} #{object.last_name}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
```
|
141
|
+
### Attributes Blocks with Params
|
142
|
+
While writting attribute a block can be provided for useful transformations like `full_name` as shown below
|
143
|
+
```ruby
|
144
|
+
# frozen_string_literal: true
|
145
|
+
|
146
|
+
# User Serializer
|
147
|
+
class UserSerializer < Mutils::Serialization::BaseSerializer
|
148
|
+
attributes :id, :first_name, :last_name, :email
|
149
|
+
attribute :is_owner do |object,params|
|
150
|
+
params[:owner].id == object.id ? true:false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
```
|
154
|
+
```ruby
|
155
|
+
# in controller
|
156
|
+
|
157
|
+
user = current_user
|
158
|
+
owner = owner_user
|
159
|
+
render json: UserSerializer.new(user,{params:{owner:owner}})
|
160
|
+
```
|
161
|
+
### Custom Methods
|
162
|
+
Custom methods used in Serializer can be useful for cases as below.
|
163
|
+
`scope` will be available to reference object in Serializer in below case its `user`
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
# frozen_string_literal: true
|
167
|
+
|
168
|
+
# User Serializer
|
169
|
+
class UserSerializer < Mutils::Serialization::BaseSerializer
|
170
|
+
attributes :id, :first_name, :last_name, :email
|
171
|
+
###
|
172
|
+
custom_methods :full_name
|
173
|
+
## OR
|
174
|
+
custom_method :full_name, {always_include: true} ## this will allow to selectively include full_name
|
175
|
+
###
|
101
176
|
|
102
177
|
def full_name
|
103
178
|
"#{scope.first_name} #{scope.last_name}"
|
104
179
|
end
|
105
180
|
end
|
106
181
|
```
|
107
|
-
|
108
|
-
name_tag is used to provide custom name to serializer output keys for json
|
182
|
+
### Name Tag
|
183
|
+
name_tag is used to provide custom name to serializer output keys for json
|
109
184
|
|
110
185
|
**Options**
|
111
186
|
- ``name_tag 'Person', true`` # Include Person or People in JSON serialization as root, true|false this only implies to root serializer
|
@@ -127,20 +202,20 @@ class UserSerializer < Mutils::Serialization::BaseSerializer
|
|
127
202
|
end
|
128
203
|
```
|
129
204
|
|
130
|
-
|
205
|
+
### Sample Usage
|
131
206
|
|
132
207
|
```ruby
|
133
208
|
user = User.first
|
134
209
|
options = {includes: [:comments,:account]}
|
135
210
|
UserSerializer.new(user,options).to_h
|
136
211
|
```
|
137
|
-
###or
|
212
|
+
### or
|
138
213
|
```ruby
|
139
214
|
users = User.all
|
140
215
|
options = {includes: [:account]}
|
141
216
|
UserSerializer.new(users,options).to_json
|
142
217
|
```
|
143
|
-
###or in controllers
|
218
|
+
### or in controllers
|
144
219
|
```ruby
|
145
220
|
users = User.all
|
146
221
|
options = {includes: [:account]}
|
@@ -158,4 +233,8 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
158
233
|
|
159
234
|
## Code of Conduct
|
160
235
|
|
161
|
-
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/
|
236
|
+
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/code-vedas/mutils/blob/master/CODE_OF_CONDUCT.md).
|
237
|
+
|
238
|
+
## Security
|
239
|
+
|
240
|
+
For security refer to [security](https://github.com/Code-Vedas/mutils/blob/master/SECURITY.md) document.
|
data/SECURITY.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Security Policy
|
2
|
+
|
3
|
+
## Supported Versions
|
4
|
+
|
5
|
+
Versions currently being supported with security updates.
|
6
|
+
|
7
|
+
| Version | Supported |
|
8
|
+
| ------- | ------------------ |
|
9
|
+
| 1.x.x | :white_check_mark: |
|
10
|
+
|
11
|
+
## Reporting a Vulnerability
|
12
|
+
|
13
|
+
Create an issue or email at security@codevedas.com
|
data/Version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
v1.0.1
|
@@ -0,0 +1 @@
|
|
1
|
+
module.exports = {extends: ['@commitlint/config-angular']};
|
data/gemdeploy.sh
ADDED
data/lib/mutils.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'dry/inflector'
|
3
4
|
require_relative 'mutils/version'
|
4
|
-
|
5
|
-
|
6
|
-
require 'active_support/core_ext/hash'
|
5
|
+
require_relative 'mutils/lib/helper'
|
6
|
+
require_relative 'mutils/lib/result_hash'
|
7
7
|
require_relative 'mutils/serialization/serialization_results'
|
8
8
|
require_relative 'mutils/serialization/serialization_includes'
|
9
9
|
require_relative 'mutils/serialization/serialization_methods'
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
# module Mutils
|
5
|
+
module Mutils
|
6
|
+
module Lib
|
7
|
+
# Helper: caching expensive repetitive operations
|
8
|
+
class Helper
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
self.inflector_object = Dry::Inflector.new
|
13
|
+
self.pluralize_cache = {}
|
14
|
+
self.underscore_cache = {}
|
15
|
+
self.constantize_cache = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def underscore(string)
|
19
|
+
underscore_cache[string] = inflector_object.underscore string unless underscore_cache[string]
|
20
|
+
underscore_cache[string]
|
21
|
+
end
|
22
|
+
|
23
|
+
def pluralize(string)
|
24
|
+
pluralize_cache[string] = inflector_object.pluralize string unless pluralize_cache[string]
|
25
|
+
pluralize_cache[string]
|
26
|
+
end
|
27
|
+
|
28
|
+
def constantize(string)
|
29
|
+
constantize_cache[string] = Object.const_get string unless constantize_cache[string]
|
30
|
+
constantize_cache[string]
|
31
|
+
end
|
32
|
+
|
33
|
+
def collection?(object)
|
34
|
+
object.respond_to?(:size) && !object.respond_to?(:each_pair)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_accessor :inflector_object, :pluralize_cache, :underscore_cache, :constantize_cache
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# module Mutils
|
4
|
+
module Mutils
|
5
|
+
module Lib
|
6
|
+
# ResultHash: Store result using this class.
|
7
|
+
class ResultHash
|
8
|
+
def initialize
|
9
|
+
self._hash = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def []=(key, value)
|
13
|
+
_hash[key] = value
|
14
|
+
end
|
15
|
+
|
16
|
+
def hash
|
17
|
+
_hash
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_accessor :_hash
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -33,14 +33,6 @@ module Mutils
|
|
33
33
|
JSON.generate(as_json, options)
|
34
34
|
end
|
35
35
|
|
36
|
-
def to_xml(_options = {})
|
37
|
-
to_h.to_xml(root: class_name, skip_instruct: true, indent: 2)
|
38
|
-
end
|
39
|
-
|
40
|
-
def as_xml(_options = {})
|
41
|
-
to_xml
|
42
|
-
end
|
43
|
-
|
44
36
|
private
|
45
37
|
|
46
38
|
attr_writer :scope
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Module Mutils
|
4
|
+
module Mutils
|
5
|
+
# Module SerializationCore
|
6
|
+
module Serialization
|
7
|
+
# Module Methods
|
8
|
+
module Methods
|
9
|
+
# Module Attributes
|
10
|
+
module Attributes
|
11
|
+
def attributes(*attributes_list)
|
12
|
+
parse_attributes_methods(attributes_list, false)
|
13
|
+
end
|
14
|
+
|
15
|
+
def custom_methods(*attributes_list)
|
16
|
+
parse_attributes_methods(attributes_list, true)
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_attributes_methods(list, is_method)
|
20
|
+
self.attributes_to_serialize = {} if attributes_to_serialize.nil?
|
21
|
+
list&.each do |attr|
|
22
|
+
value = { method: is_method, always_include: true }
|
23
|
+
attributes_to_serialize[attr] = value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def attribute(method_name, options = {}, &proc)
|
28
|
+
raise "if: should be a Proc object for attribute #{method_name}" if options[:if] && !options[:if].instance_of?(Proc)
|
29
|
+
|
30
|
+
if proc.instance_of? Proc
|
31
|
+
self.attributes_to_serialize_blocks = {} if attributes_to_serialize_blocks.nil?
|
32
|
+
options[:block] = proc
|
33
|
+
attributes_to_serialize_blocks[method_name] = options
|
34
|
+
else
|
35
|
+
add_single_attribute(method_name, options, false)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def custom_method(method_name, options = {})
|
40
|
+
add_single_attribute(method_name, options, true)
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_single_attribute(method_name, options, is_method)
|
44
|
+
self.attributes_to_serialize = {} if attributes_to_serialize.nil?
|
45
|
+
always_include = options[:always_include].nil? ? false : options[:always_include]
|
46
|
+
value = { method: is_method, always_include: always_include, if: options[:if] }
|
47
|
+
attributes_to_serialize[method_name] = value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Module Mutils
|
4
|
+
module Mutils
|
5
|
+
# Module SerializationCore
|
6
|
+
module Serialization
|
7
|
+
# Module Methods
|
8
|
+
module Methods
|
9
|
+
# Module Main
|
10
|
+
module Main
|
11
|
+
def name_tag(name_tag, root = nil)
|
12
|
+
self.serializer_name = name_tag
|
13
|
+
self.include_root = root
|
14
|
+
end
|
15
|
+
|
16
|
+
def class_exists?(class_name)
|
17
|
+
klass = begin
|
18
|
+
Mutils::Lib::Helper.instance.constantize(class_name.to_s)
|
19
|
+
rescue StandardError
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
klass && defined?(klass) && klass.is_a?(Class)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|