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.
- data/CHANGELOG +31 -1
- data/README +70 -69
- data/RELEASE_NOTES +70 -64
- data/Rakefile +26 -27
- data/TODO +13 -29
- data/doc/about.html +246 -0
- data/doc/configuration.html +49 -36
- data/doc/developer.html +423 -41
- data/doc/directives.html +139 -51
- data/doc/guide.html +19 -9
- data/doc/index.html +90 -224
- data/doc/installation.html +36 -28
- data/doc/media_list.html +30 -20
- data/doc/simple_diagram.html +3 -5
- data/doc/stylesheets/masterview.css +16 -1
- data/examples/rails_app_config/masterview/settings.rb +2 -1
- data/init.rb +1 -1
- data/lib/#ChangeLog# +6 -0
- data/lib/masterview/analyzer.rb +48 -34
- data/lib/masterview/attr_string_parser.rb +5 -1
- data/lib/masterview/case_insensitive_hash.rb +69 -0
- data/lib/masterview/{pathname_extensions.rb → core_ext/pathname.rb} +0 -0
- data/lib/masterview/{string_extensions.rb → core_ext/string.rb} +0 -0
- data/lib/masterview/deprecated/directive_base.rb +362 -0
- data/lib/masterview/directive_base.rb +201 -179
- data/lib/masterview/directive_dsl.rb +457 -0
- data/lib/masterview/directive_helpers.rb +28 -141
- data/lib/masterview/directive_load_path.rb +388 -0
- data/lib/masterview/directive_metadata.rb +377 -0
- data/lib/masterview/directive_registry.rb +259 -69
- data/lib/masterview/directives/.metadata +16 -0
- data/lib/masterview/directives/attr.rb +9 -8
- data/lib/masterview/directives/block.rb +11 -14
- data/lib/masterview/directives/check_box.rb +13 -18
- data/lib/masterview/directives/collection_select.rb +15 -29
- data/lib/masterview/directives/content.rb +9 -3
- data/lib/masterview/directives/else.rb +15 -13
- data/lib/masterview/directives/elsif.rb +14 -13
- data/lib/masterview/directives/eval.rb +20 -0
- data/lib/masterview/directives/form.rb +56 -9
- data/lib/masterview/directives/form_remote.rb +26 -0
- data/lib/masterview/directives/global_inline_erb.rb +10 -14
- data/lib/masterview/directives/hidden_field.rb +11 -20
- data/lib/masterview/directives/if.rb +13 -12
- data/lib/masterview/directives/image_tag.rb +20 -28
- data/lib/masterview/directives/import.rb +5 -12
- data/lib/masterview/directives/import_render.rb +7 -19
- data/lib/masterview/directives/insert_generated_comment.rb +8 -11
- data/lib/masterview/directives/javascript_include.rb +21 -12
- data/lib/masterview/directives/link_to.rb +14 -8
- data/lib/masterview/directives/link_to_function.rb +22 -0
- data/lib/masterview/directives/link_to_if.rb +15 -13
- data/lib/masterview/directives/link_to_remote.rb +13 -8
- data/lib/masterview/directives/omit_tag.rb +32 -16
- data/lib/masterview/directives/password_field.rb +10 -22
- data/lib/masterview/directives/radio_button.rb +11 -22
- data/lib/masterview/directives/replace.rb +7 -8
- data/lib/masterview/directives/select.rb +11 -24
- data/lib/masterview/directives/stylesheet_link.rb +20 -12
- data/lib/masterview/directives/submit.rb +11 -5
- data/lib/masterview/directives/text_area.rb +10 -23
- data/lib/masterview/directives/text_field.rb +10 -22
- data/lib/masterview/exceptions.rb +21 -0
- data/lib/masterview/extras/app/controllers/masterview_controller.rb +102 -75
- data/lib/masterview/extras/app/views/layouts/masterview_admin.rhtml +24 -23
- data/lib/masterview/extras/app/views/layouts/masterview_admin_config.rhtml +81 -0
- data/lib/masterview/extras/app/views/masterview/admin/configuration.rhtml +5 -1
- data/lib/masterview/extras/app/views/masterview/admin/create.rhtml +2 -2
- data/lib/masterview/extras/app/views/masterview/admin/directives.rhtml +5 -0
- data/lib/masterview/extras/app/views/masterview/admin/features.rhtml +5 -79
- data/lib/masterview/extras/app/views/masterview/admin/interact.rhtml +5 -0
- data/lib/masterview/extras/app/views/masterview/admin/list.rhtml +3 -71
- data/lib/masterview/extras/init_mv_admin_pages.rb +42 -23
- data/lib/masterview/filter_helpers.rb +26 -0
- data/lib/masterview/initializer.rb +99 -53
- data/lib/masterview/io.rb +19 -15
- data/lib/masterview/keyword_expander.rb +7 -2
- data/lib/masterview/masterview_info.rb +229 -23
- data/lib/masterview/masterview_version.rb +2 -2
- data/lib/masterview/parser.rb +275 -105
- data/lib/masterview/parser_helpers.rb +54 -0
- data/lib/masterview/rails_ext/action_controller_erb_direct.rb +29 -0
- data/lib/masterview/rails_ext/action_controller_reparse_checking.rb +27 -0
- data/lib/masterview/{extras/init_rails_erb_mv_direct.rb → rails_ext/action_view_erb_direct.rb} +12 -59
- data/lib/masterview/template_spec.rb +3 -2
- data/lib/masterview.rb +21 -12
- data/lib/rexml/parsers/baseparser_with_doctype_fix.rb +473 -0
- data/lib/rexml/parsers/sax2parser_with_doctype_fix.rb +243 -0
- data/test/directive_test_helper.rb +135 -0
- data/test/fixtures/directives/id_check.rb +18 -0
- data/test/fixtures/directives/test_directive_events.rb +70 -0
- data/test/test_helper.rb +18 -5
- data/test/tmp/views/layouts/product.rhtml +10 -10
- data/test/tmp/views/product/_form.rhtml +4 -4
- data/test/tmp/views/product/_product.rhtml +3 -3
- data/test/tmp/views/product/destroy.rhtml +5 -5
- data/test/tmp/views/product/edit.rhtml +4 -4
- data/test/tmp/views/product/list.rhtml +3 -3
- data/test/tmp/views/product/new.rhtml +4 -4
- data/test/tmp/views/product/show.rhtml +2 -2
- data/test/unit/attr_string_parser_test.rb +105 -0
- data/test/unit/case_insensitive_hash_mod_test.rb +104 -0
- data/test/unit/config_settings_test.rb +13 -1
- data/test/unit/default_generate_mio_filter_test.rb +3 -3
- data/test/unit/deprecated_directive_base_test.rb +30 -0
- data/test/unit/directive_attr_test.rb +111 -35
- data/test/unit/directive_base_test.rb +520 -1
- data/test/unit/directive_block_test.rb +30 -22
- data/test/unit/directive_content_test.rb +24 -11
- data/test/unit/directive_else_test.rb +18 -15
- data/test/unit/directive_elsif_test.rb +17 -15
- data/test/unit/directive_form_remote_test.rb +59 -0
- data/test/unit/directive_form_test.rb +31 -39
- data/test/unit/directive_global_inline_erb_test.rb +28 -17
- data/test/unit/directive_grid_test_notready.rb +38 -0
- data/test/unit/directive_helpers_test.rb +39 -0
- data/test/unit/directive_hidden_field_test.rb +44 -29
- data/test/unit/directive_if_test.rb +10 -7
- data/test/unit/directive_image_tag_test.rb +69 -61
- data/test/unit/directive_import_render_test.rb +28 -38
- data/test/unit/directive_import_test.rb +16 -14
- data/test/unit/directive_insert_generated_comment_test.rb +32 -0
- data/test/unit/directive_javascript_include_test.rb +40 -43
- data/test/unit/directive_link_to_function_test.rb +40 -0
- data/test/unit/directive_link_to_if_test.rb +52 -12
- data/test/unit/directive_link_to_remote_test.rb +58 -0
- data/test/unit/directive_link_to_test.rb +46 -31
- data/test/unit/directive_load_path_test.rb +257 -0
- data/test/unit/directive_metadata_test.rb +313 -0
- data/test/unit/directive_omit_tag_test.rb +73 -21
- data/test/unit/directive_password_field_test.rb +44 -38
- data/test/unit/directive_registry_test.rb +44 -0
- data/test/unit/directive_replace_test.rb +28 -12
- data/test/unit/directive_stylesheet_link_test.rb +43 -36
- data/test/unit/directive_submit_test.rb +29 -30
- data/test/unit/directive_text_area_test.rb +40 -36
- data/test/unit/directive_text_field_test.rb +44 -38
- data/test/unit/example_directive_child_events_test.rb +41 -0
- data/test/unit/example_test.rb +31 -4
- data/test/unit/file_mio_test.rb +18 -13
- data/test/unit/filter_helpers_test.rb +10 -8
- data/test/unit/find_directive_parent_test.rb +174 -0
- data/test/unit/keyword_expander_test.rb +4 -2
- data/test/unit/mio_test.rb +18 -11
- data/test/unit/mtime_string_hash_mio_tree_test.rb +5 -1
- data/test/unit/parser_test.rb +41 -29
- data/test/unit/pathname_extensions_test.rb +1 -1
- data/test/unit/run_parser_test.rb +2 -2
- data/test/unit/simplified_directive_base_test.rb +256 -0
- data/test/unit/string_hash_mio_test.rb +5 -1
- data/test/unit/template_file_watcher_test.rb +2 -2
- data/test/unit/template_test.rb +221 -46
- metadata +86 -45
- data/lib/masterview/directives/testfilter.rb +0 -55
- data/lib/masterview/extras/init_rails_reparse_checking.rb +0 -62
@@ -0,0 +1,388 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require File.join( File.dirname(__FILE__), 'exceptions' )
|
3
|
+
|
4
|
+
module MasterView
|
5
|
+
|
6
|
+
# An InvalidPathError that is raised when an invalid directory path
|
7
|
+
# is encountered on the directive load path.
|
8
|
+
class InvalidDirectivePathError < InvalidPathError
|
9
|
+
|
10
|
+
# the directive load path entry containing the invalid directory path
|
11
|
+
def path_entry
|
12
|
+
@dpe || nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize( dpe, err_msg )
|
16
|
+
super(dpe.dir_path, err_msg)
|
17
|
+
@dpe = dpe
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# The directive load path supports configuring a MasterView application
|
24
|
+
# with a list of directories from which directives are loaded.
|
25
|
+
#
|
26
|
+
# A MasterView application is always configured with the standard set of
|
27
|
+
# built-in directives, customarily referenced in templates in the
|
28
|
+
# <code>mv:</code> namespace. Additional directives can be used by
|
29
|
+
# appending directories containing the directive implementations
|
30
|
+
# to the MasterView load path specified by the Configuration.
|
31
|
+
#
|
32
|
+
module DirectiveLoadPath
|
33
|
+
|
34
|
+
# File name of metadata specs file in a directives directory
|
35
|
+
# Contains yaml specifications for directive implementations
|
36
|
+
METADATA_SPECS_FILE_NAME = '.metadata'
|
37
|
+
|
38
|
+
DEBUG_MD_DIR_SPECS = false #:nodoc: ##DEBUG##
|
39
|
+
|
40
|
+
@@path_registry = {} #:nodoc:
|
41
|
+
#cattr_reader :path_registry
|
42
|
+
def self.path_registry #:nodoc: # special hook for test cases fiddling with system state
|
43
|
+
@@path_registry
|
44
|
+
end
|
45
|
+
|
46
|
+
# Answer the directives load path specs for the current load path
|
47
|
+
def self.current
|
48
|
+
@@path_registry[:current]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Answer the default directives load path specs
|
52
|
+
def self.default_path_specs #:nodoc:
|
53
|
+
@@path_registry[:default]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Install the configured load path
|
57
|
+
def self.default_path_specs=(load_path) #:nodoc:
|
58
|
+
@@path_registry[:default] = load_path.nil? ? nil : clone_path(load_path)
|
59
|
+
if load_path && ! @@path_registry.has_key?(:current)
|
60
|
+
@@path_registry[:current] = clone_path(load_path)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# hook for test cases so they can ensure a clean system state
|
65
|
+
def self.reset_current() #:nodoc:
|
66
|
+
load_path = self.default_path_specs
|
67
|
+
@@path_registry[:current] = load_path.nil? ? nil : clone_path(load_path)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Answer a clone copy of a directive load path
|
71
|
+
#
|
72
|
+
# Does a deep_copy to ensure a clean copy of options maps
|
73
|
+
#
|
74
|
+
def self.clone_path(path)
|
75
|
+
path.collect{ | dpe | dpe.deep_copy }
|
76
|
+
end
|
77
|
+
|
78
|
+
# A PathEntry contains the specification for a directory
|
79
|
+
# on the MasterView directives load path.
|
80
|
+
#
|
81
|
+
class PathEntry
|
82
|
+
|
83
|
+
# Answer a deep copy so we have a proper clone of the options.
|
84
|
+
def self.copy_options(options)
|
85
|
+
raise ArgumentError, "PathEntry options must be a hash: #{options.inspect}" if ! options.is_a?(Hash)
|
86
|
+
Marshal.load(Marshal.dump(options))
|
87
|
+
end
|
88
|
+
|
89
|
+
# The path name of a directory containing directive implementations
|
90
|
+
#
|
91
|
+
# The pathname is normalized into an absolute path by the validation checking.
|
92
|
+
#
|
93
|
+
attr_reader :dir_path
|
94
|
+
|
95
|
+
attr_reader :options
|
96
|
+
|
97
|
+
# Define an entry for a directive path with the path name of
|
98
|
+
# a directory containing directive implementation classes to be loaded
|
99
|
+
# into the MasterView processing configuration.
|
100
|
+
#
|
101
|
+
# Optionally specify options for the directives loaded
|
102
|
+
# from this directory:
|
103
|
+
#
|
104
|
+
# :default - metadata defaults
|
105
|
+
#
|
106
|
+
# Metadata defaults extend or override any defaults specified
|
107
|
+
# in the dir_path/.metadata file, if defined, allowing application
|
108
|
+
# customization of the default defaults.
|
109
|
+
#
|
110
|
+
def initialize( dir_path, options=nil )
|
111
|
+
@dir_path = dir_path
|
112
|
+
@options = options.nil? ? {} : self.class.copy_options(options)
|
113
|
+
end
|
114
|
+
|
115
|
+
def inspect #:nodoc:
|
116
|
+
abbrev_class_name = self.class.name.split('::')
|
117
|
+
abbrev_class_name = abbrev_class_name[1..abbrev_class_name.size].join('::')
|
118
|
+
"#{abbrev_class_name}('#{dir_path}', options=#{options.inspect})"
|
119
|
+
end
|
120
|
+
|
121
|
+
# Answer a deep copy so we have a proper clone of the options.
|
122
|
+
def deep_copy()
|
123
|
+
Marshal.load(Marshal.dump(self))
|
124
|
+
end
|
125
|
+
|
126
|
+
# Answer whether the directory exists
|
127
|
+
def exists?
|
128
|
+
File.directory?(dir_path)
|
129
|
+
end
|
130
|
+
|
131
|
+
# The metadata defaults for this directory, if any
|
132
|
+
#
|
133
|
+
# Metadata defaults specified on a load path entry supplement
|
134
|
+
# any .metadata options specified in the directory itself by
|
135
|
+
# overridding and extending any options defined statically in
|
136
|
+
# the directives directory.
|
137
|
+
#
|
138
|
+
def metadata_defaults
|
139
|
+
options.fetch(:default, {})
|
140
|
+
end
|
141
|
+
|
142
|
+
# Answer whether directives loaded from this directory use the masterview
|
143
|
+
# namespace by default.
|
144
|
+
#
|
145
|
+
# This option is ordinarily specified only for builtin masterview directives.
|
146
|
+
#
|
147
|
+
def use_masterview_namespace #:nodoc:
|
148
|
+
options.fetch(:use_masterview_namespace, false)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Answer whether directives loaded from this directory use the masterview
|
152
|
+
# extensions directive namespace by default.
|
153
|
+
#
|
154
|
+
def use_extensions_namespace #:nodoc:
|
155
|
+
! use_masterview_namespace
|
156
|
+
end
|
157
|
+
|
158
|
+
# Validate the directory path entry specification.
|
159
|
+
#
|
160
|
+
# Ensures that the directory exists and that the entry specification
|
161
|
+
# is normalized to an absolute pathname.
|
162
|
+
def validate
|
163
|
+
if ! File.directory?(dir_path)
|
164
|
+
err_msg = "Invalid directive load path directory: '#{dir_path}'"
|
165
|
+
raise InvalidDirectivePathError.new(self, err_msg)
|
166
|
+
end
|
167
|
+
if @options.has_key?(:default)
|
168
|
+
md_defaults = @options[:default]
|
169
|
+
# raises ArgumentError if props are bad; has side effect of normalizing the prop values
|
170
|
+
DirectiveMetadata.validate_metadata_props! md_defaults
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# ensure normalized representation with absolute pathnames and standard options
|
175
|
+
def normalize #:nodoc:
|
176
|
+
@dir_path = File.expand_path( @dir_path )
|
177
|
+
#assert ! (['/', '\\'].contains?dir_path[-1..-1])
|
178
|
+
#tbd: (recursively) ensure keys are symbolized?
|
179
|
+
@options[:default] = {} if ! @options.has_key?(:default)
|
180
|
+
#md_defaults entries were already normalized by side effects of the validation checker
|
181
|
+
end
|
182
|
+
|
183
|
+
# Load the metadata specifications for a directives directory
|
184
|
+
def load_metadata_specs(options={})
|
185
|
+
|
186
|
+
create_if_not_defined = options.fetch(:create_if_not_defined, true)
|
187
|
+
|
188
|
+
md_file_path = "#{dir_path}/#{METADATA_SPECS_FILE_NAME}"
|
189
|
+
dir_has_md_specs = File.file?( md_file_path )
|
190
|
+
if dir_has_md_specs
|
191
|
+
STDOUT.puts "\n###Loading directive metadata specs: #{md_file_path}" if DEBUG_MD_DIR_SPECS
|
192
|
+
md_config_specs = DirectiveLoadPath.load_metadata_specs(md_file_path)
|
193
|
+
md_config_specs[:default] ||= {} # ensure that there are default specs
|
194
|
+
STDOUT.puts "...md_config_specs=#{md_config_specs.inspect}" if DEBUG_MD_DIR_SPECS
|
195
|
+
elsif create_if_not_defined
|
196
|
+
md_config_specs = { :default => {} }
|
197
|
+
else
|
198
|
+
return nil
|
199
|
+
end
|
200
|
+
|
201
|
+
md_defaults = md_config_specs[:default]
|
202
|
+
if ! md_defaults.has_key?( :description )
|
203
|
+
md_defaults[:description] = "MasterView directive from #{dir_path}"
|
204
|
+
end
|
205
|
+
# raises ArgumentError if props are bad; has side effect of normalizing the prop values
|
206
|
+
DirectiveMetadata.validate_metadata_props! md_defaults
|
207
|
+
|
208
|
+
md_config_specs
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
# A directive load Path is a list of PathEntry specifications
|
215
|
+
# for directories containing MasterView directive implementations.
|
216
|
+
#
|
217
|
+
class Path
|
218
|
+
|
219
|
+
include Enumerable
|
220
|
+
|
221
|
+
def initialize() #:nodoc: #??(entries=[])
|
222
|
+
@entries = []
|
223
|
+
#entries.each { | entry_spec | self << entry_spec }
|
224
|
+
end
|
225
|
+
|
226
|
+
def [](index)
|
227
|
+
@entries[index]
|
228
|
+
end
|
229
|
+
|
230
|
+
def []=(index, entry)
|
231
|
+
raise ArgumentError, "Invalid entry for {self.class.name}: #{entry.inspect}" if ! entry.is_a?(PathEntry)
|
232
|
+
@entries[index] = entry
|
233
|
+
end
|
234
|
+
|
235
|
+
def <<(entry)
|
236
|
+
if entry.is_a?(String)
|
237
|
+
entry = PathEntry.new(entry)
|
238
|
+
elsif entry.is_a?(Array) && entry.size == 2 && entry[0].is_a?(String) && entry[1].is_a?(Hash)
|
239
|
+
# wow, we're working WAY too hard at this compatability stuff
|
240
|
+
entry = PathEntry.new(entry[0], entry[1])
|
241
|
+
else
|
242
|
+
raise ArgumentError, "Invalid entry for {self.class.name}: #{entry.inspect}" if ! entry.is_a?(PathEntry)
|
243
|
+
end
|
244
|
+
@entries << entry
|
245
|
+
end
|
246
|
+
|
247
|
+
def size
|
248
|
+
@entries.size
|
249
|
+
end
|
250
|
+
|
251
|
+
def empty?
|
252
|
+
@entries.empty?
|
253
|
+
end
|
254
|
+
|
255
|
+
# Calls the given block once for each entry specification on the path,
|
256
|
+
# passing the element as parameter.
|
257
|
+
def each
|
258
|
+
@entries.each { |dpe| yield(dpe) }
|
259
|
+
self
|
260
|
+
end
|
261
|
+
|
262
|
+
# Calls the given block once for each entry specification on the path,
|
263
|
+
# passing the element's index as parameter.
|
264
|
+
def each_index
|
265
|
+
@entries.each_index { |index| yield(index) }
|
266
|
+
self
|
267
|
+
end
|
268
|
+
|
269
|
+
def include?(dir_path)
|
270
|
+
dir_path = dir_path.is_a?( PathEntry ) ? dir_path.dir_path : File.expand_path(dir_path)
|
271
|
+
dpe = self.detect{ |dpe| dpe.dir_path == dir_path }
|
272
|
+
! dpe.nil?
|
273
|
+
end
|
274
|
+
|
275
|
+
# Answer the directory paths
|
276
|
+
def directory_paths
|
277
|
+
dir_paths = []
|
278
|
+
self.each { |dpe| dir_paths << dpe.dir_path }
|
279
|
+
dir_paths
|
280
|
+
end
|
281
|
+
|
282
|
+
# Answer a copy of a directive load path
|
283
|
+
#
|
284
|
+
# Does a deep_copy to ensure a clean copy of options maps
|
285
|
+
#
|
286
|
+
def copy()
|
287
|
+
@entries.collect{ | dpe | dpe.deep_copy }
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
|
292
|
+
# Answer a clean path with a single entry for each directory
|
293
|
+
# and path entries validated and normalize.
|
294
|
+
#
|
295
|
+
# Specify option :dup_policy ::= { :merge || :use_latest }
|
296
|
+
# for handling options on dup entries (merge or use the
|
297
|
+
# last-defined options).
|
298
|
+
#
|
299
|
+
# Optionally provide a block arg for handling validation exceptions
|
300
|
+
#
|
301
|
+
def self.clean_path(path, options)
|
302
|
+
|
303
|
+
dup_policy = options.fetch( :dup_policy, :use_latest )
|
304
|
+
|
305
|
+
unique_paths = []
|
306
|
+
path_entries = {}
|
307
|
+
path.each { | dpe |
|
308
|
+
begin
|
309
|
+
dpe.validate()
|
310
|
+
dpe.normalize()
|
311
|
+
dir_path = dpe.dir_path
|
312
|
+
if ! unique_paths.include?(dir_path)
|
313
|
+
unique_paths << dir_path
|
314
|
+
else
|
315
|
+
# dup entry - we've already got this dir_path registered
|
316
|
+
if dup_policy == :merge
|
317
|
+
prev_options = path_entries[dir_path].options
|
318
|
+
options = prev_options.merge(dpe.options)
|
319
|
+
else # :use_latest
|
320
|
+
options = dpe.options # last-registered path entry wins
|
321
|
+
end
|
322
|
+
# replace path entry with merged or replaced options
|
323
|
+
dpe = PathEntry.new(dir_path, options)
|
324
|
+
end
|
325
|
+
path_entries[dir_path] = dpe
|
326
|
+
rescue InvalidDirectivePathError => ex
|
327
|
+
if block_given?
|
328
|
+
yield(ex)
|
329
|
+
else
|
330
|
+
raise
|
331
|
+
end
|
332
|
+
end
|
333
|
+
}
|
334
|
+
|
335
|
+
clean_path = Path.new
|
336
|
+
unique_paths.each { | dir_path |
|
337
|
+
clean_path << path_entries[dir_path]
|
338
|
+
}
|
339
|
+
clean_path
|
340
|
+
|
341
|
+
end
|
342
|
+
|
343
|
+
# Load a metadata specifications file.
|
344
|
+
#
|
345
|
+
# Normalizes options hash keys to symbols.
|
346
|
+
# Should ordinarily be used through PathEntry.load_metadata_specs.
|
347
|
+
#
|
348
|
+
def self.load_metadata_specs(file_path)
|
349
|
+
md_config_specs = YAML::load(IO.read(file_path))
|
350
|
+
#?what does yaml do with an empy file?? return {} if md_config_specs.nil?
|
351
|
+
#assert md_config_specs.is_a?(Hash)
|
352
|
+
symbolize_options_hash_keys(md_config_specs)
|
353
|
+
end
|
354
|
+
|
355
|
+
# do in-place symbolization of keys; recurse
|
356
|
+
def self.symbolize_options_hash_keys(data) #:nodoc:
|
357
|
+
#data.symbolize_keys!
|
358
|
+
original_keys = data.keys()
|
359
|
+
original_keys.each { | key |
|
360
|
+
value = data[key]
|
361
|
+
symbolizing_value = value.is_a?(Hash)
|
362
|
+
value = symbolize_options_hash_keys(value) if symbolizing_value
|
363
|
+
if ! key.is_a?(Symbol)
|
364
|
+
data[key.to_sym] = value
|
365
|
+
data.delete(key)
|
366
|
+
elsif symbolizing_value
|
367
|
+
data[key] = value
|
368
|
+
end
|
369
|
+
}
|
370
|
+
data
|
371
|
+
end
|
372
|
+
|
373
|
+
# Compute the metadata default specs for a directives directory
|
374
|
+
# Path entry options override/extend directory .metadata specs
|
375
|
+
def self.compute_md_defaults(default_md_specs, dir_md_defaults, path_entry_defaults)
|
376
|
+
md_defaults = {}
|
377
|
+
md_defaults.merge! default_md_specs # we always start with the app-wide defaults
|
378
|
+
md_defaults.merge! dir_md_defaults # bring in specs from the directory .metadata
|
379
|
+
md_defaults.merge! path_entry_defaults # and allow app ovveride on path entry config
|
380
|
+
# raises ArgumentError if props are bad
|
381
|
+
# should be superfluous because we've already done this on each individual set of defaults
|
382
|
+
DirectiveMetadata.validate_metadata_props! md_defaults
|
383
|
+
md_defaults
|
384
|
+
end
|
385
|
+
|
386
|
+
end
|
387
|
+
|
388
|
+
end
|