rutter 0.2.0 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68f5fb5ae85793cb16d135928e3a26cf043a3eda09338f8c2a03117a16985b2d
4
- data.tar.gz: c9766d83b10a8b6f103f26cc100ca753ecace464770fb739eccd4ecb2f2a876e
3
+ metadata.gz: aaf97ec12f6052df590a9a37d2979397122d416baffd31e60e18d12f932c6fff
4
+ data.tar.gz: 01ce145fe6f40151da57c92d4d7cf8acabb55e17c6b49ff82fdde2469f7838d2
5
5
  SHA512:
6
- metadata.gz: 1b0bcaae9355facffd058bf84021a4d62d1365312c254fd4e2ead08b6d907c68791572f47dc3451d35fcda32fb777ff3c94c5785b270cc290187aef3ce3e3260
7
- data.tar.gz: 10e3b47288658c8dd7068447339fa54981684e225542c4c05ac7440dc2fa3f2112c8461ac849b855e16c740e4357d0f7e673a49eabac946a762c21b028882d3a
6
+ metadata.gz: db521004f7e73d85d4c2f83482248a596dc3d4627bd1155c384c6d463c249547c1608053af0fdd8e9902c3ca168d822f33d9f84645f47ce349e049f24336d26c
7
+ data.tar.gz: a405208deab4e117809969d66d3e370d00fef1a505f8e53708d66f2f5ebb1d388d43cf46ed5a17bf03756f8cfe2965ec6070b1d39995c13132e850b4b48eae0e
data/.rubocop.yml CHANGED
@@ -1,8 +1,7 @@
1
- require:
2
- - rubocop-performance
3
-
1
+ require: rubocop-performance
4
2
  AllCops:
5
3
  TargetRubyVersion: 2.5
4
+ NewCops: enable
6
5
  DisplayCopNames: true
7
6
  Exclude:
8
7
  - "*.gemspec"
@@ -14,6 +13,9 @@ Performance:
14
13
  Style/StringLiterals:
15
14
  EnforcedStyle: double_quotes
16
15
 
16
+ Style/ClassAndModuleChildren:
17
+ Enabled: false
18
+
17
19
  Layout/EmptyLineAfterGuardClause:
18
20
  Enabled: false
19
21
 
@@ -27,9 +29,3 @@ Metrics/BlockLength:
27
29
  Metrics/ModuleLength:
28
30
  Exclude:
29
31
  - "spec/**/*"
30
-
31
- ClassAndModuleChildren:
32
- Enabled: false
33
-
34
- Naming/UncommunicativeMethodParamName:
35
- MinNameLength: 2
data/.travis.yml CHANGED
@@ -3,20 +3,15 @@ script: "bundle exec rake spec:coverage"
3
3
  cache: bundler
4
4
  env:
5
5
  global:
6
- - CC_TEST_REPORTER_ID=c1b17cd36cd4d025298f11b2a3ee678e4977c3969986f9ee497d6984a2c82c56
6
+ - CODECOV_TOKEN="21653af2-874b-4597-942d-14ddc7c2f8fa"
7
7
  before_install:
8
8
  - "gem update --system"
9
- before_script:
10
- - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
11
- - chmod +x ./cc-test-reporter
12
- - ./cc-test-reporter before-build
13
- after_script:
14
- - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
15
9
  rvm:
10
+ - 2.7.0
16
11
  - 2.6.0
17
12
  - 2.5.0
18
- - jruby-9.2.0.0
19
13
  - ruby-head
14
+ - jruby
20
15
  - jruby-head
21
16
  - truffleruby
22
17
  matrix:
data/Gemfile CHANGED
@@ -3,8 +3,8 @@
3
3
  source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
- unless ENV["CI"]
7
- gem "byebug", platform: :mri
8
- end
6
+ gem "rubocop"
7
+ gem "rubocop-performance"
9
8
 
10
9
  gem "simplecov"
