easy_serializer 0.1.1 → 0.1.2

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
  SHA1:
3
- metadata.gz: 0cc2097011b0fa8a92990c2207848e77eae0891a
4
- data.tar.gz: ea4d21a3fe3bf12dfdedd7b795b884962564a990
3
+ metadata.gz: 8c4bcd2510b26fd9bc5bce354fa24b8063ab3cd7
4
+ data.tar.gz: 6ad7cac70735ddc9ba2b5cec6285a04a8ef62f70
5
5
  SHA512:
6
- metadata.gz: 80b141c0fb80d95525bcf0ae6b9b3335795fcf61ae6bcaff8c51b253ffd4650f277eb5f57f0be5ad0d50cf229bf0faf2f13a06e5ff65fb25e9fda1b921796f30
7
- data.tar.gz: fea25e7aebe7a75967856269096a2f6ad84a049e236c1b6a88fefec005c15b5e7a024a03054d2593adbe3f451a34beb96a41a6c487e468fe1648d2eca47753af
6
+ metadata.gz: 8d7bedfffb05a5a67d7f6719cc6fdf2caea443d71506b227cdf10e840602516b1d8f92dcf86bcfcef5207953b42b60edc250e25b4cfd3f5cf7b5fc233139942e
7
+ data.tar.gz: 39425cec8ea178f8e7123483dceeac92b5790e277b7c7befa09feb4c11d950946459edcab9dc92ac1797444a7e372fa12b4299cc1e40ef1f973da20b0177a21a
data/README.md CHANGED
@@ -5,8 +5,11 @@
5
5
  [![Test Coverage](https://codeclimate.com/github/arturictus/easy_serializer/badges/coverage.svg)](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
- features:
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: :named
91
- attribute(:surname, key: :lastname) { |user| user.surname.capitalize }
111
+ attribute :name, key: :first_name
112
+ attribute(:surname, key: :last_name) { |user| user.surname.capitalize }
92
113
  end
93
114
  ```
94
115
 
95
- ### Serializing attributes with serializer
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
- collection :address, serializer: AddressSerializer
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 Proc:**
206
+ **Serializer option accepts a Block:**
207
+
208
+ The block will be executed in the Serializer instance.
148
209
 
149
210
  ```ruby
150
- class UserSerializer < EasySerializer::Base
151
- attributes :name, :surname
152
- attribute :address,
153
- serializer: proc { |serializer| "#{serializer.klass_ins.name}Serializer" },
154
- cache: true
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 result hash will be stored in the cache.
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
- of course it works with blocks:
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
- namespace = self.class.name.gsub(self.class.name.demodulize, '')
257
- object_name = klass_ins.subject_type.demodulize
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
  ```
@@ -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{Semantic serializer for making easy serializing objects.}
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
 
@@ -12,4 +12,6 @@ module EasySerializer
12
12
  config_accessor(:cache)
13
13
  end
14
14
 
15
+ require 'easy_serializer/helpers'
16
+ require 'easy_serializer/cacher'
15
17
  require 'easy_serializer/base'
@@ -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 :klass_ins
5
- def initialize(klass_ins)
6
- @klass_ins = klass_ins
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, object|
53
+ __serializable_attributes.each_with_object(HashWithIndifferentAccess.new) do |setup, hash|
52
54
  if setup[:key] === false
53
- object.merge!(attr_serializer(setup))
55
+ hash.merge!(value_or_default(setup))
54
56
  else
55
57
  key = (setup[:key] ? setup[:key] : setup[:name])
56
- object[key] = attr_serializer(setup)
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
- if cache[:block]
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
- content = cache_or_attribute(klass_ins, setup)
88
- return content unless serializer = setup[:serializer]
87
+ value = cache_or_attribute(setup)
88
+ return value unless serializer = setup[:serializer]
89
89
  if setup[:collection]
90
- Array.wrap(content).map { |o| cache_or_serialize(serializer, o, setup) }
90
+ Array.wrap(value).map { |o| cache_or_serialize(serializer, o, setup) }
91
91
  else
92
- cache_or_serialize(serializer, content, setup)
92
+ cache_or_serialize(serializer, value, setup)
93
93
  end
94
94
  end
95
95
 
96
- def cache_or_attribute(obj, setup)
96
+ def cache_or_attribute(setup)
97
97
  execute = setup[:block] || proc { |o| o.send(setup[:name]) }
98
- if EasySerializer.perform_caching && setup[:cache] && !setup[:serializer]
99
- EasySerializer.cache.fetch(obj, setup[:name]) { execute.call(obj) }
98
+ if EasySerializer.perform_caching && setup[:cache]
99
+ Cacher.call(self, setup, nil, &execute)
100
100
  else
101
- execute.call(obj)
101
+ instance_exec object, &execute
102
102
  end
103
103
  end
104
104
 
105
- def cache_or_serialize(serializer, content, opts)
106
- return unless content
105
+ def cache_or_serialize(serializer, value, opts)
106
+ return unless value
107
107
  if EasySerializer.perform_caching && opts[:cache]
108
- key = if opts[:cache_key]
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, content)
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, content)
131
- return unless content
132
- from_setup_serializer(serializer, content).new(content).serialize
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
@@ -1,3 +1,3 @@
1
1
  module EasySerializer
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  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.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-21 00:00:00.000000000 Z
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: Semantic serializer for making easy serializing objects.
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: