module MasterView # Keyword expander is used to hold variables defined to be used in expansion of # attributes. class KeywordExpander #-- # keywords related to path information about the template being processed #++ # relative path of the template being processed within the template src dir # (does *not* include the template flie extension) KW_TEMPLATE_PATH = '{template_path}' # relative path of the directory containing the template being processed # within the template src dir. # ('' if template is directly contained in the templates src dir) KW_TEMPLATE_DIR_PATH = '{template_dir_path}' # base filename of the template being processed (no file extension) KW_TEMPLATE_BASENAME = '{template_basename}' # filename extension of the template being processed (ordinarily '.html') KW_EXTENSION = '{extension}' # the default extension for generated output (ordinarily '.rhthml') KW_DEFAULT_EXTENSION = '{default_extension}' # list of all supported keywords related to the template being processed TEMPLATE_KEYWORDS = [ KW_TEMPLATE_PATH, KW_TEMPLATE_DIR_PATH, KW_TEMPLATE_BASENAME, KW_EXTENSION ] def initialize(hash = {}) @hash = hash build_key_value_array_sorted_by_desc_length end # Sets a variety of path related keywords: # # MasterView supports the following keyword expansions for # mv:generate, mv:gen_partial, mv:import, and mv:import_render # #-- # The default generated output extension is MasterView::GeneratedFileDefaultExtension, # per the masterview config.output_filename_extension setting. #++ # # For template file one/foo/bar.html when default generated output extension '.rhtml': # {template_path} == use original masterview template path with default output extension (one/foo/bar.rhtml) # {template_path}.ext == use original masterview template path with the specified extension (one/foo/bar.ext) # {template_dir_path} == direct_parent_dirname (one/foo) # {template_basename} == basename (bar) # {extension} == extension (.html) # # For example: # with MasterView template file one/two/three.html and default generated output extension '.rhtml' # mv:generate="{template_path}" expands to mv:generate="one/two/three.rhtml" (default generation output extension used) # mv:generate="{template_path}.rcss" expands to mv:generate="one/two/three.rcss" # mv:generate="{template_dir_path}/{template_basename}" expands to mv:generate="one/two/three" (no extension) # mv:generate="{template_dir_path}/{template_basename}.rcss" expands to mv:generate="one/two/three.rcss" # mv:generate="{template_dir_path}/{template_basename}-bar.rtxt" expands to mv:generate="one/two/three-bar.rtxt" # mv:generate="somewhere/{template_basename}-bar{extension}" expands to mv:generate="somewhere/three-bar.html" # # Note: All path values use forward slashes # def set_template_pathname(template_pathname, default_erb_extension) return if template_pathname.nil? pn = Pathname.for_path(template_pathname) default_erb_extension = '' if default_erb_extension.nil? @hash[KW_TEMPLATE_PATH] = convert_pathname_to_s(pn.path_no_ext) #defer decision: + default_erb_extension @hash[KW_TEMPLATE_DIR_PATH] = convert_pathname_to_s(pn.dirname) @hash[KW_TEMPLATE_BASENAME] = convert_pathname_to_s(pn.basename(pn.extname)) @hash[KW_EXTENSION] = pn.extname @hash[KW_DEFAULT_EXTENSION] = default_erb_extension build_key_value_array_sorted_by_desc_length end # set the value, regenerate a reverse sorted hash value array so that it will # replace the longer replacement keys before the shorter ones, so FOO_BAR will be # replaced before FOO def set(key, value) @hash[key] = value build_key_value_array_sorted_by_desc_length end def [](key) @hash[key] end # expand all keywords, return value def expand_keywords(str) # maybe consider: add parm check_template_path=false that mv:generate processor would turn on # so that ext. defaulting cleverness only applies in that specific context. # Might be overaggressive (or just unnecessary) to this this on *all* substitution mappings # [DJL 18-Jun-2006] return nil if str.nil? append_default_ext = str.ends_with?(KW_TEMPLATE_PATH) and @hash.has_key?(KW_DEFAULT_EXTENSION) val = str.clone @hash_values_by_desc_key_length.each { |k,v| val.gsub!(k,v) } val << @hash[KW_DEFAULT_EXTENSION] if append_default_ext val end # finds the attribute using the key deleting it from hash, expands value using current binding # which allows KEYWORD substitutions before returning string, return nil if not found def resolveAttrAndDelete(attributes, key) attr_value = attributes.delete(key) attr_value = expand_keywords(attr_value) unless attr_value.nil? attr_value end private # convert pathname to string, for '.' we want empty string def convert_pathname_to_s(pathname) (pathname.to_s == '.') ? '' : pathname.to_s end def build_key_value_array_sorted_by_desc_length @hash_values_by_desc_key_length = @hash.sort { |a,b| b[0].length <=> a[0].length } # longest keys first end end end