lib/masterview/initializer.rb in masterview-0.2.5 vs lib/masterview/initializer.rb in masterview-0.3.0
- old
+ new
@@ -44,11 +44,18 @@
# [JJB 13-Jun-2006]
#++
#
require 'date'
+# we can't be assured of the load path state if initializer is run standalone
+# to construct a configuration prior to full MasterView initialization
+currentPath = File.dirname(__FILE__)
+require File.join( currentPath, 'directive_metadata' )
+require File.join( currentPath, 'directive_load_path' )
+DEBUG_DIRECTIVE_PATH = false #:nodoc: # temp debug
+
module MasterView
# A Configuration holds all the configuration settings used the
# MasterView::Initializer to configure the template engine.
#
@@ -152,14 +159,47 @@
# is installed by default. If the application provides
# a <tt>masterview/directives</tt> 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
+ # A directive load path entry specifiess a directory path
+ # from which masterview directives are loaded.
+ # Configuration options can optionally be specified to override
+ # or extend any .metadata specifications in the directory.
+ #
+ # Use add_directive_path to append additional directory path(s)
+ # from which to load custom directives.
+ #
+ attr_accessor :directive_load_path
+ # Deprecated - use directive_load_path
+ def directive_paths
+ @directive_load_path
+ end
+
+ # For use by Initializer to reset cleaned path
+ def directive_load_path=(path) #:nodoc:
+ @directive_load_path = path
+ end
+
+ # Add an entry to the directive_load_path list for a directory
+ # containing directive implementation classes to be loaded
+ # into the MasterView processing configuration.
+ #
+ # Optionally specify options for the directives loaded
+ # from this directory:
+ #
+ # :default - metadata defaults
+ #
+ # Metadata defaults extend or override any defaults specified
+ # in the dir_path/.metadata file, if defined, allowing application
+ # customization of the default defaults.
+ #
+ def add_directive_path(dir_path, options=nil)
+ directive_load_path << DirectiveLoadPath::PathEntry.new( dir_path, options )
+ end
+
# 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.
#
@@ -331,16 +371,22 @@
# Path on this system to tidy library if <tt>:tidy</tt> 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.
+ # XML name space prefix for builtin MasterView directive attributes in template html.
# e.g. mv:generate="target.rhtml".
#
# Default: <tt>'mv:'</tt>
attr_accessor :namespace_prefix
+ # XML name space prefix for MasterView extension directive attributes in template html.
+ # e.g. mvx:custom_directive="foo".
+ #
+ # Default: <tt>'mvx:'</tt>
+ attr_accessor :namespace_prefix_extensions
+
# Xhtml-safe substitution for '<%' in a masterview template
# NOTE: you must also update inline_erb_substitution_regex if this is changed.
#
# Default: <tt>'{{{'</tt>
attr_accessor :inline_erb_start
@@ -420,10 +466,14 @@
# will be merged with these to arrive at the result. This allows us to easily
# add new defaults in and even if users empty this hash, the defaults will get added
# to disable they specifically set something to false or nil
OriginalDefaultParserOptions = { :tidy => false, :escape_erb => true, :default_generate => true } # :nodoc: save the originals
+ # list of [ :log_level, msg ] pairs for config initialization/validation messages
+ # used by the initializer to validate load path and report any problems
+ attr_accessor :initialization_messages #:nodoc:
+
# 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
@@ -436,18 +486,12 @@
#
# 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={} ) #:nodoc:
- # list of [ :log_level, msg ] pairs for config initialization/validation messages
- # used by the initializer to validate load path and report any problems
- attr_accessor :initialization_messages #:nodoc:
- ####:invalid_directive_paths
-
- def initialize( params={} )
-
rails_env = (defined?(RAILS_ENV)) ? RAILS_ENV : nil
# unpack the supported keyword args
app_root_path = params[:app_root_path]
rails_app_root_path = params[:rails_app_root_path]
env = params[:environment] || rails_env
@@ -522,11 +566,12 @@
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 ]
+ self.directive_load_path = DirectiveLoadPath::Path.new
+ add_directive_path builtin_directives_path, { :use_masterview_namespace => true, }
discover_standard_directive_path_additions()
#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
@@ -538,11 +583,11 @@
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(', ')} ]"
+ STDOUT.puts "...directive_load_path=[ #{directive_load_path.directory_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'
@@ -573,10 +618,11 @@
self.handle_parse_exceptions = true
self.default_parser_options = OriginalDefaultParserOptions.clone #we'll merge in whatever changes they make over the original set in const above
# default locations where tidy likely to be found; assume on user's PATH if on Windows
self.tidy_path = RUBY_PLATFORM =~ /mswin32/ ? 'c:/tidy/lib/tidy.dll' : '/usr/lib/libtidy.so'
self.namespace_prefix = 'mv:'
+ self.namespace_prefix_extensions = 'mvx:'
self.inline_erb_start = '{{{'
self.inline_erb_end = '}}}'
self.inline_erb_substitution_regex = /\{\{\{(([^}]|\}[^}]|\}\}[^}])*)\}\}\}/
# Rails application options
@@ -613,11 +659,12 @@
def discover_standard_directive_path_additions() #:nodoc:
return if ! rails_app? #?or can we take a point of view of std loc? e.g., 'masterview/directives'
app_directives_path = rails_app? ? "app/masterview/directives" : nil #??"masterview/directives"?
app_directives_path = File.join( root_path, app_directives_path )
if File.directory?(app_directives_path) #?and not empty?
- directive_paths << app_directives_path #root_path already expanded
+ #{ :use_masterview_namespace => false, }
+ add_directive_path app_directives_path #root_path already expanded
end
end
# The path to the application's config settings file.
# By default the file is at <tt>config/masterview/settings.rb</tt>.
@@ -727,11 +774,10 @@
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 <tt>{config.config_dir_path}/settings.rb</tt>
# and <tt>{config.config_dir_path}/environments/{config.environment}.rb</tt>.
@@ -766,25 +812,19 @@
config = configuration
#??config.root_path = File.expand_path(config.root_path) if config.root_path #?? ensure bolted down firmly?
# ensure that the directive load path entries are clean and available
- if not config.directive_paths.empty?
- clean_paths = []
- config.directive_paths.each { | dir |
- if dir.nil?: continue; end
- if ! File.directory?(dir)
- err_msg = "Invalid directive load path directory: '#{dir}'"
- #overzealous: raise InvalidPathError.new(err_msg)
- # just note the problem and let initializer report it later
- config.initialization_messages << [ :error, err_msg ]
- else
- dir_path = File.expand_path( dir )
- clean_paths << dir_path if ! clean_paths.include?(dir_path) # no dups
- end
+ if not config.directive_load_path.empty?
+ STDOUT.puts "###DEBUG: cleaning directive_load_path #{config.directive_load_path.inspect}" if DEBUG_DIRECTIVE_PATH
+ clean_path = DirectiveLoadPath.clean_path( config.directive_load_path, :dup_policy => :use_latest ) { | ex |
+ # record validation error from a path entry and press on
+ # just note the problem and let initializer report it later
+ config.initialization_messages << [ :error, ex.message ]
}
- config.directive_paths = clean_paths
+ config.directive_load_path = clean_path
+ STDOUT.puts "###DEBUG: CLEANED directive_load_path #{config.directive_load_path.inspect}" if DEBUG_DIRECTIVE_PATH
end
# template source and generation options
if config.on_rails?
#TODO: ensure that the config.template_dst_dir_path is
@@ -807,28 +847,24 @@
end
# Install the configuration settings
def install_config_settings #:nodoc:
set_module_constants
+ DirectiveLoadPath.default_path_specs = configuration.directive_load_path # does clone before freezing config
end
def set_module_constants #:nodoc:
config = configuration
-
- # save configuration so we can get to it later
- MasterView.const_set('LoadedConfiguration', config)
# create loaded feature map - this map will track exactly what was loaded taking into account failures, so it can differ
# from what is configured. key = feature symbol, value = true if enabled and loaded
MasterView.const_set('LoadedFeatures', {} )
# 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???
@@ -837,37 +873,33 @@
# template parsing options
MasterView.const_set('RescueExceptions', config.handle_parse_exceptions)
MasterView.const_set('DefaultParserOptions', Configuration::OriginalDefaultParserOptions.merge(config.default_parser_options)) # merge in changes with original, so we can add more defaults later, users have to explicitly set an option to false to cancel them
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 own code has been loaded
def complete_plugin_installation #:nodoc:
#?? return if MasterView.const_defined?(:Initialized) ??
+ MasterView::DirectiveRegistry.register_default_namespaces(
+ configuration.namespace_prefix,
+ configuration.namespace_prefix_extensions )
initialize_logger
initialize_mio
#Back out experiment: causes load order problems
##load_directives # held off on this until logger is installed
install_in_rails
@@ -887,38 +919,39 @@
end
# Initialize the MasterView I/O subsystem
def initialize_mio
config = configuration
- MasterView.const_set('DefaultSerializer', MIOSerializer)
+ MasterView.const_set('DefaultSerializer', TemplateProcessing::MIOSerializer)
# all root_path directory anchor points for I/O are expanded absolute paths
- io_mgr = MIOTrees.new
+ io_mgr = MIO::MIOTrees.new
template_extension = File.extname( config.template_filename_pattern )
- io_mgr.template = FileMIOTree.new( config.template_src_dir_path, template_extension,
+ io_mgr.template = MIO::FileMIOTree.new( config.template_src_dir_path, template_extension,
:escape_erb => DefaultParserOptions[:escape_erb], # use DefaultParserOptions since already has config merged
:tidy => DefaultParserOptions[:tidy],
:default_generate => DefaultParserOptions[:default_generate],
#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)
+ io_mgr.erb = MIO::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)
+ io_mgr.erb = MIO::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
+ io_mgr.backup = MIO::FileMIOTree.new( config.rebuild_backups_tmp_dir_path ) if config.rebuild_backups_tmp_dir_path
MasterView.const_set('IOMgr', io_mgr)
MasterView::LoadedFeatures[:tidy_template_read] = config.default_parser_options[:tidy]
end
+ #NOTE: not currently used - caused problems during startup, so reverted to original
+ # scheme where loading is triggered on demand by template parsing
+ # [SJL 20-Sep-2006]
def load_directives #:nodoc:
# get the directives loaded prior to firing up any template parsing
return if ! configuration.on_rails? #ISSUE: causes problem for test cases; is this ever a good idea??
- MasterView::DirectivesRegistry.process_directives_load_path(
- configuration.directive_paths,
- configuration.namespace_prefix )
+ MasterView::DirectiveRegistry.current.process_directives_load_path( configuration.directive_load_path )
end
def install_in_rails #:nodoc:
return if ! configuration.on_rails?
enable_mv_admin_pages
@@ -943,22 +976,35 @@
end
MasterView::LoadedFeatures[:rails_parse_at_startup] = true
end
end
+ #--
+ # DBC-style notation per DbC - rubydbc-0.1 (Andy Hunt's Design by Contract)
+ #pre( MasterView::ParseMasterViewTemplatesAtStartup )
+ #pre( MasterView::ReparseChangedMasterViewTemplates )
+ #pre( defined?(ActionController) && ActionController::Base.perform_caching )
+ #++
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
+ # DBC-style notation per DbC - rubydbc-0.1 (Andy Hunt's Design by Contract)
+ #pre( MasterView::ParseMasterViewTemplatesAtStartup )
+ #pre( defined?(ActionController) && ActionController::Base.perform_caching )
require 'masterview/extras/watcher' #:nodoc:
- require 'masterview/extras/init_rails_reparse_checking'
+ MasterView::Log.info { 'Adding hook to allow MasterView to check for templates that have changed when processing a request' }
+ require 'masterview/rails_ext/action_controller_reparse_checking' #:nodoc:
+ MasterView::LoadedFeatures[:rails_reparse_checking] = true
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'
+ MasterView::Log.info { 'Adding hooks to enable Rails to read erb directly from MasterView' }
+ require 'masterview/rails_ext/action_view_erb_direct' #:nodoc:
+ require 'masterview/rails_ext/action_controller_erb_direct' #:nodoc:
+ MasterView::LoadedFeatures[:rails_erb_mv_direct] = true
end
end
# Fires the user-supplied after_initialize block (Configuration#after_initialize)
def after_initialize #:nodoc: