Skip to content

Add expose SYMBOL, HASH BLOCK #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 8, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions CHANGELOG.markdown
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
Next Release
============
* Your contribution here.
* Fixed bug with to_json.
* Add `:using` option to `expose SYMBOL BLOCK`

0.3.0 (2013-03-29)
==================
Expand Down
8 changes: 6 additions & 2 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ array.
* `expose SYMBOL, { :as => "alias" }`
* Expose a value, changing its hash key from SYMBOL to alias
* `:as` can only be applied to one exposure at a time
* `expose SYMBOL BLOCK`
* `expose SYMBOL, HASH BLOCK`
* HASH keys only can be `:using`
* block arguments are object and options
* expose the value returned by the block
* expose the value returned by the block (and present by `:using` option)
* block can only be applied to one exposure at a time
* `with_options HASH BLOCK`
* exposures defined within a `with_options` block will inherit any options defined in HASH. Same keys available as `expose SYMBOLS, HASH`
Expand All @@ -59,6 +60,9 @@ module API
expose :user_type, user_id, :if => lambda{ |status, options| status.user.public? }
expose :digest { |status, options| Digest::MD5.hexdigest(satus.txt) }
expose :replies, :using => API::Status, :as => :replies
expose :last_reply, :using => API::Status do |status, options|
status.replies.last
end

with_options { :format_with => :iso_timestamp } do
expose :created_at
Expand Down
9 changes: 8 additions & 1 deletion lib/grape_entity/entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,14 @@ def value_for(attribute, options = {})
exposure_options = exposures[attribute.to_sym]

if exposure_options[:proc]
exposure_options[:proc].call(object, options)
if exposure_options[:using]
using_options = options.dup
using_options.delete(:collection)
using_options[:root] = nil
exposure_options[:using].represent(exposure_options[:proc].call(object, options), using_options)
else
exposure_options[:proc].call(object, options)
end
elsif exposure_options[:using]
using_options = options.dup
using_options.delete(:collection)
Expand Down
74 changes: 72 additions & 2 deletions spec/grape_entity/entity_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@

it 'sets the :proc option in the exposure options' do
block = lambda{|_| true }
subject.expose :name, &block
subject.exposures[:name][:proc].should == block
subject.expose :name, :using => 'Awesome', &block
subject.exposures[:name].should == { :proc => block, :using => 'Awesome' }
end
end

Expand Down Expand Up @@ -341,6 +341,19 @@
res.should have_key :nonexistent_attribute
end

it "exposes attributes that don't exist on the object only when they are generated by a block with options" do
module EntitySpec
class TestEntity < Grape::Entity
end
end

fresh_class.expose :nonexistent_attribute, using: EntitySpec::TestEntity do |model, _|
"well, I do exist after all"
end
res = fresh_class.new(model).serializable_hash
res.should have_key :nonexistent_attribute
end

it "does not expose attributes that are generated by a block but have not passed criteria" do
fresh_class.expose :nonexistent_attribute, :proc => lambda {|model, _|
"I exist, but it is not yet my time to shine"
Expand Down Expand Up @@ -442,6 +455,63 @@ class FriendEntity < Grape::Entity
rep.last.serializable_hash[:name].should == 'Friend 2'
end

it "passes through the proc which returns an array of objects with custom options(:using)" do
module EntitySpec
class FriendEntity < Grape::Entity
root 'friends', 'friend'
expose :name, :email
end
end

fresh_class.class_eval do
expose :custom_friends, :using => EntitySpec::FriendEntity do |user, options|
user.friends
end
end

rep = subject.send(:value_for, :custom_friends)
rep.should be_kind_of Array
rep.reject{|r| r.is_a?(EntitySpec::FriendEntity)}.should be_empty
rep.first.serializable_hash.should == { :name => 'Friend 1', :email => '[email protected]'}
rep.last.serializable_hash.should == { :name => 'Friend 2', :email => '[email protected]'}
end
it "passes through the proc which returns single object with custom options(:using)" do
module EntitySpec
class FriendEntity < Grape::Entity
root 'friends', 'friend'
expose :name, :email
end
end

fresh_class.class_eval do
expose :first_friend, :using => EntitySpec::FriendEntity do |user, options|
user.friends.first
end
end

rep = subject.send(:value_for, :first_friend)
rep.should be_kind_of EntitySpec::FriendEntity
rep.serializable_hash.should == { :name => 'Friend 1', :email => '[email protected]'}
end
it "passes through the proc which returns empty with custom options(:using)" do
module EntitySpec
class FriendEntity < Grape::Entity
root 'friends', 'friend'
expose :name, :email
end
end

fresh_class.class_eval do
expose :first_friend, :using => EntitySpec::FriendEntity do |user, options|

end
end

rep = subject.send(:value_for, :first_friend)
rep.should be_kind_of EntitySpec::FriendEntity
rep.serializable_hash.should be_nil
end

it 'passes through custom options' do
module EntitySpec
class FriendEntity < Grape::Entity
Expand Down