1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
|
module Mustermann
# Class for pattern objects composed of multiple patterns using binary logic.
# @see Mustermann::Pattern#&
# @see Mustermann::Pattern#|
# @see Mustermann::Pattern#^
class Composite < Pattern
attr_reader :patterns, :operator
supported_options :operator, :type
# @see Mustermann::Pattern.supported?
def self.supported?(option, options = {})
return true if super
options[:type] and Mustermann[options[:type]].supported?(option, options)
end
# @return [Mustermann::Pattern] a new composite pattern
def self.new(*patterns)
options = patterns.last.kind_of?(Hash) ? patterns.pop : {}
patterns = patterns.flatten
case patterns.size
when 0 then raise ArgumentError, 'cannot create empty composite pattern'
when 1 then patterns.first
else super(patterns, options)
end
end
def initialize(patterns, options = {})
operator = options.delete(:operator) || :|
@operator = operator.to_sym
@patterns = patterns.flat_map { |p| patterns_from(p, options) }
end
# @see Mustermann::Pattern#==
def ==(pattern)
patterns == patterns_from(pattern)
end
# @see Mustermann::Pattern#===
def ===(string)
patterns.map { |p| p === string }.inject(operator)
end
# @see Mustermann::Pattern#params
def params(string)
with_matching(string, :params)
end
# @see Mustermann::Pattern#match
def match(string)
with_matching(string, :match)
end
# @!visibility private
def respond_to_special?(method)
return false unless operator == :|
patterns.all? { |p| p.respond_to?(method) }
end
# (see Mustermann::Pattern#expand)
def expand(behavior = nil, values = {})
raise NotImplementedError, 'expanding not supported' unless respond_to? :expand
@expander ||= Mustermann::Expander.new(*patterns)
@expander.expand(behavior, values)
end
# (see Mustermann::Pattern#expand)
def to_templates
raise NotImplementedError, 'template generation not supported' unless respond_to? :to_templates
patterns.flat_map(&:to_templates).uniq
end
# @return [String] the string representation of the pattern
def to_s
simple_inspect
end
# @!visibility private
def inspect
"#<%p:%s>" % [self.class, simple_inspect]
end
# @!visibility private
def simple_inspect
pattern_strings = patterns.map { |p| p.simple_inspect }
"(#{pattern_strings.join(" #{operator} ")})"
end
# @!visibility private
def with_matching(string, method)
return unless self === string
pattern = patterns.detect { |p| p === string }
pattern.public_send(method, string) if pattern
end
# @!visibility private
def patterns_from(pattern, options = nil)
return pattern.patterns if pattern.is_a? Composite and pattern.operator == self.operator
[options ? Mustermann.new(pattern, options) : pattern]
end
private :with_matching, :patterns_from
end
end
|