joshbuddy-usher 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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