rutter 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,22 +2,27 @@
2
2
 
3
3
  module Rutter
4
4
  RSpec.describe Routes do
5
- let(:router) { Builder.new }
5
+ let(:router) { Rutter.new }
6
6
  let(:routes) { Routes.new(router) }
7
+ let(:endpoint) { ->(_) {} }
7
8
 
8
9
  it "has a *_path helper method" do
9
- router.get "/books/:id", to: "Books#show", as: :book
10
- expect(routes.book_path(id: 54)).to eq("/books/54")
10
+ router.get "/books/:id", to: endpoint, as: :book
11
+
12
+ expect(routes.book_path(id: 54))
13
+ .to eq("/books/54")
11
14
  end
12
15
 
13
16
  it "has a *_url helper method" do
14
- router.get "/books/:id", to: "Books#show", as: :book
15
- expect(routes.book_url(id: 54)).to eq("http://example.com/books/54")
17
+ router.get "/books/:id", to: endpoint, as: :book
18
+
19
+ expect(routes.book_url(id: 54))
20
+ .to eq("http://localhost:9292/books/54")
16
21
  end
17
22
 
18
- it "raises ArgumentError if route not found" do
23
+ it "raises RuntimeError if route not found" do
19
24
  expect { routes.invalid_path }
20
- .to raise_error(ArgumentError)
25
+ .to raise_error(RuntimeError)
21
26
  end
22
27
 
23
28
  it "raises NoMethodError if unknown method is called" do
@@ -26,10 +31,14 @@ module Rutter
26
31
  end
27
32
 
28
33
  it "support respond_to?" do
29
- router.get "/books/:id", to: "Books#show", as: :book
30
- expect(routes.respond_to?(:book)).to eq(false)
31
- expect(routes.respond_to?(:book_path)).to eq(true)
32
- expect(routes.respond_to?(:book_url)).to eq(true)
34
+ router.get "/books/:id", to: endpoint, as: :book
35
+
36
+ expect(routes.respond_to?(:book))
37
+ .to eq(false)
38
+ expect(routes.respond_to?(:book_path))
39
+ .to eq(true)
40
+ expect(routes.respond_to?(:book_url))
41
+ .to eq(true)
33
42
  end
34
43
  end
35
44
  end
@@ -6,8 +6,9 @@ RSpec.describe Rutter do
6
6
  end
7
7
 
8
8
  describe ".new" do
9
- it "returns a new Builder object" do
10
- expect(Rutter.new).to be_a(Rutter::Builder)
9
+ it "creates a new builder object" do
10
+ expect(Rutter.new)
11
+ .to be_a(Rutter::Builder)
11
12
  end
12
13
  end
13
14
  end
@@ -1,75 +1,68 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rutter
4
- RSpec.describe Builder do
5
- let(:router) { Builder.new }
4
+ RSpec.describe Scope do
5
+ let(:router) { Rutter.new }
6
+ let(:endpoint) { ->(_) {} }
6
7
 
7
- describe "scope" do
8
- it "prepends prefixes" do
9
- router.scope path: "web", namespace: "Web" do
10
- get "/books", to: "Books#index"
8
+ it "support nested scopes" do
9
+ router.scope path: "animals", namespace: "species", as: :animals do
10
+ scope path: "mammals", namespace: "mammals", as: :mammals do
11
+ get "/cats", to: "cats#index", as: :cats
11
12
  end
12
-
13
- route = router.flat_map.first
14
-
15
- expect(route.path).to eq("/web/books")
16
- expect(route.endpoint[:controller]).to eq("Web::Books")
17
13
  end
18
14
 
19
- it "recognizes all verbs" do
20
- router.scope path: "/admin", namespace: "Secure", as: :koolaid do
21
- get "/", to: ->(env) {}
22
- post "/", to: ->(env) {}
23
- put "/", to: ->(env) {}
24
- patch "/", to: ->(env) {}
25
- delete "/", to: ->(env) {}
26
- options "/", to: ->(env) {}
27
- head "/", to: ->(env) {}
28
- trace "/", to: ->(env) {}
29
- end
15
+ route = router.flat_map.first
30
16
 
31
- expect(router.flat_map[0].method).to eq("GET")
32
- expect(router.flat_map[1].method).to eq("POST")
33
- expect(router.flat_map[2].method).to eq("PUT")
34
- expect(router.flat_map[3].method).to eq("PATCH")
35
- expect(router.flat_map[4].method).to eq("DELETE")
36
- expect(router.flat_map[5].method).to eq("OPTIONS")
37
- expect(router.flat_map[6].method).to eq("HEAD")
38
- expect(router.flat_map[7].method).to eq("TRACE")
39
- end
17
+ expect(route.path)
18
+ .to eq("/animals/mammals/cats")
19
+ expect(route.endpoint)
20
+ .to eq(controller: "Species::Mammals::Cats", action: "index")
21
+ expect(router.named_map[:animals_mammals_cats])
22
+ .to eq(route)
23
+ end
40
24
 
