joshbuddy-usher 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,57 @@
1
+ class Usher
2
+ module Interface
3
+ class Rails3Interface
4
+
5
+ @@instance = nil
6
+
7
+ def initialize
8
+ @usher = Usher.new
9
+ @controller_paths = []
10
+ @configurations_files = []
11
+
12
+ @@instance = self
13
+ end
14
+
15
+ def self.instance
16
+ @@instance
17
+ end
18
+
19
+ def draw(&blk)
20
+ @usher.instance_eval(&blk)
21
+ end
22
+
23
+ attr_accessor :controller_paths
24
+
25
+ def add_configuration_file(file)
26
+ @configurations_files << file
27
+ end
28
+
29
+ def reload!
30
+ @usher.reset!
31
+ @configurations_files.each do |c|
32
+ Kernel.load(c)
33
+ end
34
+ end
35
+
36
+ def call(env)
37
+ request = ActionDispatch::Request.new(env)
38
+ response = @usher.recognize(request, request.path_info)
39
+ request.parameters.merge!(response.path.route.default_values) if response.path.route.default_values
40
+ response.params.each{ |hk| request.parameters[hk.first] = hk.last}
41
+ controller = "#{request.parameters[:controller].to_s.camelize}Controller".constantize
42
+ controller.action(request.parameters[:action] || 'index').call(env)
43
+ end
44
+
45
+ def recognize(request)
46
+ params = recognize_path(request.path, extract_request_environment(request))
47
+ request.path_parameters = params.with_indifferent_access
48
+ "#{params[:controller].to_s.camelize}Controller".constantize
49
+ end
50
+
51
+ def load(app)
52
+ @app = app
53
+ end
54
+
55
+ end
56
+ end
57
+ end
data/lib/usher/node.rb CHANGED
@@ -4,7 +4,7 @@ class Usher
4
4
 
5
5
  class Node
6
6
 
7
- Response = Struct.new(:path, :params)
7
+ Response = Struct.new(:path, :params, :remaining_path, :matched_path)
8
8
 
9
9
  attr_reader :lookup, :greedy_lookup
10
10
  attr_accessor :terminates, :exclusive_type, :parent, :value, :request_methods
@@ -26,7 +26,7 @@ class Usher
26
26
  end
27
27
 
28
28
  def depth
29
- @depth ||= @parent && @parent.is_a?(Node) ? @parent.depth + 1 : 0
29
+ @depth ||= @parent.is_a?(Node) ? @parent.depth + 1 : 0
30
30
  end
31
31
 
32
32
  def greedy?
@@ -55,52 +55,26 @@ class Usher
55
55
 
56
56
  def add(route)
57
57
  route.paths.each do |path|
58
- parts = path.parts.dup
59
- request_methods.each do |type|
60
- parts.push(Route::RequestMethod.new(type, route.conditions[type])) if route.conditions && route.conditions.key?(type)
61
- end
62
-
63
- current_node = self
64
- until parts.size.zero?
65
- key = parts.shift
66
- target_node = case key
67
- when Route::RequestMethod
68
- current_node.upgrade_lookup if key.value.is_a?(Regexp)
69
- if current_node.exclusive_type == key.type
70
- current_node.lookup[key.value] ||= Node.new(current_node, key)
71
- elsif current_node.lookup.empty?
72
- current_node.exclusive_type = key.type
73
- current_node.lookup[key.value] ||= Node.new(current_node, key)
74
- else
75
- parts.unshift(key)
76
- current_node.lookup[nil] ||= Node.new(current_node, Route::RequestMethod.new(current_node.exclusive_type, nil))
77
- end
78
- else
79
- case key
80
- when Route::Variable
81
- (upgrade_method, lookup_method) = case key
82
- when Route::Variable::Greedy
83
- [:upgrade_greedy_lookup, :greedy_lookup]
84
- else
85
- [:upgrade_lookup, :lookup]
86
- end
87
-
88
- if key.regex_matcher
89
- current_node.send(upgrade_method)
90
- current_node.send(lookup_method)[key.regex_matcher] ||= Node.new(current_node, key)
91
- else
92
- current_node.send(lookup_method)[nil] ||= Node.new(current_node, key)
93
- end
94
- else
95
- current_node.upgrade_lookup if key.is_a?(Regexp)
96
- current_node.lookup[key] ||= Node.new(current_node, key)
97
- end
98
- end
99
- current_node = target_node
100
- end
101
- current_node.terminates = path
58
+ set_path_with_destination(path)
59
+ end
60
+ end
61
+
62
+ def delete(route)
63
+ route.paths.each do |path|
64
+ set_path_with_destination(path, nil)
65
+ end
66
+ end
67
+
68
+ def unique_routes(node = self, routes = [])
69
+ routes << node.terminates.route if node.terminates
70
+ node.lookup.values.each do |v|
71
+ unique_routes(v, routes)
72
+ end
73
+ node.greedy_lookup.values.each do |v|
74
+ unique_routes(v, routes)
102
75
  end
103
- route
76
+ routes.uniq!
77
+ routes
104
78
  end
105
79
 
106
80
  def find(usher, request, original_path, path, params = [], position = 0)
@@ -110,10 +84,16 @@ class Usher
110
84
  return ret
111
85
  end
112
86
  end
113
- elsif path.size.zero? && terminates?
114
- Response.new(terminates, params)
87
+ nil
88
+ elsif terminates? && (path.size.zero? || terminates.route.partial_match?)
89
+ if terminates.route.partial_match?
90
+ Response.new(terminates, params, original_path[position, original_path.size], original_path[0, position])
91
+ else
92
+ Response.new(terminates, params, nil, original_path)
93
+ end
94
+
115
95
  elsif !path.size.zero? && (greedy? && (match_with_result_output = greedy_lookup.match_with_result(whole_path = original_path[position, original_path.size])))
116
- next_path, matched_part = match_with_result_output
96
+ next_path, matched_part = match_with_result_output
117
97
  position += matched_part.size
118
98
  params << [next_path.value.name, whole_path.slice!(0, matched_part.size)]
119
99
  next_path.find(usher, request, original_path, whole_path.size.zero? ? whole_path : usher.splitter.url_split(whole_path), params, position)
@@ -157,5 +137,51 @@ class Usher
157
137
  end
158
138
  end
159
139
 
140
+ private
141
+ def set_path_with_destination(path, destination = path)
142
+ parts = path.parts.dup
143
+ request_methods.each do |type|
144
+ parts.push(Route::RequestMethod.new(type, path.route.conditions[type])) if path.route.conditions && path.route.conditions.key?(type)
145
+ end
146
+
147
+ current_node = self
148
+ until parts.size.zero?
149
+ key = parts.shift
150
+ target_node = case key
151
+ when Route::RequestMethod
152
+ current_node.upgrade_lookup if key.value.is_a?(Regexp)
153
+ if current_node.exclusive_type == key.type
154
+ current_node.lookup[key.value] ||= Node.new(current_node, key)
155
+ elsif current_node.lookup.empty?
156
+ current_node.exclusive_type = key.type
157
+ current_node.lookup[key.value] ||= Node.new(current_node, key)
158
+ else
159
+ parts.unshift(key)
160
+ current_node.lookup[nil] ||= Node.new(current_node, Route::RequestMethod.new(current_node.exclusive_type, nil))
161
+ end
162
+ when Route::Variable
163
+ upgrade_method, lookup_method = case key
164
+ when Route::Variable::Greedy
165
+ [:upgrade_greedy_lookup, :greedy_lookup]
166
+ else
167
+ [:upgrade_lookup, :lookup]
168
+ end
169
+
170
+ if key.regex_matcher
171
+ current_node.send(upgrade_method)
172
+ current_node.send(lookup_method)[key.regex_matcher] ||= Node.new(current_node, key)
173
+ else
174
+ current_node.send(lookup_method)[nil] ||= Node.new(current_node, key)
175
+ end
176
+ else
177
+ current_node.upgrade_lookup if key.is_a?(Regexp)
178
+ current_node.lookup[key] ||= Node.new(current_node, key)
179
+ end
180
+ current_node = target_node
181
+ end
182
+ current_node.terminates = destination
183
+ end
184
+
185
+
160
186
  end
161
187
  end
data/lib/usher/route.rb CHANGED
@@ -5,17 +5,17 @@ require File.join(File.dirname(__FILE__), 'route', 'request_method')
5
5
 
6
6
  class Usher
7
7
  class Route
8
- attr_reader :paths, :requirements, :conditions, :destination, :named, :generate_with
8
+ attr_reader :paths, :requirements, :conditions,
9
+ :destination, :named, :generate_with,
10
+ :default_values, :match_partially
11
+ attr_accessor :parent_route
9
12
 
10
13
  GenerateWith = Struct.new(:scheme, :port, :host)
11
14
 
12
- def initialize(parsed_paths, router, conditions, requirements, default_values, generate_with) # :nodoc:
13
- @router = router
14
- @requirements = requirements
15
- @conditions = conditions
16
- @default_values = default_values
17
- @generate_with = GenerateWith.new(generate_with[:scheme], generate_with[:port], generate_with[:host]) if generate_with
15
+ def initialize(parsed_paths, router, conditions, requirements, default_values, generate_with, match_partially)
18
16
  @paths = parsed_paths.collect {|path| Path.new(self, path)}
17
+ @router, @requirements, @conditions, @default_values, @match_partially = router, requirements, conditions, default_values, match_partially
18
+ @generate_with = GenerateWith.new(generate_with[:scheme], generate_with[:port], generate_with[:host]) if generate_with
19
19
  end
20
20
 
21
21
  def grapher
@@ -26,11 +26,27 @@ class Usher
26
26
  @grapher
27
27
  end
28
28
 
29
+ def dup
30
+ result = super
31
+ result.grapher = nil
32
+ result
33
+ end
34
+
29
35
  def find_matching_path(params)
30
- @paths.size == 1 ? @paths.first : grapher.find_matching_path(params)
36
+ if params.nil? || params.empty?
37
+ matching_path = @paths.first
38
+ else
39
+ matching_path = @paths.size == 1 ? @paths.first : grapher.find_matching_path(params)
40
+ end
41
+
42
+ if parent_route
43
+ matching_path = parent_route.find_matching_path(params).merge(matching_path)
44
+ matching_path.route = self
45
+ end
46
+
47
+ matching_path
31
48
  end
32
49
 
33
-
34
50
  # Sets +options+ on a route. Returns +self+.
35
51
  #
36
52
  # Request = Struct.new(:path)
@@ -39,7 +55,13 @@ class Usher
39
55
  # route.to(:controller => 'testing', :action => 'index')
40
56
  # set.recognize(Request.new('/test')).first.params => {:controller => 'testing', :action => 'index'}
41
57
  def to(options = nil, &block)
42
- @destination = (block_given? ? block : options)
58
+ raise "cannot set destintaion as block and argument" if block_given? && options
59
+ @destination = if block_given?
60
+ block
61
+ else
62
+ options.parent_route = self if options.respond_to?(:parent_route=)
63
+ options
64
+ end
43
65
  self
44
66
  end
45
67
 
@@ -53,6 +75,18 @@ class Usher
53
75
  @router.name(name, self)
54
76
  self
55
77
  end
78
+
79
+ def match_partially!
80
+ @match_partially = true
81
+ self
82
+ end
83
+
84
+ def partial_match?
85
+ @match_partially
86
+ end
87
+
88
+ private
89
+ attr_writer :grapher
56
90
 
57
91
  end
58
92
  end
@@ -2,16 +2,16 @@ class Usher
2
2
  class Route
3
3
  class Path
4
4
 
5
- attr_reader :route, :parts
5
+ attr_accessor :route
6
+ attr_reader :parts
6
7
 
7
8
  def initialize(route, parts)
8
- @route = route
9
- @parts = parts
10
- @dynamic = @parts.any?{|p| p.is_a?(Variable)}
9
+ self.route = route
10
+ self.parts = parts
11
11
  end
12
12
 
13
13
  def dynamic_indicies
14
- unless @dynamic_indicies
14
+ unless dynamic? && @dynamic_indicies
15
15
  @dynamic_indicies = []
16
16
  parts.each_index{|i| @dynamic_indicies << i if parts[i].is_a?(Variable)}
17
17
  end
@@ -19,11 +19,11 @@ class Usher
19
19
  end
20
20
 
21
21
  def dynamic_parts
22
- @dynamic_parts ||= parts.values_at(*dynamic_indicies)
22
+ @dynamic_parts ||= parts.values_at(*dynamic_indicies) if dynamic?
23
23
  end
24
24
 
25
25
  def dynamic_map
26
- unless @dynamic_map
26
+ unless dynamic? && @dynamic_map
27
27
  @dynamic_map = {}
