grape 0.2.6 → 0.3.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.

Potentially problematic release.


This version of grape might be problematic. Click here for more details.

Files changed (50) hide show
  1. data/{CHANGELOG.markdown → CHANGELOG.md} +21 -1
  2. data/Gemfile +1 -0
  3. data/{README.markdown → README.md} +178 -125
  4. data/grape.gemspec +1 -1
  5. data/lib/grape.rb +25 -3
  6. data/lib/grape/api.rb +43 -20
  7. data/lib/grape/endpoint.rb +32 -13
  8. data/lib/grape/exceptions/base.rb +50 -1
  9. data/lib/grape/exceptions/invalid_formatter.rb +13 -0
  10. data/lib/grape/exceptions/invalid_versioner_option.rb +14 -0
  11. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +15 -0
  12. data/lib/grape/exceptions/missing_mime_type.rb +14 -0
  13. data/lib/grape/exceptions/missing_option.rb +13 -0
  14. data/lib/grape/exceptions/missing_vendor_option.rb +13 -0
  15. data/lib/grape/exceptions/unknown_options.rb +14 -0
  16. data/lib/grape/exceptions/unknown_validator.rb +12 -0
  17. data/lib/grape/exceptions/{validation_error.rb → validation.rb} +3 -1
  18. data/lib/grape/formatter/xml.rb +2 -1
  19. data/lib/grape/locale/en.yml +20 -0
  20. data/lib/grape/middleware/base.rb +0 -5
  21. data/lib/grape/middleware/error.rb +1 -2
  22. data/lib/grape/middleware/formatter.rb +9 -5
  23. data/lib/grape/middleware/versioner.rb +1 -1
  24. data/lib/grape/middleware/versioner/header.rb +16 -6
  25. data/lib/grape/middleware/versioner/param.rb +1 -1
  26. data/lib/grape/middleware/versioner/path.rb +1 -1
  27. data/lib/grape/util/content_types.rb +0 -2
  28. data/lib/grape/validations.rb +7 -14
  29. data/lib/grape/validations/coerce.rb +2 -1
  30. data/lib/grape/validations/presence.rb +2 -1
  31. data/lib/grape/validations/regexp.rb +2 -1
  32. data/lib/grape/version.rb +1 -1
  33. data/spec/grape/api_spec.rb +150 -5
  34. data/spec/grape/endpoint_spec.rb +51 -157
  35. data/spec/grape/entity_spec.rb +142 -520
  36. data/spec/grape/exceptions/invalid_formatter_spec.rb +18 -0
  37. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +18 -0
  38. data/spec/grape/exceptions/missing_mime_type_spec.rb +24 -0
  39. data/spec/grape/exceptions/missing_option_spec.rb +18 -0
  40. data/spec/grape/exceptions/unknown_options_spec.rb +18 -0
  41. data/spec/grape/exceptions/unknown_validator_spec.rb +18 -0
  42. data/spec/grape/middleware/formatter_spec.rb +40 -34
  43. data/spec/grape/middleware/versioner/header_spec.rb +78 -20
  44. data/spec/grape/middleware/versioner/path_spec.rb +12 -8
  45. data/spec/grape/validations/coerce_spec.rb +1 -0
  46. data/spec/grape/validations/presence_spec.rb +8 -8
  47. data/spec/grape/validations_spec.rb +26 -3
  48. data/spec/spec_helper.rb +3 -6
  49. metadata +44 -9
  50. data/lib/grape/entity.rb +0 -386
@@ -58,6 +58,29 @@ describe Grape::Validations do
58
58
  end
59
59
  end
60
60
 
61
+ context 'group' do
62
+ before do
63
+ subject.params {
64
+ group :items do
65
+ requires :key
66
+ end
67
+ }
68
+ subject.get '/required' do 'required works'; end
69
+ end
70
+
71
+ it 'errors when param not present' do
72
+ get '/required'
73
+ last_response.status.should == 400
74
+ last_response.body.should == 'missing parameter: items[key]'
75
+ end
76
+
77
+ it "doesn't throw a missing param when param is present" do
78
+ get '/required', { :items => [:key => 'hello', :key => 'world'] }
79
+ last_response.status.should == 200
80
+ last_response.body.should == 'required works'
81
+ end
82
+ end
83
+
61
84
  context 'custom validation' do
