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
   endYou 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
   endYou'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
   endWhich 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
   endBoth 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
   endInternally 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
   endWhich can be used for duck-typing and to promote DRYness:
   UserPresenter.new(User.first).to_hash
   UserPresenter.new(Customer.first).to_hash