Skip to content

Commit 925087b

Browse files
author
Michael Bleigh
committed
Adds exposures that are block-driven.
1 parent d5a64fe commit 925087b

File tree

2 files changed

+41
-8
lines changed

2 files changed

+41
-8
lines changed

lib/grape/entity.rb

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ module Grape
1010
# module API
1111
# module Entities
1212
# class User < Grape::Endpoint
13-
# expose :name, :screen_name, :location
13+
# expose :first_name, :last_name, :screen_name, :location
1414
# expose :latest_status, :using => API::Status, :as => :status, :unless => {:collection => true}
1515
# expose :email, :if => {:type => :full}
1616
# expose :new_attribute, :if => {:version => 'v2'}
17+
# expose(:name){|model,options| [model.first_name, model.last_name].join(' ')}
1718
# end
1819
# end
1920
# end
@@ -57,13 +58,21 @@ class Entity
5758
# automatically be transformed into a representation that will receive the same
5859
# options as the parent entity when called. Note that arrays are fine here and
5960
# will automatically be detected and handled appropriately.
60-
def self.expose(*args)
61+
# @option options :proc If you pass a Proc into this option, it will
62+
# be used directly to determine the value for that attribute. It
63+
# will be called with the represented object as well as the
64+
# runtime options that were passed in. You can also just supply a
65+
# block to the expose call to achieve the same effect.
66+
def self.expose(*args, &block)
6167
options = args.last.is_a?(Hash) ? args.pop : {}
6268

63-
if options[:as] && args.size > 1
64-
raise ArgumentError, "You may not use the :as option on multi-attribute exposures."
69+
if args.size > 1
70+
raise ArgumentError, "You may not use the :as option on multi-attribute exposures." if options[:as]
71+
raise ArgumentError, "You may not use block-setting on multi-attribute exposures." if block_given?
6572
end
6673

74+
options[:proc] = block if block_given?
75+
6776
args.each do |attribute|
6877
exposures[attribute.to_sym] = options
6978
end
@@ -108,9 +117,10 @@ def exposures
108117
# @param options [Hash] Any options you pass in here will be known to the entity
109118
# representation, this is where you can trigger things from conditional options
110119
# etc.
111-
def serializable_hash(options = {})
120+
def serializable_hash(runtime_options = {})
121+
opts = options.merge(runtime_options)
112122
exposures.inject({}) do |output, (attribute, exposure_options)|
113-
output[key_for(attribute)] = value_for(attribute) if conditions_met?(exposure_options, options)
123+
output[key_for(attribute)] = value_for(attribute, opts) if conditions_met?(exposure_options, opts)
114124
output
115125
end
116126
end
@@ -123,10 +133,12 @@ def key_for(attribute)
123133
exposures[attribute.to_sym][:as] || attribute.to_sym
124134
end
125135

126-
def value_for(attribute)
136+
def value_for(attribute, options = {})
127137
exposure_options = exposures[attribute.to_sym]
128138

129-
if exposure_options[:using]
139+
if exposure_options[:proc]
140+
exposure_options[:proc].call(object, options)
141+
elsif exposure_options[:using]
130142
exposure_options[:using].represent(object.send(attribute))
131143
else
132144
object.send(attribute)

spec/grape/entity_spec.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,20 @@
2525
expect{ subject.expose :name, :as => :foo }.not_to raise_error
2626
end
2727
end
28+
29+
context 'with a block' do
30+
it 'should error out if called with multiple attributes' do
31+
expect{ subject.expose(:name, :email) do
32+
true
33+
end }.to raise_error(ArgumentError)
34+
end
35+
36+
it 'should set the :proc option in the exposure options' do
37+
block = lambda{|obj,opts| true }
38+
subject.expose :name, &block
39+
subject.exposures[:name][:proc].should == block
40+
end
41+
end
2842
end
2943

3044
describe '.represent' do
@@ -80,6 +94,9 @@
8094
fresh_class.class_eval do
8195
expose :name, :email
8296
expose :friends, :using => self
97+
expose :computed do |object, options|
98+
options[:awesome]
99+
end
83100
end
84101
end
85102

@@ -93,6 +110,10 @@
93110
rep.first.serializable_hash[:name].should == 'Friend 1'
94111
rep.last.serializable_hash[:name].should == 'Friend 2'
95112
end
113+
114+
it 'should call through to the proc if there is one' do
115+
subject.send(:value_for, :computed, :awesome => 123).should == 123
116+
end
96117
end
97118

98119
describe '#key_for' do

0 commit comments

Comments
 (0)