sinatra-named-routes 0.1.0 → 0.1.1

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/Gemfile.lock CHANGED
@@ -1,38 +1,38 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sinatra-named-routes (0.0.1)
4
+ sinatra-named-routes (0.1.0)
5
5
  sinatra
6
6
 
7
7
  GEM
8
8
  remote: http://rubygems.org/
9
9
  specs:
10
- backports (2.3.0)
10
+ backports (2.5.1)
11
11
  diff-lcs (1.1.3)
12
12
  eventmachine (0.12.10)
13
13
  ffi (1.0.11)
14
- guard (1.0.0)
14
+ guard (1.0.1)
15
15
  ffi (>= 0.5.0)
16
16
  thor (~> 0.14.6)
17
- guard-rspec (0.6.0)
17
+ guard-rspec (0.7.0)
18
18
  guard (>= 0.10.0)
19
- multi_json (1.0.4)
19
+ multi_json (1.2.0)
20
20
  rack (1.4.1)
21
21
  rack-protection (1.2.0)
22
22
  rack
23
23
  rack-test (0.6.1)
24
24
  rack (>= 1.0)
25
25
  rake (0.9.2.2)
26
- rspec (2.8.0)
27
- rspec-core (~> 2.8.0)
28
- rspec-expectations (~> 2.8.0)
29
- rspec-mocks (~> 2.8.0)
30
- rspec-core (2.8.0)
31
- rspec-expectations (2.8.0)
32
- diff-lcs (~> 1.1.2)
33
- rspec-mocks (2.8.0)
34
- simplecov (0.5.4)
35
- multi_json (~> 1.0.3)
26
+ rspec (2.9.0)
27
+ rspec-core (~> 2.9.0)
28
+ rspec-expectations (~> 2.9.0)
29
+ rspec-mocks (~> 2.9.0)
30
+ rspec-core (2.9.0)
31
+ rspec-expectations (2.9.1)
32
+ diff-lcs (~> 1.1.3)
33
+ rspec-mocks (2.9.0)
34
+ simplecov (0.6.1)
35
+ multi_json (~> 1.0)
36
36
  simplecov-html (~> 0.5.3)
37
37
  simplecov-html (0.5.3)
38
38
  sinatra (1.3.2)
data/README.md CHANGED
@@ -1,3 +1,69 @@
1
1
  # Sinatra Named Routes [![Build Status](https://secure.travis-ci.org/ckhampus/sinatra-named-routes.png)](http://travis-ci.org/ckhampus/sinatra-named-routes)
2
2
 
3
- This gem allows the use of named routes in Sinatra applications.
3
+ This gem allows the use of named routes in Sinatra applications.
4
+
5
+ ## Usage
6
+
7
+ To use this gem you must register it in your Sinatra application.
8
+
9
+ ```ruby
10
+ require 'sinatra/base'
11
+ require 'sinatra/named_routes'
12
+
13
+ class MyApp < Sinatra::Base
14
+ register Sinatra::NamedRoutes
15
+ end
16
+ ```
17
+
18
+ The you use the `map` method to map a route to a name, and use that name when defining your routes.
19
+
20
+ ```ruby
21
+ require 'sinatra/base'
22
+ require 'sinatra/named_routes'
23
+
24
+ class MyApp < Sinatra::Base
25
+ register Sinatra::NamedRoutes
26
+
27
+ map :article, '/article/:id'
28
+
29
+ get :article do
30
+ # get article bla bla ...
31
+ end
32
+ end
33
+ ```
34
+
35
+ To generate urls in extends Sinatras built-in methods like `url` and `to` but it does not break them. They work like before except that now you can also pass the route name and paramters. The parameters have to be always passed as the last argument. Otherwise the `url` work the same.
36
+
37
+ ```ruby
38
+ # in your route or view you can write something like this
39
+ url :article, false, :id => 123 # /article/123
40
+ ```
41
+
42
+ The `map` method supports the same routes as Sinatra does.
43
+
44
+ ```ruby
45
+ # named parameters
46
+ map :article, '/article/:id'
47
+
48
+ url :article, false, :id => 123 # /article/123
49
+
50
+ # splats
51
+ map :article, '/article/*.*'
52
+
53
+ url :article, false, [123, 'json'] # /article/123.json
54
+
55
+ # regular expressions
56
+ map :article, %r{/article/([\w]+).([\w]+)}
57
+
58
+ url :article, false, [123, 'json'] # /article/123.json
59
+
60
+ # named captures
61
+ map :article, %r{/article/(?<slug>[^/?#]+)}
62
+
63
+ url :article, false, :slug => 'hello_world' # /article/hello_world
64
+
65
+ # optional named captures
66
+ map(:articles, %r{/articles(?<format>.[^/?#]+)?})
67
+
68
+ url :articles, false, :format => '.html' # /articles.html
69
+ ```
@@ -5,7 +5,9 @@ module Sinatra
5
5
  module NamedRoutes
6
6
  module Helpers
7
7
 
8
- # def uri(addr = nil, absolute = true, add_script_name = true, params = {})
8
+ # Generates the absolute URI for a given path in the app.
9
+ # Takes Rack routers and reverse proxies into account.
10
+ # Extended support passing in named route and parameters.
9
11
  def uri(*args)
10
12
  path = args.shift if args.first.is_a? Symbol
11
13
  params = args.pop if args.last.is_a? Array or args.last.is_a? Hash
@@ -19,13 +21,17 @@ module Sinatra
19
21
  end
20
22
 
21
23
  end
24
+
22
25
  alias :to :uri
23
26
  alias :url :uri
24
27
  end
25
28
 
29
+ # Maps a path to name.
26
30
  def map(name, path)
27
31
  NamedRoutes.routes[name] = Route.new path
28
32
  end
33
+
34
+ alias :bind :map
29
35
 
30
36
  private
31
37
 
@@ -38,6 +44,7 @@ module Sinatra
38
44
  end
39
45
 
40
46
  def self.get_path(name, params = {})
47
+ raise ArgumentError, "No route with the name #{name} exists." if NamedRoutes.routes.nil?
41
48
  NamedRoutes.routes[name].build params
42
49
  end
43
50
 
@@ -1,164 +1,164 @@
1
- class Route
2
- attr_reader :source
3
1
 
4
- def initialize(route)
5
- route = route.source if route.is_a? Regexp
2
+ module Sinatra
3
+ module NamedRoutes
4
+ class Route
5
+ attr_reader :source
6
6
 
7
- @source = route
8
- @input = StringScanner.new(route)
9
- @output = []
7
+ def initialize(route)
8
+ route = route.source if route.is_a? Regexp
10
9
 
11
- parse
12
- end
13
-
14
- # Public: Build URL with parameters.
15
- #
16
- # params - The hash or array of parameters to pass to URL.
17
- #
18
- # Returns the URL as a String.
19
- def build(params = {})
20
- path = []
21
- params = {} if params.nil?
22
-
23
- @output.each_index do |index|
24
- item = @output[index]
25
- next_item = @output.fetch(index + 1, nil)
26
-
27
- case item[:token]
28
- when :slash
29
- @trailing_slash = item[:optional]
30
- path << '/'
31
- when :dot
32
- @trailing_dot = item[:optional]
33
- path << '.'
34
- when :splat
35
- if params.is_a? Hash
36
- raise ArgumentError, 'No parameters passed.' if params[:splat].empty?
37
- path << params[:splat].shift
38
- else
39
- raise ArgumentError, 'No enough parameters passed.' if params.empty?
40
- path << params.shift
41
- end
42
- when :path
43
- path << item[:value]
44
- when :named_param
45
- item_key = item[:value]
46
-
47
- if params.has_key? item_key
48
- path << params.delete(item_key)
49
- else
50
- raise ArgumentError, "No value passed for '#{item_key.to_s}'" unless item[:optional]
51
- end
52
- when :regexp
53
- name = /#{item[:value]}/.names
10
+ @source = route
11
+ @input = StringScanner.new(route)
12
+ @output = []
54
13
 
55
- if name.any?
56
- name = name.first.to_sym
14
+ parse
15
+ end
57
16
 
