truss-router 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +14 -3
- data/benchmarks/simple_bench.rb +19 -4
- data/lib/truss/router/node.rb +29 -3
- data/lib/truss/router/request.rb +7 -0
- data/lib/truss/router/version.rb +1 -1
- data/spec/lib/truss/dynamic_matcher_spec.rb +20 -0
- data/spec/lib/truss/router/node_spec.rb +12 -1
- data/spec/lib/truss/{request_spec.rb → router/request_spec.rb} +3 -0
- metadata +45 -27
- checksums.yaml +0 -7
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
[![Build Status](https://travis-ci.org/truss-io/router.png)](https://travis-ci.org/truss-io/router)
|
2
1
|
# Truss Router
|
2
|
+
[![Build Status](https://travis-ci.org/truss-io/router.png)](https://travis-ci.org/truss-io/router)
|
3
3
|
|
4
4
|
Truss Router is the first released part of Truss - a new wrapper around Rack to make writing performant Ruby web endpoints easier.
|
5
5
|
Truss Router is currently considered alpha software, and as such please don't use in any production environment, but feel free to
|
@@ -34,7 +34,7 @@ it doesn't actually support much, but features will come!
|
|
34
34
|
|
35
35
|
So, how do I use it? Basically, just require the gem, and then ```draw``` a map of your routes. Routes are evaluated from top to bottom, so routes at the top of the route block will match and return before routes below them. The route builder takes the following arguments:
|
36
36
|
|
37
|
-
1. path, e.g. "/home"
|
37
|
+
1. path, e.g. "/home" or "/posts/:id"
|
38
38
|
2. rack app, e.g. ```->(env){[200, {'Content-Type' => 'text/plain'}, ["Hi, I'm a Rack App"]]}```
|
39
39
|
3. an optional hash of options (currently not used!)
|
40
40
|
|
@@ -46,8 +46,16 @@ Truss::Router.draw do |r|
|
|
46
46
|
r.post("/login", LoginApp)
|
47
47
|
r.patch("/update", DhhApp)
|
48
48
|
r.delete("/goodbye", RemoveThisApp)
|
49
|
+
r.get("/posts/:id", PostApp) # :id is a dynamic segment
|
49
50
|
end
|
50
51
|
```
|
52
|
+
Any valid Rack endpoint is supported as an endpoint in this map, but please be aware that Truss Router will pass a
|
53
|
+
Truss::Router::Request object (a thin layer over Rack::Request) into the rack app rather than just the env hash. This
|
54
|
+
allows for passing segment options and similar without too much drama.
|
55
|
+
|
56
|
+
Any dynamic segments (declared by prefixing that segment with ```:```) will be passed into the application as part of the Truss
|
57
|
+
Request object, available under ```#routing_params``` for now, which is a simple hash of the segment name to the value. All keys
|
58
|
+
are strings and no attempt is made to coerce values, so they are all strings as well.
|
51
59
|
|
52
60
|
Finally, you can then run the Truss Router as a rack app:
|
53
61
|
|
@@ -63,7 +71,10 @@ request methods to different endpoints on the same path.
|
|
63
71
|
|
64
72
|
Having said that, there isn't much point in having candy if it makes it slow. HTTP Router inspired me to include benchmarks within
|
65
73
|
the repo that make it easy to check how performant the solution is. I'll include the current benchmark output in the wiki for each
|
66
|
-
supported platform (1.9.3/2.0.0/JRuby1.7/RBX) and update with each release to keep things current.
|
74
|
+
supported platform ([1.9.3](https://github.com/truss-io/router/wiki/Benchmarks-MRI-1.9.3) / [2.0.0](https://github.com/truss-io/router/wiki/Benchmarks-MRI-2.0.0) / [JRuby1.7](https://github.com/truss-io/router/wiki/Benchmarks-JRuby) / [RBX](https://github.com/truss-io/router/wiki/Benchmarks-RBX)) and update with each release to keep things current.
|
75
|
+
|
76
|
+
Currently, 2.0.0 is by far the slowest, which is somewhat curious - I had expected it to lose to JRuby and possibly RBX but not to
|
77
|
+
MRI 1.9.3, which is worth investigating.
|
67
78
|
|
68
79
|
## Contributing
|
69
80
|
|
data/benchmarks/simple_bench.rb
CHANGED
@@ -20,7 +20,7 @@ end
|
|
20
20
|
|
21
21
|
puts "Benchmarking in progress with 50k iterations, please wait\n\n"
|
22
22
|
|
23
|
-
Benchmark.
|
23
|
+
Benchmark.bmbm(12) do |x|
|
24
24
|
x.report("Plain app") { TIMES.times{ app.call(REQUEST) } }
|
25
25
|
x.report("Single route") { TIMES.times { Truss::Router.call(REQUEST) } }
|
26
26
|
end
|
@@ -44,9 +44,9 @@ end
|
|
44
44
|
|
45
45
|
HOME_REQUEST = Rack::MockRequest.env_for("/home", method: "GET")
|
46
46
|
|
47
|
-
Benchmark.
|
47
|
+
Benchmark.bmbm(10) do |x|
|
48
48
|
x.report("Plain app") { TIMES.times{ app.call(REQUEST) } }
|
49
|
-
x.report("
|
49
|
+
x.report("Last route") { TIMES.times { Truss::Router.call(HOME_REQUEST) } }
|
50
50
|
end
|
51
51
|
|
52
52
|
|
@@ -67,8 +67,23 @@ Truss::Router.draw do |route|
|
|
67
67
|
route.get("/home", app2)
|
68
68
|
end
|
69
69
|
|
70
|
-
Benchmark.
|
70
|
+
Benchmark.bmbm(10) do |x|
|
71
71
|
x.report("Plain app") { TIMES.times{ app.call(REQUEST) } }
|
72
72
|
x.report("Last route") { TIMES.times { Truss::Router.call(HOME_REQUEST) } }
|
73
73
|
end
|
74
74
|
|
75
|
+
puts "\n\nBenchmarking 1 dynamic segment with 50k requests\n\n"
|
76
|
+
Truss::Router.reset!
|
77
|
+
|
78
|
+
Truss::Router.draw do |route|
|
79
|
+
route.get("/posts/:id", app)
|
80
|
+
end
|
81
|
+
|
82
|
+
POSTS_REQUEST = Rack::MockRequest.env_for("/posts/9", method: "GET")
|
83
|
+
|
84
|
+
Benchmark.bmbm(11) do |x|
|
85
|
+
x.report("Plain app") { TIMES.times{ app.call(REQUEST) } }
|
86
|
+
x.report("One Dynamic") { TIMES.times { Truss::Router.call(POSTS_REQUEST) } }
|
87
|
+
end
|
88
|
+
|
89
|
+
|
data/lib/truss/router/node.rb
CHANGED
@@ -1,15 +1,25 @@
|
|
1
1
|
module Truss
|
2
2
|
module Router
|
3
3
|
class Node
|
4
|
-
attr_accessor :request_method, :path, :
|
4
|
+
attr_accessor :request_method, :path, :has_dynamic_segments,
|
5
|
+
:endpoint, :matchable_regex, :options
|
5
6
|
def initialize(method, path, endpoint, options={})
|
6
7
|
@request_method, @path, @endpoint = method, path, endpoint
|
8
|
+
@has_dynamic_segments = false
|
7
9
|
@matchable_regex = build_matchable_regex(method, path, options)
|
8
10
|
@options = options
|
9
11
|
end
|
10
12
|
|
11
13
|
def matches? request
|
12
|
-
|
14
|
+
if has_dynamic_segments
|
15
|
+
match = matchable_regex.match(request.routing_path)
|
16
|
+
if match
|
17
|
+
request.routing_params = Hash[match.names.zip(match.captures)]
|
18
|
+
end
|
19
|
+
match
|
20
|
+
else
|
21
|
+
matchable_regex.match(request.routing_path)
|
22
|
+
end
|
13
23
|
end
|
14
24
|
|
15
25
|
def call request
|
@@ -18,7 +28,12 @@ module Truss
|
|
18
28
|
|
19
29
|
private
|
20
30
|
def build_matchable_regex(method, path, options)
|
21
|
-
|
31
|
+
if path.include?(":")
|
32
|
+
self.has_dynamic_segments = true
|
33
|
+
/\A#{method_group(method)}#{segment_string(path)}\Z/
|
34
|
+
else
|
35
|
+
%r[\A#{method_group(method)}#{path}\Z]
|
36
|
+
end
|
22
37
|
end
|
23
38
|
|
24
39
|
def method_group(method)
|
@@ -31,6 +46,17 @@ module Truss
|
|
31
46
|
"(#{method.to_s.upcase}|OPTIONS)"
|
32
47
|
end
|
33
48
|
end
|
49
|
+
|
50
|
+
def segment_string(path)
|
51
|
+
components = path.split("/").map do |comp|
|
52
|
+
if comp[0] == ":"
|
53
|
+
"(?<#{comp[1..-1]}>[\\w\\-]+)"
|
54
|
+
else
|
55
|
+
comp
|
56
|
+
end
|
57
|
+
end
|
58
|
+
"#{components.join('/')}"
|
59
|
+
end
|
34
60
|
end
|
35
61
|
end
|
36
62
|
end
|
data/lib/truss/router/request.rb
CHANGED
data/lib/truss/router/version.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'truss/router'
|
2
|
+
|
3
|
+
describe Truss::Router do
|
4
|
+
context "dynamic matchers instantiate routing_params in the request object" do
|
5
|
+
subject { described_class }
|
6
|
+
let(:app) { ->(env){ [200, {'Content-Type' => 'text/plain'}, [env.routing_params['id']]] } }
|
7
|
+
let(:env) { Rack::MockRequest.env_for("/posts/9", method: "GET") }
|
8
|
+
before :each do
|
9
|
+
Truss::Router.reset!
|
10
|
+
Truss::Router.draw do |r|
|
11
|
+
r.get("/posts/:id", app)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return the id as the body of the request" do
|
16
|
+
response = subject.call(env)
|
17
|
+
response[2].first.should eq("9")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -46,6 +46,17 @@ describe Truss::Router::Node do
|
|
46
46
|
subject { Truss::Router::Node.new(:delete, "/home", app) }
|
47
47
|
its(:matchable_regex) { should eq(%r[\A(DELETE|OPTIONS)/home\Z]) }
|
48
48
|
end
|
49
|
-
|
50
49
|
end
|
50
|
+
|
51
|
+
describe "dynamic segments" do
|
52
|
+
context "single dynamic matcher" do
|
53
|
+
subject { Truss::Router::Node.new(:delete, "/:id", app) }
|
54
|
+
its(:matchable_regex) { should eq(/\A(DELETE|OPTIONS)\/(?<id>[\w\-]+)\Z/) }
|
55
|
+
end
|
56
|
+
|
57
|
+
context "multiple dynamic matchers" do
|
58
|
+
subject { Truss::Router::Node.new(:delete, "/posts/:post_id/comments/:id", app) }
|
59
|
+
its(:matchable_regex) { should eq(/\A(DELETE|OPTIONS)\/posts\/(?<post_id>[\w\-]+)\/comments\/(?<id>[\w\-]+)\Z/) }
|
60
|
+
end
|
61
|
+
end
|
51
62
|
end
|
metadata
CHANGED
@@ -1,71 +1,80 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: truss-router
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- John Maxwell
|
8
|
-
autorequire:
|
9
|
+
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-26 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: bundler
|
15
|
-
|
16
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
17
|
requirements:
|
17
18
|
- - ~>
|
18
19
|
- !ruby/object:Gem::Version
|
19
20
|
version: '1.3'
|
20
|
-
|
21
|
-
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
none: false
|
22
|
+
requirement: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.3'
|
27
|
+
none: false
|
28
|
+
prerelease: false
|
29
|
+
type: :development
|
27
30
|
- !ruby/object:Gem::Dependency
|
28
31
|
name: rake
|
29
|
-
|
32
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
33
|
requirements:
|
31
34
|
- - '>='
|
32
35
|
- !ruby/object:Gem::Version
|
33
36
|
version: '0'
|
34
|
-
|
35
|
-
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirement: !ruby/object:Gem::Requirement
|
37
39
|
requirements:
|
38
40
|
- - '>='
|
39
41
|
- !ruby/object:Gem::Version
|
40
42
|
version: '0'
|
43
|
+
none: false
|
44
|
+
prerelease: false
|
45
|
+
type: :development
|
41
46
|
- !ruby/object:Gem::Dependency
|
42
47
|
name: rspec
|
43
|
-
|
48
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
49
|
requirements:
|
45
50
|
- - '>='
|
46
51
|
- !ruby/object:Gem::Version
|
47
52
|
version: '0'
|
48
|
-
|
49
|
-
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
51
55
|
requirements:
|
52
56
|
- - '>='
|
53
57
|
- !ruby/object:Gem::Version
|
54
58
|
version: '0'
|
59
|
+
none: false
|
60
|
+
prerelease: false
|
61
|
+
type: :development
|
55
62
|
- !ruby/object:Gem::Dependency
|
56
63
|
name: rack
|
57
|
-
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
65
|
requirements:
|
59
66
|
- - ~>
|
60
67
|
- !ruby/object:Gem::Version
|
61
68
|
version: 1.5.0
|
62
|
-
|
63
|
-
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
65
71
|
requirements:
|
66
72
|
- - ~>
|
67
73
|
- !ruby/object:Gem::Version
|
68
74
|
version: 1.5.0
|
75
|
+
none: false
|
76
|
+
prerelease: false
|
77
|
+
type: :runtime
|
69
78
|
description: Truss Router is a modular Rack Router for Truss
|
70
79
|
email:
|
71
80
|
- john@musicglue.com
|
@@ -96,9 +105,10 @@ files:
|
|
96
105
|
- lib/truss/router/routeset.rb
|
97
106
|
- lib/truss/router/version.rb
|
98
107
|
- spec/lib/truss/draw_routes_spec.rb
|
99
|
-
- spec/lib/truss/
|
108
|
+
- spec/lib/truss/dynamic_matcher_spec.rb
|
100
109
|
- spec/lib/truss/route_dispatch_spec.rb
|
101
110
|
- spec/lib/truss/router/node_spec.rb
|
111
|
+
- spec/lib/truss/router/request_spec.rb
|
102
112
|
- spec/lib/truss/router/routes/delete_spec.rb
|
103
113
|
- spec/lib/truss/router/routes/get_spec.rb
|
104
114
|
- spec/lib/truss/router/routes/head_spec.rb
|
@@ -114,8 +124,7 @@ files:
|
|
114
124
|
homepage: http://truss-io.github.io
|
115
125
|
licenses:
|
116
126
|
- MIT
|
117
|
-
|
118
|
-
post_install_message:
|
127
|
+
post_install_message:
|
119
128
|
rdoc_options: []
|
120
129
|
require_paths:
|
121
130
|
- lib
|
@@ -123,23 +132,32 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
123
132
|
requirements:
|
124
133
|
- - '>='
|
125
134
|
- !ruby/object:Gem::Version
|
135
|
+
segments:
|
136
|
+
- 0
|
126
137
|
version: '0'
|
138
|
+
hash: 2
|
139
|
+
none: false
|
127
140
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
141
|
requirements:
|
129
142
|
- - '>='
|
130
143
|
- !ruby/object:Gem::Version
|
144
|
+
segments:
|
145
|
+
- 0
|
131
146
|
version: '0'
|
147
|
+
hash: 2
|
148
|
+
none: false
|
132
149
|
requirements: []
|
133
|
-
rubyforge_project:
|
134
|
-
rubygems_version:
|
135
|
-
signing_key:
|
136
|
-
specification_version:
|
150
|
+
rubyforge_project:
|
151
|
+
rubygems_version: 1.8.24
|
152
|
+
signing_key:
|
153
|
+
specification_version: 3
|
137
154
|
summary: Truss Router is a modular Rack Router for Truss
|
138
155
|
test_files:
|
139
156
|
- spec/lib/truss/draw_routes_spec.rb
|
140
|
-
- spec/lib/truss/
|
157
|
+
- spec/lib/truss/dynamic_matcher_spec.rb
|
141
158
|
- spec/lib/truss/route_dispatch_spec.rb
|
142
159
|
- spec/lib/truss/router/node_spec.rb
|
160
|
+
- spec/lib/truss/router/request_spec.rb
|
143
161
|
- spec/lib/truss/router/routes/delete_spec.rb
|
144
162
|
- spec/lib/truss/router/routes/get_spec.rb
|
145
163
|
- spec/lib/truss/router/routes/head_spec.rb
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: 9b56c1774dc9e3e09defdd552298a3a10bfc61bd
|
4
|
-
data.tar.gz: 76018cd3ef0a703260177cc158ca4223f91bcbd1
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: d3c1fc3a28002932edb13878189dca29d9b7a3cc60d76d2907263238f6d39edb6ff20b46395a00f151f98f1c5a7f7e38ddad91f1f4428e27767156b1afd21066
|
7
|
-
data.tar.gz: f02753a22f37ea3837d34c819dcae69964a53c8e2aabca5cac9bfe1069f3983e2e8b0497d1d33852246ce61b6f32b816a7eb91486d720bb8774ce1016f214b39
|