10
+ gem 'codecov', require: false
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2019 Tobias Sandelius
3
+ Copyright (c) 2019-2020 Tobias Sandelius
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,13 +1,9 @@
1
1
  # Rutter
2
2
 
3
- HTTP router for Rack.
4
-
5
- ## Status
6
-
7
- Under development, not ready for prime-time just yet.
3
+ HTTP router for Ramverk and Rack.
8
4
 
9
5
  [![Build Status](https://travis-ci.org/sandelius/rutter.svg?branch=master)](https://travis-ci.org/sandelius/rutter)
10
- [![Test Coverage](https://codeclimate.com/github/sandelius/rutter/badges/coverage.svg)](https://codeclimate.com/github/sandelius/rutter/coverage)
6
+ [![codecov](https://codecov.io/gh/sandelius/rutter/branch/master/graph/badge.svg)](https://codecov.io/gh/sandelius/rutter)
11
7
  [![Inline docs](http://inch-ci.org/github/sandelius/rutter.svg?branch=master)](http://inch-ci.org/github/sandelius/rutter)
12
8
 
13
9
  ## Installation
data/bench/config.ru CHANGED
@@ -10,7 +10,7 @@ router = Rutter.new do
10
10
  get "/", to: ->(_) { [200, {}, ["Hello World"]] }
11
11
 
12
12
  # wrk -t 2 http://localhost:9292/ruby
13
- get "/:lang", to: ->(env) { [200, {}, [env["rutter.params"]["lang"]]] }
13
+ get "/:lang", to: ->(env) { [200, {}, [env["router.params"]["lang"]]] }
14
14
  end.freeze
15
15
 
16
16
  run router
data/lib/rutter.rb CHANGED
@@ -1,10 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "rutter/version"
4
- require_relative "rutter/builder"
5
-
6
3
  # HTTP router for Rack.
7
4
  module Rutter
5
+ # Supported request verbs.
6
+ #
7
+ # @return [Array]
8
+ VERBS = %w[GET POST PUT PATCH DELETE OPTIONS].freeze
9
+
10
+ require_relative "rutter/version"
11
+ require_relative "rutter/builder"
12
+
8
13
  # Factory method for creating a new builder object.
9
14
  #
10
15
  # @param base [String]
@@ -3,7 +3,6 @@
3
3
  require "uri"
4
4
 
5
5
  require_relative "naming"
6
- require_relative "verbs"
7
6
  require_relative "route"
8
7
  require_relative "mount"
9
8
  require_relative "scope"
@@ -40,7 +39,7 @@ module Rutter
40
39
  def initialize(base: "http://localhost:9292", &block)
41
40
  @uri = URI(base).freeze
42
41
  @flat_map = []
43
- @verb_map = Hash.new { |h, k| h[k] = [] }
42
+ @verb_map = VERBS.map { |v| [v, []] }.to_h
44
43
  @named_map = {}
45
44
 
46
45
  instance_eval(&block) if block_given?
@@ -91,10 +90,12 @@ module Rutter
91
90
  # Application to mount.
92
91
  # @param at [String]
93
92
  # Path prefix to match.
93
+ # @param host [Regexp]
94
+ # Match the given host pattern.
94
95
  #
95
96
  # @return [Rutter::Mount]
96
- def mount(app, at:)
97
- route = Mount.new(at, app)
97
+ def mount(app, at:, host: nil)
98
+ route = Mount.new(at, app, host: host)
98
99
  @flat_map << route
99
100
  VERBS.each { |verb| @verb_map[verb] << route }
100
101
  route
@@ -131,12 +132,12 @@ module Rutter
131
132
  # # => "/login?return_to=/"
132
133
  # router.path(:book, id: 82)
133
134
  # # => "/books/82"
134
- def path(name, *args)
135
+ def path(name, **args)
135
136
  unless (route = @named_map[name])
136
137
  raise "No route called '#{name}' was found"
137
138
  end
138
139
 
139
- route.expand(*args)
140
+ route.expand(**args)
140
141
  end
141
142
 
142
143
  # Generates a full URL from the given arguments.
@@ -178,7 +179,7 @@ module Rutter
178
179
  host += "#{args.delete(:subdomain)}." if args.key?(:subdomain)
179
180
  host += @uri.host
180
181
  host += ":#{@uri.port}" if @uri.port != 80 && @uri.port != 443
181
- host + path(name, args)
182
+ host + path(name, **args)
182
183
  end
183
184
 
184
185
  # Add a new, frozen, route to the map.
@@ -193,14 +194,23 @@ module Rutter
193
194
  # Route name/identifier.
194
195
  # @param constraints [Hash]
195
196
  # Route segment constraints.
197
+ # @param &block [Proc]
198
+ # Endpoint as a block.
199
+ # @yieldparam env [Hash]
200
+ # Rack's environment hash.
196
201
  #
197
202
  # @return [Rutter::Route]
198
203
  #
199
204
  # @raise [ArgumentError]
200
205
  # If verb is unsupported.
206
+ # @raise [ArgumentError]
207
+ # If endpoint is missing.
201
208
  #
202
209
  # @private
203
- def add(verb, path, to:, as: nil, constraints: nil)
210
+ def add(verb, path, to: nil, as: nil, constraints: nil, &block)
211
+ to = block if block_given?
212
+ raise "Missing endpoint" unless to
213
+
204
214
  verb = verb.to_s.upcase
205
215
 
206
216
  unless VERBS.include?(verb)
@@ -229,8 +239,8 @@ module Rutter
229
239
 
230
240
  # @see #add
231
241
  VERBS.each do |verb|
232
- define_method verb.downcase do |path, to:, as: nil, constraints: nil|
233
- add verb, path, to: to, as: as, constraints: constraints
242
+ define_method verb.downcase do |path, to: nil, as: nil, constraints: nil, &block|
243
+ add verb, path, to: to, as: as, constraints: constraints, &block
234
244
  end
235
245
  end
236
246
 
data/lib/rutter/mount.rb CHANGED
@@ -7,6 +7,15 @@ module Rutter
7
7
  #
8
8
  # @private
9
9
  class Mount < Route
10
+ # @see Rutter::Route#initialize
11
+ #
12
+ # @private
13
+ def initialize(path, endpoint, constraints = nil, host: nil)
14
+ @host = host
15
+
16
+ super(path, endpoint, constraints)
17
+ end
18
+
10
19
  # Matches the app pattern against environment.
11
20
  #
12
21
  # @param env [Hash]
@@ -15,7 +24,22 @@ module Rutter
15
24
  # @return [nil, String]
16
25
  # Returns the matching substring or nil on no match.
17
26
  def match?(env)
27
+ return if @host && !@host.match?(host(env))
28
+
18
29
  @pattern.peek(env["PATH_INFO"])
19
30
  end
31
+
32
+ private
33
+
34
+ # @private
35
+ def host(env)
36
+ env["rutter.parsed_host"] ||= begin
37
+ if (forwarded = env["HTTP_X_FORWARDED_HOST"])
38
+ forwarded.split(/,\s?/).last
39
+ else
40
+ env["HTTP_HOST"] || env["SERVER_NAME"] || env["SERVER_ADDR"]
41
+ end
42
+ end
43
+ end
20
44
  end
21
45
  end
data/lib/rutter/route.rb CHANGED
@@ -71,7 +71,7 @@ module Rutter
71
71
  #
72
72
  # @return [Hash]
73
73
  def params(path)
74
- @pattern.params(path)
74
+ @pattern.params(path) || {}
75
75
  end
76
76
 
77
77
  # Calls the endpoint.
@@ -84,8 +84,8 @@ module Rutter
84
84
  #
85
85
  # @private
86
86
  def call(env)
87
- env["rutter.params"] ||= {}
88
- env["rutter.params"].merge!(params(env["PATH_INFO"]))
87
+ env["router.params"] ||= {}
88
+ env["router.params"].merge!(params(env["PATH_INFO"]))
89
89
  env["rutter.action"] = @endpoint[:action]
90
90
 
91
91
  ctrl = @endpoint[:controller]
data/lib/rutter/routes.rb CHANGED
@@ -53,10 +53,11 @@ module Rutter
53
53
  protected
54
54
 
55
55
  # @private
56
- def method_missing(method_name, *args)
56
+ def method_missing(method_name, **args)
57
57
  named_route, type = method_name.to_s.split(/\_(path|url)\z/)
58
58
  return super unless type
59
- @router.public_send(type, named_route.to_sym, *args)
59
+
60
+ @router.public_send(type, named_route.to_sym, **args)
60
61
  end
61
62
 
62
63
  # @private
data/lib/rutter/scope.rb CHANGED
@@ -34,8 +34,8 @@ module Rutter
34
34
  end
35
35
 
36
36
  # @see Rutter::Builder#mount
37
- def mount(app, at:)
38
- @router.mount app, at: Naming.join(@path, at)
37
+ def mount(app, at:, host: nil)
38
+ @router.mount app, at: Naming.join(@path, at), host: host
39
39
  end
40
40
 
41
41
  # @see Rutter::Builder#scope
@@ -49,18 +49,18 @@ module Rutter
49
49
  end
50
50
 
51
51
  # @see Rutter::Builder#add
52
- def add(verb, path, to:, as: nil, constraints: nil)
52
+ def add(verb, path, to: nil, as: nil, constraints: nil, &block)
53
53
  path = Naming.join(@path, path)
54
54
  to = Naming.join(@namespace, to) if to.is_a?(String)
55
55
  as = Naming.join(@as, as) if as
56
56
 
57
- @router.add verb, path, to: to, as: as, constraints: constraints
57
+ @router.add verb, path, to: to, as: as, constraints: constraints, &block
58
58
  end
59
59
 
60
60
  # @see Rutter::Builder#add
61
61
  VERBS.each do |verb|
62
- define_method verb.downcase do |path, to:, as: nil, constraints: nil|
63
- add verb, path, to: to, as: as, constraints: constraints
62
+ define_method verb.downcase do |path, to: nil, as: nil, constraints: nil, &block|
63
+ add verb, path, to: to, as: as, constraints: constraints, &block
64
64
  end
65
65
  end
66
66
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Rutter
4
4
  # Current version number.
5
- VERSION = "0.2.0"
5
+ VERSION = "0.3.3"
6
6
  end
data/rutter.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.test_files = spec.files.grep(%r{^(spec)/})
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_runtime_dependency "mustermann", "~> 1.0"
23
+ spec.add_runtime_dependency "mustermann", "~> 1.1"
24
24
  spec.add_runtime_dependency "rack", "~> 2.0"
25
25
 
26
26
  spec.add_development_dependency "bundler"
@@ -4,7 +4,7 @@ RSpec.describe "Rack compatible", type: :request do
4
4
  let :router do
5
5
  Rutter.new do
6
6
  get "/say/:message", to: (lambda do |env|
7
- [200, {}, ["I say, #{env['rutter.params']['message']}"]]
7
+ [200, {}, ["I say, #{env['router.params']['message']}"]]
8
8
  end)
9
9
  end
10
10
  end
@@ -21,8 +21,6 @@ RSpec.describe "Rack compatible", type: :request do
21
21
  .to eq(200)
22
22
  expect(last_response.body)
23
23
  .to eq("I say, hello-world")
24
- expect(last_response.headers["Content-Length"])
25
- .to eq("18")
26
24
  end
27
25
  end
28
26
 
data/spec/spec_helper.rb CHANGED
@@ -2,10 +2,6 @@
2
2
 
3
3
  require "bundler/setup"
4
4
 
5
- unless ENV["CI"]
6
- require "byebug"
7
- end
8
-
9
5
  if ENV["COVERAGE"] == "true"
10
6
  require "simplecov"
11
7
 
@@ -13,6 +9,11 @@ if ENV["COVERAGE"] == "true"
13
9
  command_name "spec"
14
10
  add_filter "spec"
15
11
  end
12
+
13
+ if ENV["CODECOV_TOKEN"]
14
+ require "codecov"
15
+ SimpleCov.formatter = SimpleCov::Formatter::Codecov
16
+ end
16
17
  end
17
18
 
18
19
  # Require support (helper) modules
@@ -18,6 +18,23 @@ module Rutter
18
18
  expect(route.match?(env_for("/admin/books")))
19
19
  .to eq("/admin")
20
20
  end
21
+
22
+ it "matches host if given" do
23
+ route = router.mount endpoint, at: "/v1", host: /\Aapi\./
24
+
25
+ expect(route.match?(env_for("http://example.com/v1/books")))
26
+ .to be_nil
27
+ expect(route.match?(env_for("http://api.example.com/v1/books")))
28
+ .to eq("/v1")
29
+ end
30
+
31
+ it "HTTP_X_FORWARDED_HOST are supported" do
32
+ route = router.mount endpoint, at: "/v1", host: /\Aapi\./
33
+ env = env_for("/v1/books", "HTTP_X_FORWARDED_HOST" => "api.example.com")
34
+
35
+ expect(route.match?(env))
36
+ .to eq("/v1")
37
+ end
21
38
  end
22
39
 
23
40
  describe "#path" do
@@ -90,6 +107,24 @@ module Rutter
90
107
  expect(route.match?(env_for("/books/pickaxe")))
91
108
  .to be(false)
92
109
  end
110
+
111
+ it "support block as endpoint" do
112
+ router.get "/" do |env|
113
+ [200, {}, [env["message"]]]
114
+ end
115
+
116
+ _, _, body = router.call("REQUEST_METHOD" => "GET",
117
+ "PATH_INFO" => "/",
118
+ "message" => "Hello World")
119
+
120
+ expect(body.join)
121
+ .to eq("Hello World")
122
+ end
123
+
124
+ it "raises an error if no endpoint is given" do
125
+ expect { router.get "/" }
126
+ .to raise_error("Missing endpoint")
127
+ end
93
128
  end
94
129
 
95
130
  describe "verbs" do
@@ -59,6 +59,13 @@ module Rutter
59
59
  expect(route.params("/pages/54"))
60
60
  .to eq("id" => "54", "title" => nil)
61
61
  end
62
+
63
+ it "returns always return a hash" do
64
+ route = Route.new("/pages", endpoint)
65
+
66
+ expect(route.params("/pages"))
67
+ .to eq({})
68
+ end
62
69
  end
63
70
  end
64
71
  end
@@ -34,6 +34,20 @@ module Rutter
34
34
  expect(route.match?(env_for("/books/pickaxe")))
35
35
  .to be(false)
36
36
  end
37
+
38
+ it "support block as endpoint" do
39
+ scope = router.scope path: "/books"
40
+ scope.get "/" do |env|
41
+ [200, {}, [env["message"]]]
42
+ end
43
+
44
+ _, _, body = router.call("REQUEST_METHOD" => "GET",
45
+ "PATH_INFO" => "/books",
46
+ "message" => "Hello World")
47
+
48
+ expect(body.join)
49
+ .to eq("Hello World")
50
+ end
37
51
  end
38
52
 
39
53
  describe "#mount" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rutter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Sandelius
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-28 00:00:00.000000000 Z
11
+ date: 2021-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mustermann
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '1.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '1.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rack
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -117,7 +117,6 @@ files:
117
117
  - lib/rutter/route.rb
118
118
  - lib/rutter/routes.rb
119
119
  - lib/rutter/scope.rb
120
- - lib/rutter/verbs.rb
121
120
  - lib/rutter/version.rb
122
121
  - rutter.gemspec
123
122
  - spec/integration/rack_spec.rb
data/lib/rutter/verbs.rb DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rutter
4
- # Supported request verbs.
5
- #
6
- # @return [Array]
7
- VERBS = %w[GET POST PUT PATCH DELETE OPTIONS].freeze
8
- end