router_simple 0.0.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/.gitignore ADDED
@@ -0,0 +1,17 @@
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 ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in router_simple.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 tokuhirom
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 ADDED
@@ -0,0 +1,29 @@
1
+ # RouterSimple
2
+
3
+ RouterSimple is yet another HTTP routing library.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'router_simple'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install router_simple
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 ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.pattern = "spec/*_spec.rb"
6
+ end
@@ -0,0 +1,130 @@
1
+ require "router_simple/version"
2
+
3
+ =begin
4
+
5
+ router_simple.rb - minimalistic path dispatcher
6
+
7
+ =head1 SYNOPSIS
8
+
9
+ router = RouterSimple::Router.new
10
+ router.register('GET', '/', 'Root')
11
+ router.register('POST', '/member/create', 'Member#create')
12
+ router.register('GET', '/member/:name', 'Member#detail')
13
+ router.register('GET', '/download/*path', 'Download#detail')
14
+
15
+ router.match('/')
16
+ # => ('Root', {})
17
+
18
+ router.match('/member/dankogai')
19
+ # => ('Member#detail', {"name" => 'dankogai'})
20
+
21
+ router.match('/download/growthforecast')
22
+ # => ('Download#detail', {"path" => 'growthforecast'})
23
+
24
+ =end
25
+
26
+ module RouterSimple
27
+ # Yet another HTTP Router
28
+ class Router
29
+ # Create new instance
30
+ def initialize
31
+ @patterns = []
32
+ end
33
+
34
+ # register a path to router.
35
+ #
36
+ # You can specify three pattern of path.
37
+ #
38
+ # 1. Use regexp directly
39
+ # 2. Use /:name/:id
40
+ # 3. Use /*path
41
+ #
42
+ # @param [Araray or String] http_method HTTP method. You can specify nil, ['GET', 'HEAD"], 'GET', etc.
43
+ # @param [String or Regexp] path
44
+ # @param [Any] dest Destination of this path
45
+ # @return None
46
+ def register(http_method, path, dest)
47
+ @patterns.push(Route.new(http_method, path, dest))
48
+ end
49
+
50
+ # match the path with this router.
51
+ #
52
+ # @param [String] http_method REQUEST_METHOD
53
+ # @param [String] path PATH_INFO
54
+ #
55
+ # @return dest destination info
56
+ # @return captured captured parameters
57
+ # @return method_not_allowed true if method not allowed.
58
+ def match(http_method, path)
59
+ found_method_not_allowed = false
60
+ @patterns.each do |pattern|
61
+ dest, captured, method_not_allowed = pattern.match(http_method, path)
62
+ if dest
63
+ return dest, captured
64
+ elsif method_not_allowed
65
+ found_method_not_allowed = true
66
+ end
67
+ end
68
+ return nil, nil, found_method_not_allowed
69
+ end
70
+ end
71
+
72
+ # Route class
73
+ class Route
74
+ # Create new route object
75
+ #
76
+ # @param [Araray or String or NilClass] http_method HTTP method. You can specify nil, ['GET', 'HEAD"], 'GET', etc.
77
+ # @param [String] path
78
+ # @param [Any] dest Destination of this path
79
+ def initialize(http_method, path, dest)
80
+ @path = path
81
+ @pattern = compile(path)
82
+ @dest = dest
83
+ @http_method = http_method.is_a?(String) ? [http_method] : http_method
84
+ end
85
+
86
+ # Match to this route
87
+ #
88
+ # @param [String] http_method REQUEST_METHOD
89
+ # @param [String or Regexp] path PATH_INFO
90
+ #
91
+ # @return dest Destination for this route
92
+ # @return captures captured parameters by router
93
+ # @return method_not_allowed True if the route was denied by method.
94
+ def match(http_method, path)
95
+ matched = @pattern.match(path)
96
+ if matched
97
+ if @http_method && !@http_method.any? {|m| m==http_method}
98
+ return nil, nil, true
99
+ end
100
+ captures = {}
101
+ matched.names.zip(matched.captures).each {|x|
102
+ captures[x[0]] = x[1]
103
+ }
104
+ return @dest, captures
105
+ else
106
+ return nil, nil
107
+ end
108
+ end
109
+
110
+ # compile 'path' pattern to regexp.
111
+ def compile(path)
112
+ if path.kind_of?(Regexp)
113
+ return path
114
+ else
115
+ pattern = Regexp.compile(
116
+ '\A' + (
117
+ path.gsub(/[-\[\]{}()+?.,\\^$|#\s]/) {|x|
118
+ Regexp.escape(x)
119
+ }
120
+ .gsub(/:([\w\d]+)/, "(?<\\1>[^\/]+)")
121
+ .gsub(/\*([\w\d]+)/, "(?<\\1>.+?)")
122
+ ) + '\z'
123
+ )
124
+ pattern
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+
@@ -0,0 +1,3 @@
1
+ module RouterSimple
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'router_simple/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "router_simple"
8
+ gem.version = RouterSimple::VERSION
9
+ gem.authors = ["tokuhirom"]
10
+ gem.email = ["tokuhirom@gmail.com"]
11
+ gem.description = %q{Simple HTTP routing library}
12
+ gem.summary = %q{Yet another http routing library}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency "rspec"
21
+ end
22
+
@@ -0,0 +1,90 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+
4
+ require 'router_simple'
5
+
6
+ describe RouterSimple::Route, '#match' do
7
+ describe 'GET /' do
8
+ r = RouterSimple::Route.new('GET', '/', 4)
9
+
10
+ it 'allows GET /' do
11
+ assert_equal r.match('GET', '/'), [4, {}]
12
+ end
13
+
14
+ it 'denides POST' do
15
+ assert_equal r.match('POST', '/'), [nil, nil, true]
16
+ end
17
+
18
+ it 'does not match to /foo' do
19
+ assert_equal r.match('GET', '/foo'), [nil, nil]
20
+ end
21
+ end
22
+
23
+ describe 'GET|HEAD /' do
24
+ r = RouterSimple::Route.new(['GET', 'HEAD'], '/', 4)
25
+
26
+ it 'allows GET /' do
27
+ assert_equal r.match('GET', '/'), [4, {}]
28
+ end
29
+
30
+ it 'also allows HEAD /' do
31
+ assert_equal r.match('HEAD', '/'), [4, {}]
32
+ end
33
+
34
+ it 'denides POST' do
35
+ assert_equal r.match('POST', '/'), [nil, nil, true]
36
+ end
37
+ end
38
+
39
+ describe 'GET /:name' do
40
+ route = RouterSimple::Route.new('GET', '/:name', 8)
41
+
42
+ it 'matches /dankogai' do
43
+ assert_equal route.match('GET', '/dankogai'), [8, {'name' => 'dankogai'}]
44
+ end
45
+
46
+ it 'does not matches /dankogai/4' do
47
+ assert_equal route.match('GET', '/dankogai/4'), [nil, nil]
48
+ end
49
+ end
50
+
51
+ describe 'GET /:name/:entry_id' do
52
+ router = RouterSimple::Route.new('GET', '/:name/:entry_id', 4)
53
+
54
+ it 'matches /dankogai/4' do
55
+ assert_equal router.match('GET', '/dankogai/4'), [4, {'name' => 'dankogai', 'entry_id' => '4'}]
56
+ end
57
+
58
+ it 'does not match /dankogai/' do
59
+ assert_equal router.match('GET', '/dankogai/'), [nil, nil]
60
+ end
61
+ end
62
+
63
+ describe 'GET /foo/*name' do
64
+ it 'matches /foo/yappo' do
65
+ router = RouterSimple::Route.new('GET', '/foo/*name', 8)
66
+ assert_equal router.match('GET', '/foo/yappo'), [8, {'name' => 'yappo'}]
67
+ end
68
+ end
69
+
70
+ describe 'use regexp as a path' do
71
+ describe 'using named capture' do
72
+ router = RouterSimple::Route.new('GET', %r{^/foo/(?<no>[0-9]+)$}, 8)
73
+ it 'matches /foo/111' do
74
+ assert_equal router.match('GET', '/foo/111'), [8, {'no' => '111'}]
75
+ end
76
+ it 'does not matches /foo/bar' do
77
+ assert_equal router.match('GET', '/foo/bar'), [nil, nil]
78
+ end
79
+ end
80
+ describe 'using paren capture' do
81
+ router = RouterSimple::Route.new('GET', %r{^/foo/([0-9]+)$}, 8)
82
+ it 'matches /foo/111' do
83
+ assert_equal router.match('GET', '/foo/111'), [8, {}]
84
+ end
85
+ it 'does not matches /foo/bar' do
86
+ assert_equal router.match('GET', '/foo/bar'), [nil, nil]
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,56 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+
4
+ require 'router_simple'
5
+
6
+ describe RouterSimple::Router, '#xxx' do
7
+ it 'returns nil when there is no registered pattern' do
8
+ router = RouterSimple::Router.new()
9
+ assert_equal router.match('GET', '/'), [nil, nil, false]
10
+ end
11
+
12
+ describe 'GET /' do
13
+ it 'matches / when registered /' do
14
+ router = RouterSimple::Router.new()
15
+ router.register('GET', '/', 4)
16
+ assert_equal router.match('GET', '/'), [4, {}]
17
+ end
18
+
19
+ it 'denides POST request' do
20
+ router = RouterSimple::Router.new()
21
+ router.register('GET', '/', 4)
22
+ assert_equal router.match('POST', '/'), [nil, nil, true]
23
+ end
24
+ end
25
+
26
+ it 'matches /json when registered /json' do
27
+ router = RouterSimple::Router.new()
28
+ router.register('GET', '/', 2)
29
+ router.register('GET', '/json', 4)
30
+ assert_equal router.match('GET', '/json'), [4, {}]
31
+ end
32
+
33
+ it 'matches /dankogai when registered /:name' do
34
+ router = RouterSimple::Router.new()
35
+ router.register('GET', '/:name', 4)
36
+ assert_equal router.match('GET', '/dankogai'), [4, {'name' => 'dankogai'}]
37
+ end
38
+
39
+ it 'matches /dankogai/4 when registered /:name/:entry_id' do
40
+ router = RouterSimple::Router.new()
41
+ router.register('GET', '/:name/:entry_id', 4)
42
+ assert_equal router.match('GET', '/dankogai/4'), [4, {'name' => 'dankogai', 'entry_id' => '4'}]
43
+ end
44
+
45
+ it 'does not match /dankogai/4 when registered /:name' do
46
+ router = RouterSimple::Router.new()
47
+ router.register('GET', '/:name', 4)
48
+ assert_equal router.match('GET', '/dankogai/4'), [nil, nil, false]
49
+ end
50
+
51
+ it 'supports /foo/*name' do
52
+ router = RouterSimple::Router.new()
53
+ router.register('GET', '/foo/*name', 8)
54
+ assert_equal router.match('GET', '/foo/jfsdlkaf/jajkdlsfj'), [8, {'name' => 'jfsdlkaf/jajkdlsfj'}]
55
+ end
56
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: router_simple
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - tokuhirom
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Simple HTTP routing library
31
+ email:
32
+ - tokuhirom@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - LICENSE.txt
40
+ - README.md
41
+ - Rakefile
42
+ - lib/router_simple.rb
43
+ - lib/router_simple/version.rb
44
+ - router_simple.gemspec
45
+ - spec/route_spec.rb
46
+ - spec/router_spec.rb
47
+ homepage: ''
48
+ licenses: []
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ requirements: []
66
+ rubyforge_project:
67
+ rubygems_version: 1.8.24
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: Yet another http routing library
71
+ test_files:
72
+ - spec/route_spec.rb
73
+ - spec/router_spec.rb
74
+ has_rdoc: