mustermann 0.2.0 → 0.3.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/.travis.yml +9 -6
- data/README.md +247 -10
- data/lib/mustermann.rb +13 -5
- data/lib/mustermann/ast/expander.rb +15 -0
- data/lib/mustermann/ast/pattern.rb +2 -3
- data/lib/mustermann/expander.rb +39 -4
- data/lib/mustermann/mapper.rb +94 -0
- data/lib/mustermann/pattern.rb +3 -3
- data/lib/mustermann/regular.rb +26 -0
- data/lib/mustermann/router/rack.rb +2 -2
- data/lib/mustermann/router/simple.rb +1 -1
- data/lib/mustermann/sinatra.rb +1 -1
- data/lib/mustermann/to_pattern.rb +45 -0
- data/lib/mustermann/version.rb +1 -1
- data/mustermann.gemspec +3 -1
- data/spec/expander_spec.rb +28 -0
- data/spec/mapper_spec.rb +83 -0
- data/spec/mustermann_spec.rb +30 -10
- data/spec/pattern_spec.rb +27 -4
- data/spec/regexp_based_spec.rb +1 -1
- data/spec/regular_spec.rb +36 -0
- data/spec/router/rack_spec.rb +1 -1
- data/spec/router/simple_spec.rb +9 -7
- data/spec/shell_spec.rb +1 -1
- data/spec/simple_match_spec.rb +1 -1
- data/spec/sinatra_spec.rb +13 -0
- data/spec/support/env.rb +11 -1
- data/spec/support/expand_matcher.rb +2 -2
- data/spec/support/match_matcher.rb +2 -2
- data/spec/support/pattern.rb +6 -2
- data/spec/to_pattern_spec.rb +20 -0
- metadata +64 -28
- data/lib/mustermann/equality_map.rb +0 -46
@@ -2,10 +2,9 @@ require 'mustermann/ast/parser'
|
|
2
2
|
require 'mustermann/ast/compiler'
|
3
3
|
require 'mustermann/ast/transformer'
|
4
4
|
require 'mustermann/ast/validation'
|
5
|
-
|
6
5
|
require 'mustermann/regexp_based'
|
7
|
-
require 'mustermann/equality_map'
|
8
6
|
require 'mustermann/expander'
|
7
|
+
require 'tool/equality_map'
|
9
8
|
|
10
9
|
module Mustermann
|
11
10
|
# @see Mustermann::AST::Pattern
|
@@ -62,7 +61,7 @@ module Mustermann
|
|
62
61
|
# Internal AST representation of pattern.
|
63
62
|
# @!visibility private
|
64
63
|
def to_ast
|
65
|
-
@ast_cache ||= EqualityMap.new
|
64
|
+
@ast_cache ||= Tool::EqualityMap.new
|
66
65
|
@ast_cache.fetch(@string) { validate(transform(parse(@string))) }
|
67
66
|
end
|
68
67
|
|
data/lib/mustermann/expander.rb
CHANGED
@@ -93,7 +93,7 @@ module Mustermann
|
|
93
93
|
#
|
94
94
|
# @param [Array<Symbol, Regexp, #===>] type_matchers
|
95
95
|
# To identify key/value pairs to match against.
|
96
|
-
# Regexps and Symbols match
|
96
|
+
# Regexps and Symbols match against key, everything else matches against value.
|
97
97
|
#
|
98
98
|
# @yield every key/value pair
|
99
99
|
# @yieldparam key [Symbol] omitted if block takes less than 2
|
@@ -138,7 +138,8 @@ module Mustermann
|
|
138
138
|
# @raise [NotImplementedError] raised if expand is not supported.
|
139
139
|
# @raise [Mustermann::ExpandError] raised if a value is missing or unknown
|
140
140
|
def expand(behavior = nil, **values)
|
141
|
-
values =
|
141
|
+
behavior, values = nil, behavior if behavior.is_a? Hash
|
142
|
+
values = map_values(values)
|
142
143
|
|
143
144
|
case behavior || additional_values
|
144
145
|
when :raise then @api_expander.expand(values)
|
@@ -148,10 +149,38 @@ module Mustermann
|
|
148
149
|
end
|
149
150
|
end
|
150
151
|
|
152
|
+
# @see Object#==
|
153
|
+
def ==(other)
|
154
|
+
return false unless other.class == self.class
|
155
|
+
other.patterns == patterns and other.additional_values == additional_values
|
156
|
+
end
|
157
|
+
|
158
|
+
# @see Object#eql?
|
159
|
+
def eql?(other)
|
160
|
+
return false unless other.class == self.class
|
161
|
+
other.patterns.eql? patterns and other.additional_values.eql? additional_values
|
162
|
+
end
|
163
|
+
|
164
|
+
# @see Object#hash
|
165
|
+
def hash
|
166
|
+
patterns.hash + additional_values.hash
|
167
|
+
end
|
168
|
+
|
169
|
+
def expandable?(values)
|
170
|
+
return false unless values
|
171
|
+
expandable, _ = split_values(map_values(values))
|
172
|
+
@api_expander.expandable? expandable
|
173
|
+
end
|
174
|
+
|
151
175
|
def with_rest(values)
|
176
|
+
expandable, non_expandable = split_values(values)
|
177
|
+
yield expand(:raise, slice(values, expandable)), slice(values, non_expandable)
|
178
|
+
end
|
179
|
+
|
180
|
+
def split_values(values)
|
152
181
|
expandable = @api_expander.expandable_keys(values.keys)
|
153
182
|
non_expandable = values.keys - expandable
|
154
|
-
|
183
|
+
[expandable, non_expandable]
|
155
184
|
end
|
156
185
|
|
157
186
|
def slice(hash, keys)
|
@@ -164,6 +193,12 @@ module Mustermann
|
|
164
193
|
"#{ uri }#{ uri[??]??&:?? }#{ entries.join(?&) }"
|
165
194
|
end
|
166
195
|
|
167
|
-
|
196
|
+
def map_values(values)
|
197
|
+
values = values.dup
|
198
|
+
@api_expander.keys.each { |key| values[key] ||= values.delete(key.to_s) if values.include? key.to_s }
|
199
|
+
caster.cast(values)
|
200
|
+
end
|
201
|
+
|
202
|
+
private :with_rest, :slice, :append, :caster, :map_values, :split_values
|
168
203
|
end
|
169
204
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'mustermann'
|
2
|
+
require 'mustermann/expander'
|
3
|
+
|
4
|
+
module Mustermann
|
5
|
+
# A mapper allows mapping one string to another based on pattern parsing and expanding.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# require 'mustermann/mapper'
|
9
|
+
# mapper = Mustermann::Mapper.new("/:foo" => "/:foo.html")
|
10
|
+
# mapper['/example'] # => "/example.html"
|
11
|
+
class Mapper
|
12
|
+
# Creates a new mapper.
|
13
|
+
#
|
14
|
+
# @overload initialize(**options)
|
15
|
+
# @param options [Hash] options The options hash
|
16
|
+
# @yield block for generating mappings as a hash
|
17
|
+
# @yieldreturn [Hash] see {#update}
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# require 'mustermann/mapper'
|
21
|
+
# Mustermann::Mapper.new(type: :rails) {{
|
22
|
+
# "/:foo" => ["/:foo.html", "/:foo.:format"]
|
23
|
+
# }}
|
24
|
+
#
|
25
|
+
# @overload initialize(**options)
|
26
|
+
# @param options [Hash] options The options hash
|
27
|
+
# @yield block for generating mappings as a hash
|
28
|
+
# @yieldparam mapper [Mustermann::Mapper] the mapper instance
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# require 'mustermann/mapper'
|
32
|
+
# Mustermann::Mapper.new(type: :rails) do |mapper|
|
33
|
+
# mapper["/:foo"] = ["/:foo.html", "/:foo.:format"]
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# @overload initialize(map = {}, **options)
|
37
|
+
# @param map [Hash] see {#update}
|
38
|
+
# @param [Hash] options The options hash
|
39
|
+
#
|
40
|
+
# @example map before options
|
41
|
+
# require 'mustermann/mapper'
|
42
|
+
# Mustermann::Mapper.new("/:foo" => "/:foo.html", type: :rails)
|
43
|
+
#
|
44
|
+
# @example map after options
|
45
|
+
# require 'mustermann/mapper'
|
46
|
+
# Mustermann::Mapper.new(type: :rails, "/:foo" => "/:foo.html")
|
47
|
+
def initialize(map = {}, additional_values: :ignore, **options, &block)
|
48
|
+
@map = []
|
49
|
+
@options = options
|
50
|
+
@additional_values = additional_values
|
51
|
+
block.arity == 0 ? update(yield) : yield(self) if block
|
52
|
+
update(map) if map
|
53
|
+
end
|
54
|
+
|
55
|
+
# Add multiple mappings.
|
56
|
+
#
|
57
|
+
# @param map [Hash{String, Pattern: String, Pattern, Arry<String, Pattern>, Expander}] the mapping
|
58
|
+
def update(map)
|
59
|
+
map.to_h.each_pair do |input, output|
|
60
|
+
input = Mustermann.new(input, **@options)
|
61
|
+
output = Expander.new(*output, additional_values: @additional_values, **@options) unless output.is_a? Expander
|
62
|
+
@map << [input, output]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return [Hash{Patttern: Expander}] Hash version of the mapper.
|
67
|
+
def to_h
|
68
|
+
Hash[@map]
|
69
|
+
end
|
70
|
+
|
71
|
+
# Convert a string according to mappings. You can pass in additional params.
|
72
|
+
#
|
73
|
+
# @example mapping with and without additional parameters
|
74
|
+
# mapper = Mustermann::Mapper.new("/:example" => "(/:prefix)?/:example.html")
|
75
|
+
#
|
76
|
+
def convert(input, values = {})
|
77
|
+
@map.inject(input) do |current, (pattern, expander)|
|
78
|
+
params = pattern.params(current)
|
79
|
+
params &&= Hash[values.merge(params).map { |k,v| [k.to_s, v] }]
|
80
|
+
expander.expandable?(params) ? expander.expand(params) : current
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Add a single mapping.
|
85
|
+
#
|
86
|
+
# @param key [String, Pattern] format of the input string
|
87
|
+
# @param value [String, Pattern, Arry<String, Pattern>, Expander] format of the output string
|
88
|
+
def []=(key, value)
|
89
|
+
update key => value
|
90
|
+
end
|
91
|
+
|
92
|
+
alias_method :[], :convert
|
93
|
+
end
|
94
|
+
end
|
data/lib/mustermann/pattern.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'mustermann/error'
|
2
2
|
require 'mustermann/simple_match'
|
3
|
-
require '
|
3
|
+
require 'tool/equality_map'
|
4
4
|
require 'uri'
|
5
5
|
|
6
6
|
module Mustermann
|
@@ -42,7 +42,7 @@ module Mustermann
|
|
42
42
|
raise ArgumentError, "unsupported option %p for %p" % [unsupported, self] if unsupported
|
43
43
|
end
|
44
44
|
|
45
|
-
@map ||= EqualityMap.new
|
45
|
+
@map ||= Tool::EqualityMap.new
|
46
46
|
@map.fetch(string, options) { super(string, options) }
|
47
47
|
end
|
48
48
|
|
@@ -56,7 +56,7 @@ module Mustermann
|
|
56
56
|
# @see Mustermann.new
|
57
57
|
def initialize(string, uri_decode: true, **options)
|
58
58
|
@uri_decode = uri_decode
|
59
|
-
@string = string.dup
|
59
|
+
@string = string.to_s.dup
|
60
60
|
end
|
61
61
|
|
62
62
|
# @return [String] the string representation of the pattern
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'mustermann/regexp_based'
|
2
|
+
|
3
|
+
module Mustermann
|
4
|
+
# Regexp pattern implementation.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# Mustermann.new('/.*', type: :regexp) === '/bar' # => true
|
8
|
+
#
|
9
|
+
# @see Mustermann::Pattern
|
10
|
+
# @see file:README.md#simple Syntax description in the README
|
11
|
+
class Regular < RegexpBased
|
12
|
+
# @param (see Mustermann::Pattern#initialize)
|
13
|
+
# @return (see Mustermann::Pattern#initialize)
|
14
|
+
# @see (see Mustermann::Pattern#initialize)
|
15
|
+
def initialize(string, **options)
|
16
|
+
string = $1 if string.to_s =~ /\A\(\?\-mix\:(.*)\)\Z/ && string.inspect == "/#$1/"
|
17
|
+
super(string, **options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def compile(**options)
|
21
|
+
/\A#{@string}\Z/
|
22
|
+
end
|
23
|
+
|
24
|
+
private :compile
|
25
|
+
end
|
26
|
+
end
|
@@ -5,7 +5,7 @@ module Mustermann
|
|
5
5
|
# Simple pattern based router that allows matching paths to a given Rack application.
|
6
6
|
#
|
7
7
|
# @example config.ru
|
8
|
-
# router = Mustermann::Rack do
|
8
|
+
# router = Mustermann::Rack.new do
|
9
9
|
# on '/' do |env|
|
10
10
|
# [200, {'Content-Type' => 'text/plain'}, ['Hello World!']]
|
11
11
|
# end
|
@@ -23,7 +23,7 @@ module Mustermann
|
|
23
23
|
class Rack < Simple
|
24
24
|
def initialize(env_prefix: "mustermann", params_key: "#{env_prefix}.params", pattern_key: "#{env_prefix}.pattern", **options, &block)
|
25
25
|
@params_key, @pattern_key = params_key, pattern_key
|
26
|
-
options[:default]
|
26
|
+
options[:default] = [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found"]] unless options.include? :default
|
27
27
|
super(**options, &block)
|
28
28
|
end
|
29
29
|
|
@@ -118,7 +118,7 @@ module Mustermann
|
|
118
118
|
|
119
119
|
# Finds the matching callback and calls `call` on it with the given input and the params.
|
120
120
|
# @return the callback's return value
|
121
|
-
def call(input
|
121
|
+
def call(input)
|
122
122
|
@map.each do |pattern, callback|
|
123
123
|
catch(:pass) do
|
124
124
|
next unless params = pattern.params(string_for(input))
|
data/lib/mustermann/sinatra.rb
CHANGED
@@ -10,7 +10,7 @@ module Mustermann
|
|
10
10
|
# @see file:README.md#sinatra Syntax description in the README
|
11
11
|
class Sinatra < AST::Pattern
|
12
12
|
on(nil, ??, ?)) { |c| unexpected(c) }
|
13
|
-
on(?*) { |c| node(:splat) }
|
13
|
+
on(?*) { |c| scan(/\w+/) ? node(:named_splat, buffer.matched) : node(:splat) }
|
14
14
|
on(?() { |c| node(:group) { read unless scan(?)) } }
|
15
15
|
on(?:) { |c| node(:capture) { scan(/\w+/) } }
|
16
16
|
on(?\\) { |c| node(:char, expect(/./)) }
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'mustermann'
|
2
|
+
|
3
|
+
module Mustermann
|
4
|
+
# Mixin for adding {#to_pattern} ducktyping to objects.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# require 'mustermann/to_pattern'
|
8
|
+
#
|
9
|
+
# class Foo
|
10
|
+
# include Mustermann::ToPattern
|
11
|
+
#
|
12
|
+
# def to_s
|
13
|
+
# ":foo/:bar"
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Foo.new.to_pattern # => #<Mustermann::Sinatra:":foo/:bar">
|
18
|
+
#
|
19
|
+
# By default included into {String}, {Symbol}, {Regexp} and {Mustermann::Pattern}.
|
20
|
+
module ToPattern
|
21
|
+
# Converts the object into a {Mustermann::Pattern}.
|
22
|
+
#
|
23
|
+
# @example converting a string
|
24
|
+
# ":name.png".to_pattern # => #<Mustermann::Sinatra:":name.png">
|
25
|
+
#
|
26
|
+
# @example converting a string with options
|
27
|
+
# "/*path".to_pattern(type: :rails) # => #<Mustermann::Rails:"/*path">
|
28
|
+
#
|
29
|
+
# @example converting a regexp
|
30
|
+
# /.*/.to_pattern # => #<Mustermann::Regular:".*">
|
31
|
+
#
|
32
|
+
# @example converting a pattern
|
33
|
+
# Mustermann.new("foo").to_pattern # => #<Mustermann::Sinatra:"foo">
|
34
|
+
#
|
35
|
+
# @param [Hash] options The options hash.
|
36
|
+
# @return [Mustermann::Pattern] pattern corresponding to object.
|
37
|
+
def to_pattern(**options)
|
38
|
+
Mustermann.new(self, **options)
|
39
|
+
end
|
40
|
+
|
41
|
+
append_features String
|
42
|
+
append_features Regexp
|
43
|
+
append_features Mustermann::Pattern
|
44
|
+
end
|
45
|
+
end
|
data/lib/mustermann/version.rb
CHANGED
data/mustermann.gemspec
CHANGED
@@ -17,7 +17,9 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.require_path = 'lib'
|
18
18
|
s.required_ruby_version = '>= 2.0.0'
|
19
19
|
|
20
|
-
s.
|
20
|
+
s.add_dependency 'tool', '~> 0.2'
|
21
|
+
s.add_development_dependency 'rspec' #, '~> 2.14'
|
22
|
+
s.add_development_dependency 'rspec-its'
|
21
23
|
s.add_development_dependency 'addressable'
|
22
24
|
s.add_development_dependency 'sinatra', '~> 1.4'
|
23
25
|
s.add_development_dependency 'rack-test'
|
data/spec/expander_spec.rb
CHANGED
@@ -74,4 +74,32 @@ describe Mustermann::Expander do
|
|
74
74
|
expander.expand(a: "fOo", b: "bAr").should be == "/FOO/bar"
|
75
75
|
end
|
76
76
|
end
|
77
|
+
|
78
|
+
describe :== do
|
79
|
+
example { Mustermann::Expander.new('/foo') .should be == Mustermann::Expander.new('/foo') }
|
80
|
+
example { Mustermann::Expander.new('/foo') .should_not be == Mustermann::Expander.new('/bar') }
|
81
|
+
example { Mustermann::Expander.new('/foo', type: :rails) .should be == Mustermann::Expander.new('/foo', type: :rails) }
|
82
|
+
example { Mustermann::Expander.new('/foo', type: :rails) .should_not be == Mustermann::Expander.new('/foo', type: :sinatra) }
|
83
|
+
end
|
84
|
+
|
85
|
+
describe :hash do
|
86
|
+
example { Mustermann::Expander.new('/foo') .hash.should be == Mustermann::Expander.new('/foo').hash }
|
87
|
+
example { Mustermann::Expander.new('/foo') .hash.should_not be == Mustermann::Expander.new('/bar').hash }
|
88
|
+
example { Mustermann::Expander.new('/foo', type: :rails) .hash.should be == Mustermann::Expander.new('/foo', type: :rails).hash }
|
89
|
+
example { Mustermann::Expander.new('/foo', type: :rails) .hash.should_not be == Mustermann::Expander.new('/foo', type: :sinatra).hash }
|
90
|
+
end
|
91
|
+
|
92
|
+
describe :eql? do
|
93
|
+
example { Mustermann::Expander.new('/foo') .should be_eql Mustermann::Expander.new('/foo') }
|
94
|
+
example { Mustermann::Expander.new('/foo') .should_not be_eql Mustermann::Expander.new('/bar') }
|
95
|
+
example { Mustermann::Expander.new('/foo', type: :rails) .should be_eql Mustermann::Expander.new('/foo', type: :rails) }
|
96
|
+
example { Mustermann::Expander.new('/foo', type: :rails) .should_not be_eql Mustermann::Expander.new('/foo', type: :sinatra) }
|
97
|
+
end
|
98
|
+
|
99
|
+
describe :equal? do
|
100
|
+
example { Mustermann::Expander.new('/foo') .should_not be_equal Mustermann::Expander.new('/foo') }
|
101
|
+
example { Mustermann::Expander.new('/foo') .should_not be_equal Mustermann::Expander.new('/bar') }
|
102
|
+
example { Mustermann::Expander.new('/foo', type: :rails) .should_not be_equal Mustermann::Expander.new('/foo', type: :rails) }
|
103
|
+
example { Mustermann::Expander.new('/foo', type: :rails) .should_not be_equal Mustermann::Expander.new('/foo', type: :sinatra) }
|
104
|
+
end
|
77
105
|
end
|
data/spec/mapper_spec.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'support'
|
2
|
+
require 'mustermann/mapper'
|
3
|
+
|
4
|
+
describe Mustermann::Mapper do
|
5
|
+
describe :initialize do
|
6
|
+
context 'accepts a block with no arguments, using the return value' do
|
7
|
+
subject(:mapper) { Mustermann::Mapper.new(additional_values: :raise) {{ "/foo" => "/bar" }}}
|
8
|
+
its(:to_h) { should be == { Mustermann.new("/foo") => Mustermann::Expander.new("/bar") } }
|
9
|
+
example { mapper['/foo'].should be == '/bar' }
|
10
|
+
example { mapper['/fox'].should be == '/fox' }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'accepts a block with argument, passes instance to it' do
|
14
|
+
subject(:mapper) { Mustermann::Mapper.new(additional_values: :raise) { |m| m["/foo"] = "/bar" }}
|
15
|
+
its(:to_h) { should be == { Mustermann.new("/foo") => Mustermann::Expander.new("/bar") } }
|
16
|
+
example { mapper['/foo'].should be == '/bar' }
|
17
|
+
example { mapper['/fox'].should be == '/fox' }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'accepts mappings followed by options' do
|
21
|
+
subject(:mapper) { Mustermann::Mapper.new("/foo" => "/bar", additional_values: :raise) }
|
22
|
+
its(:to_h) { should be == { Mustermann.new("/foo") => Mustermann::Expander.new("/bar") } }
|
23
|
+
example { mapper['/foo'].should be == '/bar' }
|
24
|
+
example { mapper['/fox'].should be == '/fox' }
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'accepts options followed by mappings' do
|
28
|
+
subject(:mapper) { Mustermann::Mapper.new(additional_values: :raise, "/foo" => "/bar") }
|
29
|
+
its(:to_h) { should be == { Mustermann.new("/foo") => Mustermann::Expander.new("/bar") } }
|
30
|
+
example { mapper['/foo'].should be == '/bar' }
|
31
|
+
example { mapper['/fox'].should be == '/fox' }
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'allows specifying type' do
|
35
|
+
subject(:mapper) { Mustermann::Mapper.new(additional_values: :raise, type: :rails, "/foo" => "/bar") }
|
36
|
+
its(:to_h) { should be == { Mustermann.new("/foo", type: :rails) => Mustermann::Expander.new("/bar", type: :rails) } }
|
37
|
+
example { mapper['/foo'].should be == '/bar' }
|
38
|
+
example { mapper['/fox'].should be == '/fox' }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe :convert do
|
43
|
+
subject(:mapper) { Mustermann::Mapper.new }
|
44
|
+
|
45
|
+
context 'it maps params' do
|
46
|
+
before { mapper["/:a"] = "/:a.html" }
|
47
|
+
example { mapper["/foo"] .should be == "/foo.html" }
|
48
|
+
example { mapper["/foo/bar"] .should be == "/foo/bar" }
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'it supports named splats' do
|
52
|
+
before { mapper["/*a"] = "/*a.html" }
|
53
|
+
example { mapper["/foo"] .should be == "/foo.html" }
|
54
|
+
example { mapper["/foo/bar"] .should be == "/foo/bar.html" }
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'can map from patterns' do
|
58
|
+
before { mapper[Mustermann.new("/:a")] = "/:a.html" }
|
59
|
+
example { mapper["/foo"] .should be == "/foo.html" }
|
60
|
+
example { mapper["/foo/bar"] .should be == "/foo/bar" }
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'can map to patterns' do
|
64
|
+
before { mapper[Mustermann.new("/:a")] = Mustermann.new("/:a.html") }
|
65
|
+
example { mapper["/foo"] .should be == "/foo.html" }
|
66
|
+
example { mapper["/foo/bar"] .should be == "/foo/bar" }
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'can map to expanders' do
|
70
|
+
before { mapper[Mustermann.new("/:a")] = Mustermann::Expander.new("/:a.html") }
|
71
|
+
example { mapper["/foo"] .should be == "/foo.html" }
|
72
|
+
example { mapper["/foo/bar"] .should be == "/foo/bar" }
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'can map to array' do
|
76
|
+
before { mapper["/:a"] = ["/:a.html", "/:a.:f"] }
|
77
|
+
example { mapper["/foo"] .should be == "/foo.html" }
|
78
|
+
example { mapper["/foo", "f" => 'x'] .should be == "/foo.x" }
|
79
|
+
example { mapper["/foo", f: 'x'] .should be == "/foo.x" }
|
80
|
+
example { mapper["/foo/bar"] .should be == "/foo/bar" }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|