Skip to content

Commit

Permalink
Added support for specifying the presenter class in using: in string …
Browse files Browse the repository at this point in the history
…format.
  • Loading branch information
larryzhao authored and dblock committed Jan 13, 2014
1 parent dacc671 commit 856c9d0
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Next Release
* [#33](https://github.com/intridea/grape-entity/pull/33): Support proper merging of nested conditionals - [@wyattisimo](https://github.com/wyattisimo).
* [#43](https://github.com/intridea/grape-entity/pull/43): Call procs in context of entity instance - [@joelvh](https://github.com/joelvh).
* [#47](https://github.com/intridea/grape-entity/pull/47): Support nested exposures - [@wyattisimo](https://github.com/wyattisimo).
* [#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).
* Your contribution here.

0.3.0 (2013-03-29)
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ Don't derive your model classes from `Grape::Entity`, expose them using a presen
expose :replies, using: API::Status, as: :replies
```

Presenter classes can also be specified in string format, which helps with circular dependencies.

```ruby
expose :replies, using: `API::Status`, as: :replies
```

#### Conditional Exposure

Use `:if` or `:unless` to expose fields conditionally.
Expand Down
1 change: 1 addition & 0 deletions lib/grape_entity.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
require "active_support/core_ext"
require "grape_entity/version"
require "grape_entity/entity"
2 changes: 2 additions & 0 deletions lib/grape_entity/entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@ def value_for(attribute, options = {})
nested_exposures = self.class.nested_exposures_for(attribute)

if exposure_options[:using]
exposure_options[:using] = exposure_options[:using].constantize if exposure_options[:using].respond_to? :constantize

using_options = options.dup
using_options.delete(:collection)
using_options[:root] = nil
Expand Down
56 changes: 43 additions & 13 deletions spec/grape_entity/entity_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ class BogusEntity < Grape::Entity
end

describe '.with_options' do
it 'should apply the options to all exposures inside' do
it 'applies the options to all exposures inside' do
subject.class_eval do
with_options(if: { awesome: true }) do
expose :awesome_thing, using: 'Awesome'
Expand All @@ -213,7 +213,7 @@ class BogusEntity < Grape::Entity
subject.exposures[:awesome_thing].should == { if: { awesome: true }, using: 'Awesome' }
end

it 'should allow for nested .with_options' do
it 'allows for nested .with_options' do
subject.class_eval do
with_options(if: { awesome: true }) do
with_options(using: 'Something') do
Expand All @@ -225,7 +225,7 @@ class BogusEntity < Grape::Entity
subject.exposures[:awesome_thing].should == { if: { awesome: true }, using: 'Something' }
end

it 'should override nested :as option' do
it 'overrides nested :as option' do
subject.class_eval do
with_options(as: :sweet) do
expose :awesome_thing, as: :extra_smooth
Expand All @@ -235,7 +235,7 @@ class BogusEntity < Grape::Entity
subject.exposures[:awesome_thing].should == { as: :extra_smooth }
end

it "should merge nested :if option" do
it "merges nested :if option" do
match_proc = lambda { |obj, opts| true }

subject.class_eval do
Expand All @@ -260,7 +260,7 @@ class BogusEntity < Grape::Entity
}
end

it 'should merge nested :unless option' do
it 'merges nested :unless option' do
match_proc = lambda { |obj, opts| true }

subject.class_eval do
Expand All @@ -285,7 +285,7 @@ class BogusEntity < Grape::Entity
}
end

it 'should override nested :using option' do
it 'overrides nested :using option' do
subject.class_eval do
with_options(using: 'Something') do
expose :awesome_thing, using: 'SomethingElse'
Expand All @@ -295,7 +295,7 @@ class BogusEntity < Grape::Entity
subject.exposures[:awesome_thing].should == { using: 'SomethingElse' }
end

it 'should override nested :proc option' do
it 'overrides nested :proc option' do
match_proc = lambda { |obj, opts| 'more awesomer' }

subject.class_eval do
Expand All @@ -307,7 +307,7 @@ class BogusEntity < Grape::Entity
subject.exposures[:awesome_thing].should == { proc: match_proc }
end

it 'should override nested :documentation option' do
it 'overrides nested :documentation option' do
subject.class_eval do
with_options(documentation: { desc: 'Description.' }) do
expose :awesome_thing, documentation: { desc: 'Other description.' }
Expand Down Expand Up @@ -517,7 +517,7 @@ class BogusEntity < Grape::Entity
end

context "without safe option" do
it 'should throw an exception when an attribute is not found on the object' do
it 'throws an exception when an attribute is not found on the object' do
fresh_class.expose :name, :nonexistent_attribute
expect { fresh_class.new(model).serializable_hash }.to raise_error
end
Expand Down Expand Up @@ -651,7 +651,6 @@ def timestamp(date)

context 'child representations' do
it 'disables root key name for child representations' do

module EntitySpec
class FriendEntity < Grape::Entity
root 'friends', 'friend'
Expand Down Expand Up @@ -690,6 +689,7 @@ class FriendEntity < Grape::Entity
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
Expand All @@ -708,6 +708,7 @@ class FriendEntity < Grape::Entity
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
Expand Down Expand Up @@ -772,7 +773,6 @@ class FriendEntity < Grape::Entity
rep.first.serializable_hash[:email].should == '[email protected]'
rep.last.serializable_hash[:email].should == '[email protected]'
end

end

it 'calls through to the proc if there is one' do
Expand Down Expand Up @@ -807,6 +807,37 @@ def name
rep.send(:value_for, :name).should == "cooler name"
rep.send(:value_for, :email).should == "[email protected]"
end

context "using" do
before do
module EntitySpec
class UserEntity < Grape::Entity
expose :name, :email
end
end
end
it "string" do
fresh_class.class_eval do
expose :friends, using: "EntitySpec::UserEntity"
end

rep = subject.send(:value_for, :friends)
rep.should be_kind_of Array
rep.size.should == 2
rep.all? { |r| r.is_a?(EntitySpec::UserEntity) }.should be_true
end

it 'class' do
fresh_class.class_eval do
expose :friends, using: EntitySpec::UserEntity
end

rep = subject.send(:value_for, :friends)
rep.should be_kind_of Array
rep.size.should == 2
rep.all? { |r| r.is_a?(EntitySpec::UserEntity) }.should be_true
end
end
end

describe '#documentation' do
Expand Down Expand Up @@ -951,13 +982,12 @@ def name
instance.entity.object.should == instance
end

it 'should instantiate with options if provided' do
it 'instantiates with options if provided' do
instance.entity(awesome: true).options.should == { awesome: true }
end
end
end
end
end

end
end

0 comments on commit 856c9d0

Please sign in to comment.