joshbuddy-usher 0.4.3 → 0.4.5

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.
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
+ :patch: 5
2
3
  :major: 0
3
4
  :minor: 4
4
- :patch: 3
@@ -0,0 +1,82 @@
1
+ class Usher
2
+ class Generators
3
+
4
+ class URL
5
+
6
+ def initialize(usher)
7
+ @usher = usher
8
+ end
9
+
10
+ # Generates a completed URL based on a +route+ or set of optional +params+
11
+ #
12
+ # set = Usher.new
13
+ # route = set.add_named_route(:test_route, '/:controller/:action')
14
+ # set.generate_url(nil, {:controller => 'c', :action => 'a'}) == '/c/a' => true
15
+ # set.generate_url(:test_route, {:controller => 'c', :action => 'a'}) == '/c/a' => true
16
+ # set.generate_url(route.primary_path, {:controller => 'c', :action => 'a'}) == '/c/a' => true
17
+ def generate(routing_lookup, params = nil, options = nil)
18
+ delimiter = options && options.key?(:delimiter) ? options.delete(:delimiter) : @usher.delimiters.first
19
+
20
+ path = case routing_lookup
21
+ when Symbol
22
+ route = @usher.named_routes[routing_lookup]
23
+ params.is_a?(Hash) ? route.find_matching_path(params) : route.paths.first
24
+ when Route
25
+ params.is_a?(Hash) ? routing_lookup.find_matching_path(params) : routing_lookup.paths.first
26
+ when nil
27
+ params.is_a?(Hash) ? @usher.path_for_options(params) : raise
28
+ when Route::Path
29
+ routing_lookup
30
+ end
31
+
32
+ raise UnrecognizedException.new unless path
33
+
34
+ params = Array(params) if params.is_a?(String)
35
+ if params.is_a?(Array)
36
+ extra_params = params.last.is_a?(Hash) ? params.pop : nil
37
+ params = Hash[*path.dynamic_parts.inject([]){|a, dynamic_part| a.concat([dynamic_part.name, params.shift || raise(MissingParameterException.new)]); a}]
38
+ params.merge!(extra_params) if extra_params
39
+ end
40
+
41
+ result = ''
42
+ path.parts.each do |part|
43
+ case part
44
+ when Route::Variable
45
+ value = (params && params.delete(part.name)) || part.default_value || raise(MissingParameterException.new)
46
+ case part.type
47
+ when :*
48
+ value.each_with_index do |current_value, index|
49
+ current_value = current_value.to_s unless current_value.is_a?(String)
50
+ part.valid!(current_value)
51
+ result << current_value
52
+ result << delimiter if index != value.size - 1
53
+ end
54
+ when :':'
55
+ value = value.to_s unless value.is_a?(String)
56
+ part.valid!(value)
57
+ result << value
58
+ end
59
+ else
60
+ result << part
61
+ end
62
+ end
63
+ result = URI.escape(result)
64
+
65
+ if params && !params.empty?
66
+ has_query = result[??]
67
+ params.each do |k,v|
68
+ case v
69
+ when Array
70
+ v.each do |v_part|
71
+ result << (has_query ? '&' : has_query = true && '?') << CGI.escape("#{k.to_s}[]") << '=' << CGI.escape(v_part.to_s)
72
+ end
73
+ else
74
+ result << (has_query ? '&' : has_query = true && '?') << CGI.escape(k.to_s) << '=' << CGI.escape(v.to_s)
75
+ end
76
+ end
77
+ end
78
+ result
79
+ end
80
+ end
81
+ end
82
+ end
data/lib/usher/grapher.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'set'
2
-
3
1
  class Usher
4
2
  class Grapher
5
3
 
@@ -11,29 +9,53 @@ class Usher
11
9
  @significant_keys = nil
12
10
  @orders = Hash.new{|h,k| h[k] = Hash.new{|h2, k2| h2[k2] = []}}
13
11
  @key_count = Hash.new(0)
12
+ @cache = {}
14
13
  end
15
14
 
16
15
  def add_route(route)
17
16
  route.paths.each do |path|
18
- unless path.dynamic_set.size.zero?
19
- path.dynamic_set.each do |k|
20
- @orders[path.dynamic_set.size][k] << path
17
+ unless path.dynamic_keys.size.zero?
18
+ path.dynamic_keys.each do |k|
19
+ @orders[path.dynamic_keys.size][k] << path
21
20
  @key_count[k] += 1
22
21
  end
22
+
23
+ dynamic_parts_with_defaults = path.dynamic_parts.select{|part| part.default_value }.map{|dp| dp.name}
24
+ dynamic_parts_without_defaults = path.dynamic_parts.select{|part| !part.default_value }.map{|dp| dp.name}
25
+
26
+ (1...(2 ** (dynamic_parts_with_defaults.size))).each do |i|
27
+ current_set = dynamic_parts_without_defaults.dup
28
+ dynamic_parts_with_defaults.each_with_index do |dp, index|
29
+ current_set << dp unless (index & i) == 0
30
+ end
31
+
32
+ current_set.each do |k|
33
+ @orders[current_set.size][k] << path
34
+ @key_count[k] += 1
35
+ end
36
+ end
23
37
  end
24
38
  end
25
39
  end
26
40
 
27
41
  def significant_keys
28
- @significant_keys ||= Set.new(@key_count.keys)
42
+ @significant_keys ||= @key_count.keys.uniq
29
43
  end
30
44
 
31
45
  def find_matching_path(params)
32
46
  unless params.empty?
33
- set = Set.new(params.keys) & significant_keys
47
+ set = params.keys & significant_keys
48
+ if cached = @cache[set]
49
+ return cached
50
+ end
34
51
  set.size.downto(1) do |o|
35
52
  set.each do |k|
36
- @orders[o][k].each { |r| return r if r.dynamic_set.subset?(set) }
53
+ @orders[o][k].each { |r|
54
+ if r.can_generate_from?(set)
55
+ @cache[set] = r
56
+ return r
57
+ end
58
+ }
37
59
  end
38
60
  end
39
61
  nil
@@ -22,7 +22,7 @@ class Usher
22
22
  def act(email)
23
23
  response = @routes.recognize(email, email)
24
24
  if response.path
25
- response.path.route.params.first.call(response.params.inject({}){|h,(k,v)| h[k]=v.to_s; h })
25
+ response.path.route.destination.call(response.params.inject({}){|h,(k,v)| h[k]=v.to_s; h })
26
26
  end
27
27
  end
28
28
 
@@ -13,6 +13,7 @@ class Usher
13
13
 
14
14
  def initialize(&blk)
15
15
  @routes = Usher.new(:request_methods => RequestMethods)
16
+ @generator = Usher::Generators::URL.new(@routes)
16
17
  instance_eval(&blk) if blk
17
18
  end
18
19
 
@@ -26,8 +27,14 @@ class Usher
26
27
 
27
28
  def call(env)
28
29
  response = @routes.recognize(Request.new(env['REQUEST_URI'], env['REQUEST_METHOD'].downcase, env['HTTP_HOST'], env['SERVER_PORT'].to_i, env['rack.url_scheme']))
29
- env['usher.params'] = response.params.inject({}){|h,(k,v)| h[k]=v; h }
30
- response.path.route.params.first.call(env)
30
+ params = {}
31
+ response.params.each{ |hk| params[hk.first] = hk.last}
32
+ env['usher.params'] = params
33
+ response.path.route.destination.call(env)
34
+ end
35
+
36
+ def generate(route, params = nil, options = nil)
37
+ @generator.generate(route, params, options)
31
38
  end
32
39
 
33
40
  end
@@ -1,6 +1,6 @@
1
1
  class Usher
2
2
  module Interface
3
- class Rails2Interface
3
+ class Rails2_2Interface
4
4
 
5
5
  class Mapper #:doc:
6
6
  def initialize(set) #:nodoc:
@@ -1,10 +1,10 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
 
3
- require 'rails2_interface/mapper'
3
+ require 'rails2_2_interface/mapper'
4
4
 
5
5
  class Usher
6
6
  module Interface
7
- class Rails2Interface
7
+ class Rails2_2Interface
8
8
 
9
9
  attr_reader :usher
10
10
  attr_accessor :configuration_file
@@ -15,6 +15,7 @@ class Usher
15
15
 
16
16
  def reset!
17
17
  @usher ||= Usher.new
18
+ @url_generator ||= Usher::Generators::URL.new(@usher)
18
19
  @module ||= Module.new
19
20
  @module.instance_methods.each do |selector|
20
21
  @module.class_eval { remove_method selector }
@@ -39,14 +40,14 @@ class Usher
39
40
 
40
41
  path[0, 0] = '/' unless path[0] == ?/
41
42
  route = @usher.add_route(path, options)
42
- raise "your route must include a controller" unless route.primary_path.dynamic_set.include?(:controller) || route.params.first.include?(:controller)
43
+ raise "your route must include a controller" unless route.paths.first.dynamic_keys.include?(:controller) || route.destination.include?(:controller)
43
44
  route
44
45
  end
45
46
 
46
47
  def recognize(request)
47
48
  node = @usher.recognize(request)
48
49
  params = node.params.inject({}){|h,(k,v)| h[k]=v; h }
49
- request.path_parameters = (node.params.empty? ? node.path.route.params.first : node.path.route.params.first.merge(params)).with_indifferent_access
50
+ request.path_parameters = (node.params.empty? ? node.path.route.destination : node.path.route.destination.merge(params)).with_indifferent_access
50
51
  "#{request.path_parameters[:controller].camelize}Controller".constantize
51
52
  rescue
52
53
  raise ActionController::RoutingError, "No route matches #{request.path.inspect} with #{request.inspect}"
@@ -73,7 +74,7 @@ class Usher
73
74
  unless options.key?(:action)
74
75
  options[:action] = ''
75
76
  end
76
- route_for_options(merged_options)
77
+ path_for_options(merged_options)
77
78
  end
78
79
  case method
79
80
  when :generate
@@ -87,11 +88,11 @@ class Usher
87
88
  end
88
89
 
89
90
  def generate_url(route, params)
90
- @usher.generate_url(route, params)
91
+ @url_generator.generate(route, params)
91
92
  end
92
93
 
93
- def route_for_options(options)
94
- @usher.route_for_options(options)
94
+ def path_for_options(options)
95
+ @usher.path_for_options(options)
95
96
  end
96
97
 
97
98
  def named_routes
@@ -0,0 +1,137 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ class Usher
4
+ module Interface
5
+ class Rails2_3Interface
6
+
7
+ attr_reader :configuration_files
8
+
9
+ def named_routes
10
+ @router.named_routes
11
+ end
12
+
13
+ def add_named_route(name, route, options = {})
14
+ @router.add_route(route, options).name(name)
15
+ end
16
+
17
+ def add_route(path, options = {})
18
+ if !@controller_action_route_added && path =~ %r{^/?:controller/:action/:id$}
19
+ add_route('/:controller/:action', options.dup)
20
+ @controller_action_route_added = true
21
+ end
22
+
23
+ if !@controller_route_added && path =~ %r{^/?:controller/:action$}
24
+ add_route('/:controller', options.merge({:action => 'index'}))
25
+ @controller_route_added = true
26
+ end
27
+
28
+ options[:action] = 'index' unless options[:action]
29
+
30
+ path[0, 0] = '/' unless path[0] == ?/
31
+ route = @router.add_route(path, options).to(options)
32
+
33
+ raise "your route must include a controller" unless (route.paths.first.dynamic_keys.include?(:controller) || route.destination.include?(:controller))
34
+ route
35
+ end
36
+
37
+ def initialize
38
+ reset!
39
+ end
40
+
41
+ def add_configuration_file(file)
42
+ @configuration_files << file
43
+ end
44
+
45
+ def reload!
46
+ if configuration_files.any?
47
+ configuration_files.each { |config| load(config) }
48
+ else
49
+ add_route ":controller/:action/:id"
50
+ end
51
+
52
+ end
53
+ alias_method :reload, :reload!
54
+
55
+ def route_count
56
+ routes.size
57
+ end
58
+
59
+ def routes
60
+ @router.routes
61
+ end
62
+
63
+ def call(env)
64
+ request = ActionController::Request.new(env)
65
+ app = recognize(request)
66
+ app.call(env).to_a
67
+ end
68
+
69
+ def recognize(request)
70
+ response = @router.recognize(request)
71
+ 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
72
+ response.params.each { |pair| request.path_parameters[pair.first] = pair.last }
73
+ "#{request.path_parameters[:controller].camelize}Controller".constantize
74
+ end
75
+
76
+ def reset!
77
+ @router = Usher.new
78
+ @url_generator = Usher::Generators::URL.new(@router)
79
+ @configuration_files = []
80
+ @module ||= Module.new
81
+ @controller_route_added = false
82
+ @controller_action_route_added = false
83
+ end
84
+
85
+ def draw
86
+ reset!
87
+ yield ActionController::Routing::RouteSet::Mapper.new(self)
88
+ install_helpers
89
+ end
90
+
91
+ def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false)
92
+ #*_url and hash_for_*_url
93
+ Array(destinations).each do |d| d.module_eval { include Helpers }
94
+ @router.named_routes.keys.each do |name|
95
+ @module.module_eval <<-end_eval # We use module_eval to avoid leaks
96
+ def #{name}_url(options = {})
97
+ ActionController::Routing::UsherRoutes.generate(options, {}, :generate, :#{name})
98
+ end
99
+ end_eval
100
+ end
101
+ d.__send__(:include, @module)
102
+ end
103
+ end
104
+
105
+ def generate(options, recall = {}, method = :generate, route_name = nil)
106
+ route = if(route_name)
107
+ @router.named_routes[route_name]
108
+ else
109
+ merged_options = options
110
+ merged_options[:controller] = recall[:controller] unless options.key?(:controller)
111
+ unless options.key?(:action)
112
+ options[:action] = ''
113
+ end
114
+ path_for_options(merged_options)
115
+ end
116
+ case method
117
+ when :generate
118
+ merged_options ||= recall.merge(options)
119
+ url = generate_url(route, merged_options)
120
+ url.slice!(-1) if url[-1] == ?/
121
+ url
122
+ else
123
+ raise "method #{method} not recognized"
124
+ end
125
+ end
126
+
127
+ def generate_url(route, params)
128
+ @url_generator.generate(route, params)
129
+ end
130
+
131
+ def path_for_options(options)
132
+ @router.path_for_options(options)
133
+ end
134
+
135
+ end
136
+ end
137
+ end
@@ -2,15 +2,18 @@ $:.unshift File.dirname(__FILE__)
2
2
 
3
3
  class Usher
4
4
  module Interface
5
- autoload :Rails2Interface, 'interface/rails2_interface'
5
+ autoload :Rails2_2Interface, 'interface/rails2_2_interface'
6
+ autoload :Rails2_3Interface, 'interface/rails2_3_interface'
6
7
  autoload :MerbInterface, 'interface/merb_interface'
7
8
  autoload :RackInterface, 'interface/rack_interface'
8
9
  autoload :EmailInterface, 'interface/email_interface'
9
10
 
10
11
  def self.for(type, &blk)
11
12
  case type
12
- when :rails2
13
- Rails2Interface.new(&blk)
13
+ when :rails2_2
14
+ Rails2_2Interface.new(&blk)
15
+ when :rails2_3
16
+ Rails2_3Interface.new(&blk)
14
17
  when :merb
15
18
  MerbInterface.new(&blk)
16
19
  when :rack
data/lib/usher/node.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
 
3
- require 'fuzzy_hash'
3
+ require '/Users/josh/Development/fuzzy_hash/lib/fuzzy_hash'
4
4
 
5
5
  class Usher
6
6
 
@@ -89,10 +89,10 @@ class Usher
89
89
  route
90
90
  end
91
91
 
92
- def find(request, path, params = [])
92
+ def find(usher, request, path, params = [])
93
93
  if exclusive_type
94
94
  [lookup[request.send(exclusive_type)], lookup[nil]].each do |n|
95
- if n && (ret = n.find(request, path.dup, params.dup))
95
+ if n && (ret = n.find(usher, request, path.dup, params.dup))
96
96
  return ret
97
97
  end
98
98
  end
@@ -105,15 +105,15 @@ class Usher
105
105
  when :*
106
106
  params << [next_part.value.name, []] unless params.last && params.last.first == next_part.value.name
107
107
  loop do
108
- if (next_part.value.look_ahead === part || (!part.is_a?(Symbol) && next_part.value.regex_matcher && !next_part.value.regex_matcher.match(part)))
108
+ 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)))
109
109
  path.unshift(part)
110
- path.unshift(next_part.parent.value) if next_part.parent.value.is_a?(Symbol)
110
+ path.unshift(next_part.parent.value) if usher.splitter.delimiter_chars.include?(next_part.parent.value[0])
111
111
  break
112
- else
113
- unless part.is_a?(Symbol) && !next_part.value.globs_capture_separators
114
- next_part.value.valid!(part)
115
- params.last.last << part
116
- end
112
+ elsif next_part.value.globs_capture_separators
113
+ params.last.last << part
114
+ elsif !usher.splitter.delimiter_chars.include?(part[0])
115
+ next_part.value.valid!(part)
116
+ params.last.last << part
117
117
  end
118
118
  if path.size.zero?
119
119
  break
@@ -122,15 +122,15 @@ class Usher
122
122
  end
123
123
  end
124
124
  when :':'
125
- next_part.value.valid!(part)
126
125
  var = next_part.value
127
- params << [next_part.value.name, part]
128
- until (path.first == var.look_ahead) || path.empty?
129
- params.last.last << path.shift.to_s
126
+ var.valid!(part)
127
+ params << [var.name, part]
128
+ until (var.look_ahead === path.first) || path.empty?
129
+ params.last.last << path.shift
130
130
  end
131
131
  end
132
132
  end
133
- next_part.find(request, path, params)
133
+ next_part.find(usher, request, path, params)
134
134
  else
135
135
  nil
136
136
  end