usher 0.5.11 → 0.5.12

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.
Files changed (39) hide show
  1. data/Rakefile +48 -53
  2. data/VERSION.yml +2 -2
  3. data/lib/usher.rb +12 -12
  4. data/lib/usher/delimiters.rb +7 -7
  5. data/lib/usher/interface.rb +19 -30
  6. data/lib/usher/interface/{email_interface.rb → email.rb} +1 -1
  7. data/lib/usher/interface/{merb_interface.rb → merb.rb} +1 -1
  8. data/lib/usher/interface/{rack_interface.rb → rack.rb} +14 -10
  9. data/lib/usher/interface/{rack_interface → rack}/mapper.rb +0 -0
  10. data/lib/usher/interface/rack/route.rb +16 -0
  11. data/lib/usher/interface/rails20.rb +7 -0
  12. data/lib/usher/interface/{rails2_2_interface.rb → rails22.rb} +18 -18
  13. data/lib/usher/interface/{rails2_2_interface → rails22}/mapper.rb +2 -2
  14. data/lib/usher/interface/{rails2_3_interface.rb → rails23.rb} +1 -1
  15. data/lib/usher/interface/rails23/mapper.rb +44 -0
  16. data/lib/usher/interface/{rails3_interface.rb → rails3.rb} +1 -1
  17. data/lib/usher/interface/{text_interface.rb → text.rb} +1 -1
  18. data/lib/usher/node.rb +71 -57
  19. data/lib/usher/route.rb +10 -5
  20. data/lib/usher/route/static.rb +9 -0
  21. data/lib/usher/route/variable.rb +28 -9
  22. data/lib/usher/util.rb +3 -3
  23. data/lib/usher/util/generate.rb +55 -18
  24. data/lib/usher/util/parser.rb +25 -18
  25. data/rails/init.rb +24 -8
  26. data/spec/private/generate_spec.rb +116 -1
  27. data/spec/private/generate_with_spec.rb +28 -0
  28. data/spec/private/rack/dispatch_spec.rb +23 -2
  29. data/spec/private/rack/route_spec.rb +50 -0
  30. data/spec/private/rails2_2/generate_spec.rb +1 -1
  31. data/spec/private/rails2_2/path_spec.rb +1 -1
  32. data/spec/private/rails2_2/recognize_spec.rb +1 -1
  33. data/spec/private/rails2_3/generate_spec.rb +1 -1
  34. data/spec/private/rails2_3/path_spec.rb +1 -1
  35. data/spec/private/rails2_3/recognize_spec.rb +1 -1
  36. data/spec/private/recognize_spec.rb +4 -5
  37. data/spec/private/url_parts_spec.rb +116 -0
  38. metadata +26 -12
  39. data/lib/usher/interface/rack_interface/route.rb +0 -16
