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 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: