easy_serializer 0.1.1 → 0.1.2
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/README.md +154 -17
- data/easy_serializer.gemspec +3 -1
- data/lib/easy_serializer.rb +2 -0
- data/lib/easy_serializer/base.rb +32 -47
- data/lib/easy_serializer/cacher.rb +60 -0
- data/lib/easy_serializer/helpers.rb +17 -0
- data/lib/easy_serializer/version.rb +1 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c4bcd2510b26fd9bc5bce354fa24b8063ab3cd7
|
4
|
+
data.tar.gz: 6ad7cac70735ddc9ba2b5cec6285a04a8ef62f70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d7bedfffb05a5a67d7f6719cc6fdf2caea443d71506b227cdf10e840602516b1d8f92dcf86bcfcef5207953b42b60edc250e25b4cfd3f5cf7b5fc233139942e
|
7
|
+
data.tar.gz: 39425cec8ea178f8e7123483dceeac92b5790e277b7c7befa09feb4c11d950946459edcab9dc92ac1797444a7e372fa12b4299cc1e40ef1f973da20b0177a21a
|
data/README.md
CHANGED
@@ -5,8 +5,11 @@
|
|
5
5
|
[](https://codeclimate.com/github/arturictus/easy_serializer/coverage)
|
6
6
|
|
7
7
|
Semantic serializer for making easy serializing objects.
|
8
|
+
EasySerializer is inspired in [ActiveModel Serializer > 0.10] (https://github.com/rails-api/active_model_serializers/tree/v0.10.0.rc3) it's a
|
9
|
+
simple solution for a day to day work with APIs.
|
10
|
+
It tries to give you a serializer with flexibility, full of features and important capabilities for caching.
|
8
11
|
|
9
|
-
|
12
|
+
Features:
|
10
13
|
- Nice and simple serialization DSL.
|
11
14
|
- Cache helpers to use with your favorite adapter like rails cache.
|
12
15
|
|
@@ -76,6 +79,8 @@ UserSerializer.call(user)
|
|
76
79
|
```
|
77
80
|
**Using blocks:**
|
78
81
|
|
82
|
+
Object being serialized is pass in the block as a first argument.
|
83
|
+
|
79
84
|
```ruby
|
80
85
|
class UserSerializer < EasySerializer::Base
|
81
86
|
attribute(:name) { |user| user.name.capitalize }
|
@@ -83,16 +88,70 @@ class UserSerializer < EasySerializer::Base
|
|
83
88
|
end
|
84
89
|
```
|
85
90
|
|
91
|
+
**Using helpers in blocks:**
|
92
|
+
|
93
|
+
Blocks are executed in the serializer instance, this way you can build your helpers and use them inside the blocks.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
class BlockExample < EasySerializer::Base
|
97
|
+
attribute :name do |object|
|
98
|
+
upcase object.name
|
99
|
+
end
|
100
|
+
|
101
|
+
def upcase(str)
|
102
|
+
str.upcase
|
103
|
+
end
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
86
107
|
**Changing keys:**
|
87
108
|
|
88
109
|
```ruby
|
89
110
|
class UserSerializer < EasySerializer::Base
|
90
|
-
attribute :name, key: :
|
91
|
-
attribute(:surname, key: :
|
111
|
+
attribute :name, key: :first_name
|
112
|
+
attribute(:surname, key: :last_name) { |user| user.surname.capitalize }
|
92
113
|
end
|
93
114
|
```
|
94
115
|
|
95
|
-
|
116
|
+
**Using defaults:**
|
117
|
+
|
118
|
+
Default will only be triggered when value is `nil`
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
obj = OpenStruct.new(name: 'Jack', boolean: nil, missing: nil)
|
122
|
+
|
123
|
+
class DefaultLiteral < EasySerializer::Base
|
124
|
+
attribute :name
|
125
|
+
attribute :boolean, default: true
|
126
|
+
attribute(:missing, default: 'anything') { |obj| obj.missing }
|
127
|
+
end
|
128
|
+
|
129
|
+
output = DefaultLiteral.call(obj)
|
130
|
+
output.fetch(:name) #=> 'Jack'
|
131
|
+
output.fetch(:boolean) #=> true
|
132
|
+
output.fetch(:missing) #=> 'anything'
|
133
|
+
```
|
134
|
+
|
135
|
+
Using blocks:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
obj = OpenStruct.new(name: 'Jack', boolean: nil, missing: nil)
|
139
|
+
|
140
|
+
class DefaultBlock < EasySerializer::Base
|
141
|
+
attribute :name
|
142
|
+
attribute :boolean, default: proc { |obj| obj.name == 'Jack' }
|
143
|
+
attribute :missing, default: proc { |obj| "#{obj.name}-missing" } do |obj|
|
144
|
+
obj.missing
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
output = DefaultBlock.call(obj)
|
149
|
+
output.fetch(:name) #=> 'Jack'
|
150
|
+
output.fetch(:boolean) #=> true
|
151
|
+
output.fetch(:missing) #=> 'Jack-missing'
|
152
|
+
```
|
153
|
+
|
154
|
+
### Serializing nested objects
|
96
155
|
|
97
156
|
```ruby
|
98
157
|
user = OpenStruct.new(
|
@@ -110,7 +169,7 @@ end
|
|
110
169
|
|
111
170
|
class UserSerializer < EasySerializer::Base
|
112
171
|
attributes :name, :surname
|
113
|
-
|
172
|
+
attribute :address, serializer: AddressSerializer
|
114
173
|
end
|
115
174
|
|
116
175
|
UserSerializer.call(user)
|
@@ -144,16 +203,39 @@ UserSerializer.call(user)
|
|
144
203
|
}
|
145
204
|
```
|
146
205
|
|
147
|
-
**Serializer option accepts a
|
206
|
+
**Serializer option accepts a Block:**
|
207
|
+
|
208
|
+
The block will be executed in the Serializer instance.
|
148
209
|
|
149
210
|
```ruby
|
150
|
-
class
|
151
|
-
|
152
|
-
attribute :
|
153
|
-
|
154
|
-
|
211
|
+
class DynamicSerializer < EasySerializer::Base
|
212
|
+
attribute :thing, serializer: proc { serializer_for_object }
|
213
|
+
attribute :d_name
|
214
|
+
|
215
|
+
def serializer_for_object
|
216
|
+
"#{object.class.name}Serializer".classify
|
217
|
+
end
|
155
218
|
end
|
156
219
|
```
|
220
|
+
Inside the block is yielded the value of the method
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
thing = OpenStruct.new(name: 'rigoverto', serializer: 'ThingSerializer')
|
224
|
+
obj = OpenStruct.new(d_name: 'a name', thing: thing)
|
225
|
+
|
226
|
+
class DynamicWithContentSerializer < EasySerializer::Base
|
227
|
+
attribute :thing,
|
228
|
+
serializer: proc { |value| to_const value.serializer }
|
229
|
+
# => block will output ThingSerializer
|
230
|
+
attribute :d_name
|
231
|
+
|
232
|
+
def to_const(str)
|
233
|
+
Class.const_get str.classify
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
DynamicWithContentSerializer.call(obj)
|
238
|
+
```
|
157
239
|
|
158
240
|
### Collection Example:
|
159
241
|
|
@@ -190,7 +272,7 @@ UserSerializer.call(user)
|
|
190
272
|
|
191
273
|
**Caching the serialized object:**
|
192
274
|
|
193
|
-
Serialization will happen only once and the
|
275
|
+
Serialization will happen only once and the resulting hash will be stored in the cache.
|
194
276
|
|
195
277
|
```ruby
|
196
278
|
class UserSerializer < EasySerializer::Base
|
@@ -210,7 +292,7 @@ class UserSerializer < EasySerializer::Base
|
|
210
292
|
end
|
211
293
|
```
|
212
294
|
|
213
|
-
|
295
|
+
Of course it works with blocks:
|
214
296
|
|
215
297
|
```ruby
|
216
298
|
class UserSerializer < EasySerializer::Base
|
@@ -221,6 +303,62 @@ class UserSerializer < EasySerializer::Base
|
|
221
303
|
end
|
222
304
|
```
|
223
305
|
|
306
|
+
Passing cache key:
|
307
|
+
|
308
|
+
```ruby
|
309
|
+
class UserSerializer < EasySerializer::Base
|
310
|
+
attribute(:costly_query, cache: true, cache_key: 'hello') do |user|
|
311
|
+
user.best_friends
|
312
|
+
end
|
313
|
+
end
|
314
|
+
```
|
315
|
+
|
316
|
+
Passing cache key block:
|
317
|
+
|
318
|
+
```ruby
|
319
|
+
class UserSerializer < EasySerializer::Base
|
320
|
+
attribute(
|
321
|
+
:costly_query,
|
322
|
+
cache: true,
|
323
|
+
cache_key: proc { |object| [object, 'costly_query'] }
|
324
|
+
) do |user|
|
325
|
+
user.best_friends
|
326
|
+
end
|
327
|
+
end
|
328
|
+
```
|
329
|
+
|
330
|
+
Passing options to the cache:
|
331
|
+
|
332
|
+
Any option passed in the cache method not specified for EasySerializer will be
|
333
|
+
forwarded as options to the set Cache as options for the fetch method.
|
334
|
+
|
335
|
+
example:
|
336
|
+
|
337
|
+
```ruby
|
338
|
+
class OptionForRootCache < EasySerializer::Base
|
339
|
+
cache true, expires_in: 10.minutes, another_option: true
|
340
|
+
attribute :name
|
341
|
+
end
|
342
|
+
```
|
343
|
+
|
344
|
+
Cache fetch will receive:
|
345
|
+
|
346
|
+
```ruby
|
347
|
+
EasySerializer.cache.fetch(
|
348
|
+
key,# object or defined key
|
349
|
+
expires_in: 10.minutes,
|
350
|
+
another_option: true
|
351
|
+
)
|
352
|
+
```
|
353
|
+
|
354
|
+
Use **cache_options** in attributes
|
355
|
+
|
356
|
+
```ruby
|
357
|
+
class OptionForAttributeCache < EasySerializer::Base
|
358
|
+
attribute :name, cache: true, cache_options: { expires_in: 10.minutes }
|
359
|
+
end
|
360
|
+
```
|
361
|
+
|
224
362
|
**Caching Collections:**
|
225
363
|
|
226
364
|
Cache will try to fetch the cached object in the collection **one by one, the whole collection is not cached**.
|
@@ -232,7 +370,7 @@ class UserSerializer < EasySerializer::Base
|
|
232
370
|
end
|
233
371
|
```
|
234
372
|
|
235
|
-
### Complex example using all features
|
373
|
+
### Complex example using all features
|
236
374
|
|
237
375
|
```ruby
|
238
376
|
class PolymorphicSerializer < EasySerializer::Base
|
@@ -253,9 +391,8 @@ class PolymorphicSerializer < EasySerializer::Base
|
|
253
391
|
collection :elements, serializer: ElementsSerializer, cache: true
|
254
392
|
|
255
393
|
def serializer_for_subject
|
256
|
-
|
257
|
-
object_name
|
258
|
-
"#{namespace}#{object_name}Serializer".constantize
|
394
|
+
object_name = object.subject_type.demodulize
|
395
|
+
"#{object_name}Serializer".constantize
|
259
396
|
end
|
260
397
|
end
|
261
398
|
```
|
data/easy_serializer.gemspec
CHANGED
@@ -10,7 +10,9 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["arturictus@gmail.com"]
|
11
11
|
|
12
12
|
spec.summary = %q{Semantic serializer for making easy serializing objects.}
|
13
|
-
spec.description = %q{
|
13
|
+
spec.description = %q{EasySerializer is inspired in ActiveModel Serializer > 0.10 it's a
|
14
|
+
simple solution for a day to day work with APIs.
|
15
|
+
It tries to give you a serializer with flexibility, full of features and important capabilities for caching.}
|
14
16
|
spec.homepage = "https://github.com/arturictus/easy_serializer"
|
15
17
|
spec.license = "MIT"
|
16
18
|
|
data/lib/easy_serializer.rb
CHANGED
data/lib/easy_serializer/base.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
module EasySerializer
|
2
2
|
class Base
|
3
|
+
include Helpers
|
4
|
+
|
3
5
|
delegate :to_json, :[], to: :serialize
|
4
|
-
attr_reader :
|
5
|
-
def initialize(
|
6
|
-
@
|
6
|
+
attr_reader :object
|
7
|
+
def initialize(object)
|
8
|
+
@object = object
|
7
9
|
end
|
8
10
|
|
9
11
|
class << self
|
@@ -48,12 +50,12 @@ module EasySerializer
|
|
48
50
|
private
|
49
51
|
|
50
52
|
def _serialize
|
51
|
-
__serializable_attributes.each_with_object(HashWithIndifferentAccess.new) do |setup,
|
53
|
+
__serializable_attributes.each_with_object(HashWithIndifferentAccess.new) do |setup, hash|
|
52
54
|
if setup[:key] === false
|
53
|
-
|
55
|
+
hash.merge!(value_or_default(setup))
|
54
56
|
else
|
55
57
|
key = (setup[:key] ? setup[:key] : setup[:name])
|
56
|
-
|
58
|
+
hash[key] = value_or_default(setup)
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end
|
@@ -62,17 +64,7 @@ module EasySerializer
|
|
62
64
|
return false unless EasySerializer.perform_caching
|
63
65
|
cache = __cache
|
64
66
|
return false unless cache
|
65
|
-
|
66
|
-
cache[:block].call(klass_ins, self)
|
67
|
-
else
|
68
|
-
key = if cache[:key]
|
69
|
-
cache[:key].call(klass_ins)
|
70
|
-
else
|
71
|
-
[klass_ins, 'EasySerialized']
|
72
|
-
end
|
73
|
-
fail "[Serializer] No key for cache" unless key
|
74
|
-
EasySerializer.cache.fetch(key) { _serialize }
|
75
|
-
end
|
67
|
+
Cacher.root_call(self, cache, object) { _serialize }
|
76
68
|
end
|
77
69
|
|
78
70
|
def __cache
|
@@ -83,53 +75,46 @@ module EasySerializer
|
|
83
75
|
self.class.instance_variable_get(:@__serializable_attributes) || []
|
84
76
|
end
|
85
77
|
|
78
|
+
def value_or_default(setup)
|
79
|
+
value = attr_serializer(setup)
|
80
|
+
if value.nil? && setup[:default]
|
81
|
+
return option_to_value(setup[:default], object)
|
82
|
+
end
|
83
|
+
value
|
84
|
+
end
|
85
|
+
|
86
86
|
def attr_serializer(setup)
|
87
|
-
|
88
|
-
return
|
87
|
+
value = cache_or_attribute(setup)
|
88
|
+
return value unless serializer = setup[:serializer]
|
89
89
|
if setup[:collection]
|
90
|
-
Array.wrap(
|
90
|
+
Array.wrap(value).map { |o| cache_or_serialize(serializer, o, setup) }
|
91
91
|
else
|
92
|
-
cache_or_serialize(serializer,
|
92
|
+
cache_or_serialize(serializer, value, setup)
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
def cache_or_attribute(
|
96
|
+
def cache_or_attribute(setup)
|
97
97
|
execute = setup[:block] || proc { |o| o.send(setup[:name]) }
|
98
|
-
if EasySerializer.perform_caching && setup[:cache]
|
99
|
-
|
98
|
+
if EasySerializer.perform_caching && setup[:cache]
|
99
|
+
Cacher.call(self, setup, nil, &execute)
|
100
100
|
else
|
101
|
-
execute
|
101
|
+
instance_exec object, &execute
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
-
def cache_or_serialize(serializer,
|
106
|
-
return unless
|
105
|
+
def cache_or_serialize(serializer, value, opts)
|
106
|
+
return unless value
|
107
107
|
if EasySerializer.perform_caching && opts[:cache]
|
108
|
-
|
109
|
-
opts[:cache_key].call(content)
|
110
|
-
else
|
111
|
-
[content, 'EasySerialized']
|
112
|
-
end
|
113
|
-
# Be Aware
|
114
|
-
# We are caching the serialized object
|
115
|
-
EasySerializer.cache.fetch(key) { send_to_serializer(serializer, content) }
|
108
|
+
Cacher.call(self, opts, value)
|
116
109
|
else
|
117
|
-
send_to_serializer(serializer,
|
110
|
+
send_to_serializer(serializer, value)
|
118
111
|
end
|
119
112
|
end
|
120
113
|
|
121
|
-
def from_setup_serializer(serializer, content)
|
122
|
-
case serializer
|
123
|
-
when Proc
|
124
|
-
serializer.call(self, klass_ins, content)
|
125
|
-
else
|
126
|
-
serializer
|
127
|
-
end
|
128
|
-
end
|
129
114
|
|
130
|
-
def send_to_serializer(serializer,
|
131
|
-
return unless
|
132
|
-
|
115
|
+
def send_to_serializer(serializer, value)
|
116
|
+
return unless value
|
117
|
+
option_to_value(serializer, value).call(value)
|
133
118
|
end
|
134
119
|
end
|
135
120
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module EasySerializer
|
2
|
+
Cacher = Struct.new(:serializer) do
|
3
|
+
include Helpers
|
4
|
+
|
5
|
+
def self.call(serializer, options, value, &block)
|
6
|
+
Cacher.new(serializer)
|
7
|
+
.set(options: options, block: block, value: value)
|
8
|
+
.execute
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.root_call(serializer, options, value, &block)
|
12
|
+
options[:cache_key] = options[:key]
|
13
|
+
options[:root_call] = true
|
14
|
+
call(serializer, options, value, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_accessor :object, :options, :block
|
18
|
+
attr_writer :value
|
19
|
+
|
20
|
+
delegate :object, to: :serializer
|
21
|
+
|
22
|
+
def set(options)
|
23
|
+
options.each { |k, v| send("#{k}=", v) }
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def value
|
28
|
+
return unless object && block
|
29
|
+
@value ||= serializer.instance_exec object, &block
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def key
|
34
|
+
@key ||= if options[:cache_key]
|
35
|
+
option_to_value(options[:cache_key], value, serializer)
|
36
|
+
elsif options[:serializer] || options[:root_call]
|
37
|
+
[value, 'EasySerialized'].flatten
|
38
|
+
else
|
39
|
+
[value, options[:name], 'EasySerialized'].flatten
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def options_for_cache
|
44
|
+
if options[:root_call]
|
45
|
+
options.except(:block, :cache_key, :root_call, :serializer, :key)
|
46
|
+
else
|
47
|
+
options[:cache_options]
|
48
|
+
end || {}
|
49
|
+
end
|
50
|
+
|
51
|
+
def execute
|
52
|
+
to_execute = if options[:serializer]
|
53
|
+
proc { serializer.send_to_serializer(options[:serializer], value) }
|
54
|
+
elsif !options[:serializer]
|
55
|
+
proc { serializer.instance_exec object, &block }
|
56
|
+
end
|
57
|
+
EasySerializer.cache.fetch(key, options_for_cache, &to_execute)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module EasySerializer
|
2
|
+
module Helpers
|
3
|
+
def option_to_value(option, value, instance = nil)
|
4
|
+
inst = instance || self
|
5
|
+
case option
|
6
|
+
when Proc
|
7
|
+
inst.instance_exec value, &option
|
8
|
+
# TODO
|
9
|
+
# Will be nice to be able to add classes in the options responding to call
|
10
|
+
# for complex algorithms.
|
11
|
+
# when ->(opt) { opt.respond_to?(:call) }
|
12
|
+
else
|
13
|
+
option
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: easy_serializer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Artur Pañach
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,7 +66,10 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '4.2'
|
69
|
-
description:
|
69
|
+
description: |-
|
70
|
+
EasySerializer is inspired in ActiveModel Serializer > 0.10 it's a
|
71
|
+
simple solution for a day to day work with APIs.
|
72
|
+
It tries to give you a serializer with flexibility, full of features and important capabilities for caching.
|
70
73
|
email:
|
71
74
|
- arturictus@gmail.com
|
72
75
|
executables: []
|
@@ -86,6 +89,8 @@ files:
|
|
86
89
|
- easy_serializer.gemspec
|
87
90
|
- lib/easy_serializer.rb
|
88
91
|
- lib/easy_serializer/base.rb
|
92
|
+
- lib/easy_serializer/cacher.rb
|
93
|
+
- lib/easy_serializer/helpers.rb
|
89
94
|
- lib/easy_serializer/version.rb
|
90
95
|
homepage: https://github.com/arturictus/easy_serializer
|
91
96
|
licenses:
|