#-- # Copyright (c) 2006 Jeff Barczewski and Deborah Lewis # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ # # == MasterView Configuration and Initialization # # The MasterView template engine supports a number of configuration settings # which allow a client to easily customize its operation. # # A MasterView::Configuration specification is used to allow the application to # specify custom configuration options during application startup. The configuration options # are installed in MasterView when its Initializer is run, which handles # loading and configuring MasterView for operation. # #-- # This style of configuration specification + initializer follows the technique # used by Rails itself. A configuration specification can be customized by the # application in its startup and is used by the Initialzer to configure # the MasterView template engine implementation at load time. # [D. Lewis 31-May-2006] #++ # #-- # todo - change configuration to accomodate non-file based storage, use MIOTree objects # [JJB 13-Jun-2006] #++ # module MasterView # A Configuration holds all the configuration settings used the # MasterView::Initializer to configure the template engine. # # Configuration provides defaults that suit most Rails applications. # You can change the default settings in the configuration to customize # MasterView with options suitable for your application. # # In the most common usage pattern, a Configuration instance initialized # with the standard default settings is created implicitly when the # Initializer is run, which happens automatically # when Masterview is installed as a plugin in a Rails application. # Application-specific settings are then loaded from the application's # +config+ directory and used by the Initializer to configure # the MasterView template engine for operation. # # When using MasterView in a standalone application (i.e., not within rails), # it is also possible to create the Configuration instance in advance and # pass it in explicitly to the Initializer. This technique can be useful # when it is necessary to establish the application root directory location # that MasterView uses during its operation or to specify to location of the # application's configuration files. # # require 'masterview/initializer' # config = MasterView::Configuration.new( :app_root_path => '/path/to/my/app' ) # config.template_src_dir_path = "masterview/templates" # config.template_dst_dir_path = "masterview/output" # #...set other config options... # MasterView::Initializer.run( :process, config ) # class Configuration # directory in which the MasterView plugin or gem is installed attr_reader :mv_installation_dir #:nodoc: # root directory of MasterView itself and the built-in directives # This is lib/masterview w/in the plugin or gem installation directory. attr_reader :mv_code_base_dir #:nodoc: # root directory when operating context is a rails app attr_reader :rails_root_path #:nodoc: # directory in a rails app for views (RAILS_ROOT/app/views) attr_reader :rails_views_dir_path #:nodoc: # RE spec for scripts which are used to launch rails attr_accessor :rails_runner_scripts_pattern #:nodoc: # is RAILS_ROOT defined? attr_reader :has_rails_context #:nodoc: # is the root a rails app? def rails_app? #:nodoc: @rails_root_path != nil end # Set to indicate that we're actually running the rails app (server or console...) attr_accessor :running_rails #:nodoc: # are we actually running rails when our root is a rails app? def on_rails? #:nodoc: @running_rails end # === General Options # Path to the root location for the application. # Used for resolving relative references. # # For a rails application, this is +RAILS_ROOT+. # attr_accessor :root_path # Path to the directory containing the application's MasterView # configuration settings files (if any). If no configuration # directory or settings files are defined, MasterView runs # with the standard default configuration options. # # Specified as a relative path from the application's +root_path+. # # Default: for a Rails application, this is RAILS_ROOT/config/masterview. # attr_accessor :config_dir_path # Specify the directory where masterview templates are located # as a relative path from the application's +root_path+. def config_dir_path= rel_path #:nodoc: # bolts down abs path, thanks to our firm roots @config_dir_path = rel_path.nil? ? nil : ( rel_path.empty? ? root_path : File.join( root_path, rel_path )) end # The current execution environment, if applicable # (e.g., 'development', 'test', 'production'). # # Used for loading application settings from config directory, if available. # # For a Rails application, this is +RAILS_ENV+. # attr_accessor :environment # Paths of directories to load directives from. # # The directory containing the built-in MasterView directives # is installed by default. If the application provides # a masterview/directives directory in its +root_path+, # that directory is also automatically added to the directives # load path. # # Append additional path(s) to load custom directives from specific # locations. attr_accessor :directive_paths # Relative path from +root_path+ of the temp directory used for creating # backup files before rebuilding/updating a template file. # # Set to nil to suppress backups. # # Default: RAILS_ROOT/tmp/masterview/rebuild/backups #-- # ISSUE: change this to use IOMgr mapping, how best to do this config?? # Leave existing mechanism here, but drop out of documentation and examples # until resolved #++ attr_accessor :rebuild_backups_tmp_dir_path #:nodoc: # Logger which will be used to record debug, warning, and error messages. # # Supported loggers: # 'log4r' - the Log4r logging library # 'logger' - Logger in the ruby standard class library # # Default: uses Log4r if available, otherwise a standard ruby +Logger+. attr_accessor :logger # Logging severity threshold for the logger. # # Specify the name of the logging level to use with the configured logger. # Standard logging levels in both Log4r and ruby Logger are # +DEBUG+, +INFO+, +WARN+, +ERROR+, +FATAL+. # Other level names depend on the configured logger. # # Default: +INFO+ for development, +WARN+ otherwise attr_accessor :log_level # Sets a block which will be executed after MasterView has been fully initialized. # Useful for per-environment configuration which depends on the plugin being # fully initialized. def after_initialize(&after_initialize_block) @after_initialize_block = after_initialize_block end # Returns the block set in Configuration#after_initialize def after_initialize_block @after_initialize_block end # === Template Source Options # Path to the directory where masterview templates are located. # # Assign the value as a relative path from the application's +root_path+ # or use the +template_src_dir_abs_path+ method to specify an absolute path. # # Default: RAILS_ROOT/app/views for a rails application # or {root_path}/masterview/templates for a non-rails application. attr_accessor :template_src_dir_path # Specify the directory where masterview templates are located # as a relative path from the application's +root_path+. def template_src_dir_path= rel_path #:nodoc: # bolts down abs path, thanks to our firm roots @template_src_dir_path = rel_path.nil? ? nil : ( rel_path.empty? ? root_path : File.join( root_path, rel_path )) end # Specify the absolute path to the directory where masterview templates are located. def template_src_dir_abs_path(abs_path) @template_src_dir_path = abs_path end # Filename pattern for masterview template files # within the template source directory. # # Default: '*.html' attr_accessor :template_filename_pattern # === Template Generation Options # Path to the directory where Masterview template output (rhtml) # will be generated. # # Assign the value as a relative path from the application's +root_path+ # or use the +template_dst_dir_abs_path+ method to specify an absolute path. # # Default: RAILS_ROOT/app/views attr_accessor :template_dst_dir_path # Specify the directory where masterview template output is generated # as a relative path from the application's +root_path+. def template_dst_dir_path= rel_path #:nodoc: # bolts down abs path, thanks to our firm roots @template_dst_dir_path = rel_path.nil? ? nil : ( rel_path.empty? ? root_path : File.join( root_path, rel_path )) end # Specify the absolute path to the directory where masterview template output is generated. def template_dst_dir_abs_path(abs_path) @template_dst_dir_path = abs_path end # Filename extension to use for generated output files if not # explicitly specified in the +mv:generate+ attribute value. # # Default: '.rhtml' attr_accessor :output_filename_extension # Filename extension to use for generated files if not explicitly specified. # # Default: '.rhtml' attr_accessor :generated_file_default_extension #FIXME # Boolean which controls whether to include a comment in template # output files indicating that the file was generated by MasterView. # # By default, a warning comment is generated in template output files # indicating that the file was generated by MasterView from a template # and should not be directly edited, as any changes would be lost when the # output file is regenerated. # # Default: +true+ attr_accessor :include_generated_file_comment # Text for generated-file comment inserted in rhtml template output files # generated by MasterView. # # Standard comment includes the name of the master template file which contains # the source to edit. # # Variable substitution on the comment text will replace a reference # to {template_path} with the pathname of the source template file. # attr_accessor :generated_file_comment # === Template Parsing Options # Specify whether MasterView should handle exceptions when # parsing template files. # # Exceptions that occur during template parsing are always # recorded in the debug log. These are generally problems # caused by invalid (x)html in the template. # # Set to +true+ to have the template parser catch exceptions and # continue processing after logging a problem report. # # Set to +false+ to have exceptions raised to the application. # # Default: +true+ # attr_accessor :handle_parse_exceptions # Default option settings for template parsing (a hash) # :tidy => false - run tidy before parsing (tidy_path must be set if enabled) # :escape_erb => true - escapes <% %> before parsing attr_accessor :default_parser_options # Path on this system to tidy library if :tidy parser option is enabled # so that masterview templates will be run through tidy before being parsed. # Allows invalid xhmtl to be corrected before masterview template parsing is performed. attr_accessor :tidy_path # XML name space prefix for MasterView directive attributes in template html. # e.g. mv:generate="target.rhtml". # # Default: 'mv:' attr_accessor :namespace_prefix # Xhtml-safe substitution for '<%' in a masterview template # NOTE: you must also update inline_erb_substitution_regex if this is changed. # # Default: '{{{' attr_accessor :inline_erb_start # Xhtml safe substitution for '%>'in a masterview template # NOTE: you must also update inline_erb_substitution_regex if this is changed. # # Default: '}}}' attr_accessor :inline_erb_end # regex used to find escaped inline_erb markup. # Needs to match +inline_erb_start+ and +inline_erb_end+. attr_accessor :inline_erb_substitution_regex # === Rails Application Options # Boolean which specifies whether masterview templates are parsed # during initial application startup loading. # # Set to +false+ to disable all load-time parsing. # Template parsing must be manually triggered when the auto-parse option is disabled. # # Default: +true+ attr_accessor :parse_masterview_templates_at_startup # Boolean which determines whether masterview templates are automatically # reparsed if the template changes after initial application loading. # # Set to +true+ to monitor masterview templates for file system changes # during Rails request dispatching. # # Set to +false+ to disable changed-template monitoring. # Template parsing must be manually triggered when the auto-parse option is disabled. # # This option is only supported when running as part of a Rails application. # It is enabled by default in the standard Rails development configuration # (+parse_masterview_templates_at_startup+ is enabled and # ActionController::Base.perform_caching is false so that changed classes # are dynamically reloaded during request dispatching). # # Automatic change-detection and reparsing of masterview templates is disabled # by default in the usual Rails configuration for production mode # (ActionController::Base.perform_caching is on to enable loaded class caching). # # Default: +true+ if parse_masterview_templates_at_startup is enabled # and ActionController is reloading changed classes (no caching) attr_accessor :reparse_changed_masterview_templates # Enable MasterView admin pages in the rails application. # # Enables the masterview admin controller at http://yourappdomain/masterview. # # Default: +false+ attr_accessor :enable_admin_pages # Enable MasterView admin view rhtml feature # # If MasterView admin pages are enabled, then you may set this feature to true and it # will allow you to get to the generated rhtml from the MasterView admin page which is # especially useful for debugging or understanding how MasterView is interpretting the # your templates. When enabled you may click on any of the generated rhtml parts from # the list view and it will show you the rhtml that is generated. For security purposes # you will probably want this to disable this feature in production (or even better # disable admin pages itself). Alternatively there is a rake task called mv:view_rhtml # which allows you to see the rhtml from the command line (regardless of this setting). # # Default +false+ attr_accessor :enable_view_rhtml # Generate rhtml files if true, rails will load them from there. Otherwise when this # setting is false, enable rails app to read rhtml(erb) directly from MasterView cache # bypassing the serialization to the file system. # Default: +false+ attr_accessor :generate_rhtml_files # Create a new Configuration instance, initialized with the default # values. # # Optional arguments to the constructor allow for initializing defaults # for a rails app when not actually running rails or for initializing # defaults for a standalone app with context anchored at some well-defined # point in space (other than where we're actually running). # # :app_root_path => path to the root directory of the application # :rails_app_root_path => path to the root directory of a Rails app # :environment => current environment for loading settings # # The +app_root_path+ and +rails_app_root_path+ arguments are mutually exclusive. # Use +rails_app_root_path+ when operating on a Rails application which # isn't actually running; use +app_root_path+ for a non-rails application. # def initialize( params={} ) # unpack the supported keyword args app_root_path = params[:app_root_path] rails_app_root_path = params[:rails_app_root_path] env = params[:environment] program_root_path = File.expand_path( '.' ) #assert program_root_path == Dir.pwd debug_TRACE_HACK = false #temp dev debug tracking for rails vs. non-rails init @mv_code_base_dir = File.expand_path( File.dirname(__FILE__) ) builtin_directives_path = File.join( mv_code_base_dir, 'directives') @mv_installation_dir = File.expand_path( "#{File.dirname(__FILE__)}/../.." ) #ISSUE: should probably also detect std console or breakpointer launch scripts [DJL 10-Jun-2006] @rails_runner_scripts_pattern = /server|dispatch/ @has_rails_context = (defined?(::RAILS_ROOT) != nil) decide_if_running_rails # only run if auto parsing and when launching server, check if need to update mv files # MasterView::ParseMasterViewTemplatesAtStartup #ISSUE: what about console and breakpointer scripts? if debug_TRACE_HACK STDOUT.puts "\n####Initializing MasterView config (default settings)" STDOUT.puts "...RAILS_ROOT=#{defined?(::RAILS_ROOT) ? ::RAILS_ROOT : '(undefined)'}" STDOUT.puts "...has_rails_context=#{has_rails_context.nil? ? 'nil' : has_rails_context}" end # establish the fundamental roots for anchoring relative references # Scenarios: running a rails app, operating on a rails app but not running it, standalone #assert at most one of the two args is supplied, they're mutually exclusive if has_rails_context @rails_root_path = File.expand_path( ::RAILS_ROOT ) elsif rails_app_root_path @rails_root_path = File.expand_path( rails_app_root_path ) elsif app_root_path.nil? && looks_like_rails_app? # if client hasn't specifically provided an app or rails root anchor parm # and we aren't actually launching rails, sniff around and make a good guess # at whether this app has the rails structure so we can set proper defaults # (e.g., running rake tasks on a rails app) # ISSUE: Is this just too clever? Maybe the rakefile should establish this? # [DJL 15-Ajun-2006] @rails_root_path = program_root_path else @rails_root_path = nil end @rails_views_dir_path = rails_app? ? File.join( rails_root_path, 'app/views' ) : nil #if on_rails? # #ISSUE: ActionController::Base.template_root vs. ActionController::Base.view_root???? significant diff?? # #assert rails_views_path ==ActionController::Base.template_root #end if debug_TRACE_HACK STDOUT.puts "...rails_app?=#{rails_app? ? 'yes' : 'nope'}" STDOUT.puts "...on_rails?=#{on_rails? ? 'yes' : 'nope'}" end if debug_TRACE_HACK and rails_app? STDOUT.puts "...rails_root_path=#{self.rails_root_path}" STDOUT.puts "...rails_views_dir_path=#{rails_views_dir_path}" end # general options - establish the roots to anchor MV in an operating context if rails_app? self.root_path = self.rails_root_path elsif app_root_path self.root_path = File.expand_path( app_root_path ) else #ISSUE: add hook here to check for MASTERVIEW_ROOT_PATH or ENV[xxx]??? self.root_path = program_root_path end # For a rails app, we have a point of view on where to find config files. # A standalone client needs to proactively tell us where to find their settings. self.config_dir_path = rails_app? ? "config/masterview" : nil self.environment = on_rails? ? ::RAILS_ENV : env self.directive_paths = [ builtin_directives_path ] #TODO: if rails_app? && File.exist?( "#{rails_root_path}/app/masterview/directives" ) THEN append it as well self.rebuild_backups_tmp_dir_path = rails_app? ? File.join( rails_root_path, 'tmp/masterview/rebuild/backups') : nil # use Log4r by default if available, otherwise Logger from standard ruby library # find out if Kernel#require will succeed if we try to load Log4R log4r_dir = $:.detect { |dir| File.exists?("#{dir}/log4r.rb") } #? path_contains? predicate somewhere?? self.logger = log4r_dir ? 'log4r' : 'logger' #self.log_level = nil # use the default level of the logger self.log_level = (self.environment == 'development') ? 'INFO' : 'WARN' if debug_TRACE_HACK STDOUT.puts "...root_path=#{root_path}" STDOUT.puts "...config_dir_path=#{config_dir_path || 'nil'}" STDOUT.puts "...environment=#{environment || 'nil'}" STDOUT.puts "...directive_paths=[ #{directive_paths.join(', ')} ]" end # template source options self.template_src_dir_path = rails_app? ? 'app/views' : 'masterview/templates' # bolts down abs ref self.template_filename_pattern = '*.html' STDOUT.puts "...template_src_dir_path=#{template_src_dir_path || 'nil'}" if debug_TRACE_HACK # template generation options self.template_dst_dir_path = rails_app? ? 'app/views' : 'masterview/output' # bolts down abs ref self.output_filename_extension = '.rhtml' self.generated_file_default_extension = '.rhtml' self.include_generated_file_comment = true self.generated_file_comment = <<-END # WARNING - This is a generated file created by MasterView. # Do not edit - changes will be lost when this file is re-generated. # # To make changes, edit the MasterView source file located at: END self.generated_file_comment << '# #{template_path}' # carefully avoid premature subst eval STDOUT.puts "...template_dst_dir_path=#{template_dst_dir_path || 'nil'}" if debug_TRACE_HACK # template parsing options self.handle_parse_exceptions = true self.default_parser_options = { :tidy => false, :escape_erb => true } # default locations where tidy likely to be found; assume on user's PATH if on Windows self.tidy_path = RUBY_PLATFORM =~ /mswin32/ ? 'tidy.exe' : '/usr/lib/libtidy.so' self.namespace_prefix = 'mv:' self.inline_erb_start = '{{{' self.inline_erb_end = '}}}' self.inline_erb_substitution_regex = /\{\{\{(([^}]|\}[^}]|\}\}[^}])*)\}\}\}/ # Rails application options self.parse_masterview_templates_at_startup = true self.reparse_changed_masterview_templates = on_rails? ? (not ActionController::Base.perform_caching) : false self.enable_admin_pages = false self.enable_view_rhtml = false self.generate_rhtml_files = false STDOUT.puts "...mv config initialized with default settings\n" if debug_TRACE_HACK end def decide_if_running_rails #:nodoc: @running_rails = has_rails_context && ($PROGRAM_NAME =~ rails_runner_scripts_pattern) != nil end # see if this app has the std file structure that indicates a rails application def looks_like_rails_app? #:nodoc: std_rails_directories = [ 'app', 'config', 'public' ] std_rails_directories.each { | dir_path | return if ! File.directory?(dir_path) } true end # The path to the application's config settings file. # By default the file is at config/masterview/settings.rb. def app_settings_path config_dir_path ? "#{config_dir_path}/settings.rb" : nil end # The path to the current environment's settings file (development.rb, etc.). # By default the file is at config/masterview/environments/{environment}.rb. def environment_settings_path (config_dir_path && environment) ? "#{config_dir_path}/environments/#{environment}.rb" : nil end end # The Initializer is responsible for processing the MasterView configuration. # # In a Rails application using the MasterView facilities, # the Initializer is run automatically during rails startup # when the plugin is loaded. No special action is required # by the application. # # To customize the MasterView configuration, provide config settings files # in your application's config directory, setting standard settings # in config/masterview/settings.rb and optionally setting # environment-specific values in config/masterview/environments/{environment}.rb. # The settings files are executed with the +config+ variable initialized to # the current configuration. This is the standard technique for a Rails application. # # An application using the MasterView facilities outside the Rails context # must run the MasterView::Initializer during its application startup. # # It can be run as a simple command that uses the default configuration: # # require 'masterview/initializer' # MasterView::Initializer.run # # or more simply just load MasterView: # # require 'masterview' # # In order to customize the MasterView configuration outside the Rails context, # you must explicitly provide a basic Configuration to the Initializer # which specifies the root location of the application and the paths # to the template directories if the default locations are not appropriate. # Configuration settings can be set directly or provided through config # settings file by specifying the +config_dir_path+ to the application's # setttings files. # # require 'masterview/initializer' # config = MasterView::Configuration( :app_root_path = '/path/to/my/app' ) # config.environment = 'production' # config.config_dir_path = 'masterview/config' # #... additional settings will be loaded from the config dir... # Masterview::Initializer( :process, config ) # class Initializer # The Configuration instance used by this Initializer instance. attr_reader :configuration # Runs the initializer. By default, this will invoke the #process method, # which simply executes all of the initialization routines. Alternately, # you can specify explicitly which initialization routine you want: # # MasterView::Initializer.run(:initialize_configuration) # # This is useful if you only want the config settings initialized, without # incurring the overhead of completely loading the entire component. # def self.run(command = :process, configuration = Configuration.new) if block_given? yield configuration end initializer = new(configuration) initializer.send(command) initializer end # Create a new Initializer instance that references the given Configuration # instance. def initialize(configuration) #:nodoc: @configuration = configuration end # Load the MasterView configuration settings # and initialize the template engine. def process initialize_configuration load_plugin complete_plugin_installation end # Load the Masterview configuration settings. # Does *not* load and configure the template engine. # # Intended for use in testing. def initialize_configuration #?? return if MasterView.const_defined?(:ConfigSettings) ?? load_config_settings ensure_valid_settings discover_standard_directive_path_additions install_config_settings # make a final check for running_rails? (in case config settings changed scripts spec) configuration.decide_if_running_rails # keep a permananent record of how we got started configuration.freeze configuration.directive_paths.freeze MasterView.const_set('ConfigSettings', configuration) end # Load configuration settings from {config.config_dir_path}/settings.rb # and {config.config_dir_path}/environments/{config.environment}.rb. def load_config_settings #:nodoc: load_app_settings load_environment_settings end # Loads application config settings. def load_app_settings #:nodoc: load_settings_file(configuration.app_settings_path) end # Loads config settings for the environment specified by # Configuration#environment_path, which # is typically one of development, testing, or production. def load_environment_settings #:nodoc: load_settings_file(configuration.environment_settings_path) end # Loads MasterView config settings from the specified config file. def load_settings_file(config_file_path) #:nodoc: return if not (config_file_path && File.file?(config_file_path)) config = configuration # define config var in the binding context of the settings eval eval(IO.read(config_file_path), binding) end def discover_standard_directive_path_additions #:nodoc: #TODO: check for config/masterview/directives and automatically # append to the configuration.directive_paths if found. # We have to wait until all the config settings are loaded so that # all references to root locations and client's own prefs for # locating directives. # [DJL 01-Jun-2006] #... something like: #return if not config_dir_path #config_directives_path = File.join(configuration.config_dir_path, 'directives') #if File.directory?(config_directives_path) # configuration.directivePaths << File.expand_path(config_directives_path unless it's already there #end end # ensure that the requested configuration settings are consistent and valid # before we actually install anything. Normalize representations as needed. def ensure_valid_settings #:nodoc: config = configuration #??config.root_path = File.expand_path(config.root_path) if config.root_path #?? ensure bolted down firmly? ####if config.directive_paths.length > 1 then expand_path on user-appended entries?? # template source and generation options if config.on_rails? #TODO: ensure that the config.template_dst_dir_path is # in the RAILS_ROOT/app/views directory # (ActionController::Base.view_root) # Otherwise all the fine rails view template stuff doesn't work end # Rails application options if config.on_rails? # ensure we don't activate runtime reparsing if we didn't autoparse at startup # (?overzealous? But this what we're currently asserting as the intended behavior in the docs) if not config.parse_masterview_templates_at_startup config.reparse_changed_masterview_templates = false end #else # self.reparse_changed_masterview_templates = false # not supported end end # Install the configuration settings def install_config_settings #:nodoc: set_module_constants end def set_module_constants #:nodoc: config = configuration # we don't record root_path or config_dir_path - their purpose is satisfied # by the time we're done processing this installation configuration MasterView.const_set('DefaultDirectiveLoadPaths', config.directive_paths.clone) # clone before freezing # template source options MasterView.const_set('TemplateFilenamePattern', config.template_filename_pattern) # template generation options MasterView.const_set('OutputExtension', config.output_filename_extension) ###??IS THIS NEEDED??? MasterView.const_set('OmitGeneratedComments', (not config.include_generated_file_comment)) MasterView.const_set('GeneratedCommentText', config.generated_file_comment) # template parsing options MasterView.const_set('RescueExceptions', config.handle_parse_exceptions) MasterView.const_set('DefaultParserOptions', config.default_parser_options) MasterView.const_set('TidyPath', config.tidy_path) MasterView.const_set('NamespacePrefix', config.namespace_prefix) MasterView.const_set('InlineErbStart', config.inline_erb_start) MasterView.const_set('InlineErbEnd', config.inline_erb_end) MasterView.const_set('InlineErbSubstitutionRegex', config.inline_erb_substitution_regex) # Rails application options MasterView.const_set('ParseMasterViewTemplatesAtStartup', config.parse_masterview_templates_at_startup) MasterView.const_set('ReparseChangedMasterViewTemplates', config.reparse_changed_masterview_templates) MasterView.const_set('EnableMasterViewAdminPages', config.enable_admin_pages) MasterView.const_set('EnableMasterViewAdminViewRHTML', config.enable_view_rhtml) # convenience constants for MV attributes involving output generation and imports MasterView.const_set('GenerateAttribute', config.namespace_prefix + 'generate') MasterView.const_set('ImportAttribute', config.namespace_prefix + 'import') MasterView.const_set('GenRenderAttribute', config.namespace_prefix + 'gen_partial') MasterView.const_set('ImportRenderAttribute', config.namespace_prefix + 'import_render') end # Load the masterview code def load_plugin #:nodoc: require 'masterview' #:nodoc: end # Complete installation of masterview after its code has been loaded def complete_plugin_installation #:nodoc: #?? return if MasterView.const_defined?(:Initialized) ?? initialize_mio initialize_logger install_in_rails # mark the module as fully loaded and configured MasterView.const_set('Initialized', true) after_initialize # callback to client's afer_initialize block end # Initialize the MasterView I/O subsystem def initialize_mio config = configuration MasterView.const_set('DefaultSerializer', MIOSerializer) # all root_path directory anchor points for I/O are expanded absolute paths io_mgr = MIOTrees.new template_extension = File.extname( config.template_filename_pattern ) io_mgr.template = FileMIOTree.new( config.template_src_dir_path, template_extension, :escape_erb => config.default_parser_options[:escape_erb], :tidy => config.default_parser_options[:tidy], #TODO: expose the following in Configuration.default_parser_options and document :caching => false, :logging => true ) if config.generate_rhtml_files io_mgr.erb = FileMIOTree.new( config.template_dst_dir_path, config.generated_file_default_extension, :logging => true) else io_mgr.erb = RailsErbCacheMIOTree.new( config.generated_file_default_extension, :logging => true) end io_mgr.backup = FileMIOTree.new( config.rebuild_backups_tmp_dir_path ) if config.rebuild_backups_tmp_dir_path MasterView.const_set('IOMgr', io_mgr) end # Initialize MasterView::Log with a logger which emits to std output, default DEBUG level def initialize_logger #:nodoc: #?return if defined?(Log) require 'masterview/extras/init_logger' end def install_in_rails #:nodoc: return if ! configuration.on_rails? enable_mv_admin_pages parse_templates_at_startup enable_reparse_changed_templates enable_rails_erb_direct end # install the MasterviewController to support masterview admin pages in the site def enable_mv_admin_pages #:nodoc: return if ! configuration.enable_admin_pages #MasterView::EnableMasterViewAdminPages MasterView::Log.info{ 'MasterView Admin pages enabled' } # verify that stylesheets we use are available and if not copy them to public/stylesheets mv_generator_templates_dir = "#{configuration.mv_installation_dir}/generators/masterview/templates" unless File.exist?(mv_generator_templates_dir) # we are in a gem so things are in different directories MasterView::Log.debug{ 'MasterView appears to be installed as a gem...' } mv_generator_dir = configuration.mv_installation_dir.gsub('\\','/').gsub( %r{/masterview-([^/]+)$}, '/masterview_generator-\1' ) mv_generator_templates_dir = "#{mv_generator_dir}/templates" end MasterView::Log.debug{ 'MasterView gem admin stylesheet src dir='+mv_generator_templates_dir } if File.directory?(mv_generator_templates_dir) rails_app_stylesheets_dir = Pathname.for_path(RAILS_ROOT) + 'public/stylesheets/masterview' stylesheet_specs = [ # from/to spec: [ , ] [ 'style.css', 'style.css' ], [ 'sidebox.css', 'sidebox.css' ], [ 'color-scheme.css', 'color-scheme.css' ] ] src_dir_accessor = MasterView::FileMIOTree.new( mv_generator_templates_dir ) dst_dir_accessor = MasterView::FileMIOTree.new( rails_app_stylesheets_dir, '.css', :logging => true) stylesheet_specs.each { | from, to | src_file = src_dir_accessor.path(from) dst_file = dst_dir_accessor.path(to) dst_file.write( src_file.read ) unless dst_file.exist? } end # add our app directories with the masterview_controller to the load path mv_controller_code_dirs = Dir[File.join(configuration.mv_code_base_dir, '/extras/app/**/*')].select { |dir| File.directory?(dir) } mv_controller_code_dirs.each { |dir| $LOAD_PATH.push dir } end def parse_templates_at_startup #:nodoc: if configuration.parse_masterview_templates_at_startup require 'masterview/extras/watcher' MasterView::Log.debug { 'Parsing MasterView templates...' } MasterView::IOMgr.template.find(:pattern => MasterView::TemplateFilenamePattern) do |mio| MasterView::Parser.parse_mio(mio, MasterView::IOMgr.erb) end end end def enable_reparse_changed_templates #:nodoc: if configuration.reparse_changed_masterview_templates #MasterView::ReparseChangedMasterViewTemplates # if not caching then check for masterview updates on every request # assert not ActionController::Base.perform_caching require 'masterview/extras/watcher' #:nodoc: require 'masterview/extras/init_rails_reparse_checking' end end def enable_rails_erb_direct #:nodoc: unless configuration.generate_rhtml_files # if not generating rhtml the read erb directly from masterview require 'masterview/extras/init_rails_erb_mv_direct' end end # Fires the user-supplied after_initialize block (Configuration#after_initialize) def after_initialize #:nodoc: configuration.after_initialize_block.call if configuration.after_initialize_block end end end