mustermann 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|