truss-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 +4 -4
- data/README.md +47 -3
- data/benchmarks/simple_bench.rb +74 -0
- data/lib/truss/router/node.rb +27 -5
- data/lib/truss/router/request.rb +9 -0
- data/lib/truss/router/routes.rb +10 -0
- data/lib/truss/router/routeset.rb +33 -0
- data/lib/truss/router/version.rb +1 -1
- data/lib/truss/router.rb +62 -3
- data/spec/lib/truss/draw_routes_spec.rb +55 -0
- data/spec/lib/truss/request_spec.rb +8 -0
- data/spec/lib/truss/route_dispatch_spec.rb +97 -0
- data/spec/lib/truss/router/node_spec.rb +43 -1
- data/spec/lib/truss/router/routes_spec.rb +4 -0
- data/spec/lib/truss/router/routeset_spec.rb +20 -0
- data/spec/lib/truss/router_spec.rb +52 -0
- metadata +17 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b56c1774dc9e3e09defdd552298a3a10bfc61bd
|
4
|
+
data.tar.gz: 76018cd3ef0a703260177cc158ca4223f91bcbd1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3c1fc3a28002932edb13878189dca29d9b7a3cc60d76d2907263238f6d39edb6ff20b46395a00f151f98f1c5a7f7e38ddad91f1f4428e27767156b1afd21066
|
7
|
+
data.tar.gz: f02753a22f37ea3837d34c819dcae69964a53c8e2aabca5cac9bfe1069f3983e2e8b0497d1d33852246ce61b6f32b816a7eb91486d720bb8774ce1016f214b39
|
data/README.md
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
[![Build Status](https://travis-ci.org/truss-io/router.png)](https://travis-ci.org/truss-io/router)
|
2
|
-
# Truss
|
2
|
+
# Truss 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
|
+
Truss Router is currently considered alpha software, and as such please don't use in any production environment, but feel free to
|
6
|
+
explore and see how it handles for you.
|
7
|
+
|
8
|
+
Truss supports the following Ruby platforms in Pure Ruby:
|
9
|
+
|
10
|
+
* MRI 1.9.3
|
11
|
+
* MRI 2.0.0
|
12
|
+
* JRuby 1.7
|
13
|
+
* RBX 1.9 mode
|
5
14
|
|
6
15
|
## Installation
|
7
16
|
|
@@ -19,7 +28,42 @@ Or install it yourself as:
|
|
19
28
|
|
20
29
|
## Usage
|
21
30
|
|
22
|
-
|
31
|
+
Truss Router admires Journey, although doesn't fancy doing all the hard work that it does. With that in mind, it offers a nice DSL
|
32
|
+
and some pleasant features, but doesn't currently support things like namespaces or constraints. To be honest, at this 0.0.2 release
|
33
|
+
it doesn't actually support much, but features will come!
|
34
|
+
|
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
|
+
|
37
|
+
1. path, e.g. "/home" (currently only exact matches match, dynamic segments coming soon!)
|
38
|
+
2. rack app, e.g. ```->(env){[200, {'Content-Type' => 'text/plain'}, ["Hi, I'm a Rack App"]]}```
|
39
|
+
3. an optional hash of options (currently not used!)
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
require 'truss-router'
|
43
|
+
|
44
|
+
Truss::Router.draw do |r|
|
45
|
+
r.get("/", HomeApp)
|
46
|
+
r.post("/login", LoginApp)
|
47
|
+
r.patch("/update", DhhApp)
|
48
|
+
r.delete("/goodbye", RemoveThisApp)
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
Finally, you can then run the Truss Router as a rack app:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
run Truss::Router
|
56
|
+
```
|
57
|
+
|
58
|
+
## Benchmarks
|
59
|
+
|
60
|
+
Truss Router aims to be a highly performant routing solution for your Rack apps, whilst giving you a nicer DSL than some of the
|
61
|
+
inbuilt rack types (Cascade/URLMap), and a little bit of Rails Magic, such as param matching and simple binding of different
|
62
|
+
request methods to different endpoints on the same path.
|
63
|
+
|
64
|
+
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
|
+
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.
|
23
67
|
|
24
68
|
## Contributing
|
25
69
|
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'rack'
|
3
|
+
require File.expand_path("../../lib/truss-router", __FILE__)
|
4
|
+
|
5
|
+
puts "Welcome to Truss Router v#{Truss::Router::VERSION} Benchmark suite. Please wait...\n\n"
|
6
|
+
app = ->(env) {
|
7
|
+
[
|
8
|
+
200,
|
9
|
+
{'Content-Type' => 'text/plain'},
|
10
|
+
["Hello World"]
|
11
|
+
]
|
12
|
+
}
|
13
|
+
|
14
|
+
TIMES = 50_000
|
15
|
+
REQUEST = Rack::MockRequest.env_for("/", method: "GET")
|
16
|
+
|
17
|
+
Truss::Router.draw do |route|
|
18
|
+
route.get("/", app)
|
19
|
+
end
|
20
|
+
|
21
|
+
puts "Benchmarking in progress with 50k iterations, please wait\n\n"
|
22
|
+
|
23
|
+
Benchmark.bm(12) do |x|
|
24
|
+
x.report("Plain app") { TIMES.times{ app.call(REQUEST) } }
|
25
|
+
x.report("Single route") { TIMES.times { Truss::Router.call(REQUEST) } }
|
26
|
+
end
|
27
|
+
|
28
|
+
puts "\n\nBenchmarking for 2nd preference route with 50k iterations\n\n"
|
29
|
+
|
30
|
+
Truss::Router.reset!
|
31
|
+
|
32
|
+
app2 = ->(env) {
|
33
|
+
[
|
34
|
+
200,
|
35
|
+
{'Content-Type' => 'text/plain'},
|
36
|
+
["Home Page"]
|
37
|
+
]
|
38
|
+
}
|
39
|
+
|
40
|
+
Truss::Router.draw do |route|
|
41
|
+
route.get("/", app)
|
42
|
+
route.get("/home", app2)
|
43
|
+
end
|
44
|
+
|
45
|
+
HOME_REQUEST = Rack::MockRequest.env_for("/home", method: "GET")
|
46
|
+
|
47
|
+
Benchmark.bm(12) do |x|
|
48
|
+
x.report("Plain app") { TIMES.times{ app.call(REQUEST) } }
|
49
|
+
x.report("Single route") { TIMES.times { Truss::Router.call(HOME_REQUEST) } }
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
puts "\n\nBenchmarking 10 route map with 50k iterations, hitting last route\n\n"
|
54
|
+
|
55
|
+
Truss::Router.reset!
|
56
|
+
|
57
|
+
Truss::Router.draw do |route|
|
58
|
+
route.get("/", app)
|
59
|
+
route.get("/about", app)
|
60
|
+
route.get("/contact", app)
|
61
|
+
route.get("/blog", app)
|
62
|
+
route.get("/structure", app)
|
63
|
+
route.get("/staff", app)
|
64
|
+
route.get("/news", app)
|
65
|
+
route.get("/log-in", app)
|
66
|
+
route.get("/admin", app)
|
67
|
+
route.get("/home", app2)
|
68
|
+
end
|
69
|
+
|
70
|
+
Benchmark.bm(10) do |x|
|
71
|
+
x.report("Plain app") { TIMES.times{ app.call(REQUEST) } }
|
72
|
+
x.report("Last route") { TIMES.times { Truss::Router.call(HOME_REQUEST) } }
|
73
|
+
end
|
74
|
+
|
data/lib/truss/router/node.rb
CHANGED
@@ -1,13 +1,35 @@
|
|
1
1
|
module Truss
|
2
2
|
module Router
|
3
3
|
class Node
|
4
|
-
attr_accessor :request_method, :path, :endpoint
|
5
|
-
def initialize(
|
6
|
-
@request_method, @path, @endpoint =
|
7
|
-
@
|
4
|
+
attr_accessor :request_method, :path, :endpoint, :matchable_regex, :options
|
5
|
+
def initialize(method, path, endpoint, options={})
|
6
|
+
@request_method, @path, @endpoint = method, path, endpoint
|
7
|
+
@matchable_regex = build_matchable_regex(method, path, options)
|
8
|
+
@options = options
|
8
9
|
end
|
9
10
|
|
10
|
-
def matches?
|
11
|
+
def matches? request
|
12
|
+
matchable_regex.match(request.routing_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def call request
|
16
|
+
endpoint.call(request)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def build_matchable_regex(method, path, options)
|
21
|
+
%r[\A#{method_group(method)}#{path}\Z]
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_group(method)
|
25
|
+
origin = case method
|
26
|
+
when :get
|
27
|
+
"(GET|HEAD|OPTIONS)"
|
28
|
+
when :options
|
29
|
+
"OPTIONS"
|
30
|
+
else
|
31
|
+
"(#{method.to_s.upcase}|OPTIONS)"
|
32
|
+
end
|
11
33
|
end
|
12
34
|
end
|
13
35
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Truss
|
2
|
+
module Router
|
3
|
+
class Routeset
|
4
|
+
|
5
|
+
attr_accessor :nodes
|
6
|
+
def initialize(nodes=[])
|
7
|
+
@nodes = nodes
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_node(node)
|
11
|
+
@nodes << node
|
12
|
+
end
|
13
|
+
|
14
|
+
def <<(node)
|
15
|
+
@nodes << node
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](node)
|
19
|
+
@nodes[node]
|
20
|
+
end
|
21
|
+
|
22
|
+
def length
|
23
|
+
@nodes.length
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_route request
|
27
|
+
@nodes.detect do |node|
|
28
|
+
node.matches?(request)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/truss/router/version.rb
CHANGED
data/lib/truss/router.rb
CHANGED
@@ -1,7 +1,66 @@
|
|
1
1
|
require "truss/router/version"
|
2
|
+
require "truss/router/node"
|
3
|
+
require "truss/router/routes"
|
4
|
+
require "truss/router/routeset"
|
5
|
+
require "truss/router/request"
|
2
6
|
|
3
7
|
module Truss
|
4
|
-
|
5
|
-
|
6
|
-
|
8
|
+
module Router
|
9
|
+
extend self
|
10
|
+
def draw(&block)
|
11
|
+
raise ArgumentError unless block_given?
|
12
|
+
block.call(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def routeset
|
16
|
+
@routeset ||= Truss::Router::Routeset.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def get(path, endpoint, opts={})
|
20
|
+
build_node :Get, path, endpoint, opts
|
21
|
+
end
|
22
|
+
|
23
|
+
def post(path, endpoint, opts={})
|
24
|
+
build_node :Post, path, endpoint, opts
|
25
|
+
end
|
26
|
+
|
27
|
+
def options(path, endpoint, opts={})
|
28
|
+
build_node :Options, path, endpoint, opts
|
29
|
+
end
|
30
|
+
|
31
|
+
def head(path, endpoint, opts={})
|
32
|
+
build_node :Head, path, endpoint, opts
|
33
|
+
end
|
34
|
+
|
35
|
+
def put(path, endpoint, opts={})
|
36
|
+
build_node :Put, path, endpoint, opts
|
37
|
+
end
|
38
|
+
|
39
|
+
def patch(path, endpoint, opts={})
|
40
|
+
build_node :Patch, path, endpoint, opts
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete(path, endpoint, opts={})
|
44
|
+
build_node :Delete, path, endpoint, opts
|
45
|
+
end
|
46
|
+
|
47
|
+
def reset!
|
48
|
+
@routeset = Truss::Router::Routeset.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def call env
|
52
|
+
request = Request.new(env.dup)
|
53
|
+
route = routeset.find_route(request)
|
54
|
+
if route
|
55
|
+
route.call(request)
|
56
|
+
else
|
57
|
+
[404, {'Content-Type' => 'text/plain'}, ["Not Found"]]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
def build_node method, path, endpoint, opts
|
63
|
+
routeset << Routes.const_get(method).new(path, endpoint, opts)
|
64
|
+
end
|
65
|
+
end
|
7
66
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'truss/router'
|
2
|
+
|
3
|
+
describe Truss::Router do
|
4
|
+
let(:app) { ->(env){[200, {'Content-Type' => 'text/plain'}, ["Hello World"]]} }
|
5
|
+
subject { described_class }
|
6
|
+
before(:each) { subject.reset! }
|
7
|
+
it "requires a block to be passed to #draw" do
|
8
|
+
expect {
|
9
|
+
subject.draw
|
10
|
+
}.to raise_error(ArgumentError)
|
11
|
+
end
|
12
|
+
|
13
|
+
context "drawing routes" do
|
14
|
+
context "triggers the right route builder" do
|
15
|
+
let(:map) { ->(m){
|
16
|
+
m.get("/home", app)
|
17
|
+
m.post("/home", app)
|
18
|
+
m.put("/home", app)
|
19
|
+
m.patch("/home", app)
|
20
|
+
m.options("/home", app)
|
21
|
+
m.head("/home", app)
|
22
|
+
m.delete("/home", app)
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
it { subject.should_receive(:get).with("/home", app); subject.draw(&map) }
|
27
|
+
it { subject.should_receive(:post).with("/home", app); subject.draw(&map) }
|
28
|
+
it { subject.should_receive(:put).with("/home", app); subject.draw(&map) }
|
29
|
+
it { subject.should_receive(:patch).with("/home", app); subject.draw(&map) }
|
30
|
+
it { subject.should_receive(:head).with("/home", app); subject.draw(&map) }
|
31
|
+
it { subject.should_receive(:options).with("/home", app); subject.draw(&map) }
|
32
|
+
it { subject.should_receive(:delete).with("/home", app); subject.draw(&map) }
|
33
|
+
end
|
34
|
+
|
35
|
+
context "populates the routeset" do
|
36
|
+
let(:map) { ->(m){
|
37
|
+
m.get("/home", app)
|
38
|
+
m.post("/home", app)
|
39
|
+
}
|
40
|
+
}
|
41
|
+
before(:each) do
|
42
|
+
subject.draw(&map)
|
43
|
+
end
|
44
|
+
it "should have two route" do
|
45
|
+
subject.routeset.length.should eq(2)
|
46
|
+
end
|
47
|
+
it "should have a Get route as the first member of the routeset" do
|
48
|
+
subject.routeset[0].should be_kind_of(Truss::Router::Routes::Get)
|
49
|
+
end
|
50
|
+
it "should have a Post route as the second member of the routeset" do
|
51
|
+
subject.routeset[1].should be_kind_of(Truss::Router::Routes::Post)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'truss/router'
|
2
|
+
|
3
|
+
describe Truss::Router do
|
4
|
+
let(:app) { ->(env){ [200, {'Content-Type' => 'text/plain'}, ["Hello World"]] } }
|
5
|
+
let(:map) { ->(r){ r.get("/home", app) } }
|
6
|
+
let(:env) { Rack::MockRequest.env_for("/home", method: "GET") }
|
7
|
+
subject { described_class.routeset }
|
8
|
+
context "single route dispatch" do
|
9
|
+
before(:each) do
|
10
|
+
described_class.reset!
|
11
|
+
described_class.draw(&map)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should interrogate the routeset when called" do
|
15
|
+
subject.should_receive(:find_route).exactly(1).times.with(kind_of(Truss::Router::Request))
|
16
|
+
described_class.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return the first route for a matching path" do
|
20
|
+
subject[0].should_receive(:call).exactly(1).times.with(kind_of(Truss::Router::Request))
|
21
|
+
described_class.call(env)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return 404 response for no matching routes" do
|
25
|
+
bad_env = Rack::MockRequest.env_for("/noroute", method: "PATCH")
|
26
|
+
described_class.call(bad_env)[0].should be(404)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "multiple routes present" do
|
31
|
+
let(:multiple_map) { ->(r){
|
32
|
+
r.get("/", app)
|
33
|
+
r.get("/home", app)
|
34
|
+
r.get("/about", app)
|
35
|
+
r.post("/login", app)
|
36
|
+
r.post("/home", app)
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
before(:each) do
|
41
|
+
described_class.reset!
|
42
|
+
described_class.draw(&multiple_map)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should call the second node given a get request for /home" do
|
46
|
+
subject[1].should_receive(:call).exactly(1).times.with(kind_of(Truss::Router::Request))
|
47
|
+
described_class.call(env)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should call the third node given a get request for /about" do
|
51
|
+
about_env = Rack::MockRequest.env_for("/about", method: "GET")
|
52
|
+
subject[2].should_receive(:call).exactly(1).times.with(kind_of(Truss::Router::Request))
|
53
|
+
described_class.call(about_env)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should call the fourth node given a post request for /login" do
|
57
|
+
login_env = Rack::MockRequest.env_for("/login", method: "POST")
|
58
|
+
subject[3].should_receive(:call).exactly(1).times.with(kind_of(Truss::Router::Request))
|
59
|
+
described_class.call(login_env)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should call the fifth node given a post request for /home" do
|
63
|
+
post_home_env = Rack::MockRequest.env_for("/home", method: "POST")
|
64
|
+
subject[4].should_receive(:call).exactly(1).times.with(kind_of(Truss::Router::Request))
|
65
|
+
described_class.call(post_home_env)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should call the second node given an options request for /home" do
|
69
|
+
options_home_env = Rack::MockRequest.env_for("/home", method: "OPTIONS")
|
70
|
+
subject[1].should_receive(:call).exactly(1).times.with(kind_of(Truss::Router::Request))
|
71
|
+
described_class.call(options_home_env)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should call the second node given a head request for /home" do
|
75
|
+
head_home_env = Rack::MockRequest.env_for("/home", method: "HEAD")
|
76
|
+
subject[1].should_receive(:call).exactly(1).times.with(kind_of(Truss::Router::Request))
|
77
|
+
described_class.call(head_home_env)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should call the fourth node given an options request for /login" do
|
81
|
+
options_login_env = Rack::MockRequest.env_for("/login", method: "OPTIONS")
|
82
|
+
subject[3].should_receive(:call).exactly(1).times.with(kind_of(Truss::Router::Request))
|
83
|
+
described_class.call(options_login_env)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should call the first node given a get request for /" do
|
87
|
+
home_env = Rack::MockRequest.env_for("/", method: "GET")
|
88
|
+
subject[0].should_receive(:call).exactly(1).times.with(kind_of(Truss::Router::Request))
|
89
|
+
described_class.call(home_env)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should return a 404 response if the route doesn't match" do
|
93
|
+
missing_env = Rack::MockRequest.env_for("/noroutehere", method: "GET")
|
94
|
+
described_class.call(missing_env)[0].should be(404)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -1,9 +1,51 @@
|
|
1
1
|
require 'truss/router/node'
|
2
2
|
|
3
3
|
describe Truss::Router::Node do
|
4
|
-
|
4
|
+
let(:app) { ->(env){ [200, {'Content-Type' => 'text/plain'}, ["Hello World"]] } }
|
5
|
+
subject { Truss::Router::Node.new(:get, "/home", app) }
|
5
6
|
it { should respond_to(:request_method) }
|
6
7
|
it { should respond_to(:endpoint) }
|
7
8
|
it { should respond_to(:path) }
|
8
9
|
it { should respond_to(:matches?) }
|
10
|
+
it { should respond_to(:options) }
|
11
|
+
it { should respond_to(:matchable_regex) }
|
12
|
+
it { should respond_to(:call) }
|
13
|
+
|
14
|
+
describe "routing regexes" do
|
15
|
+
context "for get requests" do
|
16
|
+
subject { Truss::Router::Node.new(:get, "/home", app) }
|
17
|
+
its(:matchable_regex) { should eq(%r[\A(GET|HEAD|OPTIONS)/home\Z]) }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "for post requests" do
|
21
|
+
subject { Truss::Router::Node.new(:post, "/home", app) }
|
22
|
+
its(:matchable_regex) { should eq(%r[\A(POST|OPTIONS)/home\Z]) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context "for put requests" do
|
26
|
+
subject { Truss::Router::Node.new(:put, "/home", app) }
|
27
|
+
its(:matchable_regex) { should eq(%r[\A(PUT|OPTIONS)/home\Z]) }
|
28
|
+
end
|
29
|
+
|
30
|
+
context "for patch requests" do
|
31
|
+
subject { Truss::Router::Node.new(:patch, "/home", app) }
|
32
|
+
its(:matchable_regex) { should eq(%r[\A(PATCH|OPTIONS)/home\Z]) }
|
33
|
+
end
|
34
|
+
|
35
|
+
context "for head requests" do
|
36
|
+
subject { Truss::Router::Node.new(:head, "/home", app) }
|
37
|
+
its(:matchable_regex) { should eq(%r[\A(HEAD|OPTIONS)/home\Z]) }
|
38
|
+
end
|
39
|
+
|
40
|
+
context "for options requests" do
|
41
|
+
subject { Truss::Router::Node.new(:options, "/home", app) }
|
42
|
+
its(:matchable_regex) { should eq(%r[\AOPTIONS/home\Z]) }
|
43
|
+
end
|
44
|
+
|
45
|
+
context "for delete requests" do
|
46
|
+
subject { Truss::Router::Node.new(:delete, "/home", app) }
|
47
|
+
its(:matchable_regex) { should eq(%r[\A(DELETE|OPTIONS)/home\Z]) }
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
9
51
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'truss/router/routeset'
|
2
|
+
require 'truss/router/node'
|
3
|
+
|
4
|
+
describe Truss::Router::Routeset do
|
5
|
+
it { should respond_to(:nodes) }
|
6
|
+
it { should respond_to(:add_node) }
|
7
|
+
|
8
|
+
context "adding nodes" do
|
9
|
+
subject { Truss::Router::Routeset.new }
|
10
|
+
let(:app) { ->(env){[200, {'Content-Type' => 'text/plain'}, ["Hello World"]]} }
|
11
|
+
let(:node) { Truss::Router::Node.new(:get, "/home", app, {}) }
|
12
|
+
before(:each) { subject.add_node(node) }
|
13
|
+
|
14
|
+
it { subject.nodes.length.should eq(1) }
|
15
|
+
it "can contain multiple nodes" do
|
16
|
+
subject.add_node(node)
|
17
|
+
subject.nodes.length.should eq(2)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'truss/router'
|
2
|
+
|
3
|
+
describe Truss::Router do
|
4
|
+
let(:app) { ->(env){[200, {'Content-Type' => 'text/plain'}, ["Hello World"]]} }
|
5
|
+
it { described_class.should respond_to(:draw) }
|
6
|
+
it { should respond_to(:get) }
|
7
|
+
it { should respond_to(:post) }
|
8
|
+
it { should respond_to(:put) }
|
9
|
+
it { should respond_to(:head) }
|
10
|
+
it { should respond_to(:options) }
|
11
|
+
it { should respond_to(:patch) }
|
12
|
+
it { should respond_to(:delete) }
|
13
|
+
it { should respond_to(:reset!) }
|
14
|
+
its(:routeset) { should be_kind_of(Truss::Router::Routeset) }
|
15
|
+
|
16
|
+
it { should respond_to(:call) }
|
17
|
+
|
18
|
+
it "builds a Get route when #get is called" do
|
19
|
+
described_class.should_receive(:build_node).with(:Get, "/home", app, {})
|
20
|
+
described_class.get("/home", app)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "builds a Post route when #post is called" do
|
24
|
+
described_class.should_receive(:build_node).with(:Post, "/home", app, {})
|
25
|
+
described_class.post("/home", app)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "builds a Put route when #put is called" do
|
29
|
+
described_class.should_receive(:build_node).with(:Put, "/home", app, {})
|
30
|
+
described_class.put("/home", app)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "builds a Patch route when #patch is called" do
|
34
|
+
described_class.should_receive(:build_node).with(:Patch, "/home", app, {})
|
35
|
+
described_class.patch("/home", app)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "builds a Head route when #head is called" do
|
39
|
+
described_class.should_receive(:build_node).with(:Head, "/home", app, {})
|
40
|
+
described_class.head("/home", app)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "builds a Options route when #options is called" do
|
44
|
+
described_class.should_receive(:build_node).with(:Options, "/home", app, {})
|
45
|
+
described_class.options("/home", app)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "builds a Delete route when #delete is called" do
|
49
|
+
described_class.should_receive(:build_node).with(:Delete, "/home", app, {})
|
50
|
+
described_class.delete("/home", app)
|
51
|
+
end
|
52
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
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.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Maxwell
|
@@ -80,9 +80,12 @@ files:
|
|
80
80
|
- LICENSE.txt
|
81
81
|
- README.md
|
82
82
|
- Rakefile
|
83
|
+
- benchmarks/simple_bench.rb
|
83
84
|
- lib/truss-router.rb
|
84
85
|
- lib/truss/router.rb
|
85
86
|
- lib/truss/router/node.rb
|
87
|
+
- lib/truss/router/request.rb
|
88
|
+
- lib/truss/router/routes.rb
|
86
89
|
- lib/truss/router/routes/delete.rb
|
87
90
|
- lib/truss/router/routes/get.rb
|
88
91
|
- lib/truss/router/routes/head.rb
|
@@ -90,7 +93,11 @@ files:
|
|
90
93
|
- lib/truss/router/routes/patch.rb
|
91
94
|
- lib/truss/router/routes/post.rb
|
92
95
|
- lib/truss/router/routes/put.rb
|
96
|
+
- lib/truss/router/routeset.rb
|
93
97
|
- lib/truss/router/version.rb
|
98
|
+
- spec/lib/truss/draw_routes_spec.rb
|
99
|
+
- spec/lib/truss/request_spec.rb
|
100
|
+
- spec/lib/truss/route_dispatch_spec.rb
|
94
101
|
- spec/lib/truss/router/node_spec.rb
|
95
102
|
- spec/lib/truss/router/routes/delete_spec.rb
|
96
103
|
- spec/lib/truss/router/routes/get_spec.rb
|
@@ -99,6 +106,9 @@ files:
|
|
99
106
|
- spec/lib/truss/router/routes/patch_spec.rb
|
100
107
|
- spec/lib/truss/router/routes/post_spec.rb
|
101
108
|
- spec/lib/truss/router/routes/put_spec.rb
|
109
|
+
- spec/lib/truss/router/routes_spec.rb
|
110
|
+
- spec/lib/truss/router/routeset_spec.rb
|
111
|
+
- spec/lib/truss/router_spec.rb
|
102
112
|
- spec/spec_helper.rb
|
103
113
|
- truss-router.gemspec
|
104
114
|
homepage: http://truss-io.github.io
|
@@ -126,6 +136,9 @@ signing_key:
|
|
126
136
|
specification_version: 4
|
127
137
|
summary: Truss Router is a modular Rack Router for Truss
|
128
138
|
test_files:
|
139
|
+
- spec/lib/truss/draw_routes_spec.rb
|
140
|
+
- spec/lib/truss/request_spec.rb
|
141
|
+
- spec/lib/truss/route_dispatch_spec.rb
|
129
142
|
- spec/lib/truss/router/node_spec.rb
|
130
143
|
- spec/lib/truss/router/routes/delete_spec.rb
|
131
144
|
- spec/lib/truss/router/routes/get_spec.rb
|
@@ -134,4 +147,7 @@ test_files:
|
|
134
147
|
- spec/lib/truss/router/routes/patch_spec.rb
|
135
148
|
- spec/lib/truss/router/routes/post_spec.rb
|
136
149
|
- spec/lib/truss/router/routes/put_spec.rb
|
150
|
+
- spec/lib/truss/router/routes_spec.rb
|
151
|
+
- spec/lib/truss/router/routeset_spec.rb
|
152
|
+
- spec/lib/truss/router_spec.rb
|
137
153
|
- spec/spec_helper.rb
|