62
85
  module CustomValidations
63
86
  class Customvalidator < Grape::Validations::Validator
@@ -147,19 +170,19 @@ describe Grape::Validations do
147
170
  end
148
171
  end
149
172
  end
150
-
173
+
151
174
  specify 'the parent namespace uses the validator' do
152
175
  get '/nested/one', { :custom => 'im wrong, validate me'}
153
176
  last_response.status.should == 400
154
177
  last_response.body.should == 'custom: is not custom!'
155
178
  end
156
-
179
+
157
180
  specify 'the nested namesapce inherits the custom validator' do
158
181
  get '/nested/nested/two', { :custom => 'im wrong, validate me'}
159
182
  last_response.status.should == 400
160
183
  last_response.body.should == 'custom: is not custom!'
161
184
  end
162
-
185
+
163
186
  specify 'peer namesapces does not have the validator' do
164
187
  get '/peer/one', { :custom => 'im not validated' }
165
188
  last_response.status.should == 200
data/spec/spec_helper.rb CHANGED
@@ -2,20 +2,18 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'support'))
4
4
 
5
- # $stdout = StringIO.new
6
-
7
5
  require 'grape'
8
6
 
7
+ # require 'grape-entity'
8
+
9
9
  require 'rubygems'
10
10
  require 'bundler'
11
11
  Bundler.setup :default, :test
12
12
 
13
13
  require 'rack/test'
14
14
  require 'pry'
15
-
16
15
  require 'base64'
17
-
18
- require 'hashie/hash'
16
+ require 'cookiejar'
19
17
 
20
18
  Dir["#{File.dirname(__FILE__)}/support/*.rb"].each do |file|
21
19
  require file
@@ -24,4 +22,3 @@ end
24
22
  RSpec.configure do |config|
25
23
  config.include Rack::Test::Methods
26
24
  end
27
-
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-11 00:00:00.000000000 Z
12
+ date: 2013-02-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -155,6 +155,22 @@ dependencies:
155
155
  - - ! '>='
156
156
  - !ruby/object:Gem::Version
157
157
  version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: grape-entity
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: 0.2.0
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: 0.2.0
158
174
  - !ruby/object:Gem::Dependency
159
175
  name: rake
160
176
  requirement: !ruby/object:Gem::Requirement
@@ -262,24 +278,31 @@ files:
262
278
  - .rspec
263
279
  - .travis.yml
264
280
  - .yardopts
265
- - CHANGELOG.markdown
281
+ - CHANGELOG.md
266
282
  - Gemfile
267
283
  - Guardfile
268
284
  - LICENSE
269
- - README.markdown
285
+ - README.md
270
286
  - Rakefile
271
287
  - grape.gemspec
272
288
  - lib/grape.rb
273
289
  - lib/grape/api.rb
274
290
  - lib/grape/cookies.rb
275
291
  - lib/grape/endpoint.rb
276
- - lib/grape/entity.rb
277
292
  - lib/grape/error_formatter/base.rb
278
293
  - lib/grape/error_formatter/json.rb
279
294
  - lib/grape/error_formatter/txt.rb
280
295
  - lib/grape/error_formatter/xml.rb
281
296
  - lib/grape/exceptions/base.rb
282
- - lib/grape/exceptions/validation_error.rb
297
+ - lib/grape/exceptions/invalid_formatter.rb
298
+ - lib/grape/exceptions/invalid_versioner_option.rb
299
+ - lib/grape/exceptions/invalid_with_option_for_represent.rb
300
+ - lib/grape/exceptions/missing_mime_type.rb
301
+ - lib/grape/exceptions/missing_option.rb
302
+ - lib/grape/exceptions/missing_vendor_option.rb
303
+ - lib/grape/exceptions/unknown_options.rb
304
+ - lib/grape/exceptions/unknown_validator.rb
305
+ - lib/grape/exceptions/validation.rb
283
306
  - lib/grape/formatter/base.rb
284
307
  - lib/grape/formatter/json.rb
