require 'facet/annotation' require 'glue/aspects' require 'glue/markup' require 'nitro' require 'nitro/render' require 'nitro/scaffolding' require 'nitro/caching' require 'nitro/flash' require 'nitro/helper' module Nitro # Include this Mixin to a class to make objects of this class # publishable, ie accessible through a standard web (REST) # interface. module Publishable def self.included(base) super base.module_eval do include Render include Glue::Aspects include Flashing include Helpers # Override this method as needed. Unless overriden # this method is initialized by the Dispatcher to # point to Template.root/path for each Controller. def self.template_root nil end private # Helper method. def template_root self.class.template_root end end # Aliases an action #-- # gmosx, FIXME: better implementation needed. # gmosx, FIXME: copy all annotations. #++ base.module_eval do def self.alias_action(new, old) alias_method new, old ann new, :view => old end end # Return the 'action' methods for this Controller. # Some dangerous methods from ancestors are removed. # All private methods are ignored. base.module_eval do def self.action_methods classes = self.ancestors.reject do |a| [Object, Kernel, Render, Controller, Caching].include?(a) end classes.delete(PP::ObjectMixin) if defined?(PP::ObjectMixin) methods = classes.inject([]) do |action_methods, klass| action_methods + klass.public_instance_methods(false) end # gmosx: add the default action (leave this?) # methods << 'index' return methods end end # Use the method_missing hook to compile the actions # for this controller. base.module_eval do def method_missing(action, *args) if Compiler.new(self.class).compile(action) send(action, *args) else super end end end # Does this publishable respond to the given action? base.module_eval do class << self def respond_to_action?(action) action_methods.include?(action.to_s) end alias_method :action?, :respond_to_action? end end # Does this class respond to the given action? # Also looks for templates in the template root. # # Prefer to use the compiler for this. #-- # THINK: maybe move template? here #++ base.module_eval do class << self def respond_to_action_or_template?(sym) return self.respond_to_action?(sym.to_s) || Compiler.new(self).template?(sym) end end end # Cookie helpers. #-- # TODO: move elsewhere. #++ base.module_eval do private def cookies @context.cookies end def send_cookie(name, value = nil) @context.add_cookie(name, value) end end end end # The Controller part in the MVC paradigm. The controller's # published methods are called actrions. The controller class # contains the Publishable mixin and additional helper mixins. class Controller include Publishable include Scaffolding include Caching include Helpers helper Markup # This callback is called after the Controller is mounted. def self.mounted(path) # Resolve aspects. Aspects.include_advice_modules(self) # The scaffolding code is compiled after the mount, so # that template roots are finalized. compile_scaffolding_code end end end # * George Moschovitis