module Cell module BaseMethods def self.included(base) base.extend ClassMethods ### DISCUSS: move that to Rails? base.class_attribute :default_template_format base.default_template_format = :html end module ClassMethods def render_cell_for(controller, name, state, opts={}) create_cell_for(controller, name, opts).render_state(state) # FIXME: don't let BaseMethods know about controller's API. end # Creates a cell instance of the class nameCell, passing through # opts. def create_cell_for(controller, name, opts={}) #class_from_cell_name(name).new(controller, opts) class_from_cell_name(name).new(controller, opts) end # Return the default view for the given state on this cell subclass. # This is a file with the name of the state under a directory with the # name of the cell followed by a template extension. def view_for_state(state) "#{cell_name}/#{state}" end # Find a possible template for a cell's current state. It tries to find a # template file with the name of the state under a subdirectory # with the name of the cell under the app/cells directory. # If this file cannot be found, it will try to call this method on # the superclass. This way you only have to write a state template # once when a more specific cell does not need to change anything in # that view. def find_class_view_for_state(state) return [view_for_state(state)] unless superclass.respond_to?(:find_class_view_for_state) superclass.find_class_view_for_state(state) << view_for_state(state) end # Get the name of this cell's class as an underscored string, # with _cell removed. # # Example: # UserCell.cell_name # => "user" def cell_name name.underscore.sub(/_cell$/, '') end def class_from_cell_name(cell_name) "#{cell_name}_cell".classify.constantize end end attr_accessor :controller attr_reader :state_name def initialize(options={}) #@controller = controller @opts = options end def cell_name self.class.cell_name end # Invoke the state method and render the given state. def render_state(state, controller=nil) @cell = self @state_name = state dispatch_state(state) end # Call the state method. def dispatch_state(state) send(state) end # Find possible files that belong to the state. This first tries the cell's # #view_for_state method and if that returns a true value, it # will accept that value as a string and interpret it as a pathname for # the view file. If it returns a falsy value, it will call the Cell's class # method find_class_view_for_state to determine the file to check. # # You can override the ::Cell::Base#view_for_state method for a particular # cell if you wish to make it decide dynamically what file to render. def possible_paths_for_state(state) self.class.find_class_view_for_state(state).reverse! end end end