28
28
  dynamic_parts.each{|p| @dynamic_map[p.name] = p }
29
29
  end
@@ -31,11 +31,11 @@ class Usher
31
31
  end
32
32
 
33
33
  def dynamic_keys
34
- @dynamic_keys ||= dynamic_map.keys
34
+ @dynamic_keys ||= dynamic_map.keys if dynamic?
35
35
  end
36
36
 
37
37
  def dynamic_required_keys
38
- @dynamic_required_keys ||= dynamic_parts.select{|dp| !dp.default_value}.map{|dp| dp.name}
38
+ @dynamic_required_keys ||= dynamic_parts.select{|dp| !dp.default_value}.map{|dp| dp.name} if dynamic?
39
39
  end
40
40
 
41
41
  def dynamic?
@@ -45,6 +45,19 @@ class Usher
45
45
  def can_generate_from?(keys)
46
46
  (dynamic_required_keys - keys).size.zero?
47
47
  end
48
+
49
+ # Merges paths for use in generation
50
+ def merge(other_path)
51
+ new_parts = parts + other_path.parts
52
+ Path.new(route, new_parts)
53
+ end
54
+
55
+ private
56
+ def parts=(parts)
57
+ @parts = parts
58
+ @dynamic = @parts.any?{|p| p.is_a?(Variable)}
59
+ end
60
+
48
61
  end
49
62
  end
50
63
  end
@@ -29,9 +29,7 @@ class Usher
29
29
 
30
30
  class URL
31
31
 
32
- def initialize(usher)
33
- @usher = usher
34
- end
32
+ attr_accessor :usher
35
33
 
36
34
  def generate_full(routing_lookup, request, params = nil)
37
35
  path = path_for_routing_lookup(routing_lookup, params)
@@ -49,20 +47,20 @@ class Usher
49
47
  result << (path.route.generate_with && path.route.generate_with.host) ? path.route.generate_with.host : request.host
50
48
  port = path.route.generate_with && path.route.generate_with.port || request.port
51
49
  if result[4] == ?s
52
- result << ':' << port.to_s if port != 443
50
+ result << ':' << port.to_s unless port == 443
53
51
  else
54
- result << ':' << port.to_s if port != 80
52
+ result << ':' << port.to_s unless port == 80
55
53
  end
56
54
  result
57
55
  end
58
-
59
- def path_for_routing_lookup(routing_lookup, params)
56
+
57
+ def path_for_routing_lookup(routing_lookup, params = {})
60
58
  path = case routing_lookup
61
59
  when Symbol
62
60
  route = @usher.named_routes[routing_lookup]
63
- params.is_a?(Hash) ? route.find_matching_path(params) : route.paths.first
61
+ route.find_matching_path(params || {})
64
62
  when Route
65
- params.is_a?(Hash) ? routing_lookup.find_matching_path(params) : routing_lookup.paths.first
63
+ routing_lookup.find_matching_path(params || {})
66
64
  when nil
67
65
  params.is_a?(Hash) ? @usher.path_for_options(params) : raise
68
66
  when Route::Path
@@ -94,23 +92,21 @@ class Usher
94
92
  when Route::Variable::Glob
95
93
  value = (params && params.delete(part.name)) || part.default_value || raise(MissingParameterException.new)
96
94
  value.each_with_index do |current_value, index|
97
- current_value = current_value.to_s unless current_value.is_a?(String)
98
95
  part.valid!(current_value)
99
- result << current_value
96
+ result << current_value.to_s
100
97
  result << '/' if index != value.size - 1
101
98
  end
102
99
  when Route::Variable
103
100
  value = (params && params.delete(part.name)) || part.default_value || raise(MissingParameterException.new)
104
- value = value.to_s unless value.is_a?(String)
105
101
  part.valid!(value)
106
- result << value
102
+ result << value.to_s
107
103
  else
108
104
  result << part
109
105
  end
110
106
  end
111
107
  result = Rack::Utils.uri_escape(result)
112
108
 
113
- if params && !params.empty?
109
+ unless params.nil? || params.empty?
114
110
  has_query = result[??]
115
111
  params.each do |k,v|
116
112
  case v
@@ -125,7 +121,9 @@ class Usher
125
121
  end
126
122
  result
127
123
  end
124
+
128
125
  end
126
+
129
127
  end
130
128
  end
131
129
  end