58
- if params.has_key? name
59
- path << params.delete(name)
60
- else
61
- raise ArgumentError, "No value passed for '#{name.to_s}'" unless item[:optional]
62
- end
63
- else
64
- if params.is_a? Hash
65
- raise ArgumentError, 'No enough parameters passed.' if params[:captures].empty? and !item[:optional]
66
- path << params[:captures].shift
67
- else
68
- raise ArgumentError, 'No enough parameters passed.' if params.empty?
69
- path << params.shift
17
+ def build(params = {})
18
+ path = []
19
+ params = {} if params.nil?
20
+
21
+ @output.each_index do |index|
22
+ item = @output[index]
23
+ next_item = @output.fetch(index + 1, nil)
24
+
25
+ case item[:token]
26
+ when :slash
27
+ @trailing_slash = item[:optional]
28
+ path << '/'
29
+ when :dot
30
+ @trailing_dot = item[:optional]
31
+ path << '.'
32
+ when :splat
33
+ if params.is_a? Hash
34
+ raise ArgumentError, 'No parameters passed.' if params[:splat].empty?
35
+ path << params[:splat].shift
36
+ else
37
+ raise ArgumentError, 'No enough parameters passed.' if params.empty?
38
+ path << params.shift
39
+ end
40
+ when :path
41
+ path << item[:value]
42
+ when :named_param
43
+ item_key = item[:value]
44
+
45
+ if params.has_key? item_key
46
+ path << params.delete(item_key)
47
+ else
48
+ raise ArgumentError, "No value passed for '#{item_key.to_s}'" unless item[:optional]
49
+ end
50
+ when :regexp
51
+ name = /#{item[:value]}/.names
52
+
53
+ if name.any?
54
+ name = name.first.to_sym
55
+
56
+ if params.has_key? name
57
+ path << params.delete(name)
58
+ else
59
+ raise ArgumentError, "No value passed for '#{name.to_s}'" unless item[:optional]
60
+ end
61
+ else
62
+ if params.is_a? Hash
63
+ raise ArgumentError, 'No enough parameters passed.' if params[:captures].empty? and !item[:optional]
64
+ path << params[:captures].shift
65
+ else
66
+ raise ArgumentError, 'No enough parameters passed.' if params.empty?
67
+ path << params.shift
68
+ end
69
+ end
70
70
  end
71
71
  end
72
- end
73
- end
74
72
 
75
- path = path.join
73
+ path = path.join
76
74
 
77
- if @trailing_dot
78
- path = path.chomp '.'
79
- end
75
+ if @trailing_dot
76
+ path = path.chomp '.'
77
+ end
80
78
 
81
- if @trailing_slash
82
- path = path.chomp '/'
83
- end
79
+ if @trailing_slash
80
+ path = path.chomp '/'
81
+ end
84
82
 
85
- path
86
- end
83
+ path
84
+ end
87
85
 
88
- private
86
+ private
89
87
 
90
- def is_optional?
91
- @output.last[:optional] = @input.scan(/\?/) ? true : false
92
- end
88
+ def is_optional?
89
+ @output.last[:optional] = @input.scan(/\?/) ? true : false
90
+ end
93
91
 
94
- def parse
95
- while token = parse_slash || parse_path || parse_named_param ||
96
- parse_dot || parse_splat || parse_regexp
97
- @output << token
98
- is_optional?
99
- end
100
- end
92
+ def parse
93
+ while token = parse_slash || parse_path || parse_named_param ||
94
+ parse_dot || parse_splat || parse_regexp
95
+ @output << token
96
+ is_optional?
97
+ end
98
+ end
101
99
 
102
- def parse_slash
103
- if @input.scan(/\//)
104
- {
105
- :token => :slash
106
- }
107
- else
108
- nil
109
- end
110
- end
100
+ def parse_slash
101
+ if @input.scan(/\//)
102
+ {
103
+ :token => :slash
104
+ }
105
+ else
106
+ nil
107
+ end
108
+ end
111
109
 
112
- def parse_dot
113
- if @input.scan(/\./)
114
- {
115
- :token => :dot
116
- }
117
- else
118
- nil
119
- end
120
- end
110
+ def parse_dot
111
+ if @input.scan(/\./)
112
+ {
113
+ :token => :dot
114
+ }
115
+ else
116
+ nil
117
+ end
118
+ end
121
119
 
122
- def parse_splat
123
- if @input.scan(/\*/)
124
- {
125
- :token => :splat
126
- }
127
- else
128
- nil
129
- end
130
- end
120
+ def parse_splat
121
+ if @input.scan(/\*/)
122
+ {
123
+ :token => :splat
124
+ }
125
+ else
126
+ nil
127
+ end
128
+ end
131
129
 
132
- def parse_path
133
- if @input.scan(/\w+/)
134
- {
135
- :token => :path,
136
- :value => @input.matched
137
- }
138
- else
139
- nil
140
- end
141
- end
130
+ def parse_path
131
+ if @input.scan(/\w+/)
132
+ {
133
+ :token => :path,
134
+ :value => @input.matched
135
+ }
136
+ else
137
+ nil
138
+ end
139
+ end
142
140
 
143
- def parse_named_param
144
- if @input.scan(/:[^\W]*/)
145
- {
146
- :token => :named_param,
147
- :value => @input.matched.sub(':', '').to_sym
148
- }
149
- else
150
- nil
151
- end
152
- end
141
+ def parse_named_param
142
+ if @input.scan(/:[^\W]*/)
143
+ {
144
+ :token => :named_param,
145
+ :value => @input.matched.sub(':', '').to_sym
146
+ }
147
+ else
148
+ nil
149
+ end
150
+ end
153
151
 
154
- def parse_regexp
155
- if @input.scan(/\([^\)]*\)/)
156
- {
157
- :token => :regexp,
158
- :value => @input.matched
159
- }
160
- else
161
- nil
152
+ def parse_regexp
153
+ if @input.scan(/\([^\)]*\)/)
154
+ {
155
+ :token => :regexp,
156
+ :value => @input.matched
157
+ }
158
+ else
159
+ nil
160
+ end
161
+ end
162
162
  end
