userializer 0.1.2 → 0.2.0
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/.circleci/config.yml +18 -0
- data/.gitignore +1 -0
- data/README.md +146 -1
- data/lib/userializer/array_serializer.rb +22 -6
- data/lib/userializer/base_serializer.rb +2 -2
- data/lib/userializer/has_many.rb +12 -2
- data/lib/userializer/has_one.rb +12 -5
- data/lib/userializer/version.rb +1 -1
- data/userializer.gemspec +2 -2
- metadata +11 -12
- data/Gemfile.lock +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ff350c75deb5f250911135a9ea0cd76b0d0edc451186f5a870895818476862d
|
4
|
+
data.tar.gz: 6faf6e27adbc666f620235d15ec4d8ceb62b54ef39416c6693c81d0f59cf84ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55bb0fae587d95804183d68495be2e19da3fe1d3f26acb5604fd0a05a715357a14ac6027af276d42c03f59e12067f54f35b85ee09452c2455987b9bcf4be3b8a
|
7
|
+
data.tar.gz: d0219c7986d8bb650d247f1d6e43612f84afc6ee58f7919da08767b760c8a720e1a9d5aef343a03a43c89a8981dfdc936507e2036dfefe81c5fbb72ea3806c1c
|
@@ -0,0 +1,18 @@
|
|
1
|
+
version: 2
|
2
|
+
jobs:
|
3
|
+
run_tests:
|
4
|
+
docker:
|
5
|
+
- image: circleci/ruby:2.7
|
6
|
+
|
7
|
+
working_directory: ~/userializer
|
8
|
+
|
9
|
+
steps:
|
10
|
+
- checkout
|
11
|
+
- run: bundle install --path=vendor/bundle
|
12
|
+
- run: bundle exec rspec --color --require spec_helper --format progress spec
|
13
|
+
|
14
|
+
workflows:
|
15
|
+
version: 2
|
16
|
+
test:
|
17
|
+
jobs:
|
18
|
+
- run_tests
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -20,7 +20,152 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
-
|
23
|
+
USerializer's DSL is relatively close to Active Model Serializer's,
|
24
|
+
while having a few additional features including:
|
25
|
+
* Attributes Conditional Declaration
|
26
|
+
* Attributes Inline Definition
|
27
|
+
|
28
|
+
### Attributes Conditional Declaration
|
29
|
+
|
30
|
+
USerializer allows you to dynamically decide wether an attribute should
|
31
|
+
be serialized or not by passing its definition an `if` block as follows:
|
32
|
+
```ruby
|
33
|
+
attributes :conditional_attr, if: proc { |_, opts| ... }
|
34
|
+
```
|
35
|
+
|
36
|
+
Eg: Let's say you want to serialize an `Order` object but want to
|
37
|
+
include its `price` only if it's superior to *10*, your serializer
|
38
|
+
would look like the following:
|
39
|
+
```ruby
|
40
|
+
class Order < ActiveRecord::Base
|
41
|
+
def price
|
42
|
+
10
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class OrderSerializer < USerializer::BaseSerializer
|
47
|
+
attributes :price, if: proc do |obj, _|
|
48
|
+
obj.price > 10
|
49
|
+
end
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
In that case for example, the `price` attribute would be omitted from
|
54
|
+
the final response.
|
55
|
+
|
56
|
+
### Attributes Inline Definition
|
57
|
+
|
58
|
+
Using AMS, the only way to rewrite an attribute prior to serialization
|
59
|
+
is to override it using a method with the same name, leading to
|
60
|
+
something like this:
|
61
|
+
```ruby
|
62
|
+
class MyObject < ActiveRecord::Base
|
63
|
+
def random_attr
|
64
|
+
0
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class MyObjectSerializer < ActiveModel::Serializer
|
69
|
+
attributes :random_attr
|
70
|
+
|
71
|
+
def random_attr
|
72
|
+
object.random_attr + 1
|
73
|
+
end
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
While this code works perfectly, it pushes the serialized attribute
|
78
|
+
value definition back from its declaration, causing developers to lose
|
79
|
+
focus when listing their serialized attributes because the overriding is
|
80
|
+
done farther.
|
81
|
+
|
82
|
+
With USerializer, all of this is done in an inline way, so that you can
|
83
|
+
override the attribute's value while declaring using a block as
|
84
|
+
follows:
|
85
|
+
```ruby
|
86
|
+
attributes :your_attribute do |object, _|
|
87
|
+
...
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
Our `random_attr` serialization would then looks like this with
|
92
|
+
USerializer:
|
93
|
+
```ruby
|
94
|
+
class MyObjectSerializer < USerializer::BaseSerializer
|
95
|
+
attributes :random_attr do |object, _|
|
96
|
+
object.random_attr + 1
|
97
|
+
end
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
101
|
+
Way nicer, right?
|
102
|
+
|
103
|
+
### Relationships
|
104
|
+
|
105
|
+
Just like AMS, USerializer supports `has_one` and `has_many`
|
106
|
+
relationships
|
107
|
+
|
108
|
+
### Serialized Output
|
109
|
+
|
110
|
+
The following outputs will be based an on our `Order` object in
|
111
|
+
different situations:
|
112
|
+
|
113
|
+
* Order is serialized without any relationships:
|
114
|
+
```json
|
115
|
+
{
|
116
|
+
"order": {
|
117
|
+
"id": 1,
|
118
|
+
"attr_1": "value_1",
|
119
|
+
"attr_2": "value_2",
|
120
|
+
"attr_3": "value_3",
|
121
|
+
}
|
122
|
+
}
|
123
|
+
```
|
124
|
+
|
125
|
+
* Order has a `has_one` relationship with a `Client` model
|
126
|
+
```json
|
127
|
+
{
|
128
|
+
"clients": [
|
129
|
+
{
|
130
|
+
"id": 4,
|
131
|
+
"name": "userializer client",
|
132
|
+
...
|
133
|
+
}
|
134
|
+
],
|
135
|
+
"order": {
|
136
|
+
"id": 1,
|
137
|
+
"attr_1": "value_1",
|
138
|
+
"attr_2": "value_2",
|
139
|
+
"attr_3": "value_3",
|
140
|
+
"client_id": 4
|
141
|
+
}
|
142
|
+
}
|
143
|
+
```
|
144
|
+
|
145
|
+
* Order has a `has_many` relationship with an `Article` model
|
146
|
+
```json
|
147
|
+
{
|
148
|
+
"articles": [
|
149
|
+
{
|
150
|
+
"id": 1,
|
151
|
+
"name": "Article #1",
|
152
|
+
...
|
153
|
+
},
|
154
|
+
{
|
155
|
+
"id": 1,
|
156
|
+
"name": "Article #2",
|
157
|
+
...
|
158
|
+
}
|
159
|
+
],
|
160
|
+
"order": {
|
161
|
+
"id": 1,
|
162
|
+
"attr_1": "value_1",
|
163
|
+
"attr_2": "value_2",
|
164
|
+
"attr_3": "value_3",
|
165
|
+
"article_ids": [1, 2]
|
166
|
+
}
|
167
|
+
}
|
168
|
+
```
|
24
169
|
|
25
170
|
## Development
|
26
171
|
|
@@ -14,24 +14,31 @@ module USerializer
|
|
14
14
|
|
15
15
|
raise HeterogeneousArray if clss.count > 1
|
16
16
|
|
17
|
-
@root_key = opts[:root]
|
17
|
+
@root_key = opts[:root]
|
18
|
+
@root_key ||= ActiveSupport::Inflector.pluralize(
|
18
19
|
ActiveSupport::Inflector.underscore(obj_class.name).split('/').last
|
19
|
-
).to_sym
|
20
|
+
).to_sym if obj_class
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
)
|
22
|
+
serializer = opts[:each_serializer]
|
23
|
+
|
24
|
+
@serializer = if serializer&.is_a?(Proc)
|
25
|
+
serializer
|
26
|
+
elsif serializer
|
27
|
+
proc { serializer }
|
28
|
+
end
|
24
29
|
end
|
25
30
|
|
26
31
|
def merge_root(res, opts)
|
27
32
|
@objs.each do |obj|
|
28
|
-
|
33
|
+
serializer(obj, opts).merge_root(res, @root_key, false, opts)
|
29
34
|
end
|
30
35
|
end
|
31
36
|
|
32
37
|
def to_hash
|
33
38
|
res = {}
|
34
39
|
|
40
|
+
res[@root_key] = [] if @root_key
|
41
|
+
|
35
42
|
merge_root(res, @opts)
|
36
43
|
res[:meta] = @meta if @meta
|
37
44
|
|
@@ -43,5 +50,14 @@ module USerializer
|
|
43
50
|
end
|
44
51
|
|
45
52
|
def scope; @opts[:scope]; end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def serializer(obj, opts)
|
57
|
+
return @serializer.call(obj, opts).new(obj, @opts) if @serializer
|
58
|
+
return obj.serialize if obj.respond_to?(:serialize)
|
59
|
+
|
60
|
+
USerializer.infered_serializer_class(obj.class).new(obj, @opts)
|
61
|
+
end
|
46
62
|
end
|
47
63
|
end
|
@@ -8,8 +8,8 @@ module USerializer
|
|
8
8
|
class BaseSerializer
|
9
9
|
class << self
|
10
10
|
def inherited(subclass)
|
11
|
-
subclass.attrs = self.attrs || { id: Attribute.new(:id, {}, nil) }
|
12
|
-
subclass.relations = self.relations || {}
|
11
|
+
subclass.attrs = self.attrs.dup || { id: Attribute.new(:id, {}, nil) }
|
12
|
+
subclass.relations = self.relations.dup || {}
|
13
13
|
end
|
14
14
|
|
15
15
|
def attributes(*attrs, &block)
|
data/lib/userializer/has_many.rb
CHANGED
@@ -8,21 +8,31 @@ module USerializer
|
|
8
8
|
@opts = opts
|
9
9
|
@id_key = "#{ActiveSupport::Inflector.singularize(key)}_ids".to_sym
|
10
10
|
|
11
|
+
@embed_key = opts[:embed_key] || :id
|
11
12
|
@conditional_block = opts[:if] || proc { true }
|
12
13
|
end
|
13
14
|
|
14
15
|
def merge_attributes(res, ser, opts)
|
15
16
|
return unless @conditional_block.call(ser.object, opts)
|
16
17
|
|
17
|
-
res[@id_key] = (ser
|
18
|
+
res[@id_key] = (entities(ser) || []).compact.map do |obj|
|
19
|
+
obj.nil? ? nil : obj.send(@embed_key)
|
20
|
+
end.compact
|
18
21
|
end
|
19
22
|
|
20
23
|
def merge_root(res, ser, opts)
|
21
|
-
objs = ser
|
24
|
+
objs = entities(ser) || []
|
22
25
|
|
23
26
|
return if objs.empty? || !@conditional_block.call(ser.object, opts)
|
24
27
|
|
25
28
|
ArraySerializer.new(objs, @opts).merge_root(res, opts)
|
26
29
|
end
|
30
|
+
|
31
|
+
def entities(ser)
|
32
|
+
obj = ser.send(@key) || []
|
33
|
+
return obj unless @opts[:scope]
|
34
|
+
|
35
|
+
obj.send(@opts[:scope])
|
36
|
+
end
|
27
37
|
end
|
28
38
|
end
|
data/lib/userializer/has_one.rb
CHANGED
@@ -6,8 +6,15 @@ module USerializer
|
|
6
6
|
@id_key = "#{key}_id".to_sym
|
7
7
|
@root_key = opts[:root]&.to_sym
|
8
8
|
|
9
|
-
|
9
|
+
serializer = opts[:serializer]
|
10
10
|
|
11
|
+
@serializer = if serializer&.is_a?(Proc)
|
12
|
+
@serializer = serializer
|
13
|
+
elsif serializer
|
14
|
+
proc { serializer }
|
15
|
+
end
|
16
|
+
|
17
|
+
@embed_key = opts[:embed_key] || :id
|
11
18
|
@conditional_block = opts[:if] || proc { true }
|
12
19
|
end
|
13
20
|
|
@@ -17,7 +24,7 @@ module USerializer
|
|
17
24
|
return unless @conditional_block.call(ser.object, opts)
|
18
25
|
|
19
26
|
obj = ser.send(@key)
|
20
|
-
res[@id_key] = obj
|
27
|
+
res[@id_key] = obj.nil? ? nil : obj.send(@embed_key)
|
21
28
|
end
|
22
29
|
|
23
30
|
def merge_root(res, ser, opts)
|
@@ -25,13 +32,13 @@ module USerializer
|
|
25
32
|
|
26
33
|
return if obj.nil? || !@conditional_block.call(ser.object, opts)
|
27
34
|
|
28
|
-
serializer(obj).merge_root(res, root_key(obj), false, opts)
|
35
|
+
serializer(obj, opts).merge_root(res, root_key(obj), false, opts)
|
29
36
|
end
|
30
37
|
|
31
38
|
private
|
32
39
|
|
33
|
-
def serializer(obj)
|
34
|
-
return @serializer.new(obj, @opts) if @serializer
|
40
|
+
def serializer(obj, opts)
|
41
|
+
return @serializer.call(obj, opts).new(obj, @opts) if @serializer
|
35
42
|
return obj.serialize if obj.respond_to?(:serialize)
|
36
43
|
|
37
44
|
USerializer.infered_serializer_class(obj.class).new(obj, @opts)
|
data/lib/userializer/version.rb
CHANGED
data/userializer.gemspec
CHANGED
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
|
23
|
-
spec.add_development_dependency "bundler", "~>
|
24
|
-
spec.add_development_dependency "rake", "~>
|
23
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
24
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
25
25
|
spec.add_development_dependency "rspec", "~> 3.0"
|
26
26
|
spec.add_dependency "oj"
|
27
27
|
spec.add_dependency "activesupport"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: userializer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexis Montagne
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.0'
|
20
20
|
type: :development
|
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: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '13.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '13.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -87,11 +87,11 @@ executables: []
|
|
87
87
|
extensions: []
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
|
+
- ".circleci/config.yml"
|
90
91
|
- ".gitignore"
|
91
92
|
- ".rspec"
|
92
93
|
- ".travis.yml"
|
93
94
|
- Gemfile
|
94
|
-
- Gemfile.lock
|
95
95
|
- README.md
|
96
96
|
- Rakefile
|
97
97
|
- bin/console
|
@@ -107,7 +107,7 @@ files:
|
|
107
107
|
homepage: https://github.com/upfluence/userializer
|
108
108
|
licenses: []
|
109
109
|
metadata: {}
|
110
|
-
post_install_message:
|
110
|
+
post_install_message:
|
111
111
|
rdoc_options: []
|
112
112
|
require_paths:
|
113
113
|
- lib
|
@@ -122,9 +122,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
122
|
- !ruby/object:Gem::Version
|
123
123
|
version: '0'
|
124
124
|
requirements: []
|
125
|
-
|
126
|
-
|
127
|
-
signing_key:
|
125
|
+
rubygems_version: 3.0.3
|
126
|
+
signing_key:
|
128
127
|
specification_version: 4
|
129
128
|
summary: Write a short summary, because RubyGems requires one.
|
130
129
|
test_files: []
|
data/Gemfile.lock
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
userializer (0.1.2)
|
5
|
-
activesupport
|
6
|
-
oj
|
7
|
-
|
8
|
-
GEM
|
9
|
-
remote: https://rubygems.org/
|
10
|
-
specs:
|
11
|
-
activesupport (5.2.3)
|
12
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
13
|
-
i18n (>= 0.7, < 2)
|
14
|
-
minitest (~> 5.1)
|
15
|
-
tzinfo (~> 1.1)
|
16
|
-
concurrent-ruby (1.1.5)
|
17
|
-
diff-lcs (1.3)
|
18
|
-
i18n (1.6.0)
|
19
|
-
concurrent-ruby (~> 1.0)
|
20
|
-
minitest (5.11.3)
|
21
|
-
oj (3.7.12)
|
22
|
-
rake (10.4.2)
|
23
|
-
rspec (3.8.0)
|
24
|
-
rspec-core (~> 3.8.0)
|
25
|
-
rspec-expectations (~> 3.8.0)
|
26
|
-
rspec-mocks (~> 3.8.0)
|
27
|
-
rspec-core (3.8.0)
|
28
|
-
rspec-support (~> 3.8.0)
|
29
|
-
rspec-expectations (3.8.3)
|
30
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
31
|
-
rspec-support (~> 3.8.0)
|
32
|
-
rspec-mocks (3.8.0)
|
33
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
34
|
-
rspec-support (~> 3.8.0)
|
35
|
-
rspec-support (3.8.0)
|
36
|
-
thread_safe (0.3.6)
|
37
|
-
tzinfo (1.2.5)
|
38
|
-
thread_safe (~> 0.1)
|
39
|
-
|
40
|
-
PLATFORMS
|
41
|
-
ruby
|
42
|
-
|
43
|
-
DEPENDENCIES
|
44
|
-
bundler (~> 1.16)
|
45
|
-
rake (~> 10.0)
|
46
|
-
rspec (~> 3.0)
|
47
|
-
userializer!
|
48
|
-
|
49
|
-
BUNDLED WITH
|
50
|
-
1.16.1
|