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 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 'joshbuddy-fuzzy_hash', '>=0.0.3'
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
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :minor: 4
3
- :patch: 7
3
+ :patch: 8
4
4
  :major: 0
@@ -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 << delimiter if index != value.size - 1
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 = URI.escape(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 && '?') << CGI.escape("#{k.to_s}[]") << '=' << CGI.escape(v_part.to_s)
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 && '?') << CGI.escape(k.to_s) << '=' << CGI.escape(v.to_s)
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,7 +1,3 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
- require 'rack_interface/route'
4
-
5
1
  class Usher
6
2
  module Interface
7
3
  class EmailInterface
@@ -1,5 +1,3 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
1
  require 'merb-core'
4
2
  require 'merb-core/dispatch/router/behavior'
5
3
 
@@ -1,18 +1,13 @@
1
- $:.unshift File.dirname(__FILE__)
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 => RequestMethods)
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['REQUEST_URI'], env['REQUEST_METHOD'].downcase, env['HTTP_HOST'], env['SERVER_PORT'].to_i, env['rack.url_scheme']))
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
@@ -1,6 +1,4 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
- require 'rails2_2_interface/mapper'
1
+ require File.join(File.dirname(__FILE__), 'rails2_2_interface', 'mapper')
4
2
 
5
3
  class Usher
6
4
  module Interface
@@ -1,5 +1,3 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
1
  class Usher
4
2
  module Interface
5
3
  class Rails2_3Interface
@@ -1,12 +1,10 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
1
  class Usher
4
2
  module Interface
5
- autoload :Rails2_2Interface, 'interface/rails2_2_interface'
6
- autoload :Rails2_3Interface, 'interface/rails2_3_interface'
7
- autoload :MerbInterface, 'interface/merb_interface'
8
- autoload :RackInterface, 'interface/rack_interface'
9
- autoload :EmailInterface, 'interface/email_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
- $:.unshift File.dirname(__FILE__)
2
-
3
- require 'route/path'
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
- $:.unshift File.dirname(__FILE__)
2
-
3
- require 'cgi'
4
- require 'uri'
5
- require 'usher/node'
6
- require 'usher/route'
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
- route_set = Usher::Interface.for(:rack)
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
- def build_app_mock(params)
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
- env = {'REQUEST_URI' => '/sample', 'REQUEST_METHOD' => 'get', 'usher.params' => {}}
29
- route_set.add('/sample').to(build_app_mock(env.dup))
30
- route_set.call(env)
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.7
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 00:00:00 -07:00
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: joshbuddy-fuzzy_hash
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: true
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: 2
100
+ specification_version: 3
101
101
  summary: A general purpose routing library
102
102
  test_files:
103
103
  - spec/private/email/recognize_spec.rb