usher 0.4.8
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +3 -0
- data/Manifest.txt +35 -0
- data/README.rdoc +126 -0
- data/Rakefile +72 -0
- data/VERSION.yml +4 -0
- data/lib/usher/exceptions.rb +5 -0
- data/lib/usher/generate.rb +131 -0
- data/lib/usher/grapher.rb +65 -0
- data/lib/usher/interface/email_interface.rb +27 -0
- data/lib/usher/interface/merb_interface.rb +61 -0
- data/lib/usher/interface/rack_interface/mapper.rb +0 -0
- data/lib/usher/interface/rack_interface/route.rb +9 -0
- data/lib/usher/interface/rack_interface.rb +37 -0
- data/lib/usher/interface/rails2_2_interface/mapper.rb +44 -0
- data/lib/usher/interface/rails2_2_interface.rb +135 -0
- data/lib/usher/interface/rails2_3_interface.rb +135 -0
- data/lib/usher/interface.rb +27 -0
- data/lib/usher/node.rb +138 -0
- data/lib/usher/route/path.rb +24 -0
- data/lib/usher/route/request_method.rb +22 -0
- data/lib/usher/route/variable.rb +37 -0
- data/lib/usher/route.rb +58 -0
- data/lib/usher/splitter.rb +159 -0
- data/lib/usher.rb +184 -0
- data/rails/init.rb +8 -0
- data/spec/private/email/recognize_spec.rb +38 -0
- data/spec/private/generate_spec.rb +141 -0
- data/spec/private/grapher_spec.rb +41 -0
- data/spec/private/path_spec.rb +68 -0
- data/spec/private/rack/dispatch_spec.rb +29 -0
- data/spec/private/rails2_2/compat.rb +1 -0
- data/spec/private/rails2_2/generate_spec.rb +28 -0
- data/spec/private/rails2_2/path_spec.rb +16 -0
- data/spec/private/rails2_2/recognize_spec.rb +79 -0
- data/spec/private/rails2_3/compat.rb +1 -0
- data/spec/private/rails2_3/generate_spec.rb +28 -0
- data/spec/private/rails2_3/path_spec.rb +16 -0
- data/spec/private/rails2_3/recognize_spec.rb +79 -0
- data/spec/private/recognize_spec.rb +178 -0
- data/spec/private/request_method_spec.rb +15 -0
- data/spec/private/split_spec.rb +76 -0
- data/spec/spec.opts +7 -0
- metadata +120 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'rails2_2_interface', 'mapper')
|
2
|
+
|
3
|
+
class Usher
|
4
|
+
module Interface
|
5
|
+
class Rails2_2Interface
|
6
|
+
|
7
|
+
attr_reader :usher
|
8
|
+
attr_accessor :configuration_file
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
reset!
|
12
|
+
end
|
13
|
+
|
14
|
+
def reset!
|
15
|
+
@usher ||= Usher.new
|
16
|
+
@url_generator ||= Usher::Generators::URL.new(@usher)
|
17
|
+
@module ||= Module.new
|
18
|
+
@module.instance_methods.each do |selector|
|
19
|
+
@module.class_eval { remove_method selector }
|
20
|
+
end
|
21
|
+
@controller_action_route_added = false
|
22
|
+
@controller_route_added = false
|
23
|
+
@usher.reset!
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_route(path, options = {})
|
27
|
+
if !@controller_action_route_added && path =~ %r{^/?:controller/:action/:id$}
|
28
|
+
add_route('/:controller/:action', options.dup)
|
29
|
+
@controller_action_route_added = true
|
30
|
+
end
|
31
|
+
|
32
|
+
if !@controller_route_added && path =~ %r{^/?:controller/:action$}
|
33
|
+
add_route('/:controller', options.merge({:action => 'index'}))
|
34
|
+
@controller_route_added = true
|
35
|
+
end
|
36
|
+
|
37
|
+
options[:action] = 'index' unless options[:action]
|
38
|
+
|
39
|
+
path[0, 0] = '/' unless path[0] == ?/
|
40
|
+
route = @usher.add_route(path, options)
|
41
|
+
raise "your route must include a controller" unless route.paths.first.dynamic_keys.include?(:controller) || route.destination.include?(:controller)
|
42
|
+
route
|
43
|
+
end
|
44
|
+
|
45
|
+
def recognize(request)
|
46
|
+
node = @usher.recognize(request)
|
47
|
+
params = node.params.inject({}){|h,(k,v)| h[k]=v; h }
|
48
|
+
request.path_parameters = (node.params.empty? ? node.path.route.destination : node.path.route.destination.merge(params)).with_indifferent_access
|
49
|
+
"#{request.path_parameters[:controller].camelize}Controller".constantize
|
50
|
+
rescue
|
51
|
+
raise ActionController::RoutingError, "No route matches #{request.path.inspect} with #{request.inspect}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_named_route(name, route, options = {})
|
55
|
+
@usher.add_route(route, options).name(name)
|
56
|
+
end
|
57
|
+
|
58
|
+
def route_count
|
59
|
+
@usher.route_count
|
60
|
+
end
|
61
|
+
|
62
|
+
def empty?
|
63
|
+
@usher.route_count.zero?
|
64
|
+
end
|
65
|
+
|
66
|
+
def generate(options, recall = {}, method = :generate, route_name = nil)
|
67
|
+
route = if(route_name)
|
68
|
+
@usher.named_routes[route_name]
|
69
|
+
else
|
70
|
+
merged_options = options
|
71
|
+
merged_options[:controller] = recall[:controller] unless options.key?(:controller)
|
72
|
+
unless options.key?(:action)
|
73
|
+
options[:action] = ''
|
74
|
+
end
|
75
|
+
path_for_options(merged_options)
|
76
|
+
end
|
77
|
+
case method
|
78
|
+
when :generate
|
79
|
+
merged_options ||= recall.merge(options)
|
80
|
+
url = generate_url(route, merged_options)
|
81
|
+
url.slice!(-1) if url[-1] == ?/
|
82
|
+
url
|
83
|
+
else
|
84
|
+
raise "method #{method} not recognized"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def generate_url(route, params)
|
89
|
+
@url_generator.generate(route, params)
|
90
|
+
end
|
91
|
+
|
92
|
+
def path_for_options(options)
|
93
|
+
@usher.path_for_options(options)
|
94
|
+
end
|
95
|
+
|
96
|
+
def named_routes
|
97
|
+
@usher.named_routes
|
98
|
+
end
|
99
|
+
|
100
|
+
def reload
|
101
|
+
@usher.reset!
|
102
|
+
if @configuration_file
|
103
|
+
Kernel.load(@configuration_file)
|
104
|
+
else
|
105
|
+
@usher.add_route ":controller/:action/:id"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def load_routes!
|
110
|
+
reload
|
111
|
+
end
|
112
|
+
|
113
|
+
def draw
|
114
|
+
reset!
|
115
|
+
yield Mapper.new(self)
|
116
|
+
install_helpers
|
117
|
+
end
|
118
|
+
|
119
|
+
def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false)
|
120
|
+
#*_url and hash_for_*_url
|
121
|
+
Array(destinations).each do |d| d.module_eval { include Helpers }
|
122
|
+
@usher.named_routes.keys.each do |name|
|
123
|
+
@module.module_eval <<-end_eval # We use module_eval to avoid leaks
|
124
|
+
def #{name}_url(options = {})
|
125
|
+
ActionController::Routing::UsherRoutes.generate(options, {}, :generate, :#{name})
|
126
|
+
end
|
127
|
+
end_eval
|
128
|
+
end
|
129
|
+
d.__send__(:include, @module)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
class Usher
|
2
|
+
module Interface
|
3
|
+
class Rails2_3Interface
|
4
|
+
|
5
|
+
attr_reader :configuration_files
|
6
|
+
|
7
|
+
def named_routes
|
8
|
+
@router.named_routes
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_named_route(name, route, options = {})
|
12
|
+
@router.add_route(route, options).name(name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_route(path, options = {})
|
16
|
+
if !@controller_action_route_added && path =~ %r{^/?:controller/:action/:id$}
|
17
|
+
add_route('/:controller/:action', options.dup)
|
18
|
+
@controller_action_route_added = true
|
19
|
+
end
|
20
|
+
|
21
|
+
if !@controller_route_added && path =~ %r{^/?:controller/:action$}
|
22
|
+
add_route('/:controller', options.merge({:action => 'index'}))
|
23
|
+
@controller_route_added = true
|
24
|
+
end
|
25
|
+
|
26
|
+
options[:action] = 'index' unless options[:action]
|
27
|
+
|
28
|
+
path[0, 0] = '/' unless path[0] == ?/
|
29
|
+
route = @router.add_route(path, options).to(options)
|
30
|
+
|
31
|
+
raise "your route must include a controller" unless (route.paths.first.dynamic_keys.include?(:controller) || route.destination.include?(:controller))
|
32
|
+
route
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
reset!
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_configuration_file(file)
|
40
|
+
@configuration_files << file
|
41
|
+
end
|
42
|
+
|
43
|
+
def reload!
|
44
|
+
if configuration_files.any?
|
45
|
+
configuration_files.each { |config| load(config) }
|
46
|
+
else
|
47
|
+
add_route ":controller/:action/:id"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
alias_method :reload, :reload!
|
52
|
+
|
53
|
+
def route_count
|
54
|
+
routes.size
|
55
|
+
end
|
56
|
+
|
57
|
+
def routes
|
58
|
+
@router.routes
|
59
|
+
end
|
60
|
+
|
61
|
+
def call(env)
|
62
|
+
request = ActionController::Request.new(env)
|
63
|
+
app = recognize(request)
|
64
|
+
app.call(env).to_a
|
65
|
+
end
|
66
|
+
|
67
|
+
def recognize(request)
|
68
|
+
response = @router.recognize(request)
|
69
|
+
request.path_parameters = (response.params.empty? ? response.path.route.destination : response.path.route.destination.merge(response.params.inject({}){|h,(k,v)| h[k]=v; h })).with_indifferent_access
|
70
|
+
response.params.each { |pair| request.path_parameters[pair.first] = pair.last }
|
71
|
+
"#{request.path_parameters[:controller].camelize}Controller".constantize
|
72
|
+
end
|
73
|
+
|
74
|
+
def reset!
|
75
|
+
@router = Usher.new
|
76
|
+
@url_generator = Usher::Generators::URL.new(@router)
|
77
|
+
@configuration_files = []
|
78
|
+
@module ||= Module.new
|
79
|
+
@controller_route_added = false
|
80
|
+
@controller_action_route_added = false
|
81
|
+
end
|
82
|
+
|
83
|
+
def draw
|
84
|
+
reset!
|
85
|
+
yield ActionController::Routing::RouteSet::Mapper.new(self)
|
86
|
+
install_helpers
|
87
|
+
end
|
88
|
+
|
89
|
+
def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false)
|
90
|
+
#*_url and hash_for_*_url
|
91
|
+
Array(destinations).each do |d| d.module_eval { include Helpers }
|
92
|
+
@router.named_routes.keys.each do |name|
|
93
|
+
@module.module_eval <<-end_eval # We use module_eval to avoid leaks
|
94
|
+
def #{name}_url(options = {})
|
95
|
+
ActionController::Routing::UsherRoutes.generate(options, {}, :generate, :#{name})
|
96
|
+
end
|
97
|
+
end_eval
|
98
|
+
end
|
99
|
+
d.__send__(:include, @module)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def generate(options, recall = {}, method = :generate, route_name = nil)
|
104
|
+
route = if(route_name)
|
105
|
+
@router.named_routes[route_name]
|
106
|
+
else
|
107
|
+
merged_options = options
|
108
|
+
merged_options[:controller] = recall[:controller] unless options.key?(:controller)
|
109
|
+
unless options.key?(:action)
|
110
|
+
options[:action] = ''
|
111
|
+
end
|
112
|
+
path_for_options(merged_options)
|
113
|
+
end
|
114
|
+
case method
|
115
|
+
when :generate
|
116
|
+
merged_options ||= recall.merge(options)
|
117
|
+
url = generate_url(route, merged_options)
|
118
|
+
url.slice!(-1) if url[-1] == ?/
|
119
|
+
url
|
120
|
+
else
|
121
|
+
raise "method #{method} not recognized"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def generate_url(route, params)
|
126
|
+
@url_generator.generate(route, params)
|
127
|
+
end
|
128
|
+
|
129
|
+
def path_for_options(options)
|
130
|
+
@router.path_for_options(options)
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Usher
|
2
|
+
module Interface
|
3
|
+
autoload :Rails2_2Interface, File.join(File.dirname(__FILE__), 'interface', 'rails2_2_interface')
|
4
|
+
autoload :Rails2_3Interface, File.join(File.dirname(__FILE__), 'interface', 'rails2_3_interface')
|
5
|
+
autoload :MerbInterface, File.join(File.dirname(__FILE__), 'interface', 'merb_interface')
|
6
|
+
autoload :RackInterface, File.join(File.dirname(__FILE__), 'interface', 'rack_interface')
|
7
|
+
autoload :EmailInterface, File.join(File.dirname(__FILE__), 'interface', 'email_interface')
|
8
|
+
|
9
|
+
def self.for(type, &blk)
|
10
|
+
case type
|
11
|
+
when :rails2_2
|
12
|
+
Rails2_2Interface.new(&blk)
|
13
|
+
when :rails2_3
|
14
|
+
Rails2_3Interface.new(&blk)
|
15
|
+
when :merb
|
16
|
+
MerbInterface.new(&blk)
|
17
|
+
when :rack
|
18
|
+
RackInterface.new(&blk)
|
19
|
+
when :email
|
20
|
+
EmailInterface.new(&blk)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/lib/usher/node.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'fuzzy_hash'
|
2
|
+
|
3
|
+
class Usher
|
4
|
+
|
5
|
+
class Node
|
6
|
+
|
7
|
+
Response = Struct.new(:path, :params)
|
8
|
+
|
9
|
+
attr_reader :lookup
|
10
|
+
attr_accessor :terminates, :exclusive_type, :parent, :value, :request_methods, :globs_capture_separators
|
11
|
+
|
12
|
+
def initialize(parent, value)
|
13
|
+
@parent = parent
|
14
|
+
@value = value
|
15
|
+
@lookup = Hash.new
|
16
|
+
@exclusive_type = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def upgrade_lookup
|
20
|
+
@lookup = FuzzyHash.new(@lookup)
|
21
|
+
end
|
22
|
+
|
23
|
+
def depth
|
24
|
+
@depth ||= @parent && @parent.is_a?(Node) ? @parent.depth + 1 : 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.root(route_set, request_methods, globs_capture_separators)
|
28
|
+
root = self.new(route_set, nil)
|
29
|
+
root.request_methods = request_methods
|
30
|
+
root.globs_capture_separators = globs_capture_separators
|
31
|
+
root
|
32
|
+
end
|
33
|
+
|
34
|
+
def terminates?
|
35
|
+
@terminates
|
36
|
+
end
|
37
|
+
|
38
|
+
def pp
|
39
|
+
$stdout << " " * depth
|
40
|
+
$stdout << "#{depth}: #{value.inspect} #{!!terminates?}\n"
|
41
|
+
@lookup.each do |k,v|
|
42
|
+
$stdout << " " * (depth + 1)
|
43
|
+
$stdout << "#{k} ==> \n"
|
44
|
+
v.pp
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def add(route)
|
49
|
+
route.paths.each do |path|
|
50
|
+
parts = path.parts.dup
|
51
|
+
request_methods.each do |type|
|
52
|
+
parts.push(Route::RequestMethod.new(type, route.conditions[type])) if route.conditions && route.conditions.key?(type)
|
53
|
+
end
|
54
|
+
|
55
|
+
current_node = self
|
56
|
+
until parts.size.zero?
|
57
|
+
key = parts.shift
|
58
|
+
target_node = case key
|
59
|
+
when Route::RequestMethod
|
60
|
+
current_node.upgrade_lookup if key.value.is_a?(Regexp)
|
61
|
+
if current_node.exclusive_type == key.type
|
62
|
+
current_node.lookup[key.value] ||= Node.new(current_node, key)
|
63
|
+
elsif current_node.lookup.empty?
|
64
|
+
current_node.exclusive_type = key.type
|
65
|
+
current_node.lookup[key.value] ||= Node.new(current_node, key)
|
66
|
+
else
|
67
|
+
parts.unshift(key)
|
68
|
+
current_node.lookup[nil] ||= Node.new(current_node, Route::RequestMethod.new(current_node.exclusive_type, nil))
|
69
|
+
end
|
70
|
+
else
|
71
|
+
key.globs_capture_separators = globs_capture_separators if key.is_a?(Route::Variable)
|
72
|
+
|
73
|
+
if !key.is_a?(Route::Variable)
|
74
|
+
current_node.upgrade_lookup if key.is_a?(Regexp)
|
75
|
+
current_node.lookup[key] ||= Node.new(current_node, key)
|
76
|
+
elsif key.regex_matcher
|
77
|
+
current_node.upgrade_lookup
|
78
|
+
current_node.lookup[key.regex_matcher] ||= Node.new(current_node, key)
|
79
|
+
else
|
80
|
+
current_node.lookup[nil] ||= Node.new(current_node, key)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
current_node = target_node
|
84
|
+
end
|
85
|
+
current_node.terminates = path
|
86
|
+
end
|
87
|
+
route
|
88
|
+
end
|
89
|
+
|
90
|
+
def find(usher, request, path, params = [])
|
91
|
+
if exclusive_type
|
92
|
+
[lookup[request.send(exclusive_type)], lookup[nil]].each do |n|
|
93
|
+
if n && (ret = n.find(usher, request, path.dup, params.dup))
|
94
|
+
return ret
|
95
|
+
end
|
96
|
+
end
|
97
|
+
elsif path.size.zero? && terminates?
|
98
|
+
Response.new(terminates, params)
|
99
|
+
elsif !path.size.zero? && (next_part = lookup[part = path.shift] || lookup[nil])
|
100
|
+
case next_part.value
|
101
|
+
when Route::Variable
|
102
|
+
case next_part.value.type
|
103
|
+
when :*
|
104
|
+
params << [next_part.value.name, []] unless params.last && params.last.first == next_part.value.name
|
105
|
+
loop do
|
106
|
+
if (next_part.value.look_ahead === part || (!usher.splitter.delimiter_chars.include?(part[0]) && next_part.value.regex_matcher && !next_part.value.regex_matcher.match(part)))
|
107
|
+
path.unshift(part)
|
108
|
+
path.unshift(next_part.parent.value) if usher.splitter.delimiter_chars.include?(next_part.parent.value[0])
|
109
|
+
break
|
110
|
+
elsif next_part.value.globs_capture_separators
|
111
|
+
params.last.last << part
|
112
|
+
elsif !usher.splitter.delimiter_chars.include?(part[0])
|
113
|
+
next_part.value.valid!(part)
|
114
|
+
params.last.last << part
|
115
|
+
end
|
116
|
+
if path.size.zero?
|
117
|
+
break
|
118
|
+
else
|
119
|
+
part = path.shift
|
120
|
+
end
|
121
|
+
end
|
122
|
+
when :':'
|
123
|
+
var = next_part.value
|
124
|
+
var.valid!(part)
|
125
|
+
params << [var.name, part]
|
126
|
+
until (var.look_ahead === path.first) || path.empty?
|
127
|
+
params.last.last << path.shift
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
next_part.find(usher, request, path, params)
|
132
|
+
else
|
133
|
+
nil
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Usher
|
2
|
+
class Route
|
3
|
+
class Path
|
4
|
+
|
5
|
+
attr_reader :dynamic_parts, :dynamic_map, :dynamic_indicies, :route, :parts, :dynamic_required_keys, :dynamic_keys
|
6
|
+
|
7
|
+
def initialize(route, parts)
|
8
|
+
@route = route
|
9
|
+
@parts = parts
|
10
|
+
@dynamic_indicies = []
|
11
|
+
@parts.each_index{|i| @dynamic_indicies << i if @parts[i].is_a?(Variable)}
|
12
|
+
@dynamic_parts = @parts.values_at(*@dynamic_indicies)
|
13
|
+
@dynamic_map = {}
|
14
|
+
@dynamic_parts.each{|p| @dynamic_map[p.name] = p }
|
15
|
+
@dynamic_keys = @dynamic_map.keys
|
16
|
+
@dynamic_required_keys = @dynamic_parts.select{|dp| !dp.default_value}.map{|dp| dp.name}
|
17
|
+
end
|
18
|
+
|
19
|
+
def can_generate_from?(keys)
|
20
|
+
(@dynamic_required_keys - keys).size.zero?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Usher
|
2
|
+
class Route
|
3
|
+
class RequestMethod
|
4
|
+
|
5
|
+
attr_reader :type, :value
|
6
|
+
|
7
|
+
def initialize(type, value)
|
8
|
+
@type = type
|
9
|
+
@value = value
|
10
|
+
end
|
11
|
+
|
12
|
+
def hash
|
13
|
+
type.hash + value.hash
|
14
|
+
end
|
15
|
+
|
16
|
+
def eql?(o)
|
17
|
+
o.is_a?(self.class) && o.type == type && o.value == value
|
18
|
+
end
|
19
|
+
alias == eql?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Usher
|
2
|
+
class Route
|
3
|
+
class Variable
|
4
|
+
attr_reader :type, :name, :validator, :regex_matcher
|
5
|
+
attr_accessor :look_ahead, :globs_capture_separators, :default_value
|
6
|
+
|
7
|
+
def initialize(type, name, validator = nil, regex_matcher = nil, globs_capture_separators = false)
|
8
|
+
@type = type
|
9
|
+
@name = :"#{name}"
|
10
|
+
@validator = validator
|
11
|
+
@regex_matcher = regex_matcher
|
12
|
+
@globs_capture_separators = globs_capture_separators
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"#{type}#{name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid!(val)
|
20
|
+
case @validator
|
21
|
+
when Proc
|
22
|
+
begin
|
23
|
+
@validator.call(val)
|
24
|
+
rescue Exception => e
|
25
|
+
raise ValidationException.new("#{val} does not conform to #{@validator}, root cause #{e.inspect}")
|
26
|
+
end
|
27
|
+
else
|
28
|
+
@validator === val or raise(ValidationException.new("#{val} does not conform to #{@validator}, root cause #{e.inspect}"))
|
29
|
+
end if @validator
|
30
|
+
end
|
31
|
+
|
32
|
+
def ==(o)
|
33
|
+
o && (o.type == @type && o.name == @name && o.validator == @validator)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/usher/route.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'route', 'path')
|
2
|
+
require File.join(File.dirname(__FILE__), 'route', 'variable')
|
3
|
+
require File.join(File.dirname(__FILE__), 'route', 'request_method')
|
4
|
+
|
5
|
+
class Usher
|
6
|
+
class Route
|
7
|
+
attr_reader :paths, :original_path, :requirements, :conditions, :destination, :named, :generate_with
|
8
|
+
|
9
|
+
GenerateWith = Struct.new(:scheme, :port, :host)
|
10
|
+
|
11
|
+
def initialize(original_path, router, conditions, requirements, default_values, generate_with) # :nodoc:
|
12
|
+
@original_path = original_path
|
13
|
+
@router = router
|
14
|
+
@requirements = requirements
|
15
|
+
@conditions = conditions
|
16
|
+
@default_values = default_values
|
17
|
+
@paths = @router.splitter.split(@original_path, @requirements, @default_values).collect {|path| Path.new(self, path)}
|
18
|
+
@generate_with = GenerateWith.new(generate_with[:scheme], generate_with[:port], generate_with[:host]) if generate_with
|
19
|
+
end
|
20
|
+
|
21
|
+
def grapher
|
22
|
+
unless @grapher
|
23
|
+
@grapher = Grapher.new
|
24
|
+
@grapher.add_route(self)
|
25
|
+
end
|
26
|
+
@grapher
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_matching_path(params)
|
30
|
+
@paths.size == 1 ? @paths.first : grapher.find_matching_path(params)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# Sets +options+ on a route. Returns +self+.
|
35
|
+
#
|
36
|
+
# Request = Struct.new(:path)
|
37
|
+
# set = Usher.new
|
38
|
+
# route = set.add_route('/test')
|
39
|
+
# route.to(:controller => 'testing', :action => 'index')
|
40
|
+
# set.recognize(Request.new('/test')).first.params => {:controller => 'testing', :action => 'index'}
|
41
|
+
def to(options = nil, &block)
|
42
|
+
@destination = (block_given? ? block : options)
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
# Sets route as referenceable from +name+. Returns +self+.
|
47
|
+
#
|
48
|
+
# set = Usher.new
|
49
|
+
# route = set.add_route('/test').name(:route)
|
50
|
+
# set.generate_url(:route) => '/test'
|
51
|
+
def name(name)
|
52
|
+
@named = name
|
53
|
+
@router.name(name, self)
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|