class Rtml::Document < ActiveRecord::Base @@ruleset_file = File.expand_path(File.join(defined?(Rails) ? Rails.root : ".", "config/tml_dom_ruleset.rb")) @@ruleset_file = File.expand_path(File.join(Rtml.root, "rails_generators/rtml/templates/config/tml_dom_ruleset.rb")) unless File.file?(@@ruleset_file) include Rtml::DSL include Rtml::Widgets include ActionController::Layout layout :layout set_table_name 'rtml_documents' has_one :root, :class_name => 'Rtml::Dom::Element', :as => :parent, :autosave => true has_many :instructions, :class_name => 'Rtml::Instruction', :as => :source, :autosave => true attr_reader :rules, :controller delegate :render, :view_paths, :view_paths=, :to => :view delegate :request, :response, :params, :flash, :to => :controller validates_presence_of :name validates_uniqueness_of :name def initialize_with_default_document(attributes = nil) if attributes @controller = attributes.delete(:controller) @initialize_to_empty = attributes.delete(:empty) apply_document_options(attributes) end initialize_without_default_document(attributes) end include Rtml::InheritedInstanceVariables protected_instance_variables.concat ["@controller", "@changed_attributes", "@view", "@new_record", "@initialize_to_empty", "@widget_instances", "@rules", "@root", "@attributes_cache", "@attributes"] def after_initialize @rules = Rtml::Document.rules if new_record? && !@initialize_to_empty setup_default_document end end # This calls root.target, because root is technically an Association object, and target retrieves the actual object. # This resolves ambiguities such as root.build(), which exists as both an Association method (build a new root object) # and as a Widget method (build a new RTML Element). def root_with_target root_without_target.nil? ? nil : root_without_target.target end alias_method_chain :root, :target def layout(assignment = :_no_assignment) if assignment != :_no_assignment @layout_file = assignment else @layout_file end end def default_template_format :rtml end def cache(setting) case setting when :on, true, 'on', 'true', 'yes', 'allow', :yes, :allow setting = 'allow' when :off, false, 'off', 'false', 'no', 'deny', :no, :deny setting = 'deny' end root.property('cache', setting) end # Resets this document so that it contains no elements, and then follows the instructions associated with this # document. def follow_instructions! reset! instructions.each { |instruction| instruction.follow(self) } self end # Valid options include # :view_path => String # :view_paths => Array of Strings # and are removed from the hash as they are processed. # # Invalid options are dropped silently. # def apply_document_options(options) options.each do |key, value| case key.to_s when 'view_path', 'view_paths' options.delete key value = [value] unless value.kind_of?(Array) self.view_paths = value.collect { |path| File.exist?(path) ? path : File.join(Rails.root, path) } #else raise ArgumentError, "Key ungrecognized: #{key.inspect}" end end end alias_method_chain :initialize, :default_document def reset! #elements.destroy_all #self.elements = [] root.destroy if root self.root = nil setup_default_document self end def view return @view if @view @view = ActionView::Base.new(Rails.configuration.view_path, {}, @controller) @view.helpers.send :include, @controller.class.master_helper_module if @controller @view.template_format = 'rtml' @view end def /(name) if name == root.name then [root] else root / name end end def screens root ? root.elements.select { |ele| ele.name == 'screen' } : [] end def to_tml during_finalization_blocks.each { |i| self.process(&i) } ("\n" + (root ? root.to_tml : '')).gsub(/\t/, ' ') end # You can associate a block with this method, and the block will be called as a callback when self#to_tml # is called. def during_finalization(&block) during_finalization_blocks << block end class << self def ruleset_file @@ruleset_file end def rules Rtml::Rules::DomRuleset.parse(ruleset_file) end end private def during_finalization_blocks @during_finalization_blocks ||= [] end end