blueprinter 0.5.0 → 0.6.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/CHANGELOG.md +6 -0
- data/README.md +20 -1
- data/lib/blueprinter/base.rb +26 -3
- data/lib/blueprinter/extractors/auto_extractor.rb +10 -1
- data/lib/blueprinter/field.rb +32 -2
- data/lib/blueprinter/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1a0e758e71974ab97aac018c58a8fb143cedcbb0cbdfc60c62fb06050defecd
|
4
|
+
data.tar.gz: 455ff66f83def7e8aad7bb35df752580e664499ac3cb872c6354cacc9b881f9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1a697280e9f1da3ab3c59053449c965fc4785c077c6b336291451adc6dbdfa13876989c93ace254ae2545ec9cb0ff4cc5c7d9f64211d34d77a6539217b2c178
|
7
|
+
data.tar.gz: 8bc59b0805ea6bda87dd948677f8a375c321fc7d0a880882d13e4a34d5b6a844dc6c3916bd9b2913b58c3b349844f8dc86357bdf7a879c35764137c8dff65f9d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 0.6.0 - 2018/06/05
|
2
|
+
|
3
|
+
* [FEATURE] Add `date_time` format as an option to `field`. Please see pr #68. Thanks to @njbbaer.
|
4
|
+
* [FEATURE] Add conditional field support `:unless` and `:if` as an option to `field`. Please see pr #86. Thanks to @ojab.
|
5
|
+
* [BUGFIX] Fix case where miscellaneous options were not being passed through the `AutoExtractor`. See pr #83.
|
6
|
+
|
1
7
|
## 0.5.0 - 2018/05/15
|
2
8
|
|
3
9
|
* [FEATURE] Add `default` option to `association` which will be used as the serialized value instead of `null` when the association evaluates to null.
|
data/README.md
CHANGED
@@ -42,7 +42,7 @@ And the output would look like:
|
|
42
42
|
```
|
43
43
|
|
44
44
|
### Views
|
45
|
-
You may define different
|
45
|
+
You may define different outputs by utilizing views:
|
46
46
|
```ruby
|
47
47
|
class UserBlueprint < Blueprinter::Base
|
48
48
|
identifier :uuid
|
@@ -190,6 +190,25 @@ Output:
|
|
190
190
|
}
|
191
191
|
```
|
192
192
|
|
193
|
+
### Custom formatting for dates and times
|
194
|
+
To define a custom format for a Date or DateTime field, include the option `datetime_format` with the associated `strptime` format.
|
195
|
+
|
196
|
+
Usage:
|
197
|
+
```ruby
|
198
|
+
class UserBlueprint < Blueprinter::Base
|
199
|
+
identifier :name
|
200
|
+
field :birthday, datetime_format: "%m/%d/%Y"
|
201
|
+
end
|
202
|
+
```
|
203
|
+
|
204
|
+
Output:
|
205
|
+
```json
|
206
|
+
{
|
207
|
+
"name": "John Doe",
|
208
|
+
"birthday": "03/04/1994"
|
209
|
+
}
|
210
|
+
```
|
211
|
+
|
193
212
|
## Installation
|
194
213
|
Add this line to your application's Gemfile:
|
195
214
|
|
data/lib/blueprinter/base.rb
CHANGED
@@ -37,7 +37,7 @@ module Blueprinter
|
|
37
37
|
#
|
38
38
|
# @return [Field] A Field object
|
39
39
|
def self.identifier(method, name: method, extractor: AutoExtractor)
|
40
|
-
view_collection[:identifier] << Field.new(method, name, extractor)
|
40
|
+
view_collection[:identifier] << Field.new(method, name, extractor, self)
|
41
41
|
end
|
42
42
|
|
43
43
|
# Specify a field or method name to be included for serialization.
|
@@ -53,6 +53,16 @@ module Blueprinter
|
|
53
53
|
# @option options [Symbol] :name Use this to rename the method. Useful if
|
54
54
|
# if you want your JSON key named differently in the output than your
|
55
55
|
# object's field or method name.
|
56
|
+
# @option options [String] :datetime_format Format Date or DateTime object
|
57
|
+
# with given strftime formatting
|
58
|
+
# @option options [Symbol,Proc] :if Specifies a method, proc or string to
|
59
|
+
# call to determine if the field should be included (e.g.
|
60
|
+
# `if: :include_first_name?, or if: Proc.new { |user, options| options[:current_user] == user }).
|
61
|
+
# The method, proc or string should return or evaluate to a true or false value.
|
62
|
+
# @option options [Symbol,Proc] :unless Specifies a method, proc or string
|
63
|
+
# to call to determine if the field should be included (e.g.
|
64
|
+
# `unless: :include_first_name?, or unless: Proc.new { |user, options| options[:current_user] != user }).
|
65
|
+
# The method, proc or string should return or evaluate to a true or false value.
|
56
66
|
# @yield [Object] The object passed to `render` is also passed to the
|
57
67
|
# block.
|
58
68
|
#
|
@@ -68,6 +78,17 @@ module Blueprinter
|
|
68
78
|
# # other code
|
69
79
|
# end
|
70
80
|
#
|
81
|
+
# @example Passing an if proc and unless method..
|
82
|
+
# class UserBlueprint < Blueprinter::Base
|
83
|
+
# def skip_first_name?(user, options)
|
84
|
+
# user.first_name == options[:first_name]
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# field :first_name, unless: :skip_first_name?
|
88
|
+
# field :last_name, if: ->(user, options) { user.first_name != options[:first_name] }
|
89
|
+
# # other code
|
90
|
+
# end
|
91
|
+
#
|
71
92
|
# @return [Field] A Field object
|
72
93
|
def self.field(method, options = {}, &block)
|
73
94
|
options = if block_given?
|
@@ -78,6 +99,7 @@ module Blueprinter
|
|
78
99
|
current_view << Field.new(method,
|
79
100
|
options[:name],
|
80
101
|
options[:extractor],
|
102
|
+
self,
|
81
103
|
options)
|
82
104
|
end
|
83
105
|
|
@@ -107,6 +129,7 @@ module Blueprinter
|
|
107
129
|
current_view << Field.new(method,
|
108
130
|
name,
|
109
131
|
AssociationExtractor,
|
132
|
+
self,
|
110
133
|
options.merge(association: true))
|
111
134
|
end
|
112
135
|
|
@@ -163,7 +186,6 @@ module Blueprinter
|
|
163
186
|
unless view_collection.has_view? view_name
|
164
187
|
raise BlueprinterError, "View '#{view_name}' is not defined"
|
165
188
|
end
|
166
|
-
fields = view_collection.fields_for(view_name)
|
167
189
|
prepared_object = include_associations(object, view_name: view_name)
|
168
190
|
if array_like?(object)
|
169
191
|
prepared_object.map do |obj|
|
@@ -193,7 +215,7 @@ module Blueprinter
|
|
193
215
|
# @return [Array<Symbol>] an array of field names
|
194
216
|
def self.fields(*field_names)
|
195
217
|
field_names.each do |field_name|
|
196
|
-
current_view << Field.new(field_name, field_name, AutoExtractor)
|
218
|
+
current_view << Field.new(field_name, field_name, AutoExtractor, self)
|
197
219
|
end
|
198
220
|
end
|
199
221
|
|
@@ -270,6 +292,7 @@ module Blueprinter
|
|
270
292
|
|
271
293
|
def self.object_to_hash(object, view_name:, local_options:)
|
272
294
|
view_collection.fields_for(view_name).each_with_object({}) do |field, hash|
|
295
|
+
next if field.skip?(object, local_options)
|
273
296
|
hash[field.name] = field.extract(object, local_options)
|
274
297
|
end
|
275
298
|
end
|
@@ -2,7 +2,16 @@ module Blueprinter
|
|
2
2
|
class AutoExtractor < Extractor
|
3
3
|
def extract(field_name, object, local_options, options = {})
|
4
4
|
extractor = object.is_a?(Hash) ? HashExtractor : PublicSendExtractor
|
5
|
-
extractor.extract(field_name, object, local_options, options
|
5
|
+
extraction = extractor.extract(field_name, object, local_options, options)
|
6
|
+
options.key?(:datetime_format) ? format_datetime(extraction, options[:datetime_format]) : extraction
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def format_datetime(datetime, format)
|
12
|
+
datetime.strftime(format)
|
13
|
+
rescue NoMethodError
|
14
|
+
raise BlueprinterError, 'Cannot format invalid DateTime object'
|
6
15
|
end
|
7
16
|
end
|
8
17
|
end
|
data/lib/blueprinter/field.rb
CHANGED
@@ -1,14 +1,44 @@
|
|
1
1
|
# @api private
|
2
2
|
class Blueprinter::Field
|
3
|
-
attr_reader :method, :name, :extractor, :options
|
4
|
-
def initialize(method, name, extractor, options = {})
|
3
|
+
attr_reader :method, :name, :extractor, :options, :blueprint
|
4
|
+
def initialize(method, name, extractor, blueprint, options = {})
|
5
5
|
@method = method
|
6
6
|
@name = name
|
7
7
|
@extractor = extractor
|
8
|
+
@blueprint = blueprint
|
8
9
|
@options = options
|
9
10
|
end
|
10
11
|
|
11
12
|
def extract(object, local_options)
|
12
13
|
extractor.extract(method, object, local_options, options)
|
13
14
|
end
|
15
|
+
|
16
|
+
def skip?(object, local_options)
|
17
|
+
return true if if_callable && !if_callable.call(object, local_options)
|
18
|
+
unless_callable && unless_callable.call(object, local_options)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def if_callable
|
24
|
+
return @if_callable unless @if_callable.nil?
|
25
|
+
@if_callable ||= callable_from(:if)
|
26
|
+
end
|
27
|
+
|
28
|
+
def unless_callable
|
29
|
+
return @unless_callable unless @unless_callable.nil?
|
30
|
+
@unless_callable ||= callable_from(:unless)
|
31
|
+
end
|
32
|
+
|
33
|
+
def callable_from(option_name)
|
34
|
+
return false unless options.key?(option_name)
|
35
|
+
|
36
|
+
tmp = options.fetch(option_name)
|
37
|
+
case tmp
|
38
|
+
when Proc then tmp
|
39
|
+
when Symbol then blueprint.method(tmp)
|
40
|
+
else
|
41
|
+
raise ArgumentError, "#{tmp.class} is passed to :#{option_name}"
|
42
|
+
end
|
43
|
+
end
|
14
44
|
end
|
data/lib/blueprinter/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blueprinter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Hess
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-05
|
12
|
+
date: 2018-06-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|