grape-entity 0.3.0 → 0.4.0

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: b398596f88871f8170eb2a73142bfdc08ca91370
4
- data.tar.gz: 32aec8564a0c5f46522ffae2ac6167083440b8b0
3
+ metadata.gz: 35f4a45cc741d725e9cc8d180ae9db0f9123cb7a
4
+ data.tar.gz: a452232a49b72773f38710733c24104e113e7043
5
5
  SHA512:
6
- metadata.gz: e6ced06ae9b0a8bada53aae31a4eba8d5a58b717797b72adc2953ed4431dc99b21e711b370f027b45c19ac1b27f312a1d1300e29da64964e2b7e70fbc1f3a96c
7
- data.tar.gz: 58fb3f143bffa542f8a8cfe1ce3f19f1f924588a670697c1ae596e27a80dd28eefea8ee4a3031d4c7cf89eeea85f6fa7912bdf6400d29474c0273e358bf594f6
6
+ metadata.gz: aeaab5ee1c623a0f4359a4b5378b3536afefd0a23009007a5c0a91fb4086658da6abd53458ea85bcd724dea448b0598213160bf74b58084e4ee68a840e0df511
7
+ data.tar.gz: 6f187c4bb82bea91a739fb3dc8c48d04985b3b72d09e29e91e6565b42ceecb281275d3c973eb3062b25263a997955dcece3efa7fe297ca1dd1e209e7b18dc3ea
data/.gitignore CHANGED
@@ -36,3 +36,4 @@ tmp
36
36
  .rbx
37
37
 
38
38
  ## PROJECT::SPECIFIC
39
+ .project
@@ -0,0 +1,69 @@
1
+ AllCops:
2
+ Excludes:
3
+ - vendor/**
4
+
5
+ LineLength:
6
+ Enabled: false
7
+
8
+ MethodLength:
9
+ Enabled: false
10
+
11
+ ClassLength:
12
+ Enabled: false
13
+
14
+ Documentation:
15
+ # don't require classes to be documented
16
+ Enabled: false
17
+
18
+ CollectionMethods:
19
+ # don't prefer map to collect, recuce to inject
20
+ Enabled: false
21
+
22
+ Encoding:
23
+ # no need to always specify encoding
24
+ Enabled: false
25
+
26
+ HashMethods:
27
+ # key? instead of has_key?
28
+ # value? instead of has_value?
29
+ Enabled: false
30
+
31
+ StringLiterals:
32
+ # use single or double-quoted strings, as you please
33
+ Enabled: false
34
+
35
+ Void:
36
+ # == operator used in void context in specs
37
+ Enabled: false
38
+
39
+ SignalException:
40
+ # prefer raise to fail
41
+ EnforcedStyle: only_raise
42
+
43
+ RaiseArgs:
44
+ # don't care for what kind of raise
45
+ Enabled: false
46
+
47
+ PerlBackrefs:
48
+ # TODO: regular expression matching with $1, $2, etc.
49
+ Enabled: false
50
+
51
+ BlockNesting:
52
+ # TODO: fix too much nesting
53
+ Max: 4
54
+
55
+ Lambda:
56
+ # TODO: replace all lambda with -> or Proc
57
+ Enabled: false
58
+
59
+ Blocks:
60
+ # allow multi-line blocks like expect { }
61
+ Enabled: false
62
+
63
+ WordArray:
64
+ # %w vs. [ '', ... ]
65
+ Enabled: false
66
+
67
+ CyclomaticComplexity:
68
+ Enabled: false
69
+
@@ -1,8 +1,7 @@
1
+ language: ruby
2
+ cache: bundler
1
3
  rvm:
2
- - 1.8.7
3
- - 1.9.2
4
+ - 2.0.0
4
5
  - 1.9.3
5
- - jruby
6
- - rbx
7
- - ree
8
-
6
+ - jruby-19mode
7
+ - rbx-2.1.1
@@ -0,0 +1,35 @@
1
+ Next Release
2
+ ============
3
+ * Ruby 1.8.x is no longer supported - [@dblock](https://github.com/dblock).
4
+ * [#36](https://github.com/intridea/grape-entity/pull/36): Enforcing Ruby style guidelines via Rubocop - [@dblock](https://github.com/dblock).
5
+ * [#7](https://github.com/intridea/grape-entity/issues/7): Added `serializable` option to `represent` - [@mbleigh](https://github.com/mbleigh).
6
+ * [#18](https://github.com/intridea/grape-entity/pull/18): Added `safe` option to `expose`, will not raise error for a missing attribute - [@fixme](https://github.com/fixme).
7
+ * [#16](https://github.com/intridea/grape-entity/pull/16): Added `using` option to `expose SYMBOL BLOCK` - [@fahchen](https://github.com/fahchen).
8
+ * [#24](https://github.com/intridea/grape-entity/pull/24): Return documentation with `as` param considered - [@drakula2k](https://github.com/drakula2k).
9
+ * [#27](https://github.com/intridea/grape-entity/pull/27): Properly serialize hashes - [@clintonb](https://github.com/clintonb).
10
+ * [#28](https://github.com/intridea/grape-entity/pull/28): Look for method on entity before calling it on the object - [@MichaelXavier](https://github.com/MichaelXavier).
11
+ * [#33](https://github.com/intridea/grape-entity/pull/33): Support proper merging of nested conditionals - [@wyattisimo](https://github.com/wyattisimo).
12
+ * [#43](https://github.com/intridea/grape-entity/pull/43): Call procs in context of entity instance - [@joelvh](https://github.com/joelvh).
13
+ * [#47](https://github.com/intridea/grape-entity/pull/47): Support nested exposures - [@wyattisimo](https://github.com/wyattisimo).
14
+ * [#46](https://github.com/intridea/grape-entity/issues/46), [#50](https://github.com/intridea/grape-entity/pull/50): Added support for specifying the presenter class in `using` in string format - [@larryzhao](https://github.com/larryzhao).
15
+ * [#51](https://github.com/intridea/grape-entity/pull/51): Raise `ArgumentError` if an unknown option is used with `expose` - [@aj0strow](https://github.com/aj0strow).
16
+ * [#51](https://github.com/intridea/grape-entity/pull/51): Alias `:with` to `:using`, consistently with the Grape api endpoints - [@aj0strow](https://github.com/aj0strow).
17
+ * Your contribution here.
18
+
19
+ 0.3.0 (2013-03-29)
20
+ ==================
21
+
22
+ * [#9](https://github.com/intridea/grape-entity/pull/9): Added `with_options` for block-level exposure setting - [@SegFaultAX](https://github.com/SegFaultAX).
23
+ * The `instance.entity` method now optionally accepts `options` - [@mbleigh](https://github.com/mbleigh).
24
+ * You can pass symbols to `:if` and `:unless` to simply check for truthiness/falsiness of the specified options key - [@mbleigh](https://github.com/mbleigh).
25
+
26
+ 0.2.0 (2013-01-11)
27
+ ==================
28
+
29
+ * Moved the namespace back to `Grape::Entity` to preserve compatibility with Grape - [@dblock](https://github.com/dblock).
30
+
31
+ 0.1.0 (2013-01-11)
32
+ ==================
33
+
34
+ * Initial public release - [@agileanimal](https://github.com/agileanimal).
35
+
data/Gemfile CHANGED
@@ -13,4 +13,11 @@ group :development, :test do
13
13
  gem 'rspec'
14
14
  gem 'rack-test', "~> 0.6.2", :require => "rack/test"
15
15
  gem 'github-markup'
16
+ gem 'rubocop', '~> 0.16.0'
17
+ end
18
+
19
+ platforms :rbx do
20
+ gem 'rubysl', '~> 2.0'
21
+ gem 'parser', '~> 2.1'
22
+ gem 'racc', '~> 1.4'
16
23
  end
data/Guardfile CHANGED
@@ -8,7 +8,6 @@ guard 'rspec', :version => 2 do
8
8
  watch('spec/spec_helper.rb') { "spec/" }
9
9
  end
10
10
 
11
-
12
11
  guard 'bundler' do
13
12
  watch('Gemfile')
14
13
  watch(/^.+\.gemspec/)
@@ -0,0 +1,320 @@
1
+ # Grape::Entity
2
+
3
+ [![Build Status](https://travis-ci.org/agileanimal/grape-entity.png?branch=master)](https://travis-ci.org/agileanimal/grape-entity)
4
+
5
+ ## Introduction
6
+
7
+ This gem adds Entity support to API frameworks, such as [Grape](https://github.com/intridea/grape). Grape's Entity is an API focused facade that sits on top of an object model.
8
+
9
+ ### Example
10
+
11
+ ```ruby
12
+ module API
13
+ module Entities
14
+ class Status < Grape::Entity
15
+ format_with(:iso_timestamp) { |dt| dt.iso8601 }
16
+
17
+ expose :user_name
18
+ expose :text, documentation: { type: "String", desc: "Status update text." }
19
+ expose :ip, if: { type: :full }
20
+ expose :user_type, :user_id, if: lambda { |status, options| status.user.public? }
21
+ expose :contact_info do
22
+ expose :phone
23
+ expose :address, using: API::Address
24
+ end
25
+ expose :digest do |status, options|
26
+ Digest::MD5.hexdigest status.txt
27
+ end
28
+ expose :replies, using: API::Status, as: :replies
29
+ expose :last_reply, using: API::Status do |status, options|
30
+ status.replies.last
31
+ end
32
+
33
+ with_options(format_with: :iso_timestamp) do
34
+ expose :created_at
35
+ expose :updated_at
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ module API
42
+ module Entities
43
+ class StatusDetailed < API::Entities::Status
44
+ expose :internal_id
45
+ end
46
+ end
47
+ end
48
+ ```
49
+
50
+ ## Reusable Responses with Entities
51
+
52
+ Entities are a reusable means for converting Ruby objects to API responses. Entities can be used to conditionally include fields, nest other entities, and build ever larger responses, using inheritance.
53
+
54
+ ### Defining Entities
55
+
56
+ Entities inherit from Grape::Entity, and define a simple DSL. Exposures can use runtime options to determine which fields should be visible, these options are available to `:if`, `:unless`, and `:proc`.
57
+
58
+ #### Basic Exposure
59
+
60
+ Define a list of fields that will always be exposed.
61
+
62
+ ```ruby
63
+ expose :user_name, :ip
64
+ ```
65
+
66
+ #### Exposing with a Presenter
67
+
68
+ Don't derive your model classes from `Grape::Entity`, expose them using a presenter.
69
+
70
+ ```ruby
71
+ expose :replies, using: API::Status, as: :replies
72
+ ```
73
+
74
+ Presenter classes can also be specified in string format, which helps with circular dependencies.
75
+
76
+ ```ruby
77
+ expose :replies, using: `API::Status`, as: :replies
78
+ ```
79
+
80
+ #### Conditional Exposure
81
+
82
+ Use `:if` or `:unless` to expose fields conditionally.
83
+
84
+ ```ruby
85
+ expose :ip, if: { type: :full }
86
+
87
+ expose :ip, if: lambda { |instance, options| options[:type] == :full } # exposed if the function evaluates to true
88
+ expose :ip, if: :type # exposed if :type is available in the options hash
89
+ expose :ip, if { type: :full } # exposed if options :type has a value of :full
90
+
91
+ expose :ip, unless: ... # the opposite of :if
92
+ ```
93
+
94
+ #### Safe Exposure
95
+
96
+ Don't raise an exception and expose as nil, even if the :x cannot be evaluated.
97
+
98
+ ```ruby
99
+ expose :ip, safe: true
100
+ ```
101
+
102
+ #### Nested Exposure
103
+
104
+ Supply a block to define a hash using nested exposures.
105
+
106
+ ```ruby
107
+ expose :contact_info do
108
+ expose :phone
109
+ expose :address, using: API::Address
110
+ end
111
+ ```
112
+
113
+ #### Runtime Exposure
114
+
115
+ Use a block or a `Proc` to evaluate exposure at runtime. The supplied block or
116
+ `Proc` will be called with two parameters: the represented object and runtime options.
117
+
118
+ **NOTE:** A block supplied with no parameters will be evaluated as a nested exposure (see above).
119
+
120
+ ```ruby
121
+ expose :digest do |status, options|
122
+ Digest::MD5.hexdigest status.txt
123
+ end
124
+ ```
125
+
126
+ ```ruby
127
+ expose :digest, proc: ... # equivalent to a block
128
+ ```
129
+
130
+ You can also define a method on the entity and it will try that before trying
131
+ on the object the entity wraps.
132
+
133
+ ```ruby
134
+ class ExampleEntity < Grape::Entity
135
+ expose :attr_not_on_wrapped_object
136
+ # ...
137
+ private
138
+
139
+ def attr_not_on_wrapped_object
140
+ 42
141
+ end
142
+ end
143
+ ```
144
+
145
+ #### Aliases
146
+
147
+ Expose under a different name with `:as`.
148
+
149
+ ```ruby
150
+ expose :replies, using: API::Status, as: :replies
151
+ ```
152
+
153
+ #### Format Before Exposing
154
+
155
+ Apply a formatter before exposing a value.
156
+
157
+ ```ruby
158
+ format_with(:iso_timestamp) { |dt| dt.iso8601 }
159
+ with_options(format_with: :iso_timestamp) do
160
+ expose :created_at
161
+ expose :updated_at
162
+ end
163
+ ```
164
+
165
+ #### Documentation
166
+
167
+ Expose documentation with the field. Gets bubbled up when used with Grape and various API documentation systems.
168
+
169
+ ```ruby
170
+ expose :text, documentation: { type: "String", desc: "Status update text." }
171
+ ```
172
+
173
+ ### Options Hash
174
+
175
+ The option keys `:version` and `:collection` are always defined. The `:version` key is defined as `api.version`. The `:collection` key is boolean, and defined as `true` if the object presented is an array. The options also contain the runtime environment in `:env`, which includes request parameters in `options[:env][:grape.request.params]`.
176
+
177
+ Any additional options defined on the entity exposure are included as is. In the following example `user` is set to the value of `current_user`.
178
+
179
+ ```ruby
180
+ class Status < Grape::Entity
181
+ expose :user, if: lambda { |instance, options| options[:user] } do |instance, options|
182
+ # examine available environment keys with `p options[:env].keys`
183
+ options[:user]
184
+ end
185
+ end
186
+ ```
187
+
188
+ ```
189
+ present s, with: Status, user: current_user
190
+ ```
191
+
192
+ ### Using the Exposure DSL
193
+
194
+ Grape ships with a DSL to easily define entities within the context of an existing class:
195
+
196
+ ```ruby
197
+ class Status
198
+ include Grape::Entity::DSL
199
+
200
+ entity :text, :user_id do
201
+ expose :detailed, if: :conditional
202
+ end
203
+ end
204
+ ```
205
+
206
+ The above will automatically create a `Status::Entity` class and define properties on it according to the same rules as above. If you only want to define simple exposures you don't have to supply a block and can instead simply supply a list of comma-separated symbols.
207
+
208
+ ### Using Entities
209
+
210
+ With Grape, once an entity is defined, it can be used within endpoints, by calling `present`. The `present` method accepts two arguments, the object to be presented and the options associated with it. The options hash must always include `:with`, which defines the entity to expose.
211
+
212
+ If the entity includes documentation it can be included in an endpoint's description.
213
+
214
+ ```ruby
215
+ module API
216
+ class Statuses < Grape::API
217
+ version 'v1'
218
+
219
+ desc 'Statuses.', {
220
+ params: API::Entities::Status.documentation
221
+ }
222
+ get '/statuses' do
223
+ statuses = Status.all
224
+ type = current_user.admin? ? :full : :default
225
+ present statuses, with: API::Entities::Status, type: type
226
+ end
227
+ end
228
+ end
229
+ ```
230
+
231
+ ### Entity Organization
232
+
233
+ In addition to separately organizing entities, it may be useful to put them as namespaced classes underneath the model they represent.
234
+
235
+ ```ruby
236
+ class Status
237
+ def entity
238
+ Entity.new(self)
239
+ end
240
+
241
+ class Entity < Grape::Entity
242
+ expose :text, :user_id
243
+ end
244
+ end
245
+ ```
246
+
247
+ If you organize your entities this way, Grape will automatically detect the `Entity` class and use it to present your models. In this example, if you added `present User.new` to your endpoint, Grape would automatically detect that there is a `Status::Entity` class and use that as the representative entity. This can still be overridden by using the `:with` option or an explicit `represents` call.
248
+
249
+ ### Caveats
250
+
251
+ Entities with duplicate exposure names and conditions will silently overwrite one another. In the following example, when `object.check` equals "foo", only `field_a` will be exposed. However, when `object.check` equals "bar" both `field_b` and `foo` will be exposed.
252
+
253
+ ```ruby
254
+ module API
255
+ module Entities
256
+ class Status < Grape::Entity
257
+ expose :field_a, :foo, if: lambda { |object, options| object.check == "foo" }
258
+ expose :field_b, :foo, if: lambda { |object, options| object.check == "bar" }
259
+ end
260
+ end
261
+ end
262
+ ```
263
+
264
+ This can be problematic, when you have mixed collections. Using `respond_to?` is safer.
265
+
266
+ ```ruby
267
+ module API
268
+ module Entities
269
+ class Status < Grape::Entity
270
+ expose :field_a, if: lambda { |object, options| object.check == "foo" }
271
+ expose :field_b, if: lambda { |object, options| object.check == "bar" }
272
+ expose :foo, if: lambda { |object, options| object.respond_to?(:foo) }
273
+ end
274
+ end
275
+ end
276
+ ```
277
+
278
+ Also note that an `ArgumentError` is raised when unknown options are passed to either `expose` or `with_options`.
279
+
280
+ ## Installation
281
+
282
+ Add this line to your application's Gemfile:
283
+
284
+ gem 'grape-entity'
285
+
286
+ And then execute:
287
+
288
+ $ bundle
289
+
290
+ Or install it yourself as:
291
+
292
+ $ gem install grape-entity
293
+
294
+ ## Testing with Entities
295
+
296
+ Test API request/response as usual.
297
+
298
+ Also see [Grape Entity Matchers](https://github.com/agileanimal/grape-entity-matchers).
299
+
300
+ ## Project Resources
301
+
302
+ * Need help? [Grape Google Group](http://groups.google.com/group/ruby-grape)
303
+
304
+ ## Contributing
305
+
306
+ 1. Fork the project
307
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
308
+ 3. Write tests. Make changes. Run `rubocop`.
309
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
310
+ 4. Push to the branch (`git push origin my-new-feature`)
311
+ 5. Create a new pull request
312
+
313
+ ## License
314
+
315
+ MIT License. See LICENSE for details.
316
+
317
+ ## Copyright
318
+
319
+ Copyright (c) 2010-2013 Michael Bleigh, Intridea, Inc., and contributors.
320
+