joshbuddy-usher 0.5.1 → 0.5.2

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.
@@ -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