Skip to content

Commit

Permalink
Adds Entity DSL.
Browse files Browse the repository at this point in the history
  • Loading branch information
mbleigh committed Aug 28, 2012
1 parent 3641744 commit 7166363
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 0 deletions.
21 changes: 21 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,27 @@ module API
end
```

#### Using the Exposure DSL

Grape ships with a DSL to easily define entities within the context
of an existing class:

```ruby
class User
include Grape::Entity::DSL

entity :name, :email do
expose :advanced, if: :conditional
end
end
```

The above will automatically create a `User::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.

### Using Entities

Once an entity is defined, it can be used within endpoints, by calling #present. The #present
Expand Down
54 changes: 54 additions & 0 deletions lib/grape/entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,60 @@ module Grape
class Entity
attr_reader :object, :options

# The Entity DSL allows you to mix entity functionality into
# your existing classes.
module DSL
def self.included(base)
base.extend ClassMethods
ancestor_entity_class = base.ancestors.detect{|a| a.entity_class if a.respond_to?(:entity_class)}
const_set(:Entity, Class.new(ancestor_entity_class || Grape::Entity)) unless const_defined?(:Entity)
end

module ClassMethods
# Returns the automatically-created entity class for this
# Class.
def entity_class(search_ancestors=true)
klass = const_get(:Entity) if const_defined?(:Entity)
klass ||= ancestors.detect{|a| a.entity_class(false) if a.respond_to?(:entity_class) } if search_ancestors
klass
end

# Call this to make exposures to the entity for this Class.
# Can be called with symbols for the attributes to expose,
# a block that yields the full Entity DSL (See Grape::Entity),
# or both.
#
# @example Symbols only.
#
# class User
# include Grape::Entity::DSL
#
# entity :name, :email
# end
#
# @example Mixed.
#
# class User
# include Grape::Entity::DSL
#
# entity :name, :email do
# expose :latest_status, using: Status::Entity, if: :include_status
# expose :new_attribute, :if => {:version => 'v2'}
# end
# end
def entity(*exposures, &block)
entity_class.expose *exposures if exposures.any?
entity_class.class_eval(&block) if block_given?
entity_class
end
end

# Instantiates an entity version of this object.
def entity
self.class.entity_class.new(self)
end
end

# This method is the primary means by which you will declare what attributes
# should be exposed by the entity.
#
Expand Down
48 changes: 48 additions & 0 deletions spec/grape/entity_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -478,5 +478,53 @@ class FriendEntity < Grape::Entity
subject.send(:conditions_met?, exposure_options, :true => true).should be_false
end
end

describe "::DSL" do
subject{ Class.new }

it 'should create an Entity class when called' do
subject.should_not be_const_defined(:Entity)
subject.send(:include, Grape::Entity::DSL)
subject.should be_const_defined(:Entity)
end

context 'pre-mixed' do
before{ subject.send(:include, Grape::Entity::DSL) }

it 'should be able to define entity traits through DSL' do
subject.entity do
expose :name
end

subject.entity_class.exposures.should_not be_empty
end

it 'should be able to expose straight from the class' do
subject.entity :name, :email
subject.entity_class.exposures.size.should == 2
end

it 'should be able to mix field and advanced exposures' do
subject.entity :name, :email do
expose :third
end
subject.entity_class.exposures.size.should == 3
end

context 'instance' do
let(:instance){ subject.new }

describe '#entity' do
it 'should be an instance of the entity class' do
instance.entity.should be_kind_of(subject.entity_class)
end

it 'should have an object of itself' do
instance.entity.object.should == instance
end
end
end
end
end
end
end

0 comments on commit 7166363

Please sign in to comment.