joshbuddy-usher 0.0.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,133 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'rails2_interface/mapper'
4
+
5
+ class Usher
6
+ module Interface
7
+ class Rails2Interface
8
+
9
+ attr_reader :usher
10
+ attr_accessor :configuration_file
11
+
12
+ def initialize
13
+ reset!
14
+ end
15
+
16
+ def reset!
17
+ @usher ||= Usher.new
18
+ @module ||= Module.new
19
+ @module.instance_methods.each do |selector|
20
+ @module.class_eval { remove_method selector }
21
+ end
22
+ @controller_action_route_added = false
23
+ @controller_route_added = false
24
+ @usher.reset!
25
+ end
26
+
27
+ def add_route(path, options = {})
28
+ if !@controller_action_route_added && path =~ %r{^/?:controller/:action/:id$}
29
+ add_route('/:controller/:action', options.dup)
30
+ @controller_action_route_added = true
31
+ end
32
+
33
+ if !@controller_route_added && path =~ %r{^/?:controller/:action$}
34
+ add_route('/:controller', options.merge({:action => 'index'}))
35
+ @controller_route_added = true
36
+ end
37
+
38
+ options[:action] = 'index' unless options[:action]
39
+
40
+ route = @usher.add_route(path, options)
41
+ raise "your route must include a controller" unless route.primary_path.dynamic_set.include?(:controller) || route.params.include?(:controller)
42
+ route
43
+ end
44
+
45
+ def recognize(request)
46
+ (path, params_list) = @usher.recognize(request)
47
+ params = params_list.inject({}){|h,(k,v)| h[k]=v; h }
48
+ request.path_parameters = (params_list.empty? ? path.route.params : path.route.params.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] = nil
74
+ end
75
+ route_for_options(merged_options)
76
+ end
77
+ case method
78
+ when :generate
79
+ merged_options ||= recall.merge(options)
80
+ generate_url(route, merged_options)
81
+ else
82
+ raise "method #{method} not recognized"
83
+ end
84
+ end
85
+
86
+ def generate_url(route, params)
87
+ @usher.generate_url(route, params)
88
+ end
89
+
90
+ def route_for_options(options)
91
+ @usher.route_for_options(options)
92
+ end
93
+
94
+ def named_routes
95
+ @usher.named_routes
96
+ end
97
+
98
+ def reload
99
+ @usher.reset!
100
+ if @configuration_file
101
+ Kernel.load(@configuration_file)
102
+ else
103
+ @usher.add_route ":controller/:action/:id"
104
+ end
105
+ end
106
+
107
+ def load_routes!
108
+ reload
109
+ end
110
+
111
+ def draw
112
+ reset!
113
+ yield Mapper.new(self)
114
+ install_helpers
115
+ end
116
+
117
+ def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false)
118
+ #*_url and hash_for_*_url
119
+ Array(destinations).each do |d| d.module_eval { include Helpers }
120
+ @usher.named_routes.keys.each do |name|
121
+ @module.module_eval <<-end_eval # We use module_eval to avoid leaks
122
+ def #{name}_url(options = {})
123
+ ActionController::Routing::UsherRoutes.generate(options, {}, :generate, :#{name})
124
+ end
125
+ end_eval
126
+ end
127
+ d.__send__(:include, @module)
128
+ end
129
+ end
130
+
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,44 @@
1
+ class Usher
2
+ module Interface
3
+ class Rails2Interface
4
+
5
+ class Mapper #:doc:
6
+ def initialize(set) #:nodoc:
7
+ @set = set
8
+ end
9
+
10
+ def connect(path, options = {})
11
+ @set.add_route(path, options)
12
+ end
13
+
14
+ def root(options = {})
15
+ if options.is_a?(Symbol)
16
+ if source_route = @set.named_routes[options]
17
+ options = source_route.conditions.blank? ?
18
+ source_route.options.merge({ :conditions => source_route.conditions }) : source_route.options
19
+ end
20
+ end
21
+ named_route(:root, '/', options)
22
+ end
23
+
24
+ def named_route(name, path, options = {})
25
+ @set.add_named_route(name, path, options)
26
+ end
27
+
28
+ def namespace(name, options = {}, &block)
29
+ if options[:namespace]
30
+ with_options({:path_prefix => "#{options.delete(:path_prefix)}/#{name}", :name_prefix => "#{options.delete(:name_prefix)}#{name}_", :namespace => "#{options.delete(:namespace)}#{name}/" }.merge(options), &block)
31
+ else
32
+ with_options({:path_prefix => name, :name_prefix => "#{name}_", :namespace => "#{name}/" }.merge(options), &block)
33
+ end
34
+ end
35
+
36
+ def method_missing(route_name, *args, &proc) #:nodoc:
37
+ super unless args.length >= 1 && proc.nil?
38
+ @set.add_named_route(route_name, *args)
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,149 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'node/lookup'
4
+
5
+ class Usher
6
+
7
+ class Node
8
+
9
+ ConditionalTypes = [:protocol, :domain, :port, :query_string, :remote_ip, :user_agent, :referer, :method]
10
+
11
+ attr_reader :lookup
12
+ attr_accessor :terminates, :exclusive_type, :parent, :value
13
+
14
+ def initialize(parent, value)
15
+ @parent = parent
16
+ @value = value
17
+ @lookup = Lookup.new
18
+ @exclusive_type = nil
19
+ @has_globber = find_parent{|p| p.value && p.value.is_a?(Route::Variable)}
20
+ end
21
+
22
+ def depth
23
+ unless @depth
24
+ @depth = 0
25
+ p = self
26
+ while (p = p.parent) && p.is_a?(Node)
27
+ @depth += 1
28
+ end
29
+ end
30
+ @depth
31
+ end
32
+
33
+ def self.root(route_set)
34
+ self.new(route_set, nil)
35
+ end
36
+
37
+ def has_globber?
38
+ @has_globber
39
+ end
40
+
41
+ def terminates?
42
+ @terminates
43
+ end
44
+
45
+ def find_parent(&blk)
46
+ if @parent.nil? || !@parent.is_a?(Node)
47
+ nil
48
+ elsif yield @parent
49
+ @parent
50
+ else #keep searching
51
+ @parent.find_parent(&blk)
52
+ end
53
+ end
54
+
55
+ def replace(src, dest)
56
+ @lookup.replace(src, dest)
57
+ end
58
+
59
+ def pp
60
+ $stdout << " " * depth
61
+ $stdout << "#{depth}: #{value.inspect} #{!!terminates?}\n"
62
+ @lookup.each do |k,v|
63
+ $stdout << " " * (depth + 1)
64
+ $stdout << "#{k} ==> \n"
65
+ v.pp
66
+ end
67
+ end
68
+
69
+ def add(route)
70
+ route.paths.each do |path|
71
+ parts = path.parts.dup
72
+ ConditionalTypes.each do |type|
73
+ parts.push(Route::Http.new(type, route.conditions[type])) if route.conditions[type]
74
+ end
75
+
76
+ current_node = self
77
+ until parts.size.zero?
78
+ key = parts.shift
79
+ target_node = case key
80
+ when Route::Http
81
+ if current_node.exclusive_type == key.type
82
+ current_node.lookup[key.value] ||= Node.new(current_node, key)
83
+ elsif current_node.lookup.empty?
84
+ current_node.exclusive_type = key.type
85
+ current_node.lookup[key.value] ||= Node.new(current_node, key)
86
+ else
87
+ parts.unshift(key)
88
+ current_node.lookup[nil] ||= Node.new(current_node, Route::Http.new(current_node.exclusive_type, nil))
89
+ end
90
+ else
91
+ if current_node.exclusive_type
92
+ parts.unshift(key)
93
+ current_node.lookup[nil] ||= Node.new(current_node, Route::Http.new(current_node.exclusive_type, nil))
94
+ else
95
+ current_node.lookup[key.is_a?(Route::Variable) ? nil : key] ||= Node.new(current_node, key)
96
+ end
97
+ end
98
+ current_node = target_node
99
+ end
100
+ current_node.terminates = path
101
+ end
102
+ route
103
+ end
104
+
105
+ def find(request, path = Route::Splitter.url_split(request.path), params = [])
106
+ part = path.shift unless path.size.zero?
107
+ if @exclusive_type
108
+ path.unshift part
109
+ [@lookup[request.send(@exclusive_type)], @lookup[nil]].each do |n|
110
+ ret = n.find(request, path.dup, params.dup) if n
111
+ ret and return ret
112
+ end
113
+ elsif path.size.zero? && !part
114
+ if terminates?
115
+ [terminates, params]
116
+ else
117
+ nil
118
+ end
119
+ elsif next_part = @lookup[part]
120
+ next_part.find(request, path, params)
121
+ elsif next_part = @lookup[nil]
122
+ if next_part.value.is_a?(Route::Variable)
123
+ case t = next_part.value.transformer
124
+ when Proc
125
+ part = t.call(part)
126
+ when Symbol
127
+ part = part.send(t)
128
+ end
129
+ part =
130
+ raise "#{part} does not conform to #{next_part.value.validator}" if next_part.value.validator && (not next_part.value.validator === part)
131
+ case next_part.value.type
132
+ when :*
133
+ params << [next_part.value.name, []]
134
+ params.last.last << part unless next_part.is_a?(Route::Separator)
135
+ when :':'
136
+ params << [next_part.value.name, part]
137
+ end
138
+ end
139
+ next_part.find(request, path, params)
140
+ elsif has_globber? && p = find_parent{|p| !p.is_a?(Route::Separator)} && p.value.is_a?(Route::Variable) && p.value.type == :*
141
+ params.last.last << part unless part.is_a?(Route::Separator)
142
+ find(request, path, params)
143
+ else
144
+ nil
145
+ end
146
+ end
147
+
148
+ end
149
+ end
@@ -0,0 +1,78 @@
1
+ class Usher
2
+ class Node
3
+ class Lookup
4
+
5
+ def initialize
6
+ @hash = {}
7
+ @regexes = []
8
+ @hash_reverse = {}
9
+ @regexes_reverse = {}
10
+ end
11
+
12
+ def empty?
13
+ @hash.empty? && @regexes.empty?
14
+ end
15
+
16
+ def keys
17
+ @hash.keys + @regexes.collect{|r| r.first}
18
+ end
19
+
20
+ def values
21
+ @hash.values + @regexes.collect{|r| r.last}
22
+ end
23
+
24
+ def each
25
+ @hash.each{|k,v| yield k,v }
26
+ @regexes.each{|v| yield v.first, v.last }
27
+ end
28
+
29
+ def delete_value(value)
30
+ @hash.delete(@hash_reverse[value]) || ((rr = @regexes_reverse[value]) && @regexes.delete_at(rr[0]))
31
+ end
32
+
33
+ def []=(key, value)
34
+ case key
35
+ when Regexp
36
+ @regexes << [key, value]
37
+ @regex_test = nil
38
+ @regexes_reverse[value] = [@regexes.size - 1, key, value]
39
+ else
40
+ @hash[key] = value
41
+ @hash_reverse[value] = key
42
+ end
43
+ end
44
+
45
+ def replace(src, dest)
46
+ if @hash_reverse.key?(src)
47
+ key = @hash_reverse[src]
48
+ @hash[key] = dest
49
+ @hash_reverse.delete(src)
50
+ @hash_reverse[dest] = key
51
+ elsif @regexes_reverse.key?(src)
52
+ key = @regexes_reverse[src]
53
+ @regexes[rkey[0]] = [rkey[1], dest]
54
+ @regexes_reverse.delete(src)
55
+ @regexes_reverse[dest] = [rkey[0], rkey[1], dest]
56
+ end
57
+ end
58
+
59
+ def [](key)
60
+ @hash[key] || regex_lookup(key)
61
+ end
62
+
63
+ private
64
+ def regex_test
65
+ @regex_test ||= Regexp.union(*@regexes.collect{|r| r[0]})
66
+ end
67
+
68
+ def regex_lookup(key)
69
+ if !@regexes.empty? && key.is_a?(String) && data = regex_test.match(key)
70
+ (data_array = data.to_a).each_index do |i|
71
+ break @regexes[i].last if data_array.at(i)
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,33 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'route/path'
4
+ require 'route/splitter'
5
+ require 'route/separator'
6
+ require 'route/variable'
7
+ require 'route/http'
8
+
9
+ class Usher
10
+ class Route
11
+ attr_reader :paths, :original_path, :requirements, :conditions, :params, :primary_path
12
+
13
+ def initialize(original_path, router, options = {})
14
+ @original_path = original_path
15
+ @router = router
16
+ @requirements = options.delete(:requirements)
17
+ @conditions = options.delete(:conditions)
18
+ @transformers = options.delete(:transformers)
19
+ @paths = Splitter.new(@original_path, @requirements, @transformers).paths.collect {|path| Path.new(self, path)}
20
+ @primary_path = @paths.first
21
+ end
22
+
23
+ def to(options)
24
+ @params = options
25
+ self
26
+ end
27
+
28
+ def name(name)
29
+ @router.name(name, self)
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ class Usher
2
+ class Route
3
+ class Http
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?(Http) && o.type == type && o.value == value
18
+ end
19
+ end
20
+ end
21
+ end