data/Rakefile CHANGED
@@ -1,53 +1,48 @@
1
- libdir = File.expand_path("lib")
2
- $:.unshift(libdir) unless $:.include?(libdir)
3
-
4
- require 'usher'
5
-
6
- begin
7
- require 'jeweler'
8
- Jeweler::Tasks.new do |s|
9
- s.name = "usher"
10
- s.description = s.summary = "A general purpose routing library"
11
- s.email = "joshbuddy@gmail.com"
12
- s.homepage = "http://github.com/joshbuddy/usher"
13
- s.authors = ["Joshua Hull"]
14
- s.files = FileList["[A-Z]*", "{lib,spec,rails}/**/*"]
15
- s.add_dependency 'fuzzyhash', '>=0.0.9'
16
- s.rubyforge_project = 'joshbuddy-usher'
17
- end
18
- Jeweler::GemcutterTasks.new
19
- Jeweler::RubyforgeTasks.new do |rubyforge|
20
- rubyforge.doc_task = "rdoc"
21
- rubyforge.remote_doc_path = ''
22
- end
23
- rescue LoadError
24
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
25
- end
26
-
27
- require 'spec'
28
- require 'spec/rake/spectask'
29
- task :spec => 'spec:all'
30
- namespace(:spec) do
31
- Spec::Rake::SpecTask.new(:all) do |t|
32
- t.spec_opts ||= []
33
- t.spec_opts << "-rubygems"
34
- t.spec_opts << "--options" << "spec/spec.opts"
35
- t.spec_files = FileList['spec/**/*_spec.rb']
36
- end
37
-
38
- end
39
-
40
- desc "Run all examples with RCov"
41
- Spec::Rake::SpecTask.new('spec_with_rcov') do |t|
42
- t.spec_files = FileList['spec/**/*.rb']
43
- t.rcov = true
44
- t.rcov_opts = ['--exclude', 'spec']
45
- end
46
-
47
- require 'rake/rdoctask'
48
- desc "Generate documentation"
49
- Rake::RDocTask.new do |rd|
50
- rd.main = "README.rdoc"
51
- rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
52
- rd.rdoc_dir = 'rdoc'
53
- end
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'usher'))
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |s|
8
+ s.name = "usher"
9
+ s.description = s.summary = "A general purpose routing library"
10
+ s.email = "joshbuddy@gmail.com"
11
+ s.homepage = "http://github.com/joshbuddy/usher"
12
+ s.authors = ["Joshua Hull", 'Jakub Šťastný', 'Daniel Neighman', 'Daniel Vartanov'].sort
13
+ s.files = FileList["[A-Z]*", "{lib,spec,rails}/**/*"]
14
+ s.add_dependency 'fuzzyhash', '>=0.0.9'
15
+ s.rubyforge_project = 'joshbuddy-usher'
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
20
+ end
21
+
22
+ require 'spec'
23
+ require 'spec/rake/spectask'
24
+ task :spec => 'spec:all'
25
+ namespace(:spec) do
26
+ Spec::Rake::SpecTask.new(:all) do |t|
27
+ t.spec_opts ||= []
28
+ t.spec_opts << "-rubygems"
29
+ t.spec_opts << "--options" << "spec/spec.opts"
30
+ t.spec_files = FileList['spec/**/*_spec.rb']
31
+ end
32
+
33
+ end
34
+
35
+ desc "Run all examples with RCov"
36
+ Spec::Rake::SpecTask.new('spec_with_rcov') do |t|
37
+ t.spec_files = FileList['spec/**/*.rb']
38
+ t.rcov = true
39
+ t.rcov_opts = ['--exclude', 'spec']
40
+ end
41
+
42
+ require 'rake/rdoctask'
43
+ desc "Generate documentation"
44
+ Rake::RDocTask.new do |rd|
45
+ rd.main = "README.rdoc"
46
+ rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
47
+ rd.rdoc_dir = 'rdoc'
48
+ end
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  :build:
3
- :patch: 11
4
- :major: 0
5
3
  :minor: 5
4
+ :patch: 12
5
+ :major: 0
@@ -1,12 +1,13 @@
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')
7
- require File.join(File.dirname(__FILE__), 'usher', 'util')
8
- require File.join(File.dirname(__FILE__), 'usher', 'spinoffs', 'strscan_additions')
9
- require File.join(File.dirname(__FILE__), 'usher', 'delimiters')
1
+ $: << File.expand_path(File.dirname(__FILE__))
2
+ require File.join('usher', 'node')
3
+ require File.join('usher', 'route')
4
+ require File.join('usher', 'grapher')
5
+ require File.join('usher', 'interface')
6
+ require File.join('usher', 'splitter')
7
+ require File.join('usher', 'exceptions')
8
+ require File.join('usher', 'util')
9
+ require File.join('usher', 'spinoffs', 'strscan_additions')
10
+ require File.join('usher', 'delimiters')
10
11
 
11
12
  class Usher
12
13
  attr_reader :root, :named_routes, :routes, :splitter,
@@ -53,8 +54,7 @@ class Usher
53
54
  # Array of methods called against the request object for the purposes of matching route requirements.
54
55
  def initialize(options = nil)
55
56
  self.generator = options && options.delete(:generator)
