Presentability module
Extended With |
|
Facade-based presenter toolkit with minimal assumptions.
Basic Usage
Basic usage of Presentability
requires two steps: declaring presenters and then using them.
Declaring Presenters
Presenters are just regular Ruby classes with some convenience methods for declaring exposures, but in a lot of cases you’ll want to declare them all in one place. Presentability
offers a mixin that implements a simple DSL for declaring presenters and their associations to entity classes, intended to be used in a container module:
require 'presentability' module Acme::Presenters extend Presentability presenter_for( Acme::Widget ) do expose :sku expose :name expose :unit_price end end
The block of presenter_for
is evaluated in the context of a new Presenter
class, so refer to that documentation for what’s possible there.
Sometimes you can’t (or don’t want to) have to load the entity class to declare a presenter for it, so you can also declare it using the class’s name:
presenter_for( 'Acme::Widget' ) do expose :sku expose :name expose :unit_price end
Using Presenters
You use presenters by instantiating them with the object they are a facade for (the “subject”), and then applying it:
acme_widget = Acme::Widget.new( sku: "FF-2237H455", name: "Throbbing Frobnulator", unit_price: 299, inventory_count: 301, wholesale_cost: 39 ) presentation = Acme::Presenters.present( acme_widget ) # => { :sku => "FF-2237H455", :name => "Throbbing Frobnulator", :unit_price => 299 }
If you want to present a collection of objects as a collection, you can apply presenters to the collection instead:
widgets_in_stock = Acme::Widget.where { inventory_count > 0 } collection_presentation = Acme::Presenters.present_collection( widgets_in_stock ) # => [ {:sku => "FF-2237H455", [...]}, {:sku => "FF-2237H460", [...]}, [...] ]
The collection can be anything that is Enumerable
.
Presentation Options
Sometimes you want a bit more flexibility in what you present, allowing a single uniform presenter to be used in multiple use cases. To facilitate this, you can pass an options keyword hash to #present
:
presenter_for( 'Acme::Widget' ) do expose :sku expose :name expose :unit_price # Only expose the wholesale cost if presented via an internal API expose :wholesale_cost, if: :internal_api end acme_widget = Acme::Widget.new( sku: "FF-2237H455", name: "Throbbing Frobnulator", unit_price: 299, inventory_count: 301, wholesale_cost: 39 ) # External API remains unchanged: presentation = Acme::Presenters.present( acme_widget ) # => { :sku => "FF-2237H455", :name => "Throbbing Frobnulator", :unit_price => 299 } # But when run from an internal service: internal_presentation = Acme::Presenters.present( acme_widget, internal_api: true ) # => { :sku => "FF-2237H455", :name => "Throbbing Frobnulator", :unit_price => 299, # :wholesale_cost => 39 }
There are some options that are set for you:
- Set if the current object is being presented as part of a collection.
:in_collection
Constants
- VERSION
Package version
Public Class Methods
Extension hook – decorate the including mod
.
Public Instance Methods
Return a representation of the object
by applying a declared presentation.
Return an Array of all representations of the members of the collection
by applying a declared presentation.
Set up a presentation for the given entity_class
.
Serialize the specified object
if a serializer has been declared for it and return the scalar result.
Default serializer for an Array; returns a new array of presented objects.
Default serializer for a Hash; returns a new Hash of presented keys and values.
Set up a rule for how to serialize objects of the given type
if there is no presenter declared for it.
Protected Instance Methods
Return a representation of the object
by applying a presenter declared for its class. Returns nil
if no such presenter exists.
Return a representation of the object
by applying a presenter declared for its class name. Returns nil
if no such presenter exists.