285
308
  - lib/grape/formatter/serializable_hash.rb
@@ -312,6 +335,12 @@ files:
312
335
  - spec/grape/api_spec.rb
313
336
  - spec/grape/endpoint_spec.rb
314
337
  - spec/grape/entity_spec.rb
338
+ - spec/grape/exceptions/invalid_formatter_spec.rb
339
+ - spec/grape/exceptions/invalid_versioner_option_spec.rb
340
+ - spec/grape/exceptions/missing_mime_type_spec.rb
341
+ - spec/grape/exceptions/missing_option_spec.rb
342
+ - spec/grape/exceptions/unknown_options_spec.rb
343
+ - spec/grape/exceptions/unknown_validator_spec.rb
315
344
  - spec/grape/middleware/auth/basic_spec.rb
316
345
  - spec/grape/middleware/auth/digest_spec.rb
317
346
  - spec/grape/middleware/auth/oauth2_spec.rb
@@ -348,7 +377,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
348
377
  version: '0'
349
378
  segments:
350
379
  - 0
351
- hash: 1249607937311024438
380
+ hash: 1796003249167814741
352
381
  required_rubygems_version: !ruby/object:Gem::Requirement
353
382
  none: false
354
383
  requirements:
@@ -357,10 +386,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
357
386
  version: '0'
358
387
  segments:
359
388
  - 0
360
- hash: 1249607937311024438
389
+ hash: 1796003249167814741
361
390
  requirements: []
362
391
  rubyforge_project: grape
363
- rubygems_version: 1.8.24
392
+ rubygems_version: 1.8.25
364
393
  signing_key:
365
394
  specification_version: 3
366
395
  summary: A simple Ruby framework for building REST-like APIs.
@@ -368,6 +397,12 @@ test_files:
368
397
  - spec/grape/api_spec.rb
369
398
  - spec/grape/endpoint_spec.rb
370
399
  - spec/grape/entity_spec.rb
400
+ - spec/grape/exceptions/invalid_formatter_spec.rb
401
+ - spec/grape/exceptions/invalid_versioner_option_spec.rb
402
+ - spec/grape/exceptions/missing_mime_type_spec.rb
403
+ - spec/grape/exceptions/missing_option_spec.rb
404
+ - spec/grape/exceptions/unknown_options_spec.rb
405
+ - spec/grape/exceptions/unknown_validator_spec.rb
371
406
  - spec/grape/middleware/auth/basic_spec.rb
372
407
  - spec/grape/middleware/auth/digest_spec.rb
373
408
  - spec/grape/middleware/auth/oauth2_spec.rb
data/lib/grape/entity.rb DELETED
@@ -1,386 +0,0 @@
1
- require 'hashie'
2
-
3
- module Grape
4
- # An Entity is a lightweight structure that allows you to easily
5
- # represent data from your application in a consistent and abstracted
6
- # way in your API. Entities can also provide documentation for the
7
- # fields exposed.
8
- #
9
- # @example Entity Definition
10
- #
11
- # module API
12
- # module Entities
13
- # class User < Grape::Entity
14
- # expose :first_name, :last_name, :screen_name, :location
15
- # expose :field, :documentation => {:type => "string", :desc => "describe the field"}
16
- # expose :latest_status, :using => API::Status, :as => :status, :unless => {:collection => true}
17
- # expose :email, :if => {:type => :full}
18
- # expose :new_attribute, :if => {:version => 'v2'}
19
- # expose(:name){|model,options| [model.first_name, model.last_name].join(' ')}
20
- # end
21
- # end
22
- # end
23
- #
24
- # Entities are not independent structures, rather, they create
25
- # **representations** of other Ruby objects using a number of methods
26
- # that are convenient for use in an API. Once you've defined an Entity,
27
- # you can use it in your API like this:
28
- #
29
- # @example Usage in the API Layer
30
- #
31
- # module API
32
- # class Users < Grape::API
33
- # version 'v2'
34
- #
35
- # desc 'User index', { :object_fields => API::Entities::User.documentation }
36
- # get '/users' do
37
- # @users = User.all
38
- # type = current_user.admin? ? :full : :default
39
- # present @users, :with => API::Entities::User, :type => type
40
- # end
41
- # end
42
- # end
43
- class Entity
44
- attr_reader :object, :options
45
-
46
- # The Entity DSL allows you to mix entity functionality into
47
- # your existing classes.
48
- module DSL
49
- def self.included(base)
50
- base.extend ClassMethods
51
- ancestor_entity_class = base.ancestors.detect{|a| a.entity_class if a.respond_to?(:entity_class)}
52
- base.const_set(:Entity, Class.new(ancestor_entity_class || Grape::Entity)) unless const_defined?(:Entity)
53
- end
54
-
55
- module ClassMethods
56
- # Returns the automatically-created entity class for this
57
- # Class.
58
- def entity_class(search_ancestors=true)
59
- klass = const_get(:Entity) if const_defined?(:Entity)
60
- klass ||= ancestors.detect{|a| a.entity_class(false) if a.respond_to?(:entity_class) } if search_ancestors
61
- klass
62
- end
63
-
64
- # Call this to make exposures to the entity for this Class.
65
- # Can be called with symbols for the attributes to expose,
66
- # a block that yields the full Entity DSL (See Grape::Entity),
67
- # or both.
68
- #
69
- # @example Symbols only.
70
- #
71
- # class User
72
- # include Grape::Entity::DSL
73
- #
74
- # entity :name, :email
75
- # end
76
- #
77
- # @example Mixed.
78
- #
79
- # class User
80
- # include Grape::Entity::DSL
81
- #
82
- # entity :name, :email do
83
- # expose :latest_status, using: Status::Entity, if: :include_status
84
- # expose :new_attribute, :if => {:version => 'v2'}
85
- # end
86
- # end
87
- def entity(*exposures, &block)
88
- entity_class.expose *exposures if exposures.any?
89
- entity_class.class_eval(&block) if block_given?
90
- entity_class
91
- end
92
- end
93
-
94
- # Instantiates an entity version of this object.
95
- def entity
96
- self.class.entity_class.new(self)
97
- end
98
- end
99
-
100
- # This method is the primary means by which you will declare what attributes
101
- # should be exposed by the entity.
102
- #
103
- # @option options :as Declare an alias for the representation of this attribute.
104
- # @option options :if When passed a Hash, the attribute will only be exposed if the
105
- # runtime options match all the conditions passed in. When passed a lambda, the
106
- # lambda will execute with two arguments: the object being represented and the
107
- # options passed into the representation call. Return true if you want the attribute
108
- # to be exposed.
109
- # @option options :unless When passed a Hash, the attribute will be exposed if the
110
- # runtime options fail to match any of the conditions passed in. If passed a lambda,
111
- # it will yield the object being represented and the options passed to the
112
- # representation call. Return true to prevent exposure, false to allow it.
113
- # @option options :using This option allows you to map an attribute to another Grape
114
- # Entity. Pass it a Grape::Entity class and the attribute in question will
115
- # automatically be transformed into a representation that will receive the same
116
- # options as the parent entity when called. Note that arrays are fine here and
117
- # will automatically be detected and handled appropriately.
118
- # @option options :proc If you pass a Proc into this option, it will
119
- # be used directly to determine the value for that attribute. It
120
- # will be called with the represented object as well as the
121
- # runtime options that were passed in. You can also just supply a
122
- # block to the expose call to achieve the same effect.
123
- # @option options :documentation Define documenation for an exposed
124
- # field, typically the value is a hash with two fields, type and desc.
125
- def self.expose(*args, &block)
126
- options = args.last.is_a?(Hash) ? args.pop : {}
127
-
128
- if args.size > 1
129
- raise ArgumentError, "You may not use the :as option on multi-attribute exposures." if options[:as]
130
- raise ArgumentError, "You may not use block-setting on multi-attribute exposures." if block_given?
131
- end
132
-
133
- raise ArgumentError, "You may not use block-setting when also using format_with" if block_given? && options[:format_with].respond_to?(:call)
134
-
135
- options[:proc] = block if block_given?
136
-
137
- args.each do |attribute|
138
- exposures[attribute.to_sym] = options
139
- end
140
- end
141
-
142
- # Returns a hash of exposures that have been declared for this Entity or ancestors. The keys
143
- # are symbolized references to methods on the containing object, the values are
144
- # the options that were passed into expose.
145
- def self.exposures
146
- @exposures ||= {}
147
-
148
- if superclass.respond_to? :exposures
149
- @exposures = superclass.exposures.merge(@exposures)
150
- end
151
-
152
- @exposures
153
- end
154
-
155
- # Returns a hash, the keys are symbolized references to fields in the entity,
156
- # the values are document keys in the entity's documentation key. When calling
157
- # #docmentation, any exposure without a documentation key will be ignored.
158
- def self.documentation
159
- @documentation ||= exposures.inject({}) do |memo, value|
160
- unless value[1][:documentation].nil? || value[1][:documentation].empty?
161
- memo[value[0]] = value[1][:documentation]
162
- end
163
- memo
164
- end
165
-
166
- if superclass.respond_to? :documentation
167
- @documentation = superclass.documentation.merge(@documentation)
168
- end
169
-
170
- @documentation
171
- end
172
-
173
- # This allows you to declare a Proc in which exposures can be formatted with.
174
- # It take a block with an arity of 1 which is passed as the value of the exposed attribute.
175
- #
176
- # @param name [Symbol] the name of the formatter
177
- # @param block [Proc] the block that will interpret the exposed attribute
178
- #
179
- #
180
- #
181
- # @example Formatter declaration
182
- #
183
- # module API
184
- # module Entities
185
- # class User < Grape::Entity
186
- # format_with :timestamp do |date|
187
- # date.strftime('%m/%d/%Y')
188
- # end
189
- #
190
- # expose :birthday, :last_signed_in, :format_with => :timestamp
191
- # end
192
- # end
193
- # end
194
- #
195
- # @example Formatters are available to all decendants
196
- #
197
- # Grape::Entity.format_with :timestamp do |date|
198
- # date.strftime('%m/%d/%Y')
199
- # end
200
- #
201
- def self.format_with(name, &block)
202
- raise ArgumentError, "You must pass a block for formatters" unless block_given?
203
- formatters[name.to_sym] = block
204
- end
205
-
206
- # Returns a hash of all formatters that are registered for this and it's ancestors.
207
- def self.formatters
208
- @formatters ||= {}
209
-
210
- if superclass.respond_to? :formatters
211
- @formatters = superclass.formatters.merge(@formatters)
212
- end
213
-
214
- @formatters
215
- end
216
-
217
- # This allows you to set a root element name for your representation.
218
- #
219
- # @param plural [String] the root key to use when representing
220
- # a collection of objects. If missing or nil, no root key will be used
221
- # when representing collections of objects.
222
- # @param singular [String] the root key to use when representing
223
- # a single object. If missing or nil, no root key will be used when
224
- # representing an individual object.
225
- #
226
- # @example Entity Definition
227
- #
228
- # module API
229
- # module Entities
230
- # class User < Grape::Entity
231
- # root 'users', 'user'
232
- # expose :id
233
- # end
234
- # end
235
- # end
236
- #
237
- # @example Usage in the API Layer
238
- #
239
- # module API
240
- # class Users < Grape::API
241
- # version 'v2'
242
- #
243
- # # this will render { "users": [ {"id":"1"}, {"id":"2"} ] }
244
- # get '/users' do
245
- # @users = User.all
246
- # present @users, :with => API::Entities::User
247
- # end
248
- #
249
- # # this will render { "user": {"id":"1"} }
250
- # get '/users/:id' do
251
- # @user = User.find(params[:id])
252
- # present @user, :with => API::Entities::User
253
- # end
254
- # end
255
- # end
256
- def self.root(plural, singular=nil)
257
- @collection_root = plural
258
- @root = singular
259
- end
260
-
261
- # This convenience method allows you to instantiate one or more entities by
262
- # passing either a singular or collection of objects. Each object will be
263
- # initialized with the same options. If an array of objects is passed in,
264
- # an array of entities will be returned. If a single object is passed in,
265
- # a single entity will be returned.
266
- #
267
- # @param objects [Object or Array] One or more objects to be represented.
268
- # @param options [Hash] Options that will be passed through to each entity
269
- # representation.
270
- #
271
- # @option options :root [String] override the default root name set for the
272
- #  entity. Pass nil or false to represent the object or objects with no
273
- # root name even if one is defined for the entity.
274
- def self.represent(objects, options = {})
275
- inner = if objects.respond_to?(:to_ary)
276
- objects.to_ary().map{|o| self.new(o, {:collection => true}.merge(options))}
277
- else
278
- self.new(objects, options)
279
- end
280
-
281
- root_element = if options.has_key?(:root)
282
- options[:root]
283
- else
284
- objects.respond_to?(:to_ary) ? @collection_root : @root
285
- end
286
- root_element ? { root_element => inner } : inner
287
- end
288
-
289
- def initialize(object, options = {})
290
- @object, @options = object, options
291
- end
292
-
293
- def exposures
294
- self.class.exposures
295
- end
296
-
297
- def documentation
298
- self.class.documentation
299
- end
300
-
301
- def formatters
302
- self.class.formatters
303
- end
304
-
305
- # The serializable hash is the Entity's primary output. It is the transformed
306
- # hash for the given data model and is used as the basis for serialization to
307
- # JSON and other formats.
308
- #
309
- # @param runtime_options [Hash] Any options you pass in here will be known to the entity
310
- # representation, this is where you can trigger things from conditional options
311
- # etc.
312
- def serializable_hash(runtime_options = {})
313
- return nil if object.nil?
314
- opts = options.merge(runtime_options || {})
315
- exposures.inject({}) do |output, (attribute, exposure_options)|
316
- if (exposure_options.has_key?(:proc) || object.respond_to?(attribute)) && conditions_met?(exposure_options, opts)
317
- partial_output = value_for(attribute, opts)
318
- output[key_for(attribute)] =
319
- if partial_output.respond_to? :serializable_hash
320
- partial_output.serializable_hash(runtime_options)
321
- elsif partial_output.kind_of?(Array) && !partial_output.map {|o| o.respond_to? :serializable_hash}.include?(false)
322
- partial_output.map {|o| o.serializable_hash}
323
- else
324
- partial_output
325
- end
326
- end
327
- output
328
- end
329
- end
330
-
331
- alias :as_json :serializable_hash
332
-
333
- def to_json(options = {})
334
- options = options.to_h if options && options.respond_to?(:to_h)
335
- MultiJson.dump(serializable_hash(options))
336
- end
337
-
338
- protected
339
-
340
- def key_for(attribute)
341
- exposures[attribute.to_sym][:as] || attribute.to_sym
342
- end
343
-
344
- def value_for(attribute, options = {})
345
- exposure_options = exposures[attribute.to_sym]
346
-
347
- if exposure_options[:proc]
348
- exposure_options[:proc].call(object, options)
349
- elsif exposure_options[:using]
350
- using_options = options.dup
351
- using_options.delete(:collection)
352
- using_options[:root] = nil
353
- exposure_options[:using].represent(object.send(attribute), using_options)
354
- elsif exposure_options[:format_with]
355
- format_with = exposure_options[:format_with]
356
-
357
- if format_with.is_a?(Symbol) && formatters[format_with]
358
- formatters[format_with].call(object.send(attribute))
359
- elsif format_with.is_a?(Symbol)
360
- self.send(format_with, object.send(attribute))
361
- elsif format_with.respond_to? :call
362
- format_with.call(object.send(attribute))
363
- end
364
- else
365
- object.send(attribute)
366
- end
367
- end
368
-
369
- def conditions_met?(exposure_options, options)
370
- if_condition = exposure_options[:if]
371
- unless_condition = exposure_options[:unless]
372
-
373
- case if_condition
374
- when Hash; if_condition.each_pair{|k,v| return false if options[k.to_sym] != v }
375
- when Proc; return false unless if_condition.call(object, options)
376
- end
377
-
378
- case unless_condition
379
- when Hash; unless_condition.each_pair{|k,v| return false if options[k.to_sym] == v}
380
- when Proc; return false if unless_condition.call(object, options)
381
- end
382
-
383
- true
384
- end
385
- end
386
- end