Skip to content

Instantly share code, notes, and snippets.

@joekhoobyar
Created March 13, 2014 19:13
Show Gist options
  • Save joekhoobyar/9534888 to your computer and use it in GitHub Desktop.
Save joekhoobyar/9534888 to your computer and use it in GitHub Desktop.
Dead simple model decorator base class
require 'delegate'
# A suitable base class for defining a model decorator that automatically defines a model_klass
# singleton method, on all subclasses, that returns the model's class.
#
# Caveat: Your subclass name *must* match the following template: <code>"#{model_klass.name}Decorator"</code>
#
# - Example 1: MyModelDecorator # will decorate MyModel
# - Example 2: MyNamespace::MyModelDecorator # will decorate MyNamespace::MyModel
#
class ModelDecorator < SimpleDelegator
# This is where the magic happens, albeit some very simple magic.
# Whenever a subclass is declared, a suitable implementation of model_klass is automatically defined on it.
def self.inherited(base)
decorator_name = base.name.try(:dup) or raise TypeError, "anonymous ModelDecorator classes are not supported"
decorator_name.sub!(/Decorator$/,'').present? or raise TypeError, "ModelDecorator subclass names must end with `Decorator'"
base.module_eval "def self.model_klass; ::#{decorator_name} ; end"
base.extend ClassMethods
end
module ClassMethods
delegate :send, :public_send, :model_name, to: :model_klass
def respond_to_missing?(symbol, include_private=false)
model_klass.respond_to? symbol, include_private
end
alias_method :method_missing, :public_send
private :method_missing
end
# :nodoc:
def self.model_klass
raise NotImplementedError, "subclasses must implement `model_klass`\n\nDid you, perhaps, redefine `model_klass' to call super?"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment