mustermann 0.3.1 → 0.4.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.
- checksums.yaml +4 -4
- data/README.md +429 -672
- data/lib/mustermann.rb +95 -20
- data/lib/mustermann/ast/boundaries.rb +44 -0
- data/lib/mustermann/ast/compiler.rb +13 -7
- data/lib/mustermann/ast/expander.rb +22 -12
- data/lib/mustermann/ast/node.rb +69 -5
- data/lib/mustermann/ast/param_scanner.rb +20 -0
- data/lib/mustermann/ast/parser.rb +138 -19
- data/lib/mustermann/ast/pattern.rb +59 -7
- data/lib/mustermann/ast/template_generator.rb +28 -0
- data/lib/mustermann/ast/transformer.rb +2 -2
- data/lib/mustermann/ast/translator.rb +20 -0
- data/lib/mustermann/ast/validation.rb +4 -3
- data/lib/mustermann/composite.rb +101 -0
- data/lib/mustermann/expander.rb +2 -2
- data/lib/mustermann/identity.rb +56 -0
- data/lib/mustermann/pattern.rb +185 -10
- data/lib/mustermann/pattern_cache.rb +49 -0
- data/lib/mustermann/regexp.rb +1 -0
- data/lib/mustermann/regexp_based.rb +18 -1
- data/lib/mustermann/regular.rb +4 -1
- data/lib/mustermann/simple_match.rb +5 -0
- data/lib/mustermann/sinatra.rb +22 -5
- data/lib/mustermann/to_pattern.rb +11 -6
- data/lib/mustermann/version.rb +1 -1
- data/mustermann.gemspec +1 -14
- data/spec/ast_spec.rb +14 -0
- data/spec/composite_spec.rb +147 -0
- data/spec/expander_spec.rb +15 -0
- data/spec/identity_spec.rb +44 -0
- data/spec/mustermann_spec.rb +17 -2
- data/spec/pattern_spec.rb +7 -3
- data/spec/regular_spec.rb +25 -0
- data/spec/sinatra_spec.rb +184 -9
- data/spec/to_pattern_spec.rb +49 -0
- metadata +15 -180
- data/.gitignore +0 -18
- data/.rspec +0 -2
- data/.travis.yml +0 -4
- data/.yardopts +0 -1
- data/Gemfile +0 -2
- data/LICENSE +0 -22
- data/Rakefile +0 -6
- data/internals.md +0 -64
- data/lib/mustermann/ast/tree_renderer.rb +0 -29
- data/lib/mustermann/rails.rb +0 -17
- data/lib/mustermann/shell.rb +0 -29
- data/lib/mustermann/simple.rb +0 -35
- data/lib/mustermann/template.rb +0 -47
- data/spec/rails_spec.rb +0 -521
- data/spec/shell_spec.rb +0 -108
- data/spec/simple_spec.rb +0 -236
- data/spec/support.rb +0 -5
- data/spec/support/coverage.rb +0 -16
- data/spec/support/env.rb +0 -16
- data/spec/support/expand_matcher.rb +0 -27
- data/spec/support/match_matcher.rb +0 -39
- data/spec/support/pattern.rb +0 -39
- data/spec/template_spec.rb +0 -814
@@ -0,0 +1,101 @@
|
|
1
|
+
module Mustermann
|
2
|
+
# Class for pattern objects composed of multiple patterns using binary logic.
|
3
|
+
# @see Mustermann::Pattern#&
|
4
|
+
# @see Mustermann::Pattern#|
|
5
|
+
# @see Mustermann::Pattern#^
|
6
|
+
class Composite < Pattern
|
7
|
+
attr_reader :patterns, :operator
|
8
|
+
supported_options :operator, :type
|
9
|
+
|
10
|
+
# @see Mustermann::Pattern.supported?
|
11
|
+
def self.supported?(option, **options)
|
12
|
+
return true if super
|
13
|
+
options[:type] and Mustermann[options[:type]].supported?(option, **options)
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Mustermann::Pattern] a new composite pattern
|
17
|
+
def self.new(*patterns, **options)
|
18
|
+
patterns = patterns.flatten
|
19
|
+
case patterns.size
|
20
|
+
when 0 then raise ArgumentError, 'cannot create empty composite pattern'
|
21
|
+
when 1 then patterns.first
|
22
|
+
else super(patterns, **options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(patterns, operator: :|, **options)
|
27
|
+
@operator = operator.to_sym
|
28
|
+
@patterns = patterns.flat_map { |p| patterns_from(p, **options) }
|
29
|
+
end
|
30
|
+
|
31
|
+
# @see Mustermann::Pattern#==
|
32
|
+
def ==(pattern)
|
33
|
+
patterns == patterns_from(pattern)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @see Mustermann::Pattern#===
|
37
|
+
def ===(string)
|
38
|
+
patterns.map { |p| p === string }.inject(operator)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @see Mustermann::Pattern#params
|
42
|
+
def params(string)
|
43
|
+
with_matching(string, :params)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @see Mustermann::Pattern#match
|
47
|
+
def match(string)
|
48
|
+
with_matching(string, :match)
|
49
|
+
end
|
50
|
+
|
51
|
+
# @!visibility private
|
52
|
+
def respond_to_special?(method)
|
53
|
+
return false unless operator == :|
|
54
|
+
patterns.all? { |p| p.respond_to?(method) }
|
55
|
+
end
|
56
|
+
|
57
|
+
# (see Mustermann::Pattern#expand)
|
58
|
+
def expand(behavior = nil, values = {})
|
59
|
+
raise NotImplementedError, 'expanding not supported' unless respond_to? :expand
|
60
|
+
@expander ||= Mustermann::Expander.new(*patterns)
|
61
|
+
@expander.expand(behavior, values)
|
62
|
+
end
|
63
|
+
|
64
|
+
# (see Mustermann::Pattern#expand)
|
65
|
+
def to_templates
|
66
|
+
raise NotImplementedError, 'template generation not supported' unless respond_to? :to_templates
|
67
|
+
patterns.flat_map(&:to_templates).uniq
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [String] the string representation of the pattern
|
71
|
+
def to_s
|
72
|
+
simple_inspect
|
73
|
+
end
|
74
|
+
|
75
|
+
# @!visibility private
|
76
|
+
def inspect
|
77
|
+
"#<%p:%s>" % [self.class, simple_inspect]
|
78
|
+
end
|
79
|
+
|
80
|
+
# @!visibility private
|
81
|
+
def simple_inspect
|
82
|
+
pattern_strings = patterns.map { |p| p.simple_inspect }
|
83
|
+
"(#{pattern_strings.join(" #{operator} ")})"
|
84
|
+
end
|
85
|
+
|
86
|
+
# @!visibility private
|
87
|
+
def with_matching(string, method)
|
88
|
+
return unless self === string
|
89
|
+
pattern = patterns.detect { |p| p === string }
|
90
|
+
pattern.public_send(method, string) if pattern
|
91
|
+
end
|
92
|
+
|
93
|
+
# @!visibility private
|
94
|
+
def patterns_from(pattern, options = nil)
|
95
|
+
return pattern.patterns if pattern.is_a? Composite and pattern.operator == self.operator
|
96
|
+
[options ? Mustermann.new(pattern, **options) : pattern]
|
97
|
+
end
|
98
|
+
|
99
|
+
private :with_matching, :patterns_from
|
100
|
+
end
|
101
|
+
end
|
data/lib/mustermann/expander.rb
CHANGED
@@ -41,7 +41,7 @@ module Mustermann
|
|
41
41
|
# @return [Mustermann::Expander] the expander
|
42
42
|
def add(*patterns)
|
43
43
|
patterns.each do |pattern|
|
44
|
-
pattern = Mustermann.new(pattern
|
44
|
+
pattern = Mustermann.new(pattern, **@options)
|
45
45
|
raise NotImplementedError, "expanding not supported for #{pattern.class}" unless pattern.respond_to? :to_ast
|
46
46
|
@api_expander.add(pattern.to_ast)
|
47
47
|
@patterns << pattern
|
@@ -137,7 +137,7 @@ module Mustermann
|
|
137
137
|
# @return [String] expanded string
|
138
138
|
# @raise [NotImplementedError] raised if expand is not supported.
|
139
139
|
# @raise [Mustermann::ExpandError] raised if a value is missing or unknown
|
140
|
-
def expand(behavior = nil,
|
140
|
+
def expand(behavior = nil, values = {})
|
141
141
|
behavior, values = nil, behavior if behavior.is_a? Hash
|
142
142
|
values = map_values(values)
|
143
143
|
|
data/lib/mustermann/identity.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
+
require 'mustermann'
|
1
2
|
require 'mustermann/pattern'
|
3
|
+
require 'mustermann/ast/node'
|
2
4
|
|
3
5
|
module Mustermann
|
4
6
|
# Matches strings that are identical to the pattern.
|
@@ -9,11 +11,65 @@ module Mustermann
|
|
9
11
|
# @see Mustermann::Pattern
|
10
12
|
# @see file:README.md#identity Syntax description in the README
|
11
13
|
class Identity < Pattern
|
14
|
+
register :identity
|
15
|
+
|
12
16
|
# @param (see Mustermann::Pattern#===)
|
13
17
|
# @return (see Mustermann::Pattern#===)
|
14
18
|
# @see (see Mustermann::Pattern#===)
|
15
19
|
def ===(string)
|
16
20
|
unescape(string) == @string
|
17
21
|
end
|
22
|
+
|
23
|
+
# @param (see Mustermann::Pattern#peek_size)
|
24
|
+
# @return (see Mustermann::Pattern#peek_size)
|
25
|
+
# @see (see Mustermann::Pattern#peek_size)
|
26
|
+
def peek_size(string)
|
27
|
+
return unless unescape(string).start_with? @string
|
28
|
+
return @string.size if string.start_with? @string # optimization
|
29
|
+
@string.each_char.with_index.inject(0) do |count, (char, index)|
|
30
|
+
char_size = 1
|
31
|
+
escaped = @@uri.escape(char, /./)
|
32
|
+
char_size = escaped.size if string[index, escaped.size].downcase == escaped.downcase
|
33
|
+
count + char_size
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# URI templates support generating templates (the logic is quite complex, though).
|
38
|
+
#
|
39
|
+
# @example (see Mustermann::Pattern#to_templates)
|
40
|
+
# @param (see Mustermann::Pattern#to_templates)
|
41
|
+
# @return (see Mustermann::Pattern#to_templates)
|
42
|
+
# @see Mustermann::Pattern#to_templates
|
43
|
+
def to_templates
|
44
|
+
[@@uri.escape(to_s)]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Generates an AST so it's compatible with {Mustermann::AST::Pattern}.
|
48
|
+
# Not used internally by {Mustermann::Identity}.
|
49
|
+
# @!visibility private
|
50
|
+
def to_ast
|
51
|
+
payload = @string.each_char.with_index.map { |c, i| AST::Node[c == ?/ ? :separator : :char].new(c, start: i, stop: i+1) }
|
52
|
+
AST::Node[:root].new(payload, pattern: @string, start: 0, stop: @string.length)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Identity patterns support expanding.
|
56
|
+
#
|
57
|
+
# This implementation does not use {Mustermann::Expander} internally to save memory and
|
58
|
+
# compilation time.
|
59
|
+
#
|
60
|
+
# @example (see Mustermann::Pattern#expand)
|
61
|
+
# @param (see Mustermann::Pattern#expand)
|
62
|
+
# @return (see Mustermann::Pattern#expand)
|
63
|
+
# @raise (see Mustermann::Pattern#expand)
|
64
|
+
# @see Mustermann::Pattern#expand
|
65
|
+
# @see Mustermann::Expander
|
66
|
+
def expand(behavior = nil, values = {})
|
67
|
+
return to_s if values.empty? or behavior == :ignore
|
68
|
+
raise ExpandError, "cannot expand with keys %p" % values.keys.sort if behavior == :raise
|
69
|
+
raise ArgumentError, "unknown behavior %p" % behavior if behavior != :append
|
70
|
+
params = values.map { |key, value| @@uri.escape(key.to_s) + "=" + @@uri.escape(value.to_s, /[^\w]/) }
|
71
|
+
separator = @string.include?(??) ? ?& : ??
|
72
|
+
@string + separator + params.join(?&)
|
73
|
+
end
|
18
74
|
end
|
19
75
|
end
|
data/lib/mustermann/pattern.rb
CHANGED
@@ -8,6 +8,7 @@ module Mustermann
|
|
8
8
|
# @abstract
|
9
9
|
class Pattern
|
10
10
|
include Mustermann
|
11
|
+
@@uri ||= URI::Parser.new
|
11
12
|
|
12
13
|
# List of supported options.
|
13
14
|
#
|
@@ -26,9 +27,16 @@ module Mustermann
|
|
26
27
|
options
|
27
28
|
end
|
28
29
|
|
30
|
+
# Registers the pattern with Mustermann.
|
31
|
+
# @see Mustermann.register
|
32
|
+
# @!visibility private
|
33
|
+
def self.register(*names)
|
34
|
+
names.each { |name| Mustermann.register(name, self) }
|
35
|
+
end
|
36
|
+
|
29
37
|
# @param [Symbol] option The option to check.
|
30
38
|
# @return [Boolean] Whether or not option is supported.
|
31
|
-
def self.supported?(option)
|
39
|
+
def self.supported?(option, **options)
|
32
40
|
supported_options.include? option
|
33
41
|
end
|
34
42
|
|
@@ -40,7 +48,7 @@ module Mustermann
|
|
40
48
|
# @see #initialize
|
41
49
|
def self.new(string, ignore_unknown_options: false, **options)
|
42
50
|
unless ignore_unknown_options
|
43
|
-
unsupported = options.keys.detect { |key| not supported?(key) }
|
51
|
+
unsupported = options.keys.detect { |key| not supported?(key, **options) }
|
44
52
|
raise ArgumentError, "unsupported option %p for %p" % [unsupported, self] if unsupported
|
45
53
|
end
|
46
54
|
|
@@ -90,13 +98,73 @@ module Mustermann
|
|
90
98
|
raise NotImplementedError, 'subclass responsibility'
|
91
99
|
end
|
92
100
|
|
93
|
-
#
|
101
|
+
# Tries to match the pattern against the beginning of the string (as opposed to the full string).
|
102
|
+
# Will return the count of the matching characters if it matches.
|
103
|
+
#
|
104
|
+
# @example
|
105
|
+
# pattern = Mustermann.new('/:name')
|
106
|
+
# pattern.size("/Frank/Sinatra") # => 6
|
107
|
+
#
|
108
|
+
# @param [String] string The string to match against
|
109
|
+
# @return [Integer, nil] the number of characters that match
|
110
|
+
def peek_size(string)
|
111
|
+
# this is a very naive, unperformant implementation
|
112
|
+
string.size.downto(0).detect { |s| self === string[0, s] }
|
113
|
+
end
|
114
|
+
|
115
|
+
# Tries to match the pattern against the beginning of the string (as opposed to the full string).
|
116
|
+
# Will return the substring if it matches.
|
117
|
+
#
|
118
|
+
# @example
|
119
|
+
# pattern = Mustermann.new('/:name')
|
120
|
+
# pattern.peek("/Frank/Sinatra") # => "/Frank"
|
121
|
+
#
|
122
|
+
# @param [String] string The string to match against
|
123
|
+
# @return [String, nil] matched subsctring
|
124
|
+
def peek(string)
|
125
|
+
size = peek_size(string)
|
126
|
+
string[0, size] if size
|
127
|
+
end
|
128
|
+
|
129
|
+
# Tries to match the pattern against the beginning of the string (as opposed to the full string).
|
130
|
+
# Will return a MatchData or similar instance for the matched substring.
|
131
|
+
#
|
132
|
+
# @example
|
133
|
+
# pattern = Mustermann.new('/:name')
|
134
|
+
# pattern.peek("/Frank/Sinatra") # => #<MatchData "/Frank" name:"Frank">
|
135
|
+
#
|
136
|
+
# @param [String] string The string to match against
|
137
|
+
# @return [MatchData, Mustermann::SimpleMatch, nil] MatchData or similar object if the pattern matches.
|
138
|
+
# @see #peek_params
|
139
|
+
def peek_match(string)
|
140
|
+
matched = peek(string)
|
141
|
+
match(matched) if matched
|
142
|
+
end
|
143
|
+
|
144
|
+
# Tries to match the pattern against the beginning of the string (as opposed to the full string).
|
145
|
+
# Will return a two element Array with the params parsed from the substring as first entry and the length of
|
146
|
+
# the substring as second.
|
147
|
+
#
|
148
|
+
# @example
|
149
|
+
# pattern = Mustermann.new('/:name')
|
150
|
+
# params, _ = pattern.peek_params("/Frank/Sinatra")
|
151
|
+
#
|
152
|
+
# puts "Hello, #{params['name']}!" # Hello, Frank!
|
153
|
+
#
|
154
|
+
# @param [String] string The string to match against
|
155
|
+
# @return [Array<Hash, Integer>, nil] Array with params hash and length of substing if matched, nil otherwise
|
156
|
+
def peek_params(string)
|
157
|
+
match = peek_match(string)
|
158
|
+
[params(captures: match), match.to_s.size] if match
|
159
|
+
end
|
160
|
+
|
161
|
+
# @return [Hash{String: Array<Integer>}] capture names mapped to capture index.
|
94
162
|
# @see http://ruby-doc.org/core-2.0/Regexp.html#method-i-named_captures Regexp#named_captures
|
95
163
|
def named_captures
|
96
164
|
{}
|
97
165
|
end
|
98
166
|
|
99
|
-
# @return [
|
167
|
+
# @return [Array<String>] capture names.
|
100
168
|
# @see http://ruby-doc.org/core-2.0/Regexp.html#method-i-names Regexp#names
|
101
169
|
def names
|
102
170
|
[]
|
@@ -129,20 +197,122 @@ module Mustermann
|
|
129
197
|
# warn "does not support expanding"
|
130
198
|
# end
|
131
199
|
#
|
132
|
-
#
|
200
|
+
# Expanding is supported by almost all patterns (notable execptions are {Mustermann::Shell},
|
201
|
+
# {Mustermann::Regular} and {Mustermann::Simple}).
|
202
|
+
#
|
203
|
+
# Union {Mustermann::Composite} patterns (with the | operator) support expanding if all
|
204
|
+
# patterns they are composed of also support it.
|
205
|
+
#
|
206
|
+
# @param (see Mustermann::Expander#expand)
|
133
207
|
# @return [String] expanded string
|
134
208
|
# @raise [NotImplementedError] raised if expand is not supported.
|
135
209
|
# @raise [Mustermann::ExpandError] raised if a value is missing or unknown
|
136
210
|
# @see Mustermann::Expander
|
137
|
-
def expand(
|
211
|
+
def expand(behavior = nil, values = {})
|
138
212
|
raise NotImplementedError, "expanding not supported by #{self.class}"
|
139
213
|
end
|
140
214
|
|
215
|
+
# @note This method is only implemented by certain subclasses.
|
216
|
+
#
|
217
|
+
# Generates a list of URI template strings representing the pattern.
|
218
|
+
#
|
219
|
+
# Note that this transformation is lossy and the strings matching these
|
220
|
+
# templates might not match the pattern (and vice versa).
|
221
|
+
#
|
222
|
+
# This comes in quite handy since URI templates are not made for pattern matching.
|
223
|
+
# That way you can easily use a more precise template syntax and have it automatically
|
224
|
+
# generate hypermedia links for you.
|
225
|
+
#
|
226
|
+
# @example generating templates
|
227
|
+
# Mustermann.new("/:name").to_templates # => ["/{name}"]
|
228
|
+
# Mustermann.new("/:foo(@:bar)?/*baz").to_templates # => ["/{foo}@{bar}/{+baz}", "/{foo}/{+baz}"]
|
229
|
+
# Mustermann.new("/{name}", type: :template).to_templates # => ["/{name}"]
|
230
|
+
#
|
231
|
+
# @example generating templates from composite patterns
|
232
|
+
# pattern = Mustermann.new('/:name')
|
233
|
+
# pattern |= Mustermann.new('/{name}', type: :template)
|
234
|
+
# pattern |= Mustermann.new('/example/*nested')
|
235
|
+
# pattern.to_templates # => ["/{name}", "/example/{+nested}"]
|
236
|
+
#
|
237
|
+
# Template generation is supported by almost all patterns (notable execptions are
|
238
|
+
# {Mustermann::Shell}, {Mustermann::Regular} and {Mustermann::Simple}).
|
239
|
+
# Union {Mustermann::Composite} patterns (with the | operator) support template generation
|
240
|
+
# if all patterns they are composed of also support it.
|
241
|
+
#
|
242
|
+
# @example Checking if a pattern supports expanding
|
243
|
+
# if pattern.respond_to? :to_templates
|
244
|
+
# pattern.to_templates
|
245
|
+
# else
|
246
|
+
# warn "does not support template generation"
|
247
|
+
# end
|
248
|
+
#
|
249
|
+
# @return [Array<String>] list of URI templates
|
250
|
+
def to_templates
|
251
|
+
raise NotImplementedError, "template generation not supported by #{self.class}"
|
252
|
+
end
|
253
|
+
|
254
|
+
# @overload |(other)
|
255
|
+
# Creates a pattern that matches any string matching either one of the patterns.
|
256
|
+
# If a string is supplied, it is treated as an identity pattern.
|
257
|
+
#
|
258
|
+
# @example
|
259
|
+
# pattern = Mustermann.new('/foo/:name') | Mustermann.new('/:first/:second')
|
260
|
+
# pattern === '/foo/bar' # => true
|
261
|
+
# pattern === '/fox/bar' # => true
|
262
|
+
# pattern === '/foo' # => false
|
263
|
+
#
|
264
|
+
# @overload &(other)
|
265
|
+
# Creates a pattern that matches any string matching both of the patterns.
|
266
|
+
# If a string is supplied, it is treated as an identity pattern.
|
267
|
+
#
|
268
|
+
# @example
|
269
|
+
# pattern = Mustermann.new('/foo/:name') & Mustermann.new('/:first/:second')
|
270
|
+
# pattern === '/foo/bar' # => true
|
271
|
+
# pattern === '/fox/bar' # => false
|
272
|
+
# pattern === '/foo' # => false
|
273
|
+
#
|
274
|
+
# @overload ^(other)
|
275
|
+
# Creates a pattern that matches any string matching exactly one of the patterns.
|
276
|
+
# If a string is supplied, it is treated as an identity pattern.
|
277
|
+
#
|
278
|
+
# @example
|
279
|
+
# pattern = Mustermann.new('/foo/:name') ^ Mustermann.new('/:first/:second')
|
280
|
+
# pattern === '/foo/bar' # => false
|
281
|
+
# pattern === '/fox/bar' # => true
|
282
|
+
# pattern === '/foo' # => false
|
283
|
+
#
|
284
|
+
# @param [Mustermann::Pattern, String] other the other pattern
|
285
|
+
# @return [Mustermann::Pattern] a composite pattern
|
286
|
+
def |(other)
|
287
|
+
Mustermann.new(self, other, operator: __callee__, type: :identity)
|
288
|
+
end
|
289
|
+
|
290
|
+
alias_method :&, :|
|
291
|
+
alias_method :^, :|
|
292
|
+
|
293
|
+
# @example
|
294
|
+
# pattern = Mustermann.new('/:a/:b')
|
295
|
+
# strings = ["foo/bar", "/foo/bar", "/foo/bar/"]
|
296
|
+
# strings.detect(&pattern) # => "/foo/bar"
|
297
|
+
#
|
298
|
+
# @return [Proc] proc wrapping {#===}
|
299
|
+
def to_proc
|
300
|
+
@to_proc ||= method(:===).to_proc
|
301
|
+
end
|
302
|
+
|
141
303
|
# @!visibility private
|
142
304
|
# @return [Boolean]
|
143
305
|
# @see Object#respond_to?
|
144
306
|
def respond_to?(method, *args)
|
145
|
-
|
307
|
+
return super unless %i[expand to_templates].include? method
|
308
|
+
respond_to_special?(method)
|
309
|
+
end
|
310
|
+
|
311
|
+
# @!visibility private
|
312
|
+
# @return [Boolean]
|
313
|
+
# @see #respond_to?
|
314
|
+
def respond_to_special?(method)
|
315
|
+
method(method).owner != Mustermann::Pattern
|
146
316
|
end
|
147
317
|
|
148
318
|
# @!visibility private
|
@@ -150,6 +320,12 @@ module Mustermann
|
|
150
320
|
"#<%p:%p>" % [self.class, @string]
|
151
321
|
end
|
152
322
|
|
323
|
+
# @!visibility private
|
324
|
+
def simple_inspect
|
325
|
+
type = self.class.name[/[^:]+$/].downcase
|
326
|
+
"%s:%p" % [type, @string]
|
327
|
+
end
|
328
|
+
|
153
329
|
# @!visibility private
|
154
330
|
def map_param(key, value)
|
155
331
|
unescape(value, true)
|
@@ -158,8 +334,7 @@ module Mustermann
|
|
158
334
|
# @!visibility private
|
159
335
|
def unescape(string, decode = @uri_decode)
|
160
336
|
return string unless decode and string
|
161
|
-
|
162
|
-
@uri.unescape(string)
|
337
|
+
@@uri.unescape(string)
|
163
338
|
end
|
164
339
|
|
165
340
|
# @!visibility private
|
@@ -170,7 +345,7 @@ module Mustermann
|
|
170
345
|
ALWAYS_ARRAY.include? key
|
171
346
|
end
|
172
347
|
|
173
|
-
private :unescape, :map_param
|
348
|
+
private :unescape, :map_param, :respond_to_special?
|
174
349
|
private_constant :ALWAYS_ARRAY
|
175
350
|
end
|
176
351
|
end
|