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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
require 'mustermann/ast/parser'
require 'mustermann/ast/boundaries'
require 'mustermann/ast/compiler'
require 'mustermann/ast/transformer'
require 'mustermann/ast/validation'
require 'mustermann/ast/template_generator'
require 'mustermann/ast/param_scanner'
require 'mustermann/regexp_based'
require 'mustermann/expander'
require 'mustermann/equality_map'
module Mustermann
# @see Mustermann::AST::Pattern
module AST
# Superclass for pattern styles that parse an AST from the string pattern.
# @abstract
class Pattern < Mustermann::RegexpBased
supported_options :capture, :except, :greedy, :space_matches_plus
extend Forwardable, SingleForwardable
single_delegate on: :parser, suffix: :parser
instance_delegate %w[parser compiler transformer validation template_generator param_scanner boundaries].map(&:to_sym) => 'self.class'
instance_delegate parse: :parser, transform: :transformer, validate: :validation,
generate_templates: :template_generator, scan_params: :param_scanner, set_boundaries: :boundaries
# @api private
# @return [#parse] parser object for pattern
# @!visibility private
def self.parser
return Parser if self == AST::Pattern
const_set :Parser, Class.new(superclass.parser) unless const_defined? :Parser, false
const_get :Parser
end
# @api private
# @return [#compile] compiler object for pattern
# @!visibility private
def self.compiler
Compiler
end
# @api private
# @return [#set_boundaries] translator making sure start and stop is set on all nodes
# @!visibility private
def self.boundaries
Boundaries
end
# @api private
# @return [#transform] transformer object for pattern
# @!visibility private
def self.transformer
Transformer
end
# @api private
# @return [#validate] validation object for pattern
# @!visibility private
def self.validation
Validation
end
# @api private
# @return [#generate_templates] generates URI templates for pattern
# @!visibility private
def self.template_generator
TemplateGenerator
end
# @api private
# @return [#scan_params] param scanner for pattern
# @!visibility private
def self.param_scanner
ParamScanner
end
# @!visibility private
def compile(options = {})
options[:except] &&= parse options[:except]
compiler.compile(to_ast, options)
rescue CompileError => error
error.message << ": %p" % @string
raise error
end
# Internal AST representation of pattern.
# @!visibility private
def to_ast
@ast_cache ||= EqualityMap.new
@ast_cache.fetch(@string) do
ast = parse(@string, pattern: self)
ast &&= transform(ast)
ast &&= set_boundaries(ast, string: @string)
validate(ast)
end
end
# All AST-based pattern implementations support expanding.
#
# @example (see Mustermann::Pattern#expand)
# @param (see Mustermann::Pattern#expand)
# @return (see Mustermann::Pattern#expand)
# @raise (see Mustermann::Pattern#expand)
# @see Mustermann::Pattern#expand
# @see Mustermann::Expander
def expand(behavior = nil, values = {})
@expander ||= Mustermann::Expander.new(self)
@expander.expand(behavior, values)
end
# All AST-based pattern implementations support generating templates.
#
# @example (see Mustermann::Pattern#to_templates)
# @param (see Mustermann::Pattern#to_templates)
# @return (see Mustermann::Pattern#to_templates)
# @see Mustermann::Pattern#to_templates
def to_templates
@to_templates ||= generate_templates(to_ast)
end
# @!visibility private
# @see Mustermann::Pattern#map_param
def map_param(key, value)
return super unless param_converters.include? key
param_converters[key][super]
end
# @!visibility private
def param_converters
@param_converters ||= scan_params(to_ast)
end
private :compile, :parse, :transform, :validate, :generate_templates, :param_converters, :scan_params, :set_boundaries
end
end
end
|