Module: Invoicing::ClassInfo
- Defined in:
- lib/invoicing/class_info.rb
Overview
This module is intended for use only internally within this framework. It implements a pattern needed in several other modules: an acts_as_something_or_other
method can be called within the scope of an ActiveRecord
class, given a number of arguments; including options which define how columns are renamed in a given model object. The information from these arguments needs to be stored in a class variable for later use in instances of that class. It must be possible to call the acts_as_
method multiple times, combining the arguments from the various calls, to make the whole thing look nicely declarative. Subclasses should inherit acts_as_
arguments from their superclass, but should be able to override them with their own values.
This pattern assumes a particular module structure, like the following:
module MyNamespace # you may use arbitrarily nested modules for namespacing (optional)
module Teleporter # the name of this module defines auto-generated method names
module ActMethods
def acts_as_teleporter(*args) # should be called "acts_as_#{module_name.underscore}"
Invoicing::ClassInfo.acts_as(MyNamespace::Teleporter, self, args)
end
end
def transmogrify_the_instance # will become an instance method of the class on which the
info = teleporter_class_info # acts_as_ method is called.
info.do_transmogrify
end
module ClassMethods
def transmogrify_the_class # will become a class method of the class on which the
info = teleporter_class_info # acts_as_ method is called.
info.do_transmogrify
end
end
class ClassInfo < Invoicing::ClassInfo::Base
def do_transmogrify
case [:transmogrification]
when :total then "Transmogrified by #{all_args.first}"
end
end
end
end
end
ActiveRecord::Base.send(:extend, MyNamespace::Teleporter::ActMethods)
ClassInfo
is used to store and process the arguments passed to the acts_as_teleporter
method when it is called in the scope of an ActiveRecord
model class. Finally, the feature defined by the Teleporter
module above can be used like this:
class Teleporter < ActiveRecord::Base
acts_as_teleporter 'Zoom2020', :transmogrification => :total
end
Teleporter.transmogrify_the_class # both return "Transmogrified by Zoom2020"
Teleporter.find(42).transmogrify_the_instance
Defined Under Namespace
Classes: Base
Class Method Summary collapse
-
.acts_as(source_module, calling_class, args) ⇒ Object
Provides the main implementation pattern for an
acts_as_
method.
Class Method Details
.acts_as(source_module, calling_class, args) ⇒ Object
Provides the main implementation pattern for an acts_as_
method. See the example above for usage.
source_module
-
The module object which is using the
ClassInfo
pattern calling_class
-
The class in whose scope the
acts_as_
method was called args
-
The array of arguments (including options hash) to the
acts_as_
method
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/invoicing/class_info.rb', line 64 def self.acts_as(source_module, calling_class, args) # The name by which the particular module using ClassInfo is known module_name = source_module.name.split('::').last.underscore class_info_method = "#{module_name}_class_info" previous_info = if calling_class.respond_to?(class_info_method, true) # acts_as has been called before on the same class, or a superclass calling_class.send(class_info_method) || calling_class.superclass.send(class_info_method) else # acts_as is being called for the first time -- do the mixins! calling_class.send(:include, source_module) nil # no previous_info end # Instantiate the ClassInfo::Base subclass and assign it to an instance variable in calling_class class_info_class = source_module.const_get('ClassInfo') class_info = class_info_class.new(calling_class, previous_info, args) calling_class.instance_variable_set("@#{class_info_method}", class_info) # Define a getter class method on calling_class through which the ClassInfo::Base # instance can be accessed. calling_class.class_eval " class << self\n def \#{class_info_method}\n if superclass.respond_to?(\"\#{class_info_method}\", true)\n @\#{class_info_method} ||= superclass.send(\"\#{class_info_method}\")\n end\n @\#{class_info_method}\n end\n private \"\#{class_info_method}\"\n end\n CLASSEVAL\n\n # For convenience, also define an instance method which does the same as the class method\n calling_class.class_eval do\n define_method class_info_method do\n self.class.send(class_info_method)\n end\n private class_info_method\n end\nend\n" |