pragma-decorator 0.1.0 → 1.0.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/.gitignore +0 -1
- data/README.md +1 -210
- data/doc/01-basic-usage.md +42 -0
- data/doc/02-object-types.md +47 -0
- data/doc/03-associations.md +91 -0
- data/doc/04-timestamps.md +33 -0
- data/lib/pragma/decorator/association/binding.rb +8 -12
- data/lib/pragma/decorator/association/reflection.rb +6 -6
- data/lib/pragma/decorator/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ff48d9c11a4d5a07d7a11f0b8c90005a06ff998
|
4
|
+
data.tar.gz: 53f69d42826745d481a7dc0317e28e90be17904e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf5197a94d5f7664b8ed594687c5d549abf3c01a9f61166a68c8a93dbd89bf4ade857efd1568b0e6645f9ec3f2396434eb56045805b977cdb9a38d8f4783f58e
|
7
|
+
data.tar.gz: 37bea54b8e417195fccfb37cfda43635bd625570f8569afa5cb68fc7de70b5652e7d1834f0e30f480a7709fdf2e6c430b13d214699391bf8137364bdce140769
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -32,216 +32,7 @@ $ gem install pragma-decorator
|
|
32
32
|
|
33
33
|
## Usage
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
```ruby
|
38
|
-
module API
|
39
|
-
module V1
|
40
|
-
module User
|
41
|
-
module Decorator
|
42
|
-
class Resource < Pragma::Decorator::Base
|
43
|
-
property :id
|
44
|
-
property :email
|
45
|
-
property :full_name
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
```
|
52
|
-
|
53
|
-
Just instantiate the decorator by passing it an object to decorate, then call `#to_hash` or
|
54
|
-
`#to_json`:
|
55
|
-
|
56
|
-
```ruby
|
57
|
-
decorator = API::V1::User::Decorator::Resource.new(user)
|
58
|
-
decorator.to_json
|
59
|
-
```
|
60
|
-
|
61
|
-
This will produce the following JSON:
|
62
|
-
|
63
|
-
```json
|
64
|
-
{
|
65
|
-
"id": 1,
|
66
|
-
"email": "jdoe@example.com",
|
67
|
-
"full_name": "John Doe"
|
68
|
-
}
|
69
|
-
```
|
70
|
-
|
71
|
-
Since Pragma::Decorator is built on top of [ROAR](https://github.com/apotonick/roar) (which, in
|
72
|
-
turn, is built on top of [Representable](https://github.com/apotonick/representable)), you should
|
73
|
-
consult their documentation for the basic usage of decorators; the rest of this section only covers
|
74
|
-
the features provided specifically by Pragma::Decorator.
|
75
|
-
|
76
|
-
### Object types
|
77
|
-
|
78
|
-
It is recommended that decorators expose the type of the decorated object. You can achieve this
|
79
|
-
with the `Type` mixin:
|
80
|
-
|
81
|
-
```ruby
|
82
|
-
module API
|
83
|
-
module V1
|
84
|
-
module User
|
85
|
-
module Decorator
|
86
|
-
class Resource < Pragma::Decorator::Base
|
87
|
-
feature Pragma::Decorator::Type
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
```
|
94
|
-
|
95
|
-
This would result in the following representation:
|
96
|
-
|
97
|
-
```json
|
98
|
-
{
|
99
|
-
"type": "user",
|
100
|
-
"...": "...""
|
101
|
-
}
|
102
|
-
```
|
103
|
-
|
104
|
-
You can also set a custom type name (just make sure to use it consistently!):
|
105
|
-
|
106
|
-
```ruby
|
107
|
-
module API
|
108
|
-
module V1
|
109
|
-
module User
|
110
|
-
module Decorator
|
111
|
-
class Resource < Pragma::Decorator::Base
|
112
|
-
def type
|
113
|
-
:custom_type
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
```
|
121
|
-
|
122
|
-
Note: `array` is already overridden with the more language-agnostic `list`.
|
123
|
-
|
124
|
-
### Associations
|
125
|
-
|
126
|
-
`Pragma::Decorator::Association` allows you to define associations in your decorator (currently,
|
127
|
-
only `belongs_to`/`has_one` associations are supported):
|
128
|
-
|
129
|
-
```ruby
|
130
|
-
module API
|
131
|
-
module V1
|
132
|
-
module Invoice
|
133
|
-
module Decorator
|
134
|
-
class Resource < Pragma::Decorator::Base
|
135
|
-
feature Pragma::Decorator::Association
|
136
|
-
|
137
|
-
belongs_to :customer
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
```
|
144
|
-
|
145
|
-
Rendering an invoice will now create the following representation:
|
146
|
-
|
147
|
-
```json
|
148
|
-
{
|
149
|
-
"customer": {
|
150
|
-
"id": 19
|
151
|
-
}
|
152
|
-
}
|
153
|
-
```
|
154
|
-
|
155
|
-
Not impressed? Just wait.
|
156
|
-
|
157
|
-
We also support association expansion through an interface similar to the one provided by the
|
158
|
-
[Stripe API](https://stripe.com/docs/api/curl#expanding_objects). You can define which associations
|
159
|
-
are expandable in the decorator:
|
160
|
-
|
161
|
-
```ruby
|
162
|
-
module API
|
163
|
-
module V1
|
164
|
-
module Invoice
|
165
|
-
module Decorator
|
166
|
-
class Resource < Pragma::Decorator::Base
|
167
|
-
feature Pragma::Decorator::Association
|
168
|
-
|
169
|
-
belongs_to :customer, expandable: true
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
```
|
176
|
-
|
177
|
-
You can now pass `expand[]=customer` as a request parameter and have the `customer` property
|
178
|
-
expanded into a full object!
|
179
|
-
|
180
|
-
```json
|
181
|
-
{
|
182
|
-
"customer": {
|
183
|
-
"id": 19,
|
184
|
-
"...": "..."
|
185
|
-
}
|
186
|
-
}
|
187
|
-
```
|
188
|
-
|
189
|
-
This also works for nested associations. For instance, if the customer has a `company` association
|
190
|
-
marked as expandable, you can pass `expand[]=customer&expand[]=customer.company` to get that
|
191
|
-
association expanded too.
|
192
|
-
|
193
|
-
In order for association expansion to work, you will have to pass the associations to expand to the
|
194
|
-
representer as a user option:
|
195
|
-
|
196
|
-
```ruby
|
197
|
-
decorator = API::V1::Invoice::Decorator::Resource.new(invoice)
|
198
|
-
decorator.to_json(user_options: {
|
199
|
-
expand: ['customer', 'customer.company', 'customer.company.contact']
|
200
|
-
})
|
201
|
-
```
|
202
|
-
|
203
|
-
Here's a list of options accepted when defining an association:
|
204
|
-
|
205
|
-
Name | Type | Default | Meaning
|
206
|
-
---- | ---- | ------- | -------
|
207
|
-
`expandable` | Boolean | `false` | Whether this association is expandable by consumers. Attempting to expand a non-expandable association will raise a `UnexpandableError`.
|
208
|
-
`decorator` | Class | - | If provided, decorates the expanded object with this decorator. Otherwise, simply calls `#to_hash` on the object to get a representable hash.
|
209
|
-
`render_nil` | Boolean | `false` | Whether the property should be rendered at all when it is `nil`.
|
210
|
-
`exec_context` | Symbol | `:decorated` | Whether to call the getter on the decorator (`:decorator`) or the decorated object (`:decorated`).
|
211
|
-
|
212
|
-
### Timestamps
|
213
|
-
|
214
|
-
[UNIX time](https://en.wikipedia.org/wiki/Unix_time) is your safest bet when rendering/parsing
|
215
|
-
timestamps in your API, as it doesn't require a timezone indicator (the timezone is always UTC).
|
216
|
-
|
217
|
-
You can use the `Timestamp` mixin for converting `Time` instances to UNIX times:
|
218
|
-
|
219
|
-
```ruby
|
220
|
-
module API
|
221
|
-
module V1
|
222
|
-
module User
|
223
|
-
module Decorator
|
224
|
-
class Resource < Pragma::Decorator::Base
|
225
|
-
feature Pragma::Decorator::Timestamp
|
226
|
-
|
227
|
-
timestamp :created_at
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
233
|
-
```
|
234
|
-
|
235
|
-
This will render a user like this:
|
236
|
-
|
237
|
-
```json
|
238
|
-
{
|
239
|
-
"type": "user",
|
240
|
-
"created_at": 1480287994
|
241
|
-
}
|
242
|
-
```
|
243
|
-
|
244
|
-
The `#timestamp` method supports all the options supported by `#property` (except for `:as`).
|
35
|
+
All documentation is in the [doc](https://github.com/pragmarb/pragma-decorator/tree/master/doc) folder.
|
245
36
|
|
246
37
|
## Contributing
|
247
38
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Basic usage
|
2
|
+
|
3
|
+
Creating a decorator is as simple as inheriting from `Pragma::Decorator::Base`:
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
module API
|
7
|
+
module V1
|
8
|
+
module User
|
9
|
+
module Decorator
|
10
|
+
class Resource < Pragma::Decorator::Base
|
11
|
+
property :id
|
12
|
+
property :email
|
13
|
+
property :full_name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
```
|
20
|
+
|
21
|
+
Just instantiate the decorator by passing it an object to decorate, then call `#to_hash` or
|
22
|
+
`#to_json`:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
decorator = API::V1::User::Decorator::Resource.new(user)
|
26
|
+
decorator.to_json
|
27
|
+
```
|
28
|
+
|
29
|
+
This will produce the following JSON:
|
30
|
+
|
31
|
+
```json
|
32
|
+
{
|
33
|
+
"id": 1,
|
34
|
+
"email": "jdoe@example.com",
|
35
|
+
"full_name": "John Doe"
|
36
|
+
}
|
37
|
+
```
|
38
|
+
|
39
|
+
Since Pragma::Decorator is built on top of [ROAR](https://github.com/apotonick/roar) (which, in
|
40
|
+
turn, is built on top of [Representable](https://github.com/apotonick/representable)), you should
|
41
|
+
consult their documentation for the basic usage of decorators; the rest of this section only covers
|
42
|
+
the features provided specifically by Pragma::Decorator.
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Object types
|
2
|
+
|
3
|
+
It is recommended that decorators expose the type of the decorated object. You can achieve this
|
4
|
+
with the `Type` mixin:
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
module API
|
8
|
+
module V1
|
9
|
+
module User
|
10
|
+
module Decorator
|
11
|
+
class Resource < Pragma::Decorator::Base
|
12
|
+
feature Pragma::Decorator::Type
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
```
|
19
|
+
|
20
|
+
This would result in the following representation:
|
21
|
+
|
22
|
+
```json
|
23
|
+
{
|
24
|
+
"type": "user",
|
25
|
+
"...": "...""
|
26
|
+
}
|
27
|
+
```
|
28
|
+
|
29
|
+
You can also set a custom type name (just make sure to use it consistently!):
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
module API
|
33
|
+
module V1
|
34
|
+
module User
|
35
|
+
module Decorator
|
36
|
+
class Resource < Pragma::Decorator::Base
|
37
|
+
def type
|
38
|
+
:custom_type
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
Note: `array` is already overridden with the more language-agnostic `list`.
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# Associations
|
2
|
+
|
3
|
+
`Pragma::Decorator::Association` allows you to define associations in your decorator (currently,
|
4
|
+
only `belongs_to`/`has_one` associations are supported):
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
module API
|
8
|
+
module V1
|
9
|
+
module Invoice
|
10
|
+
module Decorator
|
11
|
+
class Resource < Pragma::Decorator::Base
|
12
|
+
feature Pragma::Decorator::Association
|
13
|
+
|
14
|
+
belongs_to :customer
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
Rendering an invoice will now create the following representation:
|
23
|
+
|
24
|
+
```json
|
25
|
+
{
|
26
|
+
"customer": 19
|
27
|
+
}
|
28
|
+
```
|
29
|
+
|
30
|
+
Not impressed? Just wait.
|
31
|
+
|
32
|
+
## Expanding associations
|
33
|
+
|
34
|
+
We also support association expansion through an interface similar to the one provided by the
|
35
|
+
[Stripe API](https://stripe.com/docs/api/curl#expanding_objects). You can define which associations
|
36
|
+
are expandable in the decorator:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
module API
|
40
|
+
module V1
|
41
|
+
module Invoice
|
42
|
+
module Decorator
|
43
|
+
class Resource < Pragma::Decorator::Base
|
44
|
+
feature Pragma::Decorator::Association
|
45
|
+
|
46
|
+
belongs_to :customer, expandable: true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
You can now pass `expand[]=customer` as a request parameter and have the `customer` property
|
55
|
+
expanded into a full object!
|
56
|
+
|
57
|
+
```json
|
58
|
+
{
|
59
|
+
"customer": {
|
60
|
+
"id": 19,
|
61
|
+
"...": "..."
|
62
|
+
}
|
63
|
+
}
|
64
|
+
```
|
65
|
+
|
66
|
+
## Nested associations
|
67
|
+
|
68
|
+
This also works for nested associations. For instance, if the customer has a `company` association
|
69
|
+
marked as expandable, you can pass `expand[]=customer&expand[]=customer.company` to get that
|
70
|
+
association expanded too.
|
71
|
+
|
72
|
+
In order for association expansion to work, you will have to pass the associations to expand to the
|
73
|
+
representer as a user option:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
decorator = API::V1::Invoice::Decorator::Resource.new(invoice)
|
77
|
+
decorator.to_json(user_options: {
|
78
|
+
expand: ['customer', 'customer.company', 'customer.company.contact']
|
79
|
+
})
|
80
|
+
```
|
81
|
+
|
82
|
+
## Accepted options
|
83
|
+
|
84
|
+
Here's a list of options accepted when defining an association:
|
85
|
+
|
86
|
+
Name | Type | Default | Meaning
|
87
|
+
---- | ---- | ------- | -------
|
88
|
+
`expandable` | Boolean | `false` | Whether this association is expandable by consumers. Attempting to expand a non-expandable association will raise a `UnexpandableError`.
|
89
|
+
`decorator` | Class | - | If provided, decorates the expanded object with this decorator. Otherwise, simply calls `#to_hash` on the object to get a representable hash.
|
90
|
+
`render_nil` | Boolean | `false` | Whether the property should be rendered at all when it is `nil`.
|
91
|
+
`exec_context` | Symbol | `:decorated` | Whether to call the getter on the decorator (`:decorator`) or the decorated object (`:decorated`).
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Timestamps
|
2
|
+
|
3
|
+
[UNIX time](https://en.wikipedia.org/wiki/Unix_time) is your safest bet when rendering/parsing
|
4
|
+
timestamps in your API, as it doesn't require a timezone indicator (the timezone is always UTC).
|
5
|
+
|
6
|
+
You can use the `Timestamp` mixin for converting `Time` instances to UNIX times:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
module API
|
10
|
+
module V1
|
11
|
+
module User
|
12
|
+
module Decorator
|
13
|
+
class Resource < Pragma::Decorator::Base
|
14
|
+
feature Pragma::Decorator::Timestamp
|
15
|
+
|
16
|
+
timestamp :created_at
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
```
|
23
|
+
|
24
|
+
This will render a user like this:
|
25
|
+
|
26
|
+
```json
|
27
|
+
{
|
28
|
+
"type": "user",
|
29
|
+
"created_at": 1480287994
|
30
|
+
}
|
31
|
+
```
|
32
|
+
|
33
|
+
The `#timestamp` method supports all the options supported by `#property` (except for `:as`).
|
@@ -34,19 +34,15 @@ module Pragma
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
# Returns the unexpanded
|
38
|
-
# property).
|
37
|
+
# Returns the unexpanded value for the associated object (i.e. its +id+ property).
|
39
38
|
#
|
40
|
-
# @return [
|
41
|
-
def
|
39
|
+
# @return [String]
|
40
|
+
def unexpanded_value
|
42
41
|
return unless associated_object
|
43
|
-
|
44
|
-
{
|
45
|
-
id: associated_object.id
|
46
|
-
}
|
42
|
+
associated_object.id
|
47
43
|
end
|
48
44
|
|
49
|
-
# Returns the expanded
|
45
|
+
# Returns the expanded value for the associated object.
|
50
46
|
#
|
51
47
|
# If a decorator was specified for the association, first decorates the associated object,
|
52
48
|
# then calls +#to_hash+ to render it as a hash.
|
@@ -61,7 +57,7 @@ module Pragma
|
|
61
57
|
# @return [Hash]
|
62
58
|
#
|
63
59
|
# @raise [UnexpandableError] if the association is not expandable
|
64
|
-
def
|
60
|
+
def expanded_value(expand)
|
65
61
|
fail UnexpandableError, reflection unless reflection.expandable?
|
66
62
|
|
67
63
|
return unless associated_object
|
@@ -91,9 +87,9 @@ module Pragma
|
|
91
87
|
expand ||= []
|
92
88
|
|
93
89
|
if expand.any? { |value| value.to_s == reflection.property.to_s }
|
94
|
-
|
90
|
+
expanded_value(expand)
|
95
91
|
else
|
96
|
-
|
92
|
+
unexpanded_value
|
97
93
|
end
|
98
94
|
end
|
99
95
|
|
@@ -56,12 +56,12 @@ module Pragma
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def validate_options
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
return if [:decorator, :decorated].include?(options[:exec_context])
|
60
|
+
|
61
|
+
fail(
|
62
|
+
ArgumentError,
|
63
|
+
"'#{options[:exec_context]}' is not a valid value for :exec_context."
|
64
|
+
)
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pragma-decorator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alessandro Desantis
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: roar
|
@@ -139,6 +139,10 @@ files:
|
|
139
139
|
- Rakefile
|
140
140
|
- bin/console
|
141
141
|
- bin/setup
|
142
|
+
- doc/01-basic-usage.md
|
143
|
+
- doc/02-object-types.md
|
144
|
+
- doc/03-associations.md
|
145
|
+
- doc/04-timestamps.md
|
142
146
|
- lib/pragma/decorator.rb
|
143
147
|
- lib/pragma/decorator/association.rb
|
144
148
|
- lib/pragma/decorator/association/binding.rb
|
@@ -169,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
169
173
|
version: '0'
|
170
174
|
requirements: []
|
171
175
|
rubyforge_project:
|
172
|
-
rubygems_version: 2.
|
176
|
+
rubygems_version: 2.6.8
|
173
177
|
signing_key:
|
174
178
|
specification_version: 4
|
175
179
|
summary: Convert your API resources into JSON with minimum hassle.
|