41
- describe "#root" do
42
- it "adds a root path with a root name" do
43
- router.scope path: "/admin", namespace: "Secure", as: :koolaid do
44
- root to: ->(env) {}
45
- end
25
+ describe "#add" do
26
+ it "support using route constraints" do
27
+ scope = router.scope path: "/books"
28
+ route = scope.get "/:id",
29
+ to: endpoint,
30
+ constraints: { id: /\d+/ }
46
31
 
47
- expect(router.flat_map.first.path).to eq("/admin")
48
- expect(router.named_map.key?(:koolaid_root)).to eq(true)
49
- end
32
+ expect(route.match?(env_for("/books/82")))
33
+ .to be(true)
34
+ expect(route.match?(env_for("/books/pickaxe")))
35
+ .to be(false)
50
36
  end
37
+ end
51
38
 
52
- it "support nested scopes" do
53
- router.scope path: "animals", namespace: "Species", as: :animals do
54
- scope path: "mammals", namespace: "Mammals", as: :mammals do
55
- get "/cats", to: "Cats#index", as: :cats
56
- end
57
- end
58
-
59
- route = router.flat_map.first
39
+ describe "#mount" do
40
+ it "matches path prefixes" do
41
+ scope = router.scope path: "/api"
42
+ route = scope.mount endpoint, at: "/v1"
60
43
 
61
- expect(route.path).to eq("/animals/mammals/cats")
62
- expect(route.endpoint[:controller]).to eq("Species::Mammals::Cats")
63
- expect(route.endpoint[:action]).to eq("index")
64
- expect(router.named_map.key?(:animals_mammals_cats)).to eq(true)
44
+ expect(route.match?(env_for("/")))
45
+ .to be_nil
46
+ expect(route.match?(env_for("/api")))
47
+ .to be_nil
48
+ expect(route.match?(env_for("/api/v1")))
49
+ .to eq("/api/v1")
50
+ expect(route.match?(env_for("/api/v1/books")))
51
+ .to eq("/api/v1")
65
52
  end
53
+ end
54
+
55
+ describe "verbs" do
56
+ let(:scope) { router.scope }
66
57
 
67
- describe "#mount" do
68
- it "calls the root mount with path prefix" do
69
- app = ->(_env) {}
58
+ VERBS.each do |verb|
59
+ describe "##{verb.downcase}" do
60
+ it "recognize #{verb} verb" do
61
+ route = scope.public_send verb.downcase, "/", to: endpoint
70
62
 
71
- expect(router).to receive(:mount).with(app, at: "/admin/books")
72
- router.scope(path: "/admin") { mount app, at: "books" }
63
+ expect(router.verb_map[verb])
64
+ .to eq([route])
65
+ end
73
66
  end
74
67
  end
75
68
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rutter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Sandelius
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-05 00:00:00.000000000 Z
11
+ date: 2019-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mustermann
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rack
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -96,25 +110,21 @@ files:
96
110
  - README.md
97
111
  - Rakefile
98
112
  - bench/config.ru
99
- - bench/dynamic_routes
100
- - bench/expand
101
- - bench/helper.rb
102
- - bench/mount
103
- - bench/routes_helper
104
- - bench/static_routes
105
113
  - lib/rutter.rb
106
114
  - lib/rutter/builder.rb
115
+ - lib/rutter/mount.rb
116
+ - lib/rutter/naming.rb
107
117
  - lib/rutter/route.rb
108
118
  - lib/rutter/routes.rb
109
119
  - lib/rutter/scope.rb
120
+ - lib/rutter/verbs.rb
110
121
  - lib/rutter/version.rb
111
122
  - rutter.gemspec
112
- - spec/integration/mount_spec.rb
113
- - spec/integration/params_spec.rb
114
123
  - spec/integration/rack_spec.rb
115
- - spec/integration/redirect_spec.rb
116
124
  - spec/spec_helper.rb
125
+ - spec/support/rack.rb
117
126
  - spec/unit/builder_spec.rb
127
+ - spec/unit/namespace_spec.rb
118
128
  - spec/unit/route_spec.rb
119
129
  - spec/unit/routes_spec.rb
120
130
  - spec/unit/rutter_spec.rb
@@ -131,25 +141,23 @@ required_ruby_version: !ruby/object:Gem::Requirement
131
141
  requirements:
132
142
  - - ">="
133
143
  - !ruby/object:Gem::Version
134
- version: 2.4.0
144
+ version: 2.5.0
135
145
  required_rubygems_version: !ruby/object:Gem::Requirement
136
146
  requirements:
137
147
  - - ">="
138
148
  - !ruby/object:Gem::Version
139
149
  version: 2.5.0
140
150
  requirements: []
141
- rubyforge_project:
142
- rubygems_version: 2.6.13
151
+ rubygems_version: 3.0.3
143
152
  signing_key:
144
153
  specification_version: 4
145
154
  summary: HTTP router for Rack.
146
155
  test_files:
