Skip to content

whoward/depict

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Description

Depict is a presentation library for Ruby which will let you define multiple presentations for any Ruby class using a (hopefully) pleasant DSL. It also includes the vital missing component from other presentation libraries which will be instantiating a new instance of a class from a presentation you specify - a common use case for this would be, for example, having multiple presentations of an object to support aging versions of a Web API.

DSL

This will be how you define a presentation inline in your class:

   class User
      include Depict
      
      # presentation for unprivileged users
      define_presentation :user do
         maps :id
         maps :email
      end
      
      # presentation for superusers
      define_presentation :admin, :extends => :user do
         maps :role
      end
   end

You will also be able to define presentations outside of your class if you want to break it up over several files

   class User
      include Depict
   end
   
   User.define_presentation :user do
      maps :id
      maps :email
   end
   
   User.define_presentation :admin, :extends => :user do
      maps :role
   end

You'll be able to convert into a presentation using a standard parameterized method

   >> person = User.new(:id => 1, :email => "foo@example.com", :role => "user")
   => #<User:0xb73df4c0>
   >> person.to_presentation(:user)
   => {:id => 1, :email => "foo@example.com"}
   >> person.to_presentation(:admin)
   => {:id => 1, :email => "foo@example.com", :role => "user"}

There will also be some method_missing magic

   >> person = User.new(:id => 1, :email => "foo@example.com", :role => "user")
   => #<User:0xb73df4c0>
   >> person.to_user_presentation
   => {:id => 1, :email => "foo@example.com"}   

And you will be able to construct new objects from a given presentation

   >> person = User.new_from_presentation(:user, {:email => "foo@example.com"})
   => #<User:0xb73df4c0>
   >> person.id
   => nil
   >> person.email
   => "foo@example.com"

Which also has some method_missing magic

   >> person = User.new_from_user_presentation(:email => "foo@example.com")
   => #<User:0xb73df4c0>
   >> person.id
   => nil
   >> person.email
   => "foo@example.com"

And will inherently give you some help with against mass assignment protection

  >> User.new_from_user_presentation(:role => "admin").role
  => nil
  >> User.new_from_admin_presentation(:role => "admin").role
  => "admin"

Back to the DSL - you'll be able to specify your own custom serializers, so the mapped value is more appropriate

   class User
      include Depict
      
      # UNIX timestamp representations for javascript friendly presentations
      define_presentation :javascript do
         maps :created_at, :serializes_with => lambda { |x| x.utc.to_i * 1000 }
      end
      
      # ISO 8601 formatted timestamps for XML friendly presentations
      define_presentation :xml do
         maps :created_at, :serializes_with => lambda { |x| x.strftime('%Y-%m-%dT%H:%M:%S%z') }
      end
   end

Which has deserializer counterparts as well

   class User
      include Depict
      
      # UNIX timestamp representations for javascript friendly presentations
      define_presentation :javascript do
         maps :created_at, :serializes_with => lambda { |x| x.utc.to_i * 1000 },
                           :deserializes_with => lambda { |x| Time.at((x / 1000).to_i).utc }
      end
      
      # ISO 8601 formatted timestamps for XML friendly presentations
      define_presentation :xml do
         maps :created_at, :serializes_with => lambda { |x| x.strftime('%Y-%m-%dT%H:%M:%S%z') },
                           :deserializes_with => lambda { |x| Date.iso8601(x) }
      end
   end

Both of which will be able to be DRYed up with a serializer/deserializer class of some kind

   class UnixTimestampConverter
      def serialize(value)
         value.utc.to_i * 1000
      end
      def deserialize(value)
         Time.at((value / 1000).to_i).utc
      end
   end
   
   class IsoTimestampConverter
      def serialize(value)
         value.strftime('%Y-%m%dT%H:%M:%S%z')
      end
      def deserialize(value)
         Date.iso8601(value)
      end
   end

   class User
      include Depict
      
      # UNIX timestamp representations for javascript friendly presentations
      define_presentation :javascript do
         maps :created_at, :with => UnixTimestampConverter.new
      end
      
      # ISO 8601 formatted timestamps for XML friendly presentations
      define_presentation :xml do
         maps :created_at, :with => IsoTimestampConverter.new
      end
   end

Internally all of this syntactic sugar is managed by the Depict::Presenter class which can be used without associating it directly with any model:

   UserPresenter = Depict::Presenter.define do
      maps :id
      maps :name
      maps :role
   end

Which can be used for duck-typing and to promote DRYness:

   UserPresenter.new(User.first).to_hash
   UserPresenter.new(Customer.first).to_hash

About

Object presentation library for ruby with bidirectional transformations and definitions by DSL or wrapper classes

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages