joshbuddy-usher 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -16,50 +16,50 @@ Tree-based router library. Useful for (specifically) for Rails and Rack, but pro
16
16
 
17
17
  From the rdoc:
18
18
 
19
- <tt>+path+</tt>::
20
- A path consists a mix of dynamic and static parts delimited by <tt>/</tt>
21
-
22
- *Dynamic*
23
-
24
- Dynamic parts are prefixed with either :, *. :variable matches only one part of the path, whereas *variable can match one or
25
- more parts.
26
-
27
- Example:
28
- <tt>/path/:variable/path</tt> would match
29
-
30
- * <tt>/path/test/path</tt>
31
- * <tt>/path/something_else/path</tt>
32
- * <tt>/path/one_more/path</tt>
33
-
34
- In the above examples, 'test', 'something_else' and 'one_more' respectively would be bound to the key <tt>:variable</tt>.
35
- However, <tt>/path/test/one_more/path</tt> would not be matched.
36
-
37
- Example:
38
- <tt>/path/*variable/path</tt> would match
39
-
40
- * <tt>/path/one/two/three/path</tt>
41
- * <tt>/path/four/five/path</tt>
42
-
43
- In the above examples, ['one', 'two', 'three'] and ['four', 'five'] respectively would be bound to the key :variable.
44
-
45
- *Static*
46
-
47
- Static parts of literal character sequences. For instance, <tt>/path/something.html</tt> would match only the same path.
48
-
49
- <b>Optional sections</b>
50
-
51
- Sections of a route can be marked as optional by surrounding it with brackets. For instance, in the above static example, <tt>/path/something(.html)</tt> would match both <tt>/path/something</tt> and <tt>/path/something.html</tt>.
52
-
53
- <b>One and only one sections</b>
54
-
55
- Sections of a route can be marked as "one and only one" by surrounding it with brackets and separating parts of the route with pipes. For instance, the path, <tt>/path/something(.xml|.html)</tt> would only match <tt>/path/something.xml</tt> and <tt>/path/something.html</tt>.
56
-
57
- <tt>+options+</tt>::
58
- --
59
- * :transformers - Transforms a variable before it gets to the conditions and requirements. Takes either a +proc+ or a +symbol+. If its a +symbol+, calls the method on the incoming parameter. If its a +proc+, its called with the variable.
60
- * :requirements - After transformation, tests the condition using ===. If it returns false, it raises an <tt>Usher::ValidationException</tt>
61
- * :conditions - Accepts any of the following <tt>:protocol</tt>, <tt>:domain</tt>, <tt>:port</tt>, <tt>:query_string</tt>, <tt>:remote_ip</tt>, <tt>:user_agent</tt>, <tt>:referer</tt> and <tt>:method</tt>. This can be either a <tt>string</tt> or a <tt>regexp</tt>.
62
- * any other key is interpreted as a requirement for the variable of its name.
19
+ Creates a route from +path+ and +options+
20
+
21
+ === +path+
22
+ A path consists a mix of dynamic and static parts delimited by <tt>/</tt>
23
+
24
+ ==== Dynamic
25
+ Dynamic parts are prefixed with either :, *. :variable matches only one part of the path, whereas *variable can match one or
26
+ more parts.
27
+
28
+ <b>Example:</b>
29
+ <tt>/path/:variable/path</tt> would match
30
+
31
+ * <tt>/path/test/path</tt>
32
+ * <tt>/path/something_else/path</tt>
33
+ * <tt>/path/one_more/path</tt>
34
+
35
+ In the above examples, 'test', 'something_else' and 'one_more' respectively would be bound to the key <tt>:variable</tt>.
36
+ However, <tt>/path/test/one_more/path</tt> would not be matched.
37
+
38
+ <b>Example:</b>
39
+ <tt>/path/*variable/path</tt> would match
40
+
41
+ * <tt>/path/one/two/three/path</tt>
42
+ * <tt>/path/four/five/path</tt>
43
+
44
+ In the above examples, ['one', 'two', 'three'] and ['four', 'five'] respectively would be bound to the key :variable.
45
+
46
+ ==== Static
47
+
48
+ Static parts of literal character sequences. For instance, <tt>/path/something.html</tt> would match only the same path.
49
+
50
+ ==== Optional sections
51
+
52
+ Sections of a route can be marked as optional by surrounding it with brackets. For instance, in the above static example, <tt>/path/something(.html)</tt> would match both <tt>/path/something</tt> and <tt>/path/something.html</tt>.
53
+
54
+ ==== One and only one sections
55
+
56
+ Sections of a route can be marked as "one and only one" by surrounding it with brackets and separating parts of the route with pipes. For instance, the path, <tt>/path/something(.xml|.html)</tt> would only match <tt>/path/something.xml</tt> and <tt>/path/something.html</tt>.
57
+
58
+ === +options+
59
+ * +transformers+ - Transforms a variable before it gets to the requirements. Takes either a +proc+ or a +symbol+. If its a +symbol+, calls the method on the incoming parameter. If its a +proc+, its called with the variable.
60
+ * +requirements+ - After transformation, tests the condition using ===. If it returns false, it raises an <tt>Usher::ValidationException</tt>
61
+ * +conditions+ - Accepts any of the following <tt>:protocol</tt>, <tt>:domain</tt>, <tt>:port</tt>, <tt>:query_string</tt>, <tt>:remote_ip</tt>, <tt>:user_agent</tt>, <tt>:referer</tt> and <tt>:method</tt>. This can be either a <tt>string</tt> or a regular expression.
62
+ * Any other key is interpreted as a requirement for the variable of its name.
63
63
 
64
64
  == Rails
65
65
 
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 1
3
- :major: 0
4
2
  :minor: 2
3
+ :patch: 2
4
+ :major: 0
data/lib/usher.rb CHANGED
@@ -61,50 +61,48 @@ class Usher
61
61
 
62
62
  # Creates a route from +path+ and +options+
63
63
  #
64
- # <tt>+path+</tt>::
65
- # A path consists a mix of dynamic and static parts delimited by <tt>/</tt>
64
+ # === +path+
65
+ # A path consists a mix of dynamic and static parts delimited by <tt>/</tt>
66
66
  #
67
- # *Dynamic*
67
+ # ==== Dynamic
68
+ # Dynamic parts are prefixed with either :, *. :variable matches only one part of the path, whereas *variable can match one or
69
+ # more parts.
68
70
  #
69
- # Dynamic parts are prefixed with either :, *. :variable matches only one part of the path, whereas *variable can match one or
70
- # more parts.
71
+ # <b>Example:</b>
72
+ # <tt>/path/:variable/path</tt> would match
71
73
  #
72
- # Example:
73
- # <tt>/path/:variable/path</tt> would match
74
+ # * <tt>/path/test/path</tt>
75
+ # * <tt>/path/something_else/path</tt>
76
+ # * <tt>/path/one_more/path</tt>
74
77
  #
75
- # * <tt>/path/test/path</tt>
76
- # * <tt>/path/something_else/path</tt>
77
- # * <tt>/path/one_more/path</tt>
78
+ # In the above examples, 'test', 'something_else' and 'one_more' respectively would be bound to the key <tt>:variable</tt>.
79
+ # However, <tt>/path/test/one_more/path</tt> would not be matched.
78
80
  #
79
- # In the above examples, 'test', 'something_else' and 'one_more' respectively would be bound to the key <tt>:variable</tt>.
80
- # However, <tt>/path/test/one_more/path</tt> would not be matched.
81
+ # <b>Example:</b>
82
+ # <tt>/path/*variable/path</tt> would match
81
83
  #
82
- # Example:
83
- # <tt>/path/*variable/path</tt> would match
84
+ # * <tt>/path/one/two/three/path</tt>
85
+ # * <tt>/path/four/five/path</tt>
84
86
  #
85
- # * <tt>/path/one/two/three/path</tt>
86
- # * <tt>/path/four/five/path</tt>
87
+ # In the above examples, ['one', 'two', 'three'] and ['four', 'five'] respectively would be bound to the key :variable.
87
88
  #
88
- # In the above examples, ['one', 'two', 'three'] and ['four', 'five'] respectively would be bound to the key :variable.
89
+ # ==== Static
89
90
  #
90
- # *Static*
91
+ # Static parts of literal character sequences. For instance, <tt>/path/something.html</tt> would match only the same path.
91
92
  #
92
- # Static parts of literal character sequences. For instance, <tt>/path/something.html</tt> would match only the same path.
93
+ # ==== Optional sections
93
94
  #
94
- # <b>Optional sections</b>
95
+ # Sections of a route can be marked as optional by surrounding it with brackets. For instance, in the above static example, <tt>/path/something(.html)</tt> would match both <tt>/path/something</tt> and <tt>/path/something.html</tt>.
95
96
  #
96
- # Sections of a route can be marked as optional by surrounding it with brackets. For instance, in the above static example, <tt>/path/something(.html)</tt> would match both <tt>/path/something</tt> and <tt>/path/something.html</tt>.
97
+ # ==== One and only one sections
97
98
  #
98
- # <b>One and only one sections</b>
99
+ # Sections of a route can be marked as "one and only one" by surrounding it with brackets and separating parts of the route with pipes. For instance, the path, <tt>/path/something(.xml|.html)</tt> would only match <tt>/path/something.xml</tt> and <tt>/path/something.html</tt>.
99
100
  #
100
- # Sections of a route can be marked as "one and only one" by surrounding it with brackets and separating parts of the route with pipes. For instance, the path, <tt>/path/something(.xml|.html)</tt> would only match <tt>/path/something.xml</tt> and <tt>/path/something.html</tt>.
101
- #
102
- # <tt>+options+</tt>::
103
- # --
104
- # * :transformers - Transforms a variable before it gets to the requirements. Takes either a +proc+ or a +symbol+. If its a +symbol+, calls the method on the incoming parameter. If its a +proc+, its called with the variable.
105
- # * :requirements - After transformation, tests the condition using ===. If it returns false, it raises an <tt>Usher::ValidationException</tt>
106
- # * :conditions - Accepts any of the following <tt>:protocol</tt>, <tt>:domain</tt>, <tt>:port</tt>, <tt>:query_string</tt>, <tt>:remote_ip</tt>, <tt>:user_agent</tt>, <tt>:referer</tt> and <tt>:method</tt>. This can be either a <tt>string</tt> or a <tt>regexp</tt>.
107
- # * any other key is interpreted as a requirement for the variable of its name.
101
+ # === +options+
102
+ # * +transformers+ - Transforms a variable before it gets to the requirements. Takes either a +proc+ or a +symbol+. If its a +symbol+, calls the method on the incoming parameter. If its a +proc+, its called with the variable.
103
+ # * +requirements+ - After transformation, tests the condition using ===. If it returns false, it raises an <tt>Usher::ValidationException</tt>
104
+ # * +conditions+ - Accepts any of the following <tt>:protocol</tt>, <tt>:domain</tt>, <tt>:port</tt>, <tt>:query_string</tt>, <tt>:remote_ip</tt>, <tt>:user_agent</tt>, <tt>:referer</tt> and <tt>:method</tt>. This can be either a <tt>string</tt> or a regular expression.
105
+ # * Any other key is interpreted as a requirement for the variable of its name.
108
106
  def add_route(path, options = {})
109
107
  transformers = options.delete(:transformers) || {}
110
108
  conditions = options.delete(:conditions) || {}
@@ -144,14 +142,16 @@ class Usher
144
142
  @grapher.find_matching_path(options)
145
143
  end
146
144
 
147
- # Generates a completed URL based on a +route+ or set of +params+
145
+ # Generates a completed URL based on a +route+ or set of optional +params+
148
146
  #
149
147
  # set = Usher.new
150
148
  # route = set.add_named_route(:test_route, '/:controller/:action')
151
149
  # set.generate_url(nil, {:controller => 'c', :action => 'a'}) == '/c/a' => true
152
150
  # set.generate_url(:test_route, {:controller => 'c', :action => 'a'}) == '/c/a' => true
153
151
  # set.generate_url(route.primary_path, {:controller => 'c', :action => 'a'}) == '/c/a' => true
154
- def generate_url(route, params)
152
+ def generate_url(route, params = {}, options = {})
153
+ check_variables = options.key?(:check_variables) ? options.delete(:check_variables) : false
154
+
155
155
  path = case route
156
156
  when Symbol
157
157
  @named_routes[route]
@@ -181,10 +181,13 @@ class Usher
181
181
  when Route::Variable
182
182
  case p.type
183
183
  when :*
184
- generated_path << '/' << param_list.shift * '/'
184
+ param_list.first.each {|dp| p.valid!(dp.to_s) } if check_variables
185
+ generated_path << '/' << param_list.shift.collect{|dp| dp.to_s} * '/'
185
186
  when :'.:'
187
+ p.valid!(param_list.first.to_s) if check_variables
186
188
  (dp = param_list.shift) && generated_path << '.' << dp.to_s
187
189
  else
190
+ p.valid!(param_list.first.to_s) if check_variables
188
191
  (dp = param_list.shift) && generated_path << '/' << dp.to_s
189
192
  end
190
193
  else
data/lib/usher/grapher.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  class Usher
2
4
  class Grapher
3
5
 
@@ -2,17 +2,17 @@ $:.unshift File.dirname(__FILE__)
2
2
 
3
3
  class Usher
4
4
  module Interface
5
+ autoload :Rails2Interface, 'interface/rails2_interface'
6
+ autoload :MerbInterface, 'interface/merb_interface'
7
+ autoload :RackInterface, 'interface/rack_interface'
5
8
 
6
9
  def self.for(type)
7
10
  case type
8
11
  when :rails2
9
- require 'interface/rails2_interface'
10
12
  Rails2Interface.new
11
13
  when :merb
12
- require 'interface/merb_interface'
13
14
  MerbInterface.new
14
15
  when :rack
15
- require 'interface/rack_interface'
16
16
  RackInterface.new
17
17
  end
18
18
  end
data/lib/usher/route.rb CHANGED
@@ -9,7 +9,7 @@ class Usher
9
9
  class Route
10
10
  attr_reader :paths, :original_path, :requirements, :conditions, :params, :primary_path
11
11
 
12
- def initialize(original_path, router, options = {})
12
+ def initialize(original_path, router, options = {}) # :nodoc:
13
13
  @original_path = original_path
14
14
  @router = router
15
15
  @requirements = options.delete(:requirements)
@@ -20,7 +20,7 @@ class Usher
20
20
  end
21
21
 
22
22
 
23
- # Sets +options+ on a route
23
+ # Sets +options+ on a route. Returns +self+.
24
24
  #
25
25
  # Request = Struct.new(:path)
26
26
  # set = Usher.new
@@ -32,6 +32,11 @@ class Usher
32
32
  self
33
33
  end
34
34
 
35
+ # Sets route as referenceable from +name+. Returns +self+.
36
+ #
37
+ # set = Usher.new
38
+ # route = set.add_route('/test').name(:route)
39
+ # set.generate_url(:route) => '/test'
35
40
  def name(name)
36
41
  @router.name(name, self)
37
42
  end
@@ -35,7 +35,7 @@ class Usher
35
35
  @validator === val or raise
36
36
  end if @validator
37
37
  rescue Exception => e
38
- raise ValidationException.new(e, "#{val} does not conform to #{@validator}")
38
+ raise ValidationException.new("#{val} does not conform to #{@validator}, root cause #{e.inspect}")
39
39
  end
40
40
 
41
41
  def ==(o)
@@ -0,0 +1,34 @@
1
+ require 'lib/usher'
2
+
3
+ route_set = Usher.new
4
+
5
+ describe "Usher grapher" do
6
+
7
+ before(:each) do
8
+ route_set.reset!
9
+ end
10
+
11
+ it "should find a simple path" do
12
+ route_set.add_route('/:a/:b/:c')
13
+ route_set.generate_url(nil, {:a => 'A', :b => 'B', :c => 'C'}).should == '/A/B/C'
14
+ end
15
+
16
+ it "should pick a more specific route" do
17
+ route_set.add_route('/:a/:b')
18
+ route_set.add_route('/:a/:b/:c')
19
+ route_set.generate_url(nil, {:a => 'A', :b => 'B', :c => 'C'}).should == '/A/B/C'
20
+ end
21
+
22
+ it "should find the most specific route and append extra parts on as a query string" do
23
+ route_set.add_route('/:a/:b/:c')
24
+ route_set.add_route('/:a/:b')
25
+ route_set.generate_url(nil, {:a => 'A', :b => 'B', :d => 'C'}).should == '/A/B?d=C'
26
+ end
27
+
28
+ it "should do a validity check against the incoming variables when asked to" do
29
+ route_set.add_route('/:a/:b', :b => /\d+/)
30
+ route_set.generate_url(nil, {:a => 'A', :b => 'B'}).should == '/A/B'
31
+ proc{ route_set.generate_url(nil, {:a => 'A', :b => 'B'}, :check_variables => true).should == '/A/B?d=C'}.should raise_error Usher::ValidationException
32
+ end
33
+
34
+ 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.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Hull
@@ -58,6 +58,7 @@ files:
58
58
  - lib/usher/route.rb
59
59
  - lib/usher.rb
60
60
  - spec/generate_spec.rb
61
+ - spec/grapher_spec.rb
61
62
  - spec/path_spec.rb
62
63
  - spec/rack
63
64
  - spec/rack/dispatch_spec.rb