masterview 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. data/CHANGELOG +31 -1
  2. data/README +70 -69
  3. data/RELEASE_NOTES +70 -64
  4. data/Rakefile +26 -27
  5. data/TODO +13 -29
  6. data/doc/about.html +246 -0
  7. data/doc/configuration.html +49 -36
  8. data/doc/developer.html +423 -41
  9. data/doc/directives.html +139 -51
  10. data/doc/guide.html +19 -9
  11. data/doc/index.html +90 -224
  12. data/doc/installation.html +36 -28
  13. data/doc/media_list.html +30 -20
  14. data/doc/simple_diagram.html +3 -5
  15. data/doc/stylesheets/masterview.css +16 -1
  16. data/examples/rails_app_config/masterview/settings.rb +2 -1
  17. data/init.rb +1 -1
  18. data/lib/#ChangeLog# +6 -0
  19. data/lib/masterview/analyzer.rb +48 -34
  20. data/lib/masterview/attr_string_parser.rb +5 -1
  21. data/lib/masterview/case_insensitive_hash.rb +69 -0
  22. data/lib/masterview/{pathname_extensions.rb → core_ext/pathname.rb} +0 -0
  23. data/lib/masterview/{string_extensions.rb → core_ext/string.rb} +0 -0
  24. data/lib/masterview/deprecated/directive_base.rb +362 -0
  25. data/lib/masterview/directive_base.rb +201 -179
  26. data/lib/masterview/directive_dsl.rb +457 -0
  27. data/lib/masterview/directive_helpers.rb +28 -141
  28. data/lib/masterview/directive_load_path.rb +388 -0
  29. data/lib/masterview/directive_metadata.rb +377 -0
  30. data/lib/masterview/directive_registry.rb +259 -69
  31. data/lib/masterview/directives/.metadata +16 -0
  32. data/lib/masterview/directives/attr.rb +9 -8
  33. data/lib/masterview/directives/block.rb +11 -14
  34. data/lib/masterview/directives/check_box.rb +13 -18
  35. data/lib/masterview/directives/collection_select.rb +15 -29
  36. data/lib/masterview/directives/content.rb +9 -3
  37. data/lib/masterview/directives/else.rb +15 -13
  38. data/lib/masterview/directives/elsif.rb +14 -13
  39. data/lib/masterview/directives/eval.rb +20 -0
  40. data/lib/masterview/directives/form.rb +56 -9
  41. data/lib/masterview/directives/form_remote.rb +26 -0
  42. data/lib/masterview/directives/global_inline_erb.rb +10 -14
  43. data/lib/masterview/directives/hidden_field.rb +11 -20
  44. data/lib/masterview/directives/if.rb +13 -12
  45. data/lib/masterview/directives/image_tag.rb +20 -28
  46. data/lib/masterview/directives/import.rb +5 -12
  47. data/lib/masterview/directives/import_render.rb +7 -19
  48. data/lib/masterview/directives/insert_generated_comment.rb +8 -11
  49. data/lib/masterview/directives/javascript_include.rb +21 -12
  50. data/lib/masterview/directives/link_to.rb +14 -8
  51. data/lib/masterview/directives/link_to_function.rb +22 -0
  52. data/lib/masterview/directives/link_to_if.rb +15 -13
  53. data/lib/masterview/directives/link_to_remote.rb +13 -8
  54. data/lib/masterview/directives/omit_tag.rb +32 -16
  55. data/lib/masterview/directives/password_field.rb +10 -22
  56. data/lib/masterview/directives/radio_button.rb +11 -22
  57. data/lib/masterview/directives/replace.rb +7 -8
  58. data/lib/masterview/directives/select.rb +11 -24
  59. data/lib/masterview/directives/stylesheet_link.rb +20 -12
  60. data/lib/masterview/directives/submit.rb +11 -5
  61. data/lib/masterview/directives/text_area.rb +10 -23
  62. data/lib/masterview/directives/text_field.rb +10 -22
  63. data/lib/masterview/exceptions.rb +21 -0
  64. data/lib/masterview/extras/app/controllers/masterview_controller.rb +102 -75
  65. data/lib/masterview/extras/app/views/layouts/masterview_admin.rhtml +24 -23
  66. data/lib/masterview/extras/app/views/layouts/masterview_admin_config.rhtml +81 -0
  67. data/lib/masterview/extras/app/views/masterview/admin/configuration.rhtml +5 -1
  68. data/lib/masterview/extras/app/views/masterview/admin/create.rhtml +2 -2
  69. data/lib/masterview/extras/app/views/masterview/admin/directives.rhtml +5 -0
  70. data/lib/masterview/extras/app/views/masterview/admin/features.rhtml +5 -79
  71. data/lib/masterview/extras/app/views/masterview/admin/interact.rhtml +5 -0
  72. data/lib/masterview/extras/app/views/masterview/admin/list.rhtml +3 -71
  73. data/lib/masterview/extras/init_mv_admin_pages.rb +42 -23
  74. data/lib/masterview/filter_helpers.rb +26 -0
  75. data/lib/masterview/initializer.rb +99 -53
  76. data/lib/masterview/io.rb +19 -15
  77. data/lib/masterview/keyword_expander.rb +7 -2
  78. data/lib/masterview/masterview_info.rb +229 -23
  79. data/lib/masterview/masterview_version.rb +2 -2
  80. data/lib/masterview/parser.rb +275 -105
  81. data/lib/masterview/parser_helpers.rb +54 -0
  82. data/lib/masterview/rails_ext/action_controller_erb_direct.rb +29 -0
  83. data/lib/masterview/rails_ext/action_controller_reparse_checking.rb +27 -0
  84. data/lib/masterview/{extras/init_rails_erb_mv_direct.rb → rails_ext/action_view_erb_direct.rb} +12 -59
  85. data/lib/masterview/template_spec.rb +3 -2
  86. data/lib/masterview.rb +21 -12
  87. data/lib/rexml/parsers/baseparser_with_doctype_fix.rb +473 -0
  88. data/lib/rexml/parsers/sax2parser_with_doctype_fix.rb +243 -0
  89. data/test/directive_test_helper.rb +135 -0
  90. data/test/fixtures/directives/id_check.rb +18 -0
  91. data/test/fixtures/directives/test_directive_events.rb +70 -0
  92. data/test/test_helper.rb +18 -5
  93. data/test/tmp/views/layouts/product.rhtml +10 -10
  94. data/test/tmp/views/product/_form.rhtml +4 -4
  95. data/test/tmp/views/product/_product.rhtml +3 -3
  96. data/test/tmp/views/product/destroy.rhtml +5 -5
  97. data/test/tmp/views/product/edit.rhtml +4 -4
  98. data/test/tmp/views/product/list.rhtml +3 -3
  99. data/test/tmp/views/product/new.rhtml +4 -4
  100. data/test/tmp/views/product/show.rhtml +2 -2
  101. data/test/unit/attr_string_parser_test.rb +105 -0
  102. data/test/unit/case_insensitive_hash_mod_test.rb +104 -0
  103. data/test/unit/config_settings_test.rb +13 -1
  104. data/test/unit/default_generate_mio_filter_test.rb +3 -3
  105. data/test/unit/deprecated_directive_base_test.rb +30 -0
  106. data/test/unit/directive_attr_test.rb +111 -35
  107. data/test/unit/directive_base_test.rb +520 -1
  108. data/test/unit/directive_block_test.rb +30 -22
  109. data/test/unit/directive_content_test.rb +24 -11
  110. data/test/unit/directive_else_test.rb +18 -15
  111. data/test/unit/directive_elsif_test.rb +17 -15
  112. data/test/unit/directive_form_remote_test.rb +59 -0
  113. data/test/unit/directive_form_test.rb +31 -39
  114. data/test/unit/directive_global_inline_erb_test.rb +28 -17
  115. data/test/unit/directive_grid_test_notready.rb +38 -0
  116. data/test/unit/directive_helpers_test.rb +39 -0
  117. data/test/unit/directive_hidden_field_test.rb +44 -29
  118. data/test/unit/directive_if_test.rb +10 -7
  119. data/test/unit/directive_image_tag_test.rb +69 -61
  120. data/test/unit/directive_import_render_test.rb +28 -38
  121. data/test/unit/directive_import_test.rb +16 -14
  122. data/test/unit/directive_insert_generated_comment_test.rb +32 -0
  123. data/test/unit/directive_javascript_include_test.rb +40 -43
  124. data/test/unit/directive_link_to_function_test.rb +40 -0
  125. data/test/unit/directive_link_to_if_test.rb +52 -12
  126. data/test/unit/directive_link_to_remote_test.rb +58 -0
  127. data/test/unit/directive_link_to_test.rb +46 -31
  128. data/test/unit/directive_load_path_test.rb +257 -0
  129. data/test/unit/directive_metadata_test.rb +313 -0
  130. data/test/unit/directive_omit_tag_test.rb +73 -21
  131. data/test/unit/directive_password_field_test.rb +44 -38
  132. data/test/unit/directive_registry_test.rb +44 -0
  133. data/test/unit/directive_replace_test.rb +28 -12
  134. data/test/unit/directive_stylesheet_link_test.rb +43 -36
  135. data/test/unit/directive_submit_test.rb +29 -30
  136. data/test/unit/directive_text_area_test.rb +40 -36
  137. data/test/unit/directive_text_field_test.rb +44 -38
  138. data/test/unit/example_directive_child_events_test.rb +41 -0
  139. data/test/unit/example_test.rb +31 -4
  140. data/test/unit/file_mio_test.rb +18 -13
  141. data/test/unit/filter_helpers_test.rb +10 -8
  142. data/test/unit/find_directive_parent_test.rb +174 -0
  143. data/test/unit/keyword_expander_test.rb +4 -2
  144. data/test/unit/mio_test.rb +18 -11
  145. data/test/unit/mtime_string_hash_mio_tree_test.rb +5 -1
  146. data/test/unit/parser_test.rb +41 -29
  147. data/test/unit/pathname_extensions_test.rb +1 -1
  148. data/test/unit/run_parser_test.rb +2 -2
  149. data/test/unit/simplified_directive_base_test.rb +256 -0
  150. data/test/unit/string_hash_mio_test.rb +5 -1
  151. data/test/unit/template_file_watcher_test.rb +2 -2
  152. data/test/unit/template_test.rb +221 -46
  153. metadata +86 -45
  154. data/lib/masterview/directives/testfilter.rb +0 -55
  155. data/lib/masterview/extras/init_rails_reparse_checking.rb +0 -62
@@ -0,0 +1,377 @@
1
+ module MasterView
2
+
3
+ # Mixin for directives to provide metadata specifications
4
+ #
5
+ # All directives have a standard set of metadata properties:
6
+ # :attribute_name - the (unqualified) directive attribute name
7
+ # :namespace - the namespace name for the qualified directive name
8
+ # :attribute_qname - the fully-qualified directive name (ns:attribute)
9
+ # :priority - the DirectivePriority for processing
10
+ #
11
+ # Additional properties can be set to provide documentation and usage
12
+ # information (:summary, :description) or to record custom settings.
13
+ #
14
+ #--
15
+ #TBD: How can we automatically extract directive rdoc from its class??
16
+ #++
17
+ #
18
+ module DirectiveMetadata
19
+
20
+ DEBUG_MD_INSTALLATION = false #:nodoc:
21
+ DEBUG_MD_PROPS = false #:nodoc:
22
+
23
+ # well-known metadata properties
24
+ MARKUP_PROPERTY_NAMES = [ :namespace, :namespace_prefix, :attribute_name, :attribute_qname ] #:nodoc:
25
+ PROCESSING_PROPERTY_NAMES = [ :priority ] #:nodoc:
26
+ DOC_PROPERTY_NAMES = [ :summary, :description ] #:nodoc:
27
+ STANDARD_PROPERTY_NAMES = MARKUP_PROPERTY_NAMES + PROCESSING_PROPERTY_NAMES + DOC_PROPERTY_NAMES #:nodoc:
28
+ HARDENED_PROPERTY_NAMES = MARKUP_PROPERTY_NAMES + PROCESSING_PROPERTY_NAMES #:nodoc:
29
+
30
+ # implementation hack for DirectiveMetadata class var
31
+ # putting class var @@metadata_values got muddled by subclassing, punt to this scheme
32
+ DirectiveMetadataRegistry = {} #:nodoc:
33
+
34
+ #convenience constants defined to allow priority to directives
35
+ #higher priority (lower value) will be executed first in chain
36
+ module DirectivePriorities
37
+ Highest = 0
38
+ UltraHigh = 0x3FFFFFFF/16
39
+ VeryHigh = 0x3FFFFFFF/8
40
+ High = 0x3FFFFFFF/4
41
+ MediumHigh = 0x3FFFFFFF/3
42
+ Medium = 0x3FFFFFFF/2
43
+ MediumLow = (0x3FFFFFFF/3)*2
44
+ Low = (0x3FFFFFFF/4)*3
45
+ VeryLow = (0x3FFFFFFF/8)*7
46
+ UltraLow = (0x3FFFFFFF/16)*15
47
+ Lowest = 0x3FFFFFFF
48
+ # convenience
49
+ Default = Medium
50
+ end
51
+
52
+ PriorityNames = [] #:nodoc:
53
+ PrioritiesMap = {} #:nodoc:
54
+ DirectivePriorities.constants.each { | const_name |
55
+ level_name = const_name.to_s #???
56
+ next if level_name == 'Default' # only record real names
57
+ PriorityNames << level_name
58
+ PrioritiesMap[DirectivePriorities.const_get(const_name)] = level_name
59
+ }
60
+ # Answer the name of a priority level
61
+ def self.get_priority_name(priority) #:nodoc:
62
+ PrioritiesMap.fetch( priority, priority.to_s ) #?? "%08x" % priority
63
+ end
64
+
65
+ def self.get_priority_label(priority) #:nodoc:
66
+ name = get_priority_name(priority)
67
+ # 'default (Med)' was nicer, but admin page doesn't format width properly
68
+ name = 'default' if priority == DirectivePriorities::Default
69
+ name
70
+ end
71
+
72
+ # Answer whether a name is a legal XML markup identifier.
73
+ # Used to validate attribute and namespace names for directives.
74
+ #
75
+ def self.validate_xml_identifier(name)
76
+ #todo: add re defn to verify syntactically legal xml id
77
+ # XML 1.0 spec: A Name is a token beginning with a letter or one of a few
78
+ # punctuation characters, and continuing with letters, digits, hyphens,
79
+ # underscores, colons, or full stops, together known as name characters.
80
+ #TODO: name =~ /^[a-zA-Z](\w|-|_)*$/
81
+ true
82
+ end
83
+
84
+ # Ensure that a set of metadata values are valid and consistent.
85
+ # This is a banger because it takes liberties normalizing the properties.
86
+ def self.validate_metadata_props!(md_props)
87
+
88
+ md_prop_name = :attribute_name
89
+ if md_props.has_key?( md_prop_name )
90
+ attr_name = md_props[md_prop_name]
91
+ raise ArgumentError, "Invalid #{md_prop_name.inspect} '#{attr_name}'" if ! DirectiveMetadata.validate_xml_identifier(attr_name)
92
+ end
93
+
94
+ # allow :namespace_name as a synonym for :namespace
95
+ md_prop_name = :namespace_name
96
+ if md_props.has_key?( md_prop_name )
97
+ ns_name = md_props[md_prop_name]
98
+ if md_props.has_key?(:namespace)
99
+ # we actually ought to just unconditionally complain, it's silly and redundant to do both of these
100
+ other_ns_name = md_props[:namespace]
101
+ raise ArgumentError, "Inconsistent namespace settigs (:namespace='#{other_ns_name}', :namespace_name='#{ns_name}')" if other_ns_name != ns_name
102
+ else
103
+ md_props[:namespace] = ns_name
104
+ end
105
+ # always get rid of :namespace_name, we just want to record :namespace
106
+ md_props.delete(md_prop_name)
107
+ end
108
+
109
+ md_prop_name = :namespace
110
+ if md_props.has_key?( md_prop_name )
111
+ ns_name = md_props[md_prop_name]
112
+ raise ArgumentError, "Invalid #{md_prop_name.inspect} '#{ns_name}'" if ns_name[-1..-1] == ':'
113
+ raise ArgumentError, "Invalid #{md_prop_name.inspect} '#{ns_name}'" if ! DirectiveMetadata.validate_xml_identifier(ns_name)
114
+ # ensure both namespace props we use are present and consistent
115
+ ns_prefix = "#{ns_name}:"
116
+ if md_props.has_key?( :namespace_prefix )
117
+ ns_prefix_prop = md_props[:namespace_prefix]
118
+ raise ArgumentError, "Inconsistent namespace settings (:namespace='#{ns_name}', :namespace_prefix='#{ns_prefix_prop}')" if ns_prefix_prop != ns_prefix
119
+ else
120
+ md_props[:namespace_prefix] = ns_prefix
121
+ end
122
+ end
123
+
124
+ md_prop_name = :namespace_prefix
125
+ if md_props.has_key?( md_prop_name )
126
+ ns_prefix = md_props[md_prop_name]
127
+ raise ArgumentError, "Invalid #{md_prop_name.inspect} '#{ns_prefix}'" if ns_prefix[-1..-1] != ':'
128
+ ns_name = ns_prefix[0...-1]
129
+ raise ArgumentError, "Invalid #{md_prop_name.inspect} '#{ns_prefix}'" if ! DirectiveMetadata.validate_xml_identifier(ns_name)
130
+ # ensure namespace settings are both present and consistent
131
+ if md_props.has_key?( :namespace )
132
+ ns_name_prop = md_props[:namespace]
133
+ raise ArgumentError, "Inconsistent namespace settings (:namespace='#{ns_name_prop}', :namespace_prefix='#{ns_prefix}')" if ns_name_prop != ns_name
134
+ else
135
+ md_props[:namespace] = ns_name
136
+ end
137
+ end
138
+
139
+ md_prop_name = :priority
140
+ if md_props.has_key?( md_prop_name )
141
+ priority = md_props[md_prop_name]
142
+ if priority.is_a?( String ) || priority.is_a?( Symbol )
143
+ begin
144
+ priority = 'Default' if [ 'default', :default ].include?(priority) #synonyms
145
+ priority = DirectiveMetadata::DirectivePriorities.const_get(priority)
146
+ md_props[md_prop_name] = priority
147
+ rescue NameError
148
+ #invalid priority name - fall through to error code below
149
+ end
150
+ end
151
+ priority_range = (DirectiveMetadata::DirectivePriorities::Highest..DirectiveMetadata::DirectivePriorities::Lowest)
152
+ raise ArgumentError, "Invalid #{md_prop_name.inspect}: #{md_props[md_prop_name].inspect}" if ! (priority_range.include? priority)
153
+ end
154
+
155
+ if DEBUG_MD_PROPS
156
+ err_msg = "BAD DIRECTIVE MD PROPS: #{md_props.inspect}"
157
+ raise RuntimeError, err_msg if md_props.has_key?(:namespace_name) # temp check on internal impl rework cutover
158
+ raise RuntimeError, err_msg if (md_props.has_key?(:namespace) && ! md_props.has_key?(:namespace_prefix))
159
+ raise RuntimeError, err_msg if (md_props.has_key?(:namespace_prefix) && ! md_props.has_key?(:namespace))
160
+ #??raise RuntimeError, err_msg if md_props.has_key?(:attribute_qname)???
161
+ end
162
+
163
+ end
164
+
165
+ module ClassMethods
166
+
167
+ # the metadata values for the directive class
168
+ def metadata_values #:nodoc:
169
+ return DirectiveMetadataRegistry[self.name] || {}
170
+ end
171
+ def self.extended(base) #:nodoc:
172
+ STDOUT.puts "...adding #{self} into #{base} (id=#{base.object_id})" if DEBUG_MD_INSTALLATION
173
+ #base.class_eval '@@metadata_values = {}'
174
+ #md_accessor_code = <<-END
175
+ # def #{base}.metadata_values
176
+ # @@metadata_values ||= {}
177
+ # end
178
+ #END
179
+ #base.class_eval md_accessor_code
180
+ DirectiveMetadataRegistry[base.name] = {}
181
+ STDOUT.puts "...#{base}.@@metadata_values=#{base.metadata_values.object_id}" if DEBUG_MD_INSTALLATION
182
+ end
183
+ def self.inherited(directive_class) #:nodoc:
184
+ STDOUT.puts "\n###inherited #{self} in #{directive_class} (id=#{directive_class.object_id})" if DEBUG_MD_INSTALLATION
185
+ #directive_class.class_eval '@@metadata_values = {}'
186
+ #md_accessor_code = <<-END
187
+ # def #{directive_class}.metadata_values
188
+ # @@metadata_values ||= {}
189
+ # end
190
+ #END
191
+ #directive_class.class_eval md_accessor_code
192
+ DirectiveMetadataRegistry[directive_class.name] = {}
193
+ STDOUT.puts "...#{directive_class}.@@metadata_values=#{directive_class.metadata_values.object_id}" if DEBUG_MD_INSTALLATION
194
+ end
195
+
196
+ # Answer the (unqualified) attribute name of the directive
197
+ def attribute_name
198
+ metadata_values[:attribute_name] || default_directive_name
199
+ end
200
+
201
+ def namespace
202
+ metadata_values[:namespace] || default_namespace_prefix[0...-1]
203
+ end
204
+
205
+ ##ISSUE: deprecate this??
206
+ def namespace_name
207
+ namespace
208
+ end
209
+
210
+ def namespace_prefix
211
+ metadata_values[:namespace_prefix] || default_namespace_prefix
212
+ end
213
+
214
+ # Answer the fully-qualified attribute name of the directive
215
+ def attribute_qname
216
+ metadata_values[:attribute_qname] || "#{namespace}:#{attribute_name}"
217
+ end
218
+
219
+ def priority
220
+ metadata_values[:priority] || DirectivePriorities::Default
221
+ end
222
+
223
+ # Answer the default directive attribute name for a directive class.
224
+ #
225
+ # If not explicitly specified, lowercased name of the class is
226
+ # assumed to be the attribute name used in template markup.
227
+ #
228
+ def default_directive_name #:nodoc:
229
+ simple_name = self.name.split(':').last # strip off module qualifiers
230
+ simple_name = simple_name.downcase_first_letter
231
+ # convert camel-case class name FooBar to snake-case foo_bar
232
+ simple_name.gsub( /[A-Z]/ ) { |letter| "_#{letter.downcase}" }
233
+ end
234
+
235
+ # Answer the default namespace prefix for a directive class.
236
+ #
237
+ def default_namespace_prefix #:nodoc:
238
+ # this is a bit squirrelly to rely on module namespace convention
239
+ # masterview brings in String#starts_with? from facets, thank you
240
+ if self.name.starts_with?('MasterView::Directives::')
241
+ MasterView::ConfigSettings.namespace_prefix
242
+ else
243
+ MasterView::ConfigSettings.namespace_prefix_extensions
244
+ end
245
+ end
246
+
247
+ # Declare metadata properties of the directive
248
+ # Specify one more prop_name => value entries
249
+ # :attibute_name, :namespace, :summary, :description
250
+ def metadata(md_props)
251
+ md_props = md_props.clone
252
+ DirectiveMetadata.validate_metadata_props!(md_props)
253
+ if ! DirectiveMetadataRegistry.has_key?( self.name )
254
+ DirectiveMetadataRegistry[self.name] = {}
255
+ STDOUT.puts "...#{self}.@@metadata_values=#{self.metadata_values.object_id} <metadata decl>" if DEBUG_MD_INSTALLATION
256
+ else
257
+ # ISSUE: not clear why we need to do this, but something's getting initialized
258
+ # by initial class load/include/extend magic that I can't figure out.
259
+ # This probably is safe, there should be exactly one metadata decl in
260
+ # a directive implementation and it should probably always have a clean
261
+ # point of view.
262
+ # [DJL 06-Oct-2006]
263
+ DirectiveMetadataRegistry[self.name].clear()
264
+ end
265
+ metadata_values.merge! md_props
266
+ end
267
+
268
+ # Fill in any defaults and ensure that all required metadata properties are defined.
269
+ #
270
+ # Ordinarily done exactly once by the directive loading mechanisms.
271
+ #
272
+ def harden_metadata(defaults={})
273
+ trace_enabled = DEBUG_MD_PROPS || DEBUG_MD_INSTALLATION
274
+ if ! DirectiveMetadataRegistry.has_key?( self.name )
275
+ DirectiveMetadataRegistry[self.name] = {}
276
+ STDOUT.puts "...#{self}.@@metadata_values=#{self.metadata_values.inspect} (id=#{self.metadata_values.object_id}) <harden_metadata>" if trace_enabled
277
+ STDOUT.puts "...DirectiveMetadataRegistry=#{DirectiveMetadataRegistry.inspect}" if trace_enabled
278
+ end
279
+ dc_md = metadata_values
280
+ STDOUT.puts "\n****HARDENING: #{self}.metadata_values=#{dc_md.inspect} (id=#{dc_md.object_id})" if trace_enabled
281
+ # install any defaults for properties which aren't explicitly set
282
+ md_to_add = defaults.reject { |key, value| dc_md.has_key?( key ) }
283
+ #assert ! md_to_add.equal?(defaults), 'safe to mess with our own copy now'
284
+ DirectiveMetadata.validate_metadata_props!( md_to_add ) # this should check and normalize any namespace-related entries
285
+ raise RuntimeError, "BAD: attr naming inappropriate in md defaults #{md_to_add.inspect}" if md_to_add.has_key?(:attribute_name) || md_to_add.has_key?(:attribute_qname)
286
+ # ensure that required properties are set
287
+ if ! dc_md.has_key?( :attribute_name )
288
+ md_to_add[:attribute_name] = default_directive_name
289
+ end
290
+ if ! dc_md.has_key?( :priority )
291
+ md_to_add[:priority] = DirectivePriorities::Default
292
+ end
293
+ if ! dc_md.has_key?( :namespace )
294
+ raise RuntimeError, "BUG: inconsistent #{self.name}.metadata_values ns entries: #{dc_md.inspect}" if dc_md.has_key?(:namespace_prefix) || dc_md.has_key?(:attribute_qname)
295
+ if md_to_add.has_key?( :namespace )
296
+ #ok, we'll fill in namespace from defaults
297
+ # quadruple-check programming errors in this mess until this stuff stabilizes [DJL 06-Oct-2006]
298
+ raise RuntimeError, 'BUG: validate_metadata_props! did not handle defaults normalization: #{md_to_add.inspect}' if ! md_to_add.has_key?(:namespace_prefix)
299
+ elsif md_to_add.has_key?( :namespace_prefix )
300
+ # quadruple-check programming errors in this mess until this stuff stabilizes [DJL 06-Oct-2006]
301
+ raise RuntimeError, 'BUG: validate_metadata_props! did not handle defaults normalization: #{md_to_add.inspect}'
302
+ else
303
+ default_prefix = default_namespace_prefix
304
+ md_to_add[:namespace] = default_prefix[0...-1]
305
+ md_to_add[:namespace_prefix] = default_prefix
306
+ end
307
+ end
308
+ if ! dc_md.has_key?( :namespace_prefix )
309
+ # we should have just taken care of this
310
+ raise RuntimeError, "BUG: inconsistent #{self.name}.metadata_values ns entries: #{dc_md.inspect}" if dc_md.has_key?(:namespace) || dc_md.has_key?(:attribute_qname)
311
+ raise RuntimeError, "BUG: incorrect construction of #{self.name} md_to_add: #{md_to_add}" if ! (md_to_add.has_key?(:namespace) && md_to_add.has_key?(:namespace_prefix))
312
+ end
313
+ dc_md.merge! md_to_add
314
+ #assert dc_md.has_key?( :namespace) && dc_md.has_key?( :namespace_prefix)
315
+ if true # ! dc_md.has_key?( :attribute_qname )
316
+ # just always do this, there's something funky about load/include/extend
317
+ # somehow we're getting backstop defaults in ahead of even the first class load
318
+ # I do not understand something subtle, so giving up and just hammering here [DJL 06-Oct-2006]
319
+ dc_md[:attribute_qname] = "#{dc_md[:namespace]}:#{dc_md[:attribute_name]}"
320
+ end
321
+ #???dc_md[:hardened] = true???
322
+ #??dc_md.freeze
323
+ if DEBUG_MD_PROPS
324
+ # quadruple-check programming errors in this mess until this stuff stabilizes [DJL 06-Oct-2006]
325
+ oops = false
326
+ HARDENED_PROPERTY_NAMES.each { |md_prop_name| oops = true if ! metadata_values.has_key?(md_prop_name) }
327
+ if oops
328
+ raise RuntimeError, "BAD MD HARDENING IN #{self.name}: #{metadata_values.inspect}"
329
+ end
330
+ if metadata_values[:namespace_prefix] != "#{metadata_values[:namespace]}:"
331
+ raise RuntimeError, "BAD MD HARDENING IN #{self.name}: #{metadata_values.inspect}"
332
+ end
333
+ if metadata_values[:attribute_qname] != "#{metadata_values[:namespace]}:#{metadata_values[:attribute_name]}"
334
+ raise RuntimeError, "BAD MD HARDENING IN #{self.name}: #{metadata_values.inspect}"
335
+ end
336
+ end
337
+ STDOUT.puts "...HARDENED MD: #{self.metadata_values.inspect}\n" if DEBUG_MD_PROPS
338
+ end
339
+
340
+ end #ClassMethods
341
+
342
+ # add class methods for DSL declarations to class which is mixing in DirectiveMetadata
343
+ def self.included(base) #:nodoc:
344
+ STDOUT.puts "\n####Mixing #{self} into #{base} (id=#{base.object_id})" if DEBUG_MD_INSTALLATION
345
+ base.extend(ClassMethods)
346
+ end
347
+
348
+ # Answer the (unqualified) attribute name used in template document markup
349
+ # for this directive.
350
+ def attribute_name
351
+ self.class.attribute_name
352
+ end
353
+
354
+ def namespace
355
+ self.class.namespace
356
+ end
357
+
358
+ def namespace_name
359
+ self.class.namespace_name
360
+ end
361
+
362
+ def namespace_prefix
363
+ self.class.namespace_prefix
364
+ end
365
+
366
+ # Answer the fully-qualified attribute name of the directive
367
+ def attribute_qname
368
+ self.class.attribute_qname
369
+ end
370
+
371
+ def priority
372
+ return self.class.priority
373
+ end
374
+
375
+ end
376
+
377
+ end