Class: MasterView::DirectiveRegistry
- Inherits:
-
Object
- Object
- MasterView::DirectiveRegistry
- Defined in:
- lib/masterview/directive_registry.rb
Overview
A DirectiveRegistry manages the directives available for processing the MasterView directive attributes in a template document.
DirectiveRegistry is an internal mechanism of the template engine, primarily used by the MasterView::Parser to support directive attribute processing.
Constant Summary collapse
- DEBUG_TRACE_LOADING =
:nodoc: ##DEBUG##
false
- TRACE_MD_HARDENING_SUBJECT =
‘MasterView::DirectiveTests::TestEventsDirective’
nil
- DEBUG_BUILTIN_DIRECTIVE_REGISTRATION =
:nodoc:
false
- DEBUG_CURRENT =
:nodoc:
false
Instance Attribute Summary collapse
-
#load_context ⇒ Object
readonly
internal mechanism to provide directory/path load context during directive class loading.
-
#loaded_classes ⇒ Object
readonly
Answer the list of directive classes which are loaded in the current configuration.
Class Method Summary collapse
-
.current ⇒ Object
The DirectiveRegistry for managing the loaded directives available for processing template markup.
-
.current=(registry) ⇒ Object
Set the current directives registry for template processing.
-
.register_default_namespaces(ns_prefix_masterview, ns_prefix_extensions) ⇒ Object
Register default namespaces for directive metadata Should be invoked once during MasterView initialization.
Instance Method Summary collapse
-
#build_directive_maps ⇒ Object
Build the directive processing tables used by the template parser.
-
#construct_directive_processors(tag_name, element_attrs) ⇒ Object
Construct directive processors needed to handle the attributes defined on a template document element.
-
#initialize ⇒ DirectiveRegistry
constructor
A new instance of DirectiveRegistry.
-
#load_directive_file(directive_file_path) ⇒ Object
Load a specific directive implementation class.
-
#load_directives(load_path = nil) ⇒ Object
Ensure that all directives on the load path are loaded.
-
#load_from_directive_path_entry(dpe, directive_file_path = nil) ⇒ Object
:nodoc:.
-
#loaded_class_names(simpleNames = true) ⇒ Object
Answer the (base) names of the loaded directive classes.
-
#loaded_namespaces ⇒ Object
Answer a list of all namespaces in use.
-
#metadata_defaults ⇒ Object
Hash containing default directive metadata properties Used during directive path loading to exploit default config specs.
-
#metadata_defaults_extensions ⇒ Object
Hash containing default directive metadata properties Used during directive path loading to exploit default config specs.
-
#mv_extensions_namespace_prefix ⇒ Object
Answer the namespace prefix of directives in the default MasterView extensions directives namespace.
-
#mv_namespace_prefix ⇒ Object
Answer the namespace prefix of directives in the standard MasterView namespace.
-
#process_directives_load_path(load_path = nil) ⇒ Object
Ensure that all directives on the load path are loaded.
-
#register_directive(directive_class) ⇒ Object
Register a directive implementation.
-
#registered_directive_names ⇒ Object
Answer the fully-qualified names of the registered directives.
-
#registered_directives ⇒ Object
Answer the the registered directives.
-
#set_load_context(context_settings, check_for_conflict = true) ⇒ Object
:nodoc:.
-
#simple_class_name(dc) ⇒ Object
Answer the simple name of a directive class (without its module qualifier).
-
#update_loaded_classes_hack(already_loaded_classes) ⇒ Object
:nodoc:.
Constructor Details
#initialize ⇒ DirectiveRegistry
Returns a new instance of DirectiveRegistry.
117 118 119 120 121 122 123 124 |
# File 'lib/masterview/directive_registry.rb', line 117 def initialize() @loaded_classes = [] set_load_context( nil ) clear_directive_maps() #STDOUT.puts "\n###Created DirectiveRegistry=#{self.object_id}" #STDOUT.puts "...loaded_classes=#{self.loaded_classes.inspect}" #STDOUT.puts "...load_context=#{self.load_context.inspect}" end |
Instance Attribute Details
#load_context ⇒ Object (readonly)
internal mechanism to provide directory/path load context during directive class loading
109 110 111 |
# File 'lib/masterview/directive_registry.rb', line 109 def load_context @load_context end |
#loaded_classes ⇒ Object (readonly)
Answer the list of directive classes which are loaded in the current configuration.
79 80 81 |
# File 'lib/masterview/directive_registry.rb', line 79 def loaded_classes @loaded_classes end |
Class Method Details
.current ⇒ Object
The DirectiveRegistry for managing the loaded directives available for processing template markup. # DirectiveRegistry.current is ordinarily configured to load the directives registered on the DirectiveLoadPath.current.
23 24 25 |
# File 'lib/masterview/directive_registry.rb', line 23 def self.current @@current end |
.current=(registry) ⇒ Object
Set the current directives registry for template processing. Ordinarily done once during masterview initialization.
29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/masterview/directive_registry.rb', line 29 def self.current=(registry) #:nodoc: if self.class_variables.include?('@@current') && @@current && registry # HACK: need to preserve the list of loaded classes. # this shouldn't ordinarily happen, but repeated class loading # occurs during, ah, say... test suite runs, yes!! registry.update_loaded_classes_hack( @@current.loaded_classes ) end @@current = registry if DEBUG_CURRENT STDOUT.puts "\n****#{self.name}.current set: #{current.object_id}" STDOUT.puts "...#{current.inspect}\n" end end |
.register_default_namespaces(ns_prefix_masterview, ns_prefix_extensions) ⇒ Object
Register default namespaces for directive metadata Should be invoked once during MasterView initialization
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/masterview/directive_registry.rb', line 49 def self.register_default_namespaces(ns_prefix_masterview, ns_prefix_extensions) #:nodoc: raise ArgumentError, "Invalid masterview namespace prefix '#{ns_prefix_masterview}'" if ns_prefix_masterview[-1..-1] != ':' raise ArgumentError, "Invalid extensions namespace prefix '#{ns_prefix_extensions}'" if ns_prefix_extensions[-1..-1] != ':' = { :namespace => ns_prefix_masterview[0...-1], :namespace_prefix => ns_prefix_masterview, } = { :namespace => ns_prefix_extensions[0...-1], :namespace_prefix => ns_prefix_extensions, } #assert NotReallyNecessary, 'because we'll just make sure we code up the right stuff here' DirectiveMetadata. DirectiveMetadata. end |
Instance Method Details
#build_directive_maps ⇒ Object
Build the directive processing tables used by the template parser.
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/masterview/directive_registry.rb', line 267 def build_directive_maps() #:nodoc: clear_directive_maps() # ensure we take a clean point of view on the matter at hand Log.debug { 'directive plugins loaded:' + loaded_class_names.inspect } if MasterView.const_defined?(:Log) #backstop for test case startup loaded_classes.each do |dc| dc.on_load if dc.respond_to?(:on_load) #ISSUE: needs review (timing, intent) [DJL 08-Oct-2006] attr_qname = dc.attribute_qname ns_name = dc.namespace_name raise NameError, "Directive qname requires namespace: '#{attr_qname} - #{dc.name}" if ns_name.nil? || ns_name.strip().empty? if DEBUG_BUILTIN_DIRECTIVE_REGISTRATION and dc.name.starts_with?('MasterView::Directives::') if ns_name != 'mv' #! attr_qname.starts_with(MasterView.mv_namespace_prefix) STDOUT.puts "****BUILTIN DIRECTIVE NAMESPACE PROBLEM: #{dc.name} qname='#{attr_qname}'" raise RuntimeError, "BUILTIN DIRECTIVE NS PROBLEM: #{dc.name} qname='#{attr_qname}" end end @directive_namespaces << ns_name if ! @directive_namespaces.include?( ns_name ) @directive_classes[attr_qname] = dc # global directives can be automatically attached to all elements (e.g., generated comments) # or conditionally attached (e.g., a directive that wants to glom onto all elements of a specific type) dc_global_spec = dc..fetch(:global_directive?, false) if dc_global_spec == true # unconditional global directive - applied to all elements @auto_directives << dc elsif dc_global_spec # conditional global directive - applied when match condition satisfied @global_directives << dc end end if MasterView.const_defined?(:Log) #backstop for test case startup Log.debug { "directives=#{@directive_classes.keys().sort!().inspect}" } Log.debug { "global_directives=#{@global_directives.inspect}" } Log.debug { "auto_directives=#{@auto_directives.inspect}" } end end |
#construct_directive_processors(tag_name, element_attrs) ⇒ Object
Construct directive processors needed to handle the attributes defined on a template document element.
Constructs processors for all global directives and for any directive attributes defined on the element.
Removes all directive attributes from the element’s attributes.
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
# File 'lib/masterview/directive_registry.rb', line 310 def construct_directive_processors( tag_name, element_attrs ) directive_processors = [] # always instantiate global directive handlers @auto_directives.each do | dc | directive_processors << dc.new(nil) end # conditionally instantiate global directives which are interested in this element @global_directives.each do | dc | attr_value = dc.[:global_directive?].call( tag_name, element_attrs ) if attr_value directive_processors << dc.new(attr_value) end end # instantiate the directive processor on the attribute value if its attr present # remove the MV attribute from the document so that its only effect is from the processor action @directive_classes.each do | attr_qname, dc | directive_attr_value = element_attrs[attr_qname] if directive_attr_value # convert the directive into a processing handler for this element element_attrs.delete(attr_qname) directive_processors << dc.new(directive_attr_value) end end directive_processors end |
#load_directive_file(directive_file_path) ⇒ Object
Load a specific directive implementation class
Mainly provided for use by unit tests
202 203 204 205 206 |
# File 'lib/masterview/directive_registry.rb', line 202 def load_directive_file(directive_file_path) dir_path = File.dirname(directive_file_path) dpe = MasterView::DirectiveLoadPath::PathEntry.new(dir_path) load_from_directive_path_entry( dpe, directive_file_path ) end |
#load_directives(load_path = nil) ⇒ Object
Ensure that all directives on the load path are loaded.
require directives_dir/foo_directive.rb
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/masterview/directive_registry.rb', line 183 def load_directives( load_path=nil ) #:nodoc: load_path = MasterView::DirectiveLoadPath.current if load_path.nil? STDOUT.puts "\n-------- LOAD DIRECTIVES ON PATH -------" if DEBUG_TRACE_LOADING load_path.each do | dpe | STDOUT.puts "DIRECTORY PATH ENTRY: #{dpe.inspect}" if DEBUG_TRACE_LOADING if dpe.exists? self.load_from_directive_path_entry( dpe ) else #raise InvalidPathError.new('Directive load path dir does not exist:'+dir_path) Log.error "Directive load path dir does not exist: '#{dpe.dir_path}'" if MasterView.const_defined?(:Log) #backstop for test case startup end end clear_directive_maps() # ensure we take a clean point of view on whatever just got loaded STDOUT.puts "------ END LOAD DIRECTIVES ------" if DEBUG_TRACE_LOADING end |
#load_from_directive_path_entry(dpe, directive_file_path = nil) ⇒ Object
:nodoc:
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/masterview/directive_registry.rb', line 208 def load_from_directive_path_entry(dpe, directive_file_path=nil) #:nodoc: dir_md_specs = dpe. # :create_if_not_defined => true is_mv_directives_dir = dir_md_specs.fetch(:use_masterview_namespace, false) app_md_defaults = is_mv_directives_dir ? : md_defaults = MasterView::DirectiveLoadPath.compute_md_defaults( app_md_defaults, dir_md_specs[:default], dpe. ) begin dir_load_context = { :metadata_defaults => md_defaults, } set_load_context( dir_load_context ) if directive_file_path # load specific file from a directive path entry directory dir_load_context[:directive_file] = directive_file_path load_single_directive_file(directive_file_path, md_defaults) #WAS: require directive_file_path else # load all directives in the directory dir_path = dpe.dir_path #??Log.debug { "Loading directives from #{dir_path} with metadata defaults #{md_defaults.inspect}" } #??load_context[:synonyms] = dir_md_specs.fetch(:synonyms, {})?? files_to_ignore = dir_md_specs.fetch(:ignore, []).collect { |fn| fn.ends_with?('.rb') ? fn : "#{fn}.rb" } Dir.entries( dir_path ).each { |fn| # we assume all .rb files in a directives dir are directive impls if fn =~ /[.]rb$/ next if files_to_ignore.include?(fn) # skip directives in the ignore list directive_file_path = "#{dir_path}/#{fn}" dir_load_context[:directive_file] = directive_file_path #??@load_context[:directive_synonyms] = dir_synonyms_specs.fetch(fn, [])?? load_single_directive_file(directive_file_path, md_defaults) #WAS: require directive_file_path end } end ensure set_load_context( nil ) end end |
#loaded_class_names(simpleNames = true) ⇒ Object
Answer the (base) names of the loaded directive classes.
By default, strips off module prefixes and returns just the directive class name for brevity.
160 161 162 163 164 |
# File 'lib/masterview/directive_registry.rb', line 160 def loaded_class_names( simpleNames=true ) @loaded_classes.collect do |dc| simpleNames ? simple_class_name(dc) : dc.name end end |
#loaded_namespaces ⇒ Object
Answer a list of all namespaces in use
82 83 84 |
# File 'lib/masterview/directive_registry.rb', line 82 def loaded_namespaces @directive_namespaces #??.clone for paranoid safety? end |
#metadata_defaults ⇒ Object
Hash containing default directive metadata properties Used during directive path loading to exploit default config specs.
98 99 100 |
# File 'lib/masterview/directive_registry.rb', line 98 def #:nodoc: end |
#metadata_defaults_extensions ⇒ Object
Hash containing default directive metadata properties Used during directive path loading to exploit default config specs.
104 105 106 |
# File 'lib/masterview/directive_registry.rb', line 104 def #:nodoc: end |
#mv_extensions_namespace_prefix ⇒ Object
Answer the namespace prefix of directives in the default MasterView extensions directives namespace.
73 74 75 76 |
# File 'lib/masterview/directive_registry.rb', line 73 def mv_extensions_namespace_prefix ##ISSUE: needs work?? Does this need to be an inst var of the registry?? [:namespace_prefix] end |
#mv_namespace_prefix ⇒ Object
Answer the namespace prefix of directives in the standard MasterView namespace.
66 67 68 69 |
# File 'lib/masterview/directive_registry.rb', line 66 def mv_namespace_prefix ##ISSUE: needs work?? Does this need to be an inst var of the registry?? [:namespace_prefix] end |
#process_directives_load_path(load_path = nil) ⇒ Object
Ensure that all directives on the load path are loaded. Build the directive processing tables used by the template parser.
174 175 176 177 178 |
# File 'lib/masterview/directive_registry.rb', line 174 def process_directives_load_path( load_path=nil ) load_path = MasterView::DirectiveLoadPath.current if load_path.nil? load_directives( load_path ) build_directive_maps end |
#register_directive(directive_class) ⇒ Object
Register a directive implementation.
A directive is ordinarily a subclass of MasterView::DirectiveBase.
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/masterview/directive_registry.rb', line 139 def register_directive(directive_class) # harden the DirectiveMetadata by filling in unspecified values from defaults #assert directive_class.ancestors.include? DirectiveMetadata ##AARGH: can't do this yet, the timing is premature [DJL 06-Oct-2006] #PUNT: md_defaults = load_context.nil? ? metadata_defaults_extensions : load_context[:metadata_defaults] #PUNT: directive_class.harden_metadata( md_defaults ) @loaded_classes << directive_class ##DEBUG## if TRACE_MD_HARDENING_SUBJECT and directive_class.name == TRACE_MD_HARDENING_SUBJECT STDOUT.puts "\nREGISTERED DIRECTIVE #{directive_class.name}" STDOUT.puts "...TOO SOON TO HARDEN METADATA" STDOUT.puts "...#{directive_class.metadata_values.object_id}: #{directive_class.metadata_values.inspect}\n" end ##DEBUG## end |
#registered_directive_names ⇒ Object
Answer the fully-qualified names of the registered directives
87 88 89 |
# File 'lib/masterview/directive_registry.rb', line 87 def registered_directive_names @directive_classes.keys end |
#registered_directives ⇒ Object
Answer the the registered directives
92 93 94 |
# File 'lib/masterview/directive_registry.rb', line 92 def registered_directives @directive_classes.values end |
#set_load_context(context_settings, check_for_conflict = true) ⇒ Object
:nodoc:
110 111 112 113 114 115 |
# File 'lib/masterview/directive_registry.rb', line 110 def set_load_context(context_settings, check_for_conflict=true) #:nodoc: if check_for_conflict && context_settings && @load_context raise RuntimeError, "Directive load operation already in progress: current context=#{@load_context.inspect}, requested context=#{context_settings.inspect}" end @load_context = context_settings end |
#simple_class_name(dc) ⇒ Object
Answer the simple name of a directive class (without its module qualifier)
167 168 169 |
# File 'lib/masterview/directive_registry.rb', line 167 def simple_class_name( dc ) dc.name.split(':').last end |
#update_loaded_classes_hack(already_loaded_classes) ⇒ Object
:nodoc:
43 44 45 |
# File 'lib/masterview/directive_registry.rb', line 43 def update_loaded_classes_hack(already_loaded_classes) #:nodoc: @loaded_classes.concat( already_loaded_classes ) end |