Module: Decor
- Defined in:
- lib/decor.rb
Overview
Decor provides a simple way to define multiple representations of an object.
This is useful for when you want to retain multiple versions of your objects while providing a consistent interface between versions.
For example:
class Company < ActiveRecord::Base
include Decor
# the first version, customers are dependent on certain artifacts
# like industry_id and industry
version "v1" do
INDUSTRIES = {1 => "Farm",
2 => "Software"}
def industry
INDUSTRIES[industry_id]
end
def as_json(*_)
super(:only => [:id, :name, :industry_id],
:methods => [:industry])
end
end
# switch to using industry standard codes, cleans up the name
version "v2" do
SIC_CODES = {...}
# use the cleaned name for the name instead
def name
name_cleaned
end
def industry
SIC_DOES[sic_code]
end
def as_json(*_)
super(:only => [:id, :name, :sic_code],
:methods => [:industry])
end
end
end
In our API, for instance, we can then define a single endpoint for both versions:
get "/api/:version/companies/:id.json" do
Company.find(params[:id]).for(version).to_json
end
This helps us keep our models fat and our “controllers” skinny. This also helps unit testing the versions of your API.
Further details can be found on [Github](github.com/mtodd/decor/).
Defined Under Namespace
Modules: ClassMethods Classes: Base
Class Method Summary collapse
-
.included(target) ⇒ Object
Decor is a mixin.
Instance Method Summary collapse
-
#for(version, options = {}) ⇒ Object
An object will be told to behave like the version specified.
-
#version_module_for(version, options = {}) ⇒ Object
Handles finding the module defined for the ‘version` specified, or overriding with the `:module` option.
Class Method Details
.included(target) ⇒ Object
Decor is a mixin. Include it into your class and then use the ‘version` class methods in the class body to define your versions, then use the `for` instance method on your objects to use a specific version.
For example:
class Model
include Decor
version "v1" do
# implement specifics for this version here
end
end
model = Model.new.for("v1")
78 79 80 81 82 |
# File 'lib/decor.rb', line 78 def self.included(target) target.send(:extend, ClassMethods) class << target; attr_accessor :versions; end target.versions = {} end |
Instance Method Details
#for(version, options = {}) ⇒ Object
An object will be told to behave like the version specified.
Options provide additional values in the context of the verions.
class Model
include Decor
version "v1" do
def versioned?
true
end
end
def versioned?
false
end
end
model = Model.new
model. versioned? #=> false
model.for("v1").versioned? #=> true
An optional context can be supplied which will make external resources available for specific functions in your versions. For example:
class User
include Decor
version "v1" do
def display_name
"%s (%s)" % [name, band.display_name]
end
end
end
user = User.find(id).for("v1", :band => external_band)
user.display_name #=> "Dan Auerbach (The Black Keys)"
Lastly, it’s possible to pass in a ‘:module` option which will override the module already defined for the version specified (making the `version` passed in almost meaningless).
module Specialized
# special considerations here
end
Model.new.for("v1", :module => Specialized)
201 202 203 204 205 206 |
# File 'lib/decor.rb', line 201 def for(version, = {}) version_module = self.version_module_for(version, ) decorator = Class.new(Base).new(self, version, ) decorator.send(:extend, version_module) decorator end |
#version_module_for(version, options = {}) ⇒ Object
Handles finding the module defined for the ‘version` specified, or overriding with the `:module` option.
See ‘for` for details.
213 214 215 216 217 |
# File 'lib/decor.rb', line 213 def version_module_for(version, = {}) return .delete(:module) if .key?(:module) return self.class.versions[version] if self.class.versions.key?(version) self.class.const_get(version.upcase) end |