rutter 0.2.0 → 0.3.3

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.
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