joshbuddy-usher 0.4.7 → 0.4.8
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/Rakefile +36 -1
- data/VERSION.yml +1 -1
- data/lib/usher/generate.rb +66 -17
- data/lib/usher/interface/email_interface.rb +0 -4
- data/lib/usher/interface/merb_interface.rb +0 -2
- data/lib/usher/interface/rack_interface.rb +3 -8
- data/lib/usher/interface/rails2_2_interface.rb +1 -3
- data/lib/usher/interface/rails2_3_interface.rb +0 -2
- data/lib/usher/interface.rb +5 -7
- data/lib/usher/node.rb +1 -3
- data/lib/usher/route.rb +8 -7
- data/lib/usher.rb +15 -16
- data/spec/private/generate_spec.rb +6 -1
- data/spec/private/rack/dispatch_spec.rb +16 -20
- metadata +5 -5
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ begin
|
|
9
9
|
s.homepage = "http://github.com/joshbuddy/usher"
|
10
10
|
s.authors = ["Joshua Hull"]
|
11
11
|
s.files = FileList["[A-Z]*", "{lib,spec,rails}/**/*"]
|
12
|
-
s.add_dependency '
|
12
|
+
s.add_dependency 'fuzzyhash', '>=0.0.3'
|
13
13
|
end
|
14
14
|
rescue LoadError
|
15
15
|
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
@@ -34,3 +34,38 @@ Spec::Rake::SpecTask.new('spec_with_rcov') do |t|
|
|
34
34
|
t.rcov = true
|
35
35
|
t.rcov_opts = ['--exclude', 'spec']
|
36
36
|
end
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
desc "Generate documentation"
|
40
|
+
Rake::RDocTask.new do |rd|
|
41
|
+
rd.main = "README.rdoc"
|
42
|
+
rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
|
43
|
+
rd.rdoc_dir = 'rdoc'
|
44
|
+
end
|
45
|
+
|
46
|
+
# These are new tasks
|
47
|
+
begin
|
48
|
+
require 'rake/contrib/sshpublisher'
|
49
|
+
namespace :rubyforge do
|
50
|
+
|
51
|
+
desc "Release gem and RDoc documentation to RubyForge"
|
52
|
+
task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
|
53
|
+
|
54
|
+
namespace :release do
|
55
|
+
desc "Publish RDoc to RubyForge."
|
56
|
+
task :docs => [:rdoc] do
|
57
|
+
config = YAML.load(
|
58
|
+
File.read(File.expand_path('~/.rubyforge/user-config.yml'))
|
59
|
+
)
|
60
|
+
|
61
|
+
host = "#{config['username']}@rubyforge.org"
|
62
|
+
remote_dir = "/var/www/gforge-projects/joshbuddy-usher/"
|
63
|
+
local_dir = 'rdoc'
|
64
|
+
|
65
|
+
Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
rescue LoadError
|
70
|
+
puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
|
71
|
+
end
|
data/VERSION.yml
CHANGED
data/lib/usher/generate.rb
CHANGED
@@ -1,22 +1,61 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
unless Rack::Utils.respond_to?(:uri_escape)
|
4
|
+
module Rack
|
5
|
+
|
6
|
+
module Utils
|
7
|
+
|
8
|
+
def uri_escape(s)
|
9
|
+
s.to_s.gsub(/([^:\/?\[\]\-_~\.!\$&'\(\)\*\+,;=@a-zA-Z0-9]+)/n) {
|
10
|
+
'%'<<$1.unpack('H2'*$1.size).join('%').upcase
|
11
|
+
}.tr(' ', '+')
|
12
|
+
end
|
13
|
+
module_function :uri_escape
|
14
|
+
|
15
|
+
def uri_unescape(s)
|
16
|
+
gsub(/((?:%[0-9a-fA-F]{2})+)/n){
|
17
|
+
[$1.delete('%')].pack('H*')
|
18
|
+
}
|
19
|
+
end
|
20
|
+
module_function :uri_unescape
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
1
26
|
class Usher
|
2
27
|
class Generators
|
3
28
|
|
4
29
|
class URL
|
5
|
-
|
30
|
+
|
6
31
|
def initialize(usher)
|
7
32
|
@usher = usher
|
8
33
|
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
34
|
|
35
|
+
def generate_full(routing_lookup, request, params = nil)
|
36
|
+
path = path_for_routing_lookup(routing_lookup, params)
|
37
|
+
result = generate_start(path, request)
|
38
|
+
result << generate_path(path, params)
|
39
|
+
end
|
40
|
+
|
41
|
+
def generate(routing_lookup, params = nil)
|
42
|
+
generate_path(path_for_routing_lookup(routing_lookup, params), params)
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate_start(path, request)
|
46
|
+
result = (path.route.generate_with && path.route.generate_with.scheme || request.scheme).dup
|
47
|
+
result << '://'
|
48
|
+
result << (path.route.generate_with && path.route.generate_with.host) ? path.route.generate_with.host : request.host
|
49
|
+
port = path.route.generate_with && path.route.generate_with.port || request.port
|
50
|
+
if result[4] == ?s
|
51
|
+
result << ':' << port.to_s if port != 443
|
52
|
+
else
|
53
|
+
result << ':' << port.to_s if port != 80
|
54
|
+
end
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
def path_for_routing_lookup(routing_lookup, params)
|
20
59
|
path = case routing_lookup
|
21
60
|
when Symbol
|
22
61
|
route = @usher.named_routes[routing_lookup]
|
@@ -28,13 +67,23 @@ class Usher
|
|
28
67
|
when Route::Path
|
29
68
|
routing_lookup
|
30
69
|
end
|
31
|
-
|
70
|
+
end
|
71
|
+
|
72
|
+
# Generates a completed URL based on a +route+ or set of optional +params+
|
73
|
+
#
|
74
|
+
# set = Usher.new
|
75
|
+
# route = set.add_named_route(:test_route, '/:controller/:action')
|
76
|
+
# set.generate_url(nil, {:controller => 'c', :action => 'a'}) == '/c/a' => true
|
77
|
+
# set.generate_url(:test_route, {:controller => 'c', :action => 'a'}) == '/c/a' => true
|
78
|
+
# set.generate_url(route.primary_path, {:controller => 'c', :action => 'a'}) == '/c/a' => true
|
79
|
+
def generate_path(path, params = nil)
|
32
80
|
raise UnrecognizedException.new unless path
|
33
81
|
|
34
82
|
params = Array(params) if params.is_a?(String)
|
35
83
|
if params.is_a?(Array)
|
84
|
+
given_size = params.size
|
36
85
|
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}]
|
86
|
+
params = Hash[*path.dynamic_parts.inject([]){|a, dynamic_part| a.concat([dynamic_part.name, params.shift || raise(MissingParameterException.new("got #{given_size}, expected #{path.dynamic_parts.size} parameters"))]); a}]
|
38
87
|
params.merge!(extra_params) if extra_params
|
39
88
|
end
|
40
89
|
|
@@ -49,7 +98,7 @@ class Usher
|
|
49
98
|
current_value = current_value.to_s unless current_value.is_a?(String)
|
50
99
|
part.valid!(current_value)
|
51
100
|
result << current_value
|
52
|
-
result <<
|
101
|
+
result << '/' if index != value.size - 1
|
53
102
|
end
|
54
103
|
when :':'
|
55
104
|
value = value.to_s unless value.is_a?(String)
|
@@ -60,7 +109,7 @@ class Usher
|
|
60
109
|
result << part
|
61
110
|
end
|
62
111
|
end
|
63
|
-
result =
|
112
|
+
result = Rack::Utils.uri_escape(result)
|
64
113
|
|
65
114
|
if params && !params.empty?
|
66
115
|
has_query = result[??]
|
@@ -68,10 +117,10 @@ class Usher
|
|
68
117
|
case v
|
69
118
|
when Array
|
70
119
|
v.each do |v_part|
|
71
|
-
result << (has_query ? '&' : has_query = true && '?') <<
|
120
|
+
result << (has_query ? '&' : has_query = true && '?') << Rack::Utils.escape("#{k.to_s}[]") << '=' << Rack::Utils.escape(v_part.to_s)
|
72
121
|
end
|
73
122
|
else
|
74
|
-
result << (has_query ? '&' : has_query = true && '?') <<
|
123
|
+
result << (has_query ? '&' : has_query = true && '?') << Rack::Utils.escape(k.to_s) << '=' << Rack::Utils.escape(v.to_s)
|
75
124
|
end
|
76
125
|
end
|
77
126
|
end
|
@@ -1,18 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'rack_interface/route'
|
1
|
+
require 'rack'
|
4
2
|
|
5
3
|
class Usher
|
6
4
|
module Interface
|
7
5
|
class RackInterface
|
8
6
|
|
9
|
-
RequestMethods = [:method, :host, :port, :scheme]
|
10
|
-
Request = Struct.new(:path, *RequestMethods)
|
11
|
-
|
12
7
|
attr_accessor :routes
|
13
8
|
|
14
9
|
def initialize(&blk)
|
15
|
-
@routes = Usher.new(:request_methods =>
|
10
|
+
@routes = Usher.new(:request_methods => [:method, :host, :port, :scheme])
|
16
11
|
@generator = Usher::Generators::URL.new(@routes)
|
17
12
|
instance_eval(&blk) if blk
|
18
13
|
end
|
@@ -26,7 +21,7 @@ class Usher
|
|
26
21
|
end
|
27
22
|
|
28
23
|
def call(env)
|
29
|
-
response = @routes.recognize(Request.new(env
|
24
|
+
response = @routes.recognize(Rack::Request.new(env))
|
30
25
|
params = {}
|
31
26
|
response.params.each{ |hk| params[hk.first] = hk.last}
|
32
27
|
env['usher.params'] = params
|
data/lib/usher/interface.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
|
-
$:.unshift File.dirname(__FILE__)
|
2
|
-
|
3
1
|
class Usher
|
4
2
|
module Interface
|
5
|
-
autoload :Rails2_2Interface, 'interface
|
6
|
-
autoload :Rails2_3Interface, 'interface
|
7
|
-
autoload :MerbInterface, 'interface
|
8
|
-
autoload :RackInterface, 'interface
|
9
|
-
autoload :EmailInterface, 'interface
|
3
|
+
autoload :Rails2_2Interface, File.join(File.dirname(__FILE__), 'interface', 'rails2_2_interface')
|
4
|
+
autoload :Rails2_3Interface, File.join(File.dirname(__FILE__), 'interface', 'rails2_3_interface')
|
5
|
+
autoload :MerbInterface, File.join(File.dirname(__FILE__), 'interface', 'merb_interface')
|
6
|
+
autoload :RackInterface, File.join(File.dirname(__FILE__), 'interface', 'rack_interface')
|
7
|
+
autoload :EmailInterface, File.join(File.dirname(__FILE__), 'interface', 'email_interface')
|
10
8
|
|
11
9
|
def self.for(type, &blk)
|
12
10
|
case type
|
data/lib/usher/node.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
$:.unshift File.dirname(__FILE__)
|
2
|
-
|
3
1
|
require 'fuzzy_hash'
|
4
2
|
|
5
3
|
class Usher
|
@@ -51,7 +49,7 @@ class Usher
|
|
51
49
|
route.paths.each do |path|
|
52
50
|
parts = path.parts.dup
|
53
51
|
request_methods.each do |type|
|
54
|
-
parts.push(Route::RequestMethod.new(type, route.conditions[type])) if route.conditions.key?(type)
|
52
|
+
parts.push(Route::RequestMethod.new(type, route.conditions[type])) if route.conditions && route.conditions.key?(type)
|
55
53
|
end
|
56
54
|
|
57
55
|
current_node = self
|
data/lib/usher/route.rb
CHANGED
@@ -1,20 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'route
|
4
|
-
require 'route/variable'
|
5
|
-
require 'route/request_method'
|
1
|
+
require File.join(File.dirname(__FILE__), 'route', 'path')
|
2
|
+
require File.join(File.dirname(__FILE__), 'route', 'variable')
|
3
|
+
require File.join(File.dirname(__FILE__), 'route', 'request_method')
|
6
4
|
|
7
5
|
class Usher
|
8
6
|
class Route
|
9
|
-
attr_reader :paths, :original_path, :requirements, :conditions, :destination, :named
|
7
|
+
attr_reader :paths, :original_path, :requirements, :conditions, :destination, :named, :generate_with
|
8
|
+
|
9
|
+
GenerateWith = Struct.new(:scheme, :port, :host)
|
10
10
|
|
11
|
-
def initialize(original_path, router, conditions, requirements, default_values) # :nodoc:
|
11
|
+
def initialize(original_path, router, conditions, requirements, default_values, generate_with) # :nodoc:
|
12
12
|
@original_path = original_path
|
13
13
|
@router = router
|
14
14
|
@requirements = requirements
|
15
15
|
@conditions = conditions
|
16
16
|
@default_values = default_values
|
17
17
|
@paths = @router.splitter.split(@original_path, @requirements, @default_values).collect {|path| Path.new(self, path)}
|
18
|
+
@generate_with = GenerateWith.new(generate_with[:scheme], generate_with[:port], generate_with[:host]) if generate_with
|
18
19
|
end
|
19
20
|
|
20
21
|
def grapher
|
data/lib/usher.rb
CHANGED
@@ -1,16 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require 'usher
|
6
|
-
require 'usher
|
7
|
-
require 'usher/grapher'
|
8
|
-
require 'usher/interface'
|
9
|
-
require 'usher/splitter'
|
10
|
-
require 'usher/exceptions'
|
11
|
-
require 'usher/generate'
|
1
|
+
require File.join(File.dirname(__FILE__), 'usher', 'node')
|
2
|
+
require File.join(File.dirname(__FILE__), 'usher', 'route')
|
3
|
+
require File.join(File.dirname(__FILE__), 'usher', 'grapher')
|
4
|
+
require File.join(File.dirname(__FILE__), 'usher', 'interface')
|
5
|
+
require File.join(File.dirname(__FILE__), 'usher', 'splitter')
|
6
|
+
require File.join(File.dirname(__FILE__), 'usher', 'exceptions')
|
12
7
|
|
13
8
|
class Usher
|
9
|
+
|
10
|
+
autoload :Generators, File.join(File.dirname(__FILE__), 'usher', 'generate')
|
11
|
+
|
14
12
|
attr_reader :tree, :named_routes, :route_count, :routes, :splitter, :delimiters
|
15
13
|
|
16
14
|
SymbolArraySorter = proc {|a,b| a.hash <=> b.hash} #:nodoc:
|
@@ -142,18 +140,19 @@ class Usher
|
|
142
140
|
# * +conditions+ - Accepts any of the +request_methods+ specificied in the construction of Usher. This can be either a <tt>string</tt> or a regular expression.
|
143
141
|
# * Any other key is interpreted as a requirement for the variable of its name.
|
144
142
|
def add_route(path, options = nil)
|
145
|
-
conditions = options && options.delete(:conditions) ||
|
146
|
-
requirements = options && options.delete(:requirements) ||
|
147
|
-
default_values = options && options.delete(:default_values) ||
|
143
|
+
conditions = options && options.delete(:conditions) || nil
|
144
|
+
requirements = options && options.delete(:requirements) || nil
|
145
|
+
default_values = options && options.delete(:default_values) || nil
|
146
|
+
generate_with = options && options.delete(:generate_with) || nil
|
148
147
|
if options
|
149
148
|
options.delete_if do |k, v|
|
150
149
|
if v.is_a?(Regexp) || v.is_a?(Proc)
|
151
|
-
requirements[k] = v
|
150
|
+
(requirements ||= {})[k] = v
|
152
151
|
true
|
153
152
|
end
|
154
153
|
end
|
155
154
|
end
|
156
|
-
route = Route.new(path, self, conditions, requirements, default_values)
|
155
|
+
route = Route.new(path, self, conditions, requirements, default_values, generate_with)
|
157
156
|
route.to(options) if options && !options.empty?
|
158
157
|
|
159
158
|
@tree.add(route)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'lib/usher'
|
2
|
-
|
2
|
+
require 'rack'
|
3
3
|
|
4
4
|
describe "Usher URL generation" do
|
5
5
|
|
@@ -87,6 +87,11 @@ describe "Usher URL generation" do
|
|
87
87
|
@url_generator.generate(:name, ['controller', 'action', 'html']).should == '/controller/action.html'
|
88
88
|
end
|
89
89
|
|
90
|
+
it "should generate a route with a specific host" do
|
91
|
+
caf = @route_set.add_named_route(:name, '/:controller/:action.:format', :generate_with => {:host => 'www.slashdot.org', :port => 80})
|
92
|
+
@url_generator.generate_full(:name, Rack::Request.new(Rack::MockRequest.env_for("http://localhost:8080")), ['controller', 'action', 'html']).should == 'http://www.slashdot.org/controller/action.html'
|
93
|
+
end
|
94
|
+
|
90
95
|
it "should require all the parameters (hash) to generate a route" do
|
91
96
|
proc {@url_generator.generate(@route_set.add_route('/:controller/:action'), {:controller => 'controller'})}.should raise_error Usher::MissingParameterException
|
92
97
|
end
|
@@ -1,22 +1,8 @@
|
|
1
1
|
require 'lib/usher'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
def build_request_mock(path, method, params)
|
6
|
-
request = mock "Request"
|
7
|
-
request.should_receive(:path).any_number_of_times.and_return(path)
|
8
|
-
request.should_receive(:method).any_number_of_times.and_return(method)
|
9
|
-
params = params.with_indifferent_access
|
10
|
-
request.should_receive(:path_parameters=).any_number_of_times.with(params)
|
11
|
-
request.should_receive(:path_parameters).any_number_of_times.and_return(params)
|
12
|
-
request
|
13
|
-
end
|
3
|
+
require 'rack'
|
14
4
|
|
15
|
-
|
16
|
-
request = mock "App"
|
17
|
-
request.should_receive(:call).any_number_of_times.with(params)
|
18
|
-
request
|
19
|
-
end
|
5
|
+
route_set = Usher::Interface.for(:rack)
|
20
6
|
|
21
7
|
describe "Usher (for rack) route dispatching" do
|
22
8
|
|
@@ -25,9 +11,19 @@ describe "Usher (for rack) route dispatching" do
|
|
25
11
|
end
|
26
12
|
|
27
13
|
it "should dispatch a simple request" do
|
28
|
-
|
29
|
-
|
30
|
-
route_set.
|
14
|
+
app = mock 'app'
|
15
|
+
app.should_receive(:call).once.with {|v| v['usher.params'].should == {} }
|
16
|
+
route_set.add('/sample').to(app)
|
17
|
+
route_set.call(Rack::MockRequest.env_for("/sample", :method => 'GET'))
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should dispatch a POST request" do
|
21
|
+
bad_app = mock 'bad_app'
|
22
|
+
app = mock 'app'
|
23
|
+
app.should_receive(:call).once.with {|v| v['usher.params'].should == {} }
|
24
|
+
route_set.add('/sample').to(bad_app)
|
25
|
+
route_set.add('/sample', :requirements => {:request_method => 'POST'}).to(app)
|
26
|
+
route_set.call(Rack::MockRequest.env_for("/sample", :request_method => 'POST'))
|
31
27
|
end
|
32
28
|
|
33
|
-
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: joshbuddy-usher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Hull
|
@@ -9,11 +9,11 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-16 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
16
|
+
name: fuzzyhash
|
17
17
|
type: :runtime
|
18
18
|
version_requirement:
|
19
19
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -73,7 +73,7 @@ files:
|
|
73
73
|
- spec/private/request_method_spec.rb
|
74
74
|
- spec/private/split_spec.rb
|
75
75
|
- spec/spec.opts
|
76
|
-
has_rdoc:
|
76
|
+
has_rdoc: false
|
77
77
|
homepage: http://github.com/joshbuddy/usher
|
78
78
|
post_install_message:
|
79
79
|
rdoc_options:
|
@@ -97,7 +97,7 @@ requirements: []
|
|
97
97
|
rubyforge_project:
|
98
98
|
rubygems_version: 1.2.0
|
99
99
|
signing_key:
|
100
|
-
specification_version:
|
100
|
+
specification_version: 3
|
101
101
|
summary: A general purpose routing library
|
102
102
|
test_files:
|
103
103
|
- spec/private/email/recognize_spec.rb
|