angus-router 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 23e229a9ab8e0ab0c5a2759cccc252bf0f55df8b
4
+ data.tar.gz: 2717f43c081f4ae84cd8cff84a5d790750c47117
5
+ SHA512:
6
+ metadata.gz: 9ebabff008794050195ef91b935fe19ec1ac4bb2fa937a595ae96b593ca0269f33045dcb6b040488a8aeb2e841d95438a5a05c727884d37e1d7ae5d8c8ed9b81
7
+ data.tar.gz: 2d3e178c3ef09c9646df5768d7c2968d6138943b707adebcb18189122fc351931163b6d93c3de5c73728cdbf28073318ce0a41af77c266748ae71a6d3a43dfbd
@@ -0,0 +1 @@
1
+ require_relative 'angus/router'
data/lib/angus/router.rb CHANGED
@@ -1,7 +1,198 @@
1
- require "angus/router/version"
1
+ require 'rack'
2
2
 
3
3
  module Angus
4
- module Router
5
- # Your code goes here...
4
+ class Router
5
+
6
+ VERSION = '0.0.2'
7
+
8
+ RE_TRAILING_SLASH = %r{/\Z}
9
+
10
+ SUPPORTED_HTTP_METHODS = [
11
+ :get,
12
+ :post,
13
+ :put,
14
+ :delete,
15
+ :head,
16
+ :options,
17
+ :patch,
18
+ :trace
19
+ ]
20
+
21
+ PathPattern = Struct.new(:re_path, :param_names) do
22
+
23
+ # Matches the given path against #re_path.
24
+ #
25
+ # @return [MatchData] when match succeeds
26
+ # @return [nil] when match fails
27
+ def match(path)
28
+ re_path.match(path)
29
+ end
30
+ end
31
+
32
+ Route = Struct.new(:method, :proc, :path_pattern) do
33
+
34
+ # Returns the parameter names for this route.
35
+ #
36
+ # @return [Array<String>]
37
+ def param_names
38
+ path_pattern.param_names
39
+ end
40
+
41
+ # Returns the true if the current route contains defined params.
42
+ #
43
+ # @return [Boolean]
44
+ def params?
45
+ param_names.any?
46
+ end
47
+
48
+ # Matches the given path against #path_pattern.
49
+ #
50
+ # @return [MatchData] when match succeeds
51
+ # @return [nil] when match fails
52
+ def match(path)
53
+ path_pattern.match(path)
54
+ end
55
+ end
56
+
57
+ # It registers block to be yielded at a given HTTP method and path.
58
+ #
59
+ # @param [Symbol] m HTTP method (see SUPPORTED_HTTP_METHODS)
60
+ # @param [String] path Url path
61
+ # @param [Proc] block The block that will be yielded when an incoming request matches the route
62
+ def on(m, path, &block)
63
+ path = path.gsub(RE_TRAILING_SLASH, '')
64
+
65
+ unless SUPPORTED_HTTP_METHODS.include?(m)
66
+ raise ArgumentError.new("Unsupported HTTP method #{m}")
67
+ end
68
+
69
+ route = Route.new(m.to_s.upcase, block, compile(path))
70
+
71
+ if route.params?
72
+ dynamic_routes << route
73
+ else
74
+ static_routes << route
75
+ end
76
+ end
77
+
78
+ # Calls the corresponding previously registered block.
79
+ #
80
+ # When calling, the rack environment and the extracted path params are passed
81
+ # to the route block.
82
+ #
83
+ # @param [Hash] env A Rack environment. (see http://rack.rubyforge.org/doc/SPEC.html)
84
+ #
85
+ # @return The result of the block call
86
+ def route(env)
87
+ request = Rack::Request.new(env)
88
+
89
+ path_info = request.path_info.gsub(RE_TRAILING_SLASH, '').squeeze('/')
90
+ matched_route = match_route(env['REQUEST_METHOD'], path_info)
91
+
92
+ match, route_block, path_param_names = matched_route
93
+
94
+ unless match
95
+ raise NotImplementedError, "No route found #{request.path_info}"
96
+ end
97
+
98
+ path_params = extract_params(match, path_param_names)
99
+ whole_params = request.params.clone.merge!(path_params)
100
+ whole_params = symbolize(whole_params)
101
+
102
+ route_block.call(env, whole_params)
103
+ end
104
+
105
+ private
106
+ # Returns a shallow copy with keys as symbols of hash.
107
+ #
108
+ # @param [Hash] hash
109
+ #
110
+ # @return [Hash]
111
+ def symbolize(hash)
112
+ Hash[
113
+ hash.map { |k, v| [k.to_sym, v] }
114
+ ]
115
+ end
116
+
117
+ def dynamic_routes
118
+ @dynamic_routes ||= []
119
+ end
120
+
121
+ def static_routes
122
+ @static_routes ||= []
123
+ end
124
+
125
+ # Returns a path pattern base on the given pattern.
126
+ #
127
+ # @example compile('/users/:id')
128
+ # => PathPattern.new(/^\/users\/([^\/?#]+)$/, ['id']])
129
+ #
130
+ # @param [String] Url path
131
+ #
132
+ # @return [PathPattern]
133
+ def compile(pattern)
134
+ keys = []
135
+
136
+ pattern = pattern.to_str.squeeze('/')
137
+ pattern.gsub!(/[^\?\%\\\/\:\*\w]/) { |c| encoded(c) }
138
+ pattern.gsub!(/(:\w+)/) do |match|
139
+ keys << $1[1..-1]
140
+ "([^/?#]+)"
141
+ end
142
+
143
+ PathPattern.new(/^#{pattern}$/, keys)
144
+ end
145
+
146
+ # Escapes a char for uri regex matching.
147
+ #
148
+ # @param [String] char
149
+ #
150
+ # @return [String]
151
+ def encoded(char)
152
+ enc = URI.escape(char)
153
+ enc = "(?:#{Regexp.escape enc}|#{URI.escape char, /./})" if enc == char
154
+ enc = "(?:#{enc}|#{encoded('+')})" if char == " "
155
+ enc
156
+ end
157
+
158
+ # Returns regexp, block and path param names according to the route that matches
159
+ # the given method and path.
160
+ #
161
+ # @param [String] method HTTP method
162
+ # @param [String] path Url path
163
+ #
164
+ # @return [regexp, route_block, path_param_names]
165
+ def match_route(method, path)
166
+ [static_routes, dynamic_routes].each do |routes|
167
+ routes.each do |route|
168
+ if method == route.method && match = route.match(path)
169
+ return [match, route.proc, route.param_names]
170
+ end
171
+ end
172
+ end
173
+
174
+ nil
175
+ end
176
+
177
+ # Extracts matched values from the given match.
178
+ #
179
+ # Assoaciates each match to the corresponding key.
180
+ #
181
+ # @param [MatchData] match
182
+ # @param [Array] keys
183
+ #
184
+ # @return [Hash] A hash containing extracted key / values
185
+ def extract_params(match, keys)
186
+ hash = {}
187
+
188
+ captures = match.captures
189
+
190
+ keys.each_with_index do |k, i|
191
+ hash[k] = captures[i]
192
+ end
193
+
194
+ hash
195
+ end
196
+
6
197
  end
7
198
  end
metadata CHANGED
@@ -1,32 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: angus-router
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.0.1
4
+ version: 0.0.2
6
5
  platform: ruby
7
6
  authors:
8
- - Adrian Gomez
7
+ - Gianfranco Zas
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-10-10 00:00:00.000000000 Z
11
+ date: 2013-10-30 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: bundler
14
+ name: rack
16
15
  version_requirements: !ruby/object:Gem::Requirement
17
16
  requirements:
18
17
  - - ~>
19
18
  - !ruby/object:Gem::Version
20
- version: '1.3'
21
- none: false
19
+ version: '1.5'
22
20
  requirement: !ruby/object:Gem::Requirement
23
21
  requirements:
24
22
  - - ~>
25
23
  - !ruby/object:Gem::Version
26
- version: '1.3'
27
- none: false
24
+ version: '1.5'
28
25
  prerelease: false
29
- type: :development
26
+ type: :runtime
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  version_requirements: !ruby/object:Gem::Requirement
@@ -34,33 +31,98 @@ dependencies:
34
31
  - - '>='
35
32
  - !ruby/object:Gem::Version
36
33
  version: '0'
37
- none: false
38
34
  requirement: !ruby/object:Gem::Requirement
39
35
  requirements:
40
36
  - - '>='
41
37
  - !ruby/object:Gem::Version
42
38
  version: '0'
43
- none: false
44
39
  prerelease: false
45
40
  type: :development
46
- description: angus-router
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '2.14'
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ~>
51
+ - !ruby/object:Gem::Version
52
+ version: '2.14'
53
+ prerelease: false
54
+ type: :development
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.7.1
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - '='
65
+ - !ruby/object:Gem::Version
66
+ version: 0.7.1
67
+ prerelease: false
68
+ type: :development
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov-rcov
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 0.2.3
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '='
79
+ - !ruby/object:Gem::Version
80
+ version: 0.2.3
81
+ prerelease: false
82
+ type: :development
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov-rcov-text
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 0.0.2
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '='
93
+ - !ruby/object:Gem::Version
94
+ version: 0.0.2
95
+ prerelease: false
96
+ type: :development
97
+ - !ruby/object:Gem::Dependency
98
+ name: ci_reporter
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirement: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ prerelease: false
110
+ type: :development
111
+ description: |2
112
+ Angus-router is a powerful router for your next generation of awesome Rack applications.
113
+ Just throw your shit into angus-router and run away.
47
114
  email:
48
- - adrian.gomez@moove-it.com
115
+ - angus@moove-it.com
49
116
  executables: []
50
117
  extensions: []
51
118
  extra_rdoc_files: []
52
119
  files:
53
- - .gitignore
54
- - Gemfile
55
- - LICENSE.txt
56
- - README.md
57
- - Rakefile
58
- - angus-router.gemspec
120
+ - lib/angus-router.rb
59
121
  - lib/angus/router.rb
60
- - lib/angus/router/version.rb
61
- homepage: ''
122
+ homepage: http://mooveit.github.io/angus-router
62
123
  licenses:
63
124
  - MIT
125
+ metadata: {}
64
126
  post_install_message:
65
127
  rdoc_options: []
66
128
  require_paths:
@@ -70,17 +132,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
70
132
  - - '>='
71
133
  - !ruby/object:Gem::Version
72
134
  version: '0'
73
- none: false
74
135
  required_rubygems_version: !ruby/object:Gem::Requirement
75
136
  requirements:
76
137
  - - '>='
77
138
  - !ruby/object:Gem::Version
78
139
  version: '0'
79
- none: false
80
140
  requirements: []
81
141
  rubyforge_project:
82
- rubygems_version: 1.8.24
142
+ rubygems_version: 2.1.5
83
143
  signing_key:
84
- specification_version: 3
85
- summary: angus-router
144
+ specification_version: 4
145
+ summary: Router for Rack applications.
86
146
  test_files: []
data/.gitignore DELETED
@@ -1,17 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in angus-router.gemspec
4
- gemspec
data/LICENSE.txt DELETED
@@ -1,22 +0,0 @@
1
- Copyright (c) 2013 Adrian Gomez
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md DELETED
@@ -1,29 +0,0 @@
1
- # Angus::Router
2
-
3
- TODO: Write a gem description
4
-
5
- ## Installation
6
-
7
- Add this line to your application's Gemfile:
8
-
9
- gem 'angus-router'
10
-
11
- And then execute:
12
-
13
- $ bundle
14
-
15
- Or install it yourself as:
16
-
17
- $ gem install angus-router
18
-
19
- ## Usage
20
-
21
- TODO: Write usage instructions here
22
-
23
- ## Contributing
24
-
25
- 1. Fork it
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
data/Rakefile DELETED
@@ -1 +0,0 @@
1
- require "bundler/gem_tasks"
data/angus-router.gemspec DELETED
@@ -1,23 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'angus/router/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "angus-router"
8
- spec.version = Angus::Router::VERSION
9
- spec.authors = ["Adrian Gomez"]
10
- spec.email = ["adrian.gomez@moove-it.com"]
11
- spec.description = %q{angus-router}
12
- spec.summary = %q{angus-router}
13
- spec.homepage = ""
14
- spec.license = "MIT"
15
-
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
20
-
21
- spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake"
23
- end
@@ -1,5 +0,0 @@
1
- module Angus
2
- module Router
3
- VERSION = "0.0.1"
4
- end
5
- end