# $Id: wiki_rule.rb 181 2007-01-05 20:59:06Z bitherder $ require 'core_ext/regexp' module Tartan class WikiRule < Hash def initialize(matcher={}) matcher.each { |(a, v)| self[a] = v } end def matcher self end # define methods to access elements of matcher hash def method_missing(method_symbol) self.class.send(:define_method, method_symbol) {self[method_symbol]} self[method_symbol] end def match self[:match] ? self[:match].to_regexp : nil end def strip_match strip = self[:strip] (strip and strip[:match]) ? strip[:match].to_regexp : nil end def unstrip_match unstrip = self[:unstrip] (unstrip and unstrip[:match]) ? unstrip[:match].to_regexp : nil end def strip_replace self[:strip][:replace] end def unstrip_replace self[:unstrip][:replace] end def placed(position) self.delete(position) end def default_rule self[:default] end def start_mark(type) return false if self[type].nil? or self[type].class == TrueClass self[type][:start_mark] end def end_mark(type) return false if self[type].nil? or self[type].class == TrueClass self[type][:end_mark] end def replace_regex(type) return false if self[type].nil? or self[type].class == TrueClass self[type][:replace] end def target_position self[:position] end def vars_to_set self[:set] end def subparse_context return nil if ! self.has_key?(:subparse) if self[:subparse].is_a?(Symbol) or self[:subparse].is_a?(String) return self[:subparse] elsif self[:subparse].has_key?(:context) return self[:subparse][:context] end return nil end def subparse_match_group if has_key?(:subparse) and self[:subparse].is_a?(Hash) and self[:subparse].has_key?(:match_group) self[:subparse][:match_group] else nil end end def position_matches?(parsed, to_be_parsed, match_result) return true if !target_position pos = parsed.length return true if target_position == pos return true if :first == target_position && 0 == pos if 0 == to_be_parsed.length && match_result.post_match.empty? return true if :last == target_position return true if :all == target_position && 0 == parsed.length else return true if :not_last == target_position end return false end def has_type?(type) if String == type.class type = type.to_sym end return self[type] end def replace(parse_type, match_result, wikiparser) return unless match_result wikiparser.substitute(replace_regex(parse_type), match_result) end def block(parse_type, text, match_result, wikiparser) return unless match_result mid = text start_strip = "" end_strip = "" if subparse_match_group subparse_index = match_result.sym2index(subparse_match_group) last_match = match_result.last_match_index start_strip = match_result.pre_sub_match(subparse_index) end_strip = match_result.post_sub_match(subparse_index) mid = match_result[subparse_index] end if strip.is_a?(Hash) and strip[:match] and strip[:replace] mid = mid.gsub(strip_match, strip_replace) end # need to evaluate the start_text before the execution of the # sub-parse in case any of the wiki helper functions depend on # ordering of the text start_text = start_mark(parse_type)? wikiparser.substitute(start_mark(parse_type), match_result): "" if subparse_context mid = wikiparser.parse_by_context(parse_type, subparse_context, mid) end mid = start_text + mid if end_mark(parse_type) mid += wikiparser.substitute(end_mark(parse_type), match_result) end if ! has_key?(parse_type) mid = start_strip + mid + end_strip if unstrip mid.gsub!(unstrip_match, unstrip_replace) end end mid end def handle_match(parse_type, parsed, to_be_parsed, match_result, wikiparser) debug_opt = wikiparser.get_var('debug') if $DEBUG || debug || true == debug_opt || debug_opt == title puts "\n%s matches [[%s<<\n%s\n>>%s]]" % [title, match_result.pre_match, match_result, match_result.post_match] end wikiparser.set_vars(vars_to_set, match_result) mid = match_result[0] if replace_regex(parse_type) mid = replace(parse_type, match_result, wikiparser) elsif true == self[parse_type] or start_mark(parse_type) or end_mark(parse_type) or subparse mid = block(parse_type, mid, match_result, wikiparser) end if shelve && mid mid = wikiparser.shelve(mid) end if "" != match_result.pre_match parsed.add_text(false, match_result.pre_match) end parsed.add_text(true, mid) if "" != mid if "" != match_result.post_match to_be_parsed.add_back_text(false, match_result.post_match) end return parsed, to_be_parsed end def parse_element(parse_type, to_be_parsed, wikiparser) parsed = ParsedTextList.new position = 0 while element = to_be_parsed.shift if element.claimed? then parsed.add(element); next ; end match_result = match.match(element) unless match_result then parsed.add(element); next; end if !position_matches?(parsed, to_be_parsed, match_result) parsed.add(element) next end parsed, to_be_parsed = handle_match(parse_type, parsed, to_be_parsed, match_result, wikiparser) end parsed end end end # Tartan