mustermann19 0.3.1
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.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.travis.yml +10 -0
- data/.yardopts +1 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +1081 -0
- data/Rakefile +6 -0
- data/bench/capturing.rb +57 -0
- data/bench/regexp.rb +21 -0
- data/bench/simple_vs_sinatra.rb +23 -0
- data/bench/template_vs_addressable.rb +26 -0
- data/internals.md +64 -0
- data/lib/mustermann.rb +61 -0
- data/lib/mustermann/ast/compiler.rb +168 -0
- data/lib/mustermann/ast/expander.rb +134 -0
- data/lib/mustermann/ast/node.rb +160 -0
- data/lib/mustermann/ast/parser.rb +137 -0
- data/lib/mustermann/ast/pattern.rb +84 -0
- data/lib/mustermann/ast/transformer.rb +129 -0
- data/lib/mustermann/ast/translator.rb +108 -0
- data/lib/mustermann/ast/tree_renderer.rb +29 -0
- data/lib/mustermann/ast/validation.rb +43 -0
- data/lib/mustermann/caster.rb +117 -0
- data/lib/mustermann/equality_map.rb +48 -0
- data/lib/mustermann/error.rb +6 -0
- data/lib/mustermann/expander.rb +206 -0
- data/lib/mustermann/extension.rb +52 -0
- data/lib/mustermann/identity.rb +19 -0
- data/lib/mustermann/mapper.rb +98 -0
- data/lib/mustermann/pattern.rb +182 -0
- data/lib/mustermann/rails.rb +17 -0
- data/lib/mustermann/regexp_based.rb +30 -0
- data/lib/mustermann/regular.rb +26 -0
- data/lib/mustermann/router.rb +9 -0
- data/lib/mustermann/router/rack.rb +50 -0
- data/lib/mustermann/router/simple.rb +144 -0
- data/lib/mustermann/shell.rb +29 -0
- data/lib/mustermann/simple.rb +38 -0
- data/lib/mustermann/simple_match.rb +30 -0
- data/lib/mustermann/sinatra.rb +22 -0
- data/lib/mustermann/template.rb +48 -0
- data/lib/mustermann/to_pattern.rb +45 -0
- data/lib/mustermann/version.rb +3 -0
- data/mustermann.gemspec +31 -0
- data/spec/expander_spec.rb +105 -0
- data/spec/extension_spec.rb +296 -0
- data/spec/identity_spec.rb +83 -0
- data/spec/mapper_spec.rb +83 -0
- data/spec/mustermann_spec.rb +65 -0
- data/spec/pattern_spec.rb +49 -0
- data/spec/rails_spec.rb +522 -0
- data/spec/regexp_based_spec.rb +8 -0
- data/spec/regular_spec.rb +36 -0
- data/spec/router/rack_spec.rb +39 -0
- data/spec/router/simple_spec.rb +32 -0
- data/spec/shell_spec.rb +109 -0
- data/spec/simple_match_spec.rb +10 -0
- data/spec/simple_spec.rb +237 -0
- data/spec/sinatra_spec.rb +574 -0
- data/spec/support.rb +5 -0
- data/spec/support/coverage.rb +16 -0
- data/spec/support/env.rb +15 -0
- data/spec/support/expand_matcher.rb +27 -0
- data/spec/support/match_matcher.rb +39 -0
- data/spec/support/pattern.rb +39 -0
- data/spec/template_spec.rb +815 -0
- data/spec/to_pattern_spec.rb +20 -0
- metadata +301 -0
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'mustermann'
|
2
|
+
|
3
|
+
module Mustermann
|
4
|
+
module Router
|
5
|
+
# Simple pattern based router that allows matching a string to a given callback.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# require 'mustermann/router/simple'
|
9
|
+
#
|
10
|
+
# router = Mustermann::Router::Simple.new do
|
11
|
+
# on ':name/:sub' do |string, params|
|
12
|
+
# params['sub']
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# on 'foo' do
|
16
|
+
# "bar"
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# router.call("foo") # => "bar"
|
21
|
+
# router.call("a/b") # => "b"
|
22
|
+
# router.call("bar") # => nil
|
23
|
+
class Simple
|
24
|
+
# Default value for when no pattern matches
|
25
|
+
attr_accessor :default
|
26
|
+
|
27
|
+
# @example with a default value
|
28
|
+
# require 'mustermann/router/simple'
|
29
|
+
#
|
30
|
+
# router = Mustermann::Router::Simple.new(default: 42)
|
31
|
+
# router.on(':name', capture: :digit) { |string| string.to_i }
|
32
|
+
# router.call("23") # => 23
|
33
|
+
# router.call("example") # => 42
|
34
|
+
#
|
35
|
+
# @example block with implicit receiver
|
36
|
+
# require 'mustermann/router/simple'
|
37
|
+
#
|
38
|
+
# router = Mustermann::Router::Simple.new do
|
39
|
+
# on('/foo') { 'foo' }
|
40
|
+
# on('/bar') { 'bar' }
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# @example block with explicit receiver
|
44
|
+
# require 'mustermann/router/simple'
|
45
|
+
#
|
46
|
+
# router = Mustermann::Router::Simple.new(type: :rails) do |r|
|
47
|
+
# r.on('/foo') { 'foo' }
|
48
|
+
# r.on('/bar') { 'bar' }
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# @param default value to be returned if nothing matches
|
52
|
+
# @param options [Hash] pattern options
|
53
|
+
# @return [Mustermann::Router::Simple] new router instance
|
54
|
+
def initialize(options = {}, &block)
|
55
|
+
@options = options
|
56
|
+
@map = []
|
57
|
+
@default = @options.delete(:default)
|
58
|
+
|
59
|
+
block.arity == 0 ? instance_eval(&block) : yield(self) if block
|
60
|
+
end
|
61
|
+
|
62
|
+
# @example
|
63
|
+
# require 'mustermann/router/simple'
|
64
|
+
#
|
65
|
+
# router = Mustermann::Router::Simple.new
|
66
|
+
# router.on(':a/:b') { 42 }
|
67
|
+
# router['foo/bar'] # => <#Proc:...>
|
68
|
+
# router['foo_bar'] # => nil
|
69
|
+
#
|
70
|
+
# @return [#call, nil] callback for given string, if a pattern matches
|
71
|
+
def [](string)
|
72
|
+
string = string_for(string) unless string.is_a? String
|
73
|
+
@map.detect { |p,v| p === string }[1]
|
74
|
+
end
|
75
|
+
|
76
|
+
# @example
|
77
|
+
# require 'mustermann/router/simple'
|
78
|
+
#
|
79
|
+
# router = Mustermann::Router::Simple.new
|
80
|
+
# router['/:name'] = proc { |string, params| params['name'] }
|
81
|
+
# router.call('/foo') # => "foo"
|
82
|
+
#
|
83
|
+
# @param pattern [String, Mustermann::Pattern] matcher
|
84
|
+
# @param callback [#call] callback to call on match
|
85
|
+
# @see #on
|
86
|
+
def []=(pattern, callback)
|
87
|
+
on(pattern, call: callback)
|
88
|
+
end
|
89
|
+
|
90
|
+
# @example with block
|
91
|
+
# require 'mustermann/router/simple'
|
92
|
+
#
|
93
|
+
# router = Mustermann::Router::Simple.new
|
94
|
+
#
|
95
|
+
# router.on(':a/:b') { 42 }
|
96
|
+
# router.call('foo/bar') # => 42
|
97
|
+
# router.call('foo_bar') # => nil
|
98
|
+
#
|
99
|
+
# @example with callback option
|
100
|
+
# require 'mustermann/router/simple'
|
101
|
+
#
|
102
|
+
# callback = proc { 42 }
|
103
|
+
# router = Mustermann::Router::Simple.new
|
104
|
+
#
|
105
|
+
# router.on(':a/:b', call: callback)
|
106
|
+
# router.call('foo/bar') # => 42
|
107
|
+
# router.call('foo_bar') # => nil
|
108
|
+
#
|
109
|
+
# @param patterns [Array<String, Pattern>]
|
110
|
+
# @param call [#call] callback object, need to hand in block if missing
|
111
|
+
# @param options [Hash] pattern options
|
112
|
+
def on(*patterns)
|
113
|
+
options = patterns.last.is_a?(Hash) ? patterns.pop : {}
|
114
|
+
call = options.delete(:call) || Proc.new
|
115
|
+
patterns.each do |pattern|
|
116
|
+
pattern = Mustermann.new(pattern.to_str, @options.merge(options)) if pattern.respond_to? :to_str
|
117
|
+
@map << [pattern, call]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Finds the matching callback and calls `call` on it with the given input and the params.
|
122
|
+
# @return the callback's return value
|
123
|
+
def call(input)
|
124
|
+
@map.each do |pattern, callback|
|
125
|
+
catch(:pass) do
|
126
|
+
next unless params = pattern.params(string_for(input))
|
127
|
+
return invoke(callback, input, params, pattern)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
@default
|
131
|
+
end
|
132
|
+
|
133
|
+
def invoke(callback, input, params, pattern)
|
134
|
+
callback.call(input, params)
|
135
|
+
end
|
136
|
+
|
137
|
+
def string_for(input)
|
138
|
+
input.to_str
|
139
|
+
end
|
140
|
+
|
141
|
+
private :invoke, :string_for
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'mustermann/pattern'
|
2
|
+
require 'mustermann/simple_match'
|
3
|
+
|
4
|
+
module Mustermann
|
5
|
+
# Matches strings that are identical to the pattern.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# Mustermann.new('/*.*', type: :shell) === '/bar' # => false
|
9
|
+
#
|
10
|
+
# @see Mustermann::Pattern
|
11
|
+
# @see file:README.md#shell Syntax description in the README
|
12
|
+
class Shell < Pattern
|
13
|
+
# @param (see Mustermann::Pattern#initialize)
|
14
|
+
# @return (see Mustermann::Pattern#initialize)
|
15
|
+
# @see (see Mustermann::Pattern#initialize)
|
16
|
+
def initialize(string, options = {})
|
17
|
+
@flags = File::FNM_PATHNAME | File::FNM_DOTMATCH
|
18
|
+
@flags |= File::FNM_EXTGLOB if defined? File::FNM_EXTGLOB
|
19
|
+
super(string, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param (see Mustermann::Pattern#===)
|
23
|
+
# @return (see Mustermann::Pattern#===)
|
24
|
+
# @see (see Mustermann::Pattern#===)
|
25
|
+
def ===(string)
|
26
|
+
File.fnmatch? @string, unescape(string), @flags
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'mustermann/regexp_based'
|
2
|
+
|
3
|
+
module Mustermann
|
4
|
+
# Sinatra 1.3 style pattern implementation.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# Mustermann.new('/:foo', type: :simple) === '/bar' # => true
|
8
|
+
#
|
9
|
+
# @see Mustermann::Pattern
|
10
|
+
# @see file:README.md#simple Syntax description in the README
|
11
|
+
class Simple < RegexpBased
|
12
|
+
supported_options :greedy, :space_matches_plus
|
13
|
+
|
14
|
+
def compile(options = {})
|
15
|
+
greedy = options.fetch(:greedy, true)
|
16
|
+
uri_decode = options.fetch(:uri_decode, true)
|
17
|
+
space_matches_plus = options.fetch(:space_matches_plus, true)
|
18
|
+
pattern = @string.gsub(/[^\?\%\\\/\:\*\w]/) { |c| encoded(c, uri_decode, space_matches_plus) }
|
19
|
+
pattern.gsub!(/((:\w+)|\*)/) do |match|
|
20
|
+
match == "*" ? "(?<splat>.*?)" : "(?<#{$2[1..-1]}>[^/?#]+#{?? unless greedy})"
|
21
|
+
end
|
22
|
+
/\A#{Regexp.new(pattern)}\Z/
|
23
|
+
rescue SyntaxError, RegexpError => error
|
24
|
+
type = error.message["invalid group name"] ? CompileError : ParseError
|
25
|
+
raise type, error.message, error.backtrace
|
26
|
+
end
|
27
|
+
|
28
|
+
def encoded(char, uri_decode, space_matches_plus)
|
29
|
+
return Regexp.escape(char) unless uri_decode
|
30
|
+
parser = URI::Parser.new
|
31
|
+
encoded = Regexp.union(parser.escape(char), parser.escape(char, /./).downcase, parser.escape(char, /./).upcase)
|
32
|
+
encoded = Regexp.union(encoded, encoded('+', true, true)) if space_matches_plus and char == " "
|
33
|
+
encoded
|
34
|
+
end
|
35
|
+
|
36
|
+
private :compile, :encoded
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Mustermann
|
2
|
+
# Fakes MatchData for patterns that do not support capturing.
|
3
|
+
# @see http://ruby-doc.org/core-2.0/MatchData.html MatchData
|
4
|
+
class SimpleMatch
|
5
|
+
# @api private
|
6
|
+
def initialize(string)
|
7
|
+
@string = string.dup
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [String] the string that was matched against
|
11
|
+
def to_s
|
12
|
+
@string.dup
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Array<String>] empty array for imitating MatchData interface
|
16
|
+
def names
|
17
|
+
[]
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Array<String>] empty array for imitating MatchData interface
|
21
|
+
def captures
|
22
|
+
[]
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [nil] imitates MatchData interface
|
26
|
+
def [](*args)
|
27
|
+
captures[*args]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'mustermann/ast/pattern'
|
2
|
+
|
3
|
+
module Mustermann
|
4
|
+
# Sinatra 2.0 style pattern implementation.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# Mustermann.new('/:foo') === '/bar' # => true
|
8
|
+
#
|
9
|
+
# @see Mustermann::Pattern
|
10
|
+
# @see file:README.md#sinatra Syntax description in the README
|
11
|
+
class Sinatra < AST::Pattern
|
12
|
+
on(nil, ??, ?)) { |c| unexpected(c) }
|
13
|
+
on(?*) { |c| scan(/\w+/) ? node(:named_splat, buffer.matched) : node(:splat) }
|
14
|
+
on(?() { |c| node(:group) { read unless scan(?)) } }
|
15
|
+
on(?:) { |c| node(:capture) { scan(/\w+/) } }
|
16
|
+
on(?\\) { |c| node(:char, expect(/./)) }
|
17
|
+
|
18
|
+
suffix ?? do |char, element|
|
19
|
+
node(:optional, element)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'mustermann/ast/pattern'
|
2
|
+
|
3
|
+
module Mustermann
|
4
|
+
# URI template pattern implementation.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# Mustermann.new('/{foo}') === '/bar' # => true
|
8
|
+
#
|
9
|
+
# @see Mustermann::Pattern
|
10
|
+
# @see file:README.md#template Syntax description in the README
|
11
|
+
# @see http://tools.ietf.org/html/rfc6570 RFC 6570
|
12
|
+
class Template < AST::Pattern
|
13
|
+
on ?{ do |char|
|
14
|
+
variable = proc do
|
15
|
+
match = expect(/(?<name>\w+)(?:\:(?<prefix>\d{1,4})|(?<explode>\*))?/)
|
16
|
+
node(:variable, match[:name], prefix: match[:prefix], explode: match[:explode])
|
17
|
+
end
|
18
|
+
|
19
|
+
operator = buffer.scan(/[\+\#\.\/;\?\&\=\,\!\@\|]/)
|
20
|
+
expression = node(:expression, [variable[]], operator: operator) { variable[] if scan(?,) }
|
21
|
+
expression if expect(?})
|
22
|
+
end
|
23
|
+
|
24
|
+
on(?}) { |c| unexpected(c) }
|
25
|
+
|
26
|
+
# @!visibility private
|
27
|
+
def compile(*args)
|
28
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
29
|
+
@split_params = {}
|
30
|
+
super(*args, options.merge(:split_params => @split_params))
|
31
|
+
end
|
32
|
+
|
33
|
+
# @!visibility private
|
34
|
+
def map_param(key, value)
|
35
|
+
return super unless variable = @split_params[key]
|
36
|
+
value = value.split variable[:separator]
|
37
|
+
value.map! { |e| e.sub(/\A#{key}=/, '') } if variable[:parametric]
|
38
|
+
value.map! { |e| super(key, e) }
|
39
|
+
end
|
40
|
+
|
41
|
+
# @!visibility private
|
42
|
+
def always_array?(key)
|
43
|
+
@split_params.include? key
|
44
|
+
end
|
45
|
+
|
46
|
+
private :compile, :map_param, :always_array?
|
47
|
+
end
|
48
|
+
end
|
@@ -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/mustermann.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
$:.unshift File.expand_path("../lib", __FILE__)
|
2
|
+
require "mustermann/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "mustermann19"
|
6
|
+
s.version = Mustermann::VERSION
|
7
|
+
s.authors = ["Konstantin Haase", "namusyaka"]
|
8
|
+
s.email = "namusyaka@gmail.com"
|
9
|
+
s.homepage = "https://github.com/namusyaka/mustermann"
|
10
|
+
s.summary = %q{use patterns like regular expressions}
|
11
|
+
s.description = %q{library implementing patterns that behave like regular expressions for use in Ruby 1.9}
|
12
|
+
s.license = 'MIT'
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
s.extra_rdoc_files = %w[README.md internals.md]
|
17
|
+
s.require_path = 'lib'
|
18
|
+
s.required_ruby_version = '>= 1.9.2'
|
19
|
+
|
20
|
+
s.add_dependency 'enumerable-lazy' if RUBY_VERSION < '2.0.0'
|
21
|
+
s.add_development_dependency 'rspec' #, '~> 2.14'
|
22
|
+
s.add_development_dependency 'rspec-its'
|
23
|
+
s.add_development_dependency 'addressable'
|
24
|
+
s.add_development_dependency 'sinatra', '~> 1.4'
|
25
|
+
s.add_development_dependency 'rack-test'
|
26
|
+
s.add_development_dependency 'rake'
|
27
|
+
s.add_development_dependency 'yard'
|
28
|
+
#s.add_development_dependency 'redcarpet'
|
29
|
+
s.add_development_dependency 'simplecov'
|
30
|
+
s.add_development_dependency 'coveralls'
|
31
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'support'
|
2
|
+
require 'mustermann/expander'
|
3
|
+
|
4
|
+
describe Mustermann::Expander do
|
5
|
+
it 'expands a pattern' do
|
6
|
+
expander = Mustermann::Expander.new("/:foo.jpg")
|
7
|
+
expander.expand(foo: 42).should be == "/42.jpg"
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'expands multiple patterns' do
|
11
|
+
expander = Mustermann::Expander.new << "/:foo.:ext" << "/:foo"
|
12
|
+
expander.expand(foo: 42, ext: 'jpg').should be == "/42.jpg"
|
13
|
+
expander.expand(foo: 23).should be == "/23"
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'supports setting pattern options' do
|
17
|
+
expander = Mustermann::Expander.new(type: :rails) << "/:foo(.:ext)" << "/:bar"
|
18
|
+
expander.expand(foo: 42, ext: 'jpg').should be == "/42.jpg"
|
19
|
+
expander.expand(foo: 42).should be == "/42"
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'supports combining different pattern styles' do
|
23
|
+
expander = Mustermann::Expander.new << Mustermann.new("/:foo(.:ext)", type: :rails) << Mustermann.new("/:bar", type: :sinatra)
|
24
|
+
expander.expand(foo: 'pony', ext: 'jpg').should be == '/pony.jpg'
|
25
|
+
expander.expand(bar: 23).should be == "/23"
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'ignores nil values' do
|
29
|
+
expander = Mustermann::Expander.new << Mustermann.new("/:foo(.:ext)?")
|
30
|
+
expander.expand(foo: 'pony', ext: nil).should be == '/pony'
|
31
|
+
end
|
32
|
+
|
33
|
+
describe :additional_values do
|
34
|
+
context "illegal value" do
|
35
|
+
example { expect { Mustermann::Expander.new(additional_values: :foo) }.to raise_error(ArgumentError) }
|
36
|
+
example { expect { Mustermann::Expander.new('/').expand(:foo, a: 10) }.to raise_error(ArgumentError) }
|
37
|
+
end
|
38
|
+
|
39
|
+
context :raise do
|
40
|
+
subject(:expander) { Mustermann::Expander.new('/:a', additional_values: :raise) }
|
41
|
+
example { expander.expand(a: ?a).should be == '/a' }
|
42
|
+
example { expect { expander.expand(a: ?a, b: ?b) }.to raise_error(Mustermann::ExpandError) }
|
43
|
+
example { expect { expander.expand(b: ?b) }.to raise_error(Mustermann::ExpandError) }
|
44
|
+
end
|
45
|
+
|
46
|
+
context :ignore do
|
47
|
+
subject(:expander) { Mustermann::Expander.new('/:a', additional_values: :ignore) }
|
48
|
+
example { expander.expand(a: ?a).should be == '/a' }
|
49
|
+
example { expander.expand(a: ?a, b: ?b).should be == '/a' }
|
50
|
+
example { expect { expander.expand(b: ?b) }.to raise_error(Mustermann::ExpandError) }
|
51
|
+
end
|
52
|
+
|
53
|
+
context :append do
|
54
|
+
subject(:expander) { Mustermann::Expander.new('/:a', additional_values: :append) }
|
55
|
+
example { expander.expand(a: ?a).should be == '/a' }
|
56
|
+
example { expander.expand(a: ?a, b: ?b).should be == '/a?b=b' }
|
57
|
+
example { expect { expander.expand(b: ?b) }.to raise_error(Mustermann::ExpandError) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe :cast do
|
62
|
+
subject(:expander) { Mustermann::Expander.new('/:a(/:b)?') }
|
63
|
+
|
64
|
+
example { expander.cast { "FOOBAR" }.expand(a: "foo") .should be == "/FOOBAR" }
|
65
|
+
example { expander.cast { |v| v.upcase }.expand(a: "foo") .should be == "/FOO" }
|
66
|
+
example { expander.cast { |v| v.upcase }.expand(a: "foo", b: "bar") .should be == "/FOO/BAR" }
|
67
|
+
example { expander.cast(:a) { |v| v.upcase }.expand(a: "foo", b: "bar") .should be == "/FOO/bar" }
|
68
|
+
example { expander.cast(:a, :b) { |v| v.upcase }.expand(a: "foo", b: "bar") .should be == "/FOO/BAR" }
|
69
|
+
example { expander.cast(Integer) { |k,v| "#{k}_#{v}" }.expand(a: "foo", b: 42) .should be == "/foo/b_42" }
|
70
|
+
|
71
|
+
example do
|
72
|
+
expander.cast(:a) { |v| v.upcase }
|
73
|
+
expander.cast(:b) { |v| v.downcase }
|
74
|
+
expander.expand(a: "fOo", b: "bAr").should be == "/FOO/bar"
|
75
|
+
end
|
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
|
105
|
+
end
|