147
- - spec/integration/mount_spec.rb
148
- - spec/integration/params_spec.rb
149
156
  - spec/integration/rack_spec.rb
150
- - spec/integration/redirect_spec.rb
151
157
  - spec/spec_helper.rb
158
+ - spec/support/rack.rb
152
159
  - spec/unit/builder_spec.rb
160
+ - spec/unit/namespace_spec.rb
153
161
  - spec/unit/route_spec.rb
154
162
  - spec/unit/routes_spec.rb
155
163
  - spec/unit/rutter_spec.rb
data/bench/dynamic_routes DELETED
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env ruby -W0
2
-
3
- require_relative "helper"
4
-
5
- router = Rutter.new
6
- app = Rack::MockRequest.new(router)
7
-
8
- Benchmark.bm(50) do |b|
9
- b.report "generating routes" do
10
- DICT.each do |route|
11
- router.get "#{route}/:id", to: $endpoint
12
- end
13
- end
14
-
15
- b.report "recognizing routes" do
16
- TIMES.times do
17
- app.get("#{DICT.sample}/54")
18
- end
19
- end
20
- end
data/bench/expand DELETED
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env ruby -W0
2
-
3
- require_relative "helper"
4
-
5
- router = Rutter.new
6
-
7
- Benchmark.bm(50) do |b|
8
- b.report "generating routes" do
9
- DICT.each do |route|
10
- router.get "#{route}/:id", to: $endpoint, as: route
11
- end
12
- end
13
-
14
- b.report "expand routes" do
15
- TIMES.times do
16
- router.path(DICT.sample.to_sym, id: 54, key: "value")
17
- end
18
- end
19
- end
data/bench/helper.rb DELETED
@@ -1,19 +0,0 @@
1
- require "benchmark"
2
- require "rack"
3
- require_relative "../lib/rutter"
4
-
5
- BATCH_SIZE = 1000
6
- TIMES = 100000
7
- DICT = IO.foreach("/usr/share/dict/words")
8
- .lazy
9
- .map { |word| word.chomp.downcase }
10
- .uniq
11
- .take(BATCH_SIZE)
12
- .sort_by(&:length)
13
- .reverse
14
-
15
- $endpoint = ->(env) { [200, {}, ["Hello World"]] }
16
-
17
- puts "Loading #{BATCH_SIZE} routes, calling them #{TIMES} times...\n"
18
-
19
- GC.disable
data/bench/mount DELETED
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env ruby -W0
2
-
3
- require_relative "helper"
4
-
5
- router = Rutter.new
6
- app = Rack::MockRequest.new(router)
7
-
8
- DICT.each do |route|
9
- router.mount $endpoint, at: route
10
- end
11
-
12
- builder = Rack::Builder.app do
13
- DICT.each do |route|
14
- map("/#{route}") { run $endpoint }
15
- end
16
- end
17
-
18
- rack_app = Rack::MockRequest.new(builder)
19
-
20
- Benchmark.bm(50) do |b|
21
- b.report "recognizing mounts" do
22
- TIMES.times do
23
- app.get("/#{DICT.sample}/sub/path")
24
- end
25
- end
26
-
27
- b.report "recognizing rack map" do
28
- TIMES.times do
29
- rack_app.get("/#{DICT.sample}/sub/path")
30
- end
31
- end
32
- end
data/bench/routes_helper DELETED
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env ruby -W0
2
-
3
- require_relative "helper"
4
-
5
- router = Rutter.new
6
- routes = Rutter::Routes.new(router)
7
-
8
- DICT.each do |route|
9
- router.get "#{route}/:id", to: $endpoint, as: route
10
- end
11
-
12
- Benchmark.bm(50) do |b|
13
- b.report "dynamic *_path" do
14
- TIMES.times do
15
- routes.public_send "#{DICT.sample}_path", id: 54, key: "value"
16
- end
17
- end
18
-
19
- b.report "dynamic *_url" do
20
- TIMES.times do
21
- routes.public_send "#{DICT.sample}_url", id: 54, key: "value"
22
- end
23
- end
24
- end
data/bench/static_routes DELETED
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env ruby -W0
2
-
3
- require_relative "helper"
4
-
5
- router = Rutter.new
6
- app = Rack::MockRequest.new(router)
7
-
8
- Benchmark.bm(50) do |b|
9
- b.report "generating routes" do
10
- DICT.each do |route|
11
- router.get route, to: $endpoint
12
- end
13
- end
14
-
15
- b.report "recognizing routes" do
16
- TIMES.times do
17
- app.get(DICT.sample)
18
- end
19
- end
20
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe "Rutter::Builder#mount" do
4
- let(:router) do
5
- Rutter.new do
6
- mount ->(_env) { [200, {}, ["Admin App"]] }, at: "/admin"
7
- end
8
- end
9
-
10
- def app
11
- router.freeze
12
- end
13
-
14
- it "forwards the request to the given application" do
15
- get "/admin/with/sub/paths"
16
- expect(last_response.body).to eq("Admin App")
17
- end
18
- end