56
- delimiters_array = options && options.delete(:delimiters) || ['/', '.']
57
- self.delimiters = Delimiters.new(delimiters_array)
57
+ self.delimiters = Delimiters.new(options && options.delete(:delimiters) || ['/', '.'])
58
58
  self.valid_regex = options && options.delete(:valid_regex) || '[0-9A-Za-z\$\-_\+!\*\',]+'
59
59
  self.request_methods = options && options.delete(:request_methods)
60
60
  reset!
@@ -95,7 +95,7 @@ class Usher
95
95
  # route = set.add_route('/test')
96
96
  # set.name(:test, route)
97
97
  def name(name, route)
98
- @named_routes[name] = route
98
+ @named_routes[name.to_sym] = route
99
99
  route
100
100
  end
101
101
 
@@ -1,14 +1,14 @@
1
1
  class Delimiters < Array
2
- # TODO: caching
2
+
3
+ attr_reader :unescaped
3
4
 
4
- def unescaped
5
- self.map do |delimiter|
6
- (delimiter[0] == ?\\) ?
7
- delimiter[1..-1] :
8
- delimiter
5
+ def initialize(ary)
6
+ super ary
7
+ @unescaped = self.map do |delimiter|
8
+ (delimiter[0] == ?\\) ? delimiter[1..-1] : delimiter
9
9
  end
10
10
  end
11
-
11
+
12
12
  def first_in(array)
13
13
  # TODO: should we optimize this O(n*m)? hash or modified or KNP or at leaset sort + b-search. But they are so short
14
14
 
@@ -1,43 +1,32 @@
1
- # From Extlib
2
- module CamelCaseMixin
3
- def camel_case
4
- return self if self !~ /_/ && self =~ /[A-Z]+.*/
5
- split('_').map{|e| e.capitalize}.join
6
- end
7
- end
8
-
9
- # TODO: refactoring: I suggest to use usher/interfaces/rack.rb instead of
10
- # usher/interface/rack_interface.rb, it will enable me to simplify this code
11
1
  class Usher
12
2
  module Interface
13
- # Get root directory of interfaces of path to specified interface
14
- def self.interface_directory
15
- File.join(File.dirname(__FILE__), "interface")
16
- end
17
3
 
18
- # path to file
19
- def self.interface_path(name)
20
- File.join(self.interface_directory, "#{name}_interface.rb")
4
+ InterfaceRegistry = {}
5
+
6
+ def self.register(name, cls)
7
+ InterfaceRegistry[name] = cls
21
8
  end
22
9
 
10
+ register(:email, File.join(File.dirname(__FILE__), 'interface', 'email'))
11
+ register(:merb, File.join(File.dirname(__FILE__), 'interface', 'merb'))
12
+ register(:rails20, File.join(File.dirname(__FILE__), 'interface', 'rails20'))
13
+ register(:rails22, File.join(File.dirname(__FILE__), 'interface', 'rails22'))
14
+ register(:rails23, File.join(File.dirname(__FILE__), 'interface', 'rails23'))
15
+ register(:rack, File.join(File.dirname(__FILE__), 'interface', 'rack'))
16
+ register(:rails3, File.join(File.dirname(__FILE__), 'interface', 'rails3'))
17
+ register(:text, File.join(File.dirname(__FILE__), 'interface', 'text'))
18
+
23
19
  # Usher::Interface.for(:rack, &block)
24
20
  def self.for(name, &block)
25
- if File.exist?(self.interface_path(name))
26
- require self.interface_path(name)
27
- snake_cased = "#{name}_interface".extend(CamelCaseMixin)
28
- Usher::Interface.const_get(snake_cased.camel_case).new(&block)
21
+ name = name.to_sym
22
+ if InterfaceRegistry[name]
23
+ require InterfaceRegistry[name]
24
+ const = Usher::Interface.const_get(File.basename(InterfaceRegistry[name]).to_s.split(/_/).map{|e| e.capitalize}.join)
25
+ const.new(&block)
29
26
  else
30
- raise ArgumentError, "Interface #{name} doesn't exist. Choose one of: #{self.interfaces.inspect}"
27
+ raise ArgumentError, "Interface #{name.inspect} doesn't exist. Choose one of: #{InterfaceRegistry.keys.inspect}"
31
28
  end
32
29
  end
33
30
 
34
- # Array of symbols
35
- # Usher::Interface.interfaces
36
- # => [:email_interface, :merb_interface, :rack_interface, :rails2_2_interface, :rails2_3_interface, :rails3_interface, :text_interface]
37
- def self.interfaces
38
- Dir["#{self.interface_directory}/*.rb"].map do |interface|
39
- File.basename(interface).sub("_interface.rb", "").to_sym
40
- end
41
- end
42
31
  end
43
32
  end
@@ -1,6 +1,6 @@
1
1
  class Usher
2
2
  module Interface
3
- class EmailInterface
3
+ class Email
4
4
 
5
5
  def initialize(&blk)
6
6
  @routes = Usher.new(:delimiters => ['@', '-', '.'], :valid_regex => '[\+a-zA-Z0-9]+')
@@ -3,7 +3,7 @@ require 'merb-core/dispatch/router/behavior'
3
3
 
4
4
  class Usher
5
5
  module Interface
6
- class MerbInterface
6
+ class Merb
7
7
 
8
8
  # merb does everything with class methods.
9
9
 
@@ -1,11 +1,12 @@
1
- require 'rack'
1
+ require "rack"
2
+ require File.join(File.dirname(__FILE__), 'rack', 'route')
2
3
 
3
4
  class Usher
4
5
  module Interface
5
- class RackInterface
6
- class Builder < Rack::Builder
6
+ class Rack
7
+ class Builder < ::Rack::Builder
7
8
  def initialize(&block)
8
- @usher = Usher::Interface::RackInterface.new
9
+ @usher = Usher::Interface::Rack.new
9
10
  super
10
11
  end
11
12
 
@@ -14,7 +15,10 @@ class Usher
14
15
  @ins << @usher unless @ins.last == @usher
15
16
  end
16
17
 
18
+ # it returns route, and because you may want to work with the route,
19
+ # for example give it a name, we returns the route with GET request
17
20
  def get(path, options = nil, &block)
21
+ self.map(path, options.merge!(:conditions => {:request_method => "HEAD"}), &block)
18
22
  self.map(path, options.merge!(:conditions => {:request_method => "GET"}), &block)
19
23
  end
20
24
 
@@ -35,7 +39,7 @@ class Usher
35
39
  attr_accessor :app
36
40
 
37
41
  def initialize(app = nil, &blk)
38
- @app = app || lambda { |env| Rack::Response.new("No route found", 404).finish }
42
+ @app = app || lambda { |env| ::Rack::Response.new("No route found", 404).finish }
39
43
  @router = Usher.new(:request_methods => [:request_method, :host, :port, :scheme], :generator => Usher::Util::Generators::URL.new)
40
44
  instance_eval(&blk) if blk
41
45
  end
@@ -63,11 +67,11 @@ class Usher
63
67
  # add("/url", :conditions => {:request_method => "POST"}})
64
68
  # is the same as:
65
69
  # post("/url")
66
- #
67
- # if you need more complex setup, use method add directly, for example:
68
- # add("/url", :conditions => {:request_method => ["POST", "PUT"]}})
70
+
71
+ # it returns route, and because you may want to work with the route,
72
+ # for example give it a name, we returns the route with GET request
69
73
  def get(path, options = {})
70
- self.add(path, options.merge!(:conditions => {:request_method => "GET"}))
74
+ self.add(path, options.merge!(:conditions => {:request_method => ["HEAD", "GET"]}))
71
75
  end
72
76
 
73
77
  def post(path, options = {})
@@ -95,7 +99,7 @@ class Usher
95
99
  end
96
100
 
97
101
  def call(env)
98
- request = Rack::Request.new(env)
102
+ request = ::Rack::Request.new(env)
99
103
  response = @router.recognize(request, request.path_info)
100
104
  after_match(request, response) if response
101
105
  determine_respondant(response).call(env)
@@ -0,0 +1,16 @@
1
+ class Usher
2
+ class Route
3
+ # add("/index.html").redirect("/")
4
+ def redirect(path, status = 302)
5
+ unless (300..399).include?(status)
6
+ raise ArgumentError, "Status has to be an integer between 300 and 399"
7
+ end
8
+ @destination = lambda do |env|
9
+ response = Rack::Response.new
10
+ response.redirect(path, status)
11
+ response.finish
12
+ end
13
+ return self
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ class Usher
2
+ module Interface
3
+ class Rails20 < Rails22
4
+ Mapper = Usher::Interface::Rails22::Mapper
5
+ end
6
+ end
7
+ end
@@ -1,8 +1,8 @@
1
- require File.join(File.dirname(__FILE__), 'rails2_2_interface', 'mapper')
1
+ require File.join('usher', 'interface', 'rails22', 'mapper')
2
2
 
3
3
  class Usher
4
4
  module Interface
5
- class Rails22Interface
5
+ class Rails22
6
6
 
7
7
  attr_reader :usher
8
8
  attr_accessor :configuration_file
@@ -10,9 +10,12 @@ class Usher
10
10
  def initialize
11
11
  reset!
12
12
  end
13
-
14
- def reset!
15
- @usher ||= Usher.new(:generator => Usher::Util::Generators::URL.new, :request_methods => [:protocol, :domain, :port, :query_string, :remote_ip, :user_agent, :referer, :method, :subdomains])
13
+
14
+ def reset!(options={})
15
+ options[:generator] = options[:generator] || Usher::Util::Generators::URL.new
16
+ options[:request_methods] = options[:request_methods] || [:protocol, :domain, :port, :query_string, :remote_ip, :user_agent, :referer, :method, :subdomains]
17
+
18
+ @usher = Usher.new(options)
16
19
  @module ||= Module.new
17
20
  @module.instance_methods.each do |selector|
18
21
  @module.class_eval { remove_method selector }
@@ -32,7 +35,7 @@ class Usher
32
35
  add_route('/:controller', options.merge({:action => 'index'}))
33
36
  @controller_route_added = true
34
37
  end
35
-
38
+
36
39
  options[:action] = 'index' unless options[:action]
37
40
 
38
41
  path[0, 0] = '/' unless path[0] == ?/
@@ -109,25 +112,22 @@ class Usher
109
112
  reload
110
113
  end
111
114
 
112
- def draw
113
- reset!
115
+ def draw(options={})
116
+ reset!(options)
114
117
  yield Mapper.new(self)
115
118
  install_helpers
116
119
  end
117
120
 
118
121
  def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false)
119
- #*_url and hash_for_*_url
120
- Array(destinations).each do |d| d.module_eval { include Helpers }
121
- @usher.named_routes.keys.each do |name|
122
- @module.module_eval <<-end_eval # We use module_eval to avoid leaks
123
- def #{name}_url(options = {})
124
- ActionController::Routing::UsherRoutes.generate(options, {}, :generate, :#{name})
125
- end
126
- end_eval
127
- end
128
- d.__send__(:include, @module)
122
+ Array(destinations).each do |destination|
123
+ destination.module_eval { include Helpers }
124
+ destination.__send__(:include, @usher.generator.generation_module)
129
125
  end
130
126
  end
127
+
128
+ def routes
129
+ @usher.routes
130
+ end
131
131
 
132
132
  end
133
133
  end
@@ -1,13 +1,13 @@
1
1
  class Usher
2
2
  module Interface
3
- class Rails22Interface
3
+ class Rails22
4
4
 
5
5
  class Mapper #:doc:
6
6
  def initialize(set) #:nodoc:
7
7
  @set = set
8
8
  end
9
9
 
10
- def connect(path, options = nil)
10
+ def connect(path, options = {})
11
11
  @set.add_route(path, options)
12
12
  end
13
13
 
@@ -1,6 +1,6 @@
1
1
  class Usher
2
2
  module Interface
3
- class Rails23Interface
3
+ class Rails23
4
4
 
5
5
  attr_reader :configuration_files
6
6
 
@@ -0,0 +1,44 @@
1
+ class Usher
2
+ module Interface
3
+ class Rails23
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 = nil)
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