163
163
  end
164
164
  end
@@ -1,5 +1,5 @@
1
1
  module Sinatra
2
2
  module NamedRoutes
3
- VERSION = '0.1.0'
3
+ VERSION = '0.1.1'
4
4
  end
5
5
  end
@@ -1,46 +1,46 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
- describe Route do
3
+ describe Sinatra::NamedRoutes::Route do
4
4
  it 'supports named parameters' do
5
- route = Route.new('/hello/:person.:format')
5
+ route = Sinatra::NamedRoutes::Route.new('/hello/:person.:format')
6
6
  url = route.build :person => 'cristian', :format => 'json'
7
7
  url.should eql '/hello/cristian.json'
8
8
  end
9
9
 
10
10
  it 'throws exception if required named params are missing' do
11
11
  expect do
12
- route = Route.new('/hello/:person.:format')
12
+ route = Sinatra::NamedRoutes::Route.new('/hello/:person.:format')
13
13
  url = route.build :person => 'cristian'
14
14
  end.to raise_exception ArgumentError
15
15
  end
16
16
 
17
17
  it 'supports splats' do
18
- route = Route.new('/hello/*.*')
18
+ route = Sinatra::NamedRoutes::Route.new('/hello/*.*')
19
19
  url = route.build ['cristian', 'json']
20
20
  url.should eql '/hello/cristian.json'
21
21
  end
22
22
 
23
23
  it 'throws exception if required splats are missing' do
24
24
  expect do
25
- route = Route.new('/hello/*.*')
25
+ route = Sinatra::NamedRoutes::Route.new('/hello/*.*')
26
26
  url = route.build ['cristian']
27
27
  end.to raise_exception ArgumentError
28
28
  end
29
29
 
30
30
  it 'supports splats mixed wih named parameters' do
31
- route = Route.new('/hello/:person.*')
31
+ route = Sinatra::NamedRoutes::Route.new('/hello/:person.*')
32
32
  url = route.build :person => 'cristian', :splat => ['json']
33
33
  url.should eql '/hello/cristian.json'
34
34
  end
35
35
 
36
36
  it 'supports regular expressions' do
37
- route = Route.new(%r{/hello/([\w]+).([\w]+)})
37
+ route = Sinatra::NamedRoutes::Route.new(%r{/hello/([\w]+).([\w]+)})
38
38
  url = route.build ['cristian', 'html']
39
39
  url.should eql '/hello/cristian.html'
40
40
  end
41
41
 
42
42
  it 'supports optional regular expressions mixed with named params' do
43
- route = Route.new(%r{/hello/:lang/([\w]+).?([\w]+)?})
43
+ route = Sinatra::NamedRoutes::Route.new(%r{/hello/:lang/([\w]+).?([\w]+)?})
44
44
  url = route.build :lang => 'en', :captures => ['cristian', 'html']
45
45
  url.should eql '/hello/en/cristian.html'
46
46
 
@@ -51,7 +51,7 @@ describe Route do
51
51
  it 'supports named capture groups' do
52
52
  next if RUBY_VERSION < '1.9'
53
53
 
54
- route = Route.new(%r{/hello/(?<person>[^/?#]+)})
54
+ route = Sinatra::NamedRoutes::Route.new(%r{/hello/(?<person>[^/?#]+)})
55
55
  url = route.build :person => 'cristian'
56
56
  url.should eql '/hello/cristian'
57
57
  end
@@ -59,7 +59,7 @@ describe Route do
59
59
  it 'supports optional named capture groups' do
60
60
  next if RUBY_VERSION < '1.9'
61
61
 
62
- route = Route.new(%r{/page(?<format>.[^/?#]+)?})
62
+ route = Sinatra::NamedRoutes::Route.new(%r{/page(?<format>.[^/?#]+)?})
63
63
  url = route.build
64
64
  url.should eql '/page'
65
65
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra-named-routes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-11 00:00:00.000000000Z
12
+ date: 2012-04-10 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sinatra
16
- requirement: &70197364991660 !ruby/object:Gem::Requirement
16
+ requirement: &70101493598320 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70197364991660
24
+ version_requirements: *70101493598320
25
25
  description: Allows the use of named routes in Sinatra applications.
26
26
  email:
27
27
  - contact@cristianhampus.se