joshbuddy-usher 0.2.1 → 0.2.2

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/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