ruter 1.0.0
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +36 -0
- data/lib/ruter/core/request.rb +57 -0
- data/lib/ruter/core/response.rb +199 -0
- data/lib/ruter/core.rb +75 -0
- data/lib/ruter/middleware.rb +40 -0
- data/lib/ruter/plugin.rb +67 -0
- data/lib/ruter/settings.rb +90 -0
- data/lib/ruter/test.rb +199 -0
- data/lib/ruter/version.rb +8 -0
- data/lib/ruter.rb +14 -0
- data/test/ruter/core_test.rb +90 -0
- data/test/ruter/middleware_test.rb +95 -0
- data/test/ruter/plugin_test.rb +54 -0
- data/test/ruter/settings_test.rb +47 -0
- data/test/test_helper.rb +8 -0
- metadata +175 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c3af735d50b376a560325bd054bf4c6102db10476e7ad775e42f064b17473c4f
|
4
|
+
data.tar.gz: 5ef9e856f019be81b88356fb633bd6796dd2338af22f80717b10a12f4d9039b0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ca30469bc6740c48d41c4b4b865ed4521c85129262ab5460b1b8097f53a65c27bec99aebb78331d4caf7479a7a2cfc122ece02d1583151266d169748174c29d1
|
7
|
+
data.tar.gz: 37926e251e5a8bf557c4c9a4e734c0216b7663b1770a47e322b76ab82ae31d7eb07c983f4e3dbd4db016921cbceef95ab1b923e56a6132ff7bfc61801dcc7c02
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2021 Francesco Rodríguez and contributors
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
Ruter [](https://app.travis-ci.com/frodsan/ruter)
|
2
|
+
====
|
3
|
+
|
4
|
+
"You must buy a ticket before entering the bus" - The Inspector 🕵🏻♂️
|
5
|
+
|
6
|
+
Description
|
7
|
+
-----------
|
8
|
+
|
9
|
+
Ruter is yet another [Rack][rack] based framework, made for fun and ~~profit~~, and built on top of [Syro][syro].
|
10
|
+
|
11
|
+
Usage
|
12
|
+
-----
|
13
|
+
|
14
|
+
Here's a minimal application:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
# config.ru
|
18
|
+
require "ruter"
|
19
|
+
|
20
|
+
Ruter.define do
|
21
|
+
get do
|
22
|
+
res.write("Hello World!")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
run(Ruter) # run!
|
27
|
+
```
|
28
|
+
|
29
|
+
License
|
30
|
+
-------
|
31
|
+
|
32
|
+
Ruter is released under the [MIT License][mit].
|
33
|
+
|
34
|
+
[mit]: http://www.opensource.org/licenses/MIT
|
35
|
+
[rack]: https://github.com/rack/rack
|
36
|
+
[syro]: http://soveran.github.io/syro/
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "rack/request"
|
2
|
+
|
3
|
+
class Ruter
|
4
|
+
module Core
|
5
|
+
# Public: It provides convenience methods for pulling out information
|
6
|
+
# from a request.
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
#
|
10
|
+
# env = {
|
11
|
+
# "REQUEST_METHOD" => "GET"
|
12
|
+
# "QUERY_STRING" => "email=me@ruter.xyz"
|
13
|
+
# }
|
14
|
+
#
|
15
|
+
# req = Ruter::Core::Request.new(env)
|
16
|
+
#
|
17
|
+
# req.get? # => true
|
18
|
+
# req.post? # => false
|
19
|
+
#
|
20
|
+
# req.params # => { "email" => "me@ruter.xyz" }
|
21
|
+
# req[:email] # => "me@ruter.xyz"
|
22
|
+
#
|
23
|
+
class Request < Rack::Request
|
24
|
+
# Public: Returns the value of the +key+ param.
|
25
|
+
#
|
26
|
+
# key - Any object that responds to +to_s+.
|
27
|
+
#
|
28
|
+
# Examples
|
29
|
+
#
|
30
|
+
# req.params
|
31
|
+
# # => { "username" => "bob" }
|
32
|
+
#
|
33
|
+
# req[:username] # => "bob"
|
34
|
+
# req["username"] # => "bob"
|
35
|
+
#
|
36
|
+
# Signature
|
37
|
+
#
|
38
|
+
# [](key)
|
39
|
+
#
|
40
|
+
# Inherited by Rack::Request.
|
41
|
+
|
42
|
+
# Public: Returns a Hash of parameters. Includes data from the query
|
43
|
+
# string and the response body.
|
44
|
+
#
|
45
|
+
# Examples
|
46
|
+
#
|
47
|
+
# req.params
|
48
|
+
# # => { "user" => { "username" => "bob" } }
|
49
|
+
#
|
50
|
+
# Signature
|
51
|
+
#
|
52
|
+
# params()
|
53
|
+
#
|
54
|
+
# Inherited by Rack::Request.
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
class Ruter
|
2
|
+
module Core
|
3
|
+
# Public: It provides convenience methods to construct a Rack response.
|
4
|
+
#
|
5
|
+
# Examples
|
6
|
+
#
|
7
|
+
# res = Ruter::Core::Response.new
|
8
|
+
#
|
9
|
+
# res.status = 200
|
10
|
+
# res["Content-Type"] = "text/html"
|
11
|
+
# res.write("foo")
|
12
|
+
#
|
13
|
+
# res.finish
|
14
|
+
# # => [200, { "Content-Type" => "text/html", "Content-Length" => 3 }, ["foo"]]
|
15
|
+
#
|
16
|
+
class Response < Syro::Response
|
17
|
+
# Public: Initializes a new response object.
|
18
|
+
#
|
19
|
+
# headers - A Hash of initial headers. Defaults to <tt>{}</tt>.
|
20
|
+
#
|
21
|
+
# Examples
|
22
|
+
#
|
23
|
+
# Ruter::Core::Response.new.headers
|
24
|
+
# # => {}
|
25
|
+
#
|
26
|
+
# Ruter::Core::Response.new("Content-Type" => "text/plain").headers
|
27
|
+
# # => { "Content-Type" => "text/plain" }
|
28
|
+
#
|
29
|
+
# Signature
|
30
|
+
#
|
31
|
+
# new(headers = {})
|
32
|
+
#
|
33
|
+
# Inherited by Syro::Response.
|
34
|
+
|
35
|
+
# Public: Returns the response header corresponding to +key+.
|
36
|
+
#
|
37
|
+
# key - A String HTTP header field name.
|
38
|
+
#
|
39
|
+
# Examples
|
40
|
+
#
|
41
|
+
# res["Content-Type"] # => "text/html"
|
42
|
+
# res["Content-Length"] # => "42"
|
43
|
+
#
|
44
|
+
# Signature
|
45
|
+
#
|
46
|
+
# [](key)
|
47
|
+
#
|
48
|
+
# Inherited by Syro::Response.
|
49
|
+
|
50
|
+
# Public: Sets the given +value+ with the header corresponding to +key+.
|
51
|
+
#
|
52
|
+
# key - A String HTTP header field name.
|
53
|
+
# value - A String HTTP header field value.
|
54
|
+
#
|
55
|
+
# Examples
|
56
|
+
#
|
57
|
+
# res["Content-Type"] = "application/json"
|
58
|
+
# res["Content-Type"] # => "application/json"
|
59
|
+
#
|
60
|
+
# Signature
|
61
|
+
#
|
62
|
+
# []=(key, value)
|
63
|
+
#
|
64
|
+
# Inherited by Syro::Response.
|
65
|
+
|
66
|
+
# Public: Returns the body of the response.
|
67
|
+
#
|
68
|
+
# Examples
|
69
|
+
#
|
70
|
+
# res.body
|
71
|
+
# # => []
|
72
|
+
#
|
73
|
+
# res.write("there is")
|
74
|
+
# res.write("no try")
|
75
|
+
#
|
76
|
+
# res.body
|
77
|
+
# # => ["there is", "no try"]
|
78
|
+
#
|
79
|
+
# Signature
|
80
|
+
#
|
81
|
+
# body()
|
82
|
+
#
|
83
|
+
# Inherited by Syro::Response.
|
84
|
+
|
85
|
+
# Public: Returns an Array with three elements: the status, headers
|
86
|
+
# and body. If the status is not set, the status is set to +404+ if
|
87
|
+
# empty body, otherwise the status is set to +200+ and updates the
|
88
|
+
# +Content-Type+ header to +text/html+.
|
89
|
+
#
|
90
|
+
# Examples
|
91
|
+
#
|
92
|
+
# res.status = 200
|
93
|
+
# res.finish
|
94
|
+
# # => [200, {}, []]
|
95
|
+
#
|
96
|
+
# res.status = nil
|
97
|
+
# res.finish
|
98
|
+
# # => [404, {}, []]
|
99
|
+
#
|
100
|
+
# res.status = nil
|
101
|
+
# res.write("yo")
|
102
|
+
# res.finish
|
103
|
+
# # => [200, { "Content-Type" => "text/html", "Content-Length" => 2 }, ["yo"]]
|
104
|
+
#
|
105
|
+
# Signature
|
106
|
+
#
|
107
|
+
# finish()
|
108
|
+
#
|
109
|
+
# Inherited by Syro::Response.
|
110
|
+
|
111
|
+
# Public: Returns a Hash with the response headers.
|
112
|
+
#
|
113
|
+
# Examples
|
114
|
+
#
|
115
|
+
# res.headers
|
116
|
+
# # => { "Content-Type" => "text/html", "Content-Length" => "42" }
|
117
|
+
#
|
118
|
+
# Signature
|
119
|
+
#
|
120
|
+
# headers()
|
121
|
+
#
|
122
|
+
# Inherited by Syro::Response.
|
123
|
+
|
124
|
+
# Public: Sets the +Location+ header to +url+ and updates the status
|
125
|
+
# to +status+.
|
126
|
+
#
|
127
|
+
# url - A String URL (relative or absolute) to redirect to.
|
128
|
+
# status - An Integer status code. Defaults to +302+.
|
129
|
+
#
|
130
|
+
# Examples
|
131
|
+
#
|
132
|
+
# res.redirect("/path")
|
133
|
+
#
|
134
|
+
# res["Location"] # => "/path"
|
135
|
+
# res.status # => 302
|
136
|
+
#
|
137
|
+
# res.redirect("http://ruter.xyz", 303)
|
138
|
+
#
|
139
|
+
# res["Location"] # => "http://ruter.xyz"
|
140
|
+
# res.status # => 303
|
141
|
+
#
|
142
|
+
# Signature
|
143
|
+
#
|
144
|
+
# redirect(url, status = 302)
|
145
|
+
#
|
146
|
+
# Inherited by Syro::Response.
|
147
|
+
|
148
|
+
# Public: Returns the status of the response.
|
149
|
+
#
|
150
|
+
# Examples
|
151
|
+
#
|
152
|
+
# res.status # => 200
|
153
|
+
#
|
154
|
+
# Signature
|
155
|
+
#
|
156
|
+
# status()
|
157
|
+
#
|
158
|
+
# Inherited by Syro::Response.
|
159
|
+
|
160
|
+
# Public: Sets the status of the response.
|
161
|
+
#
|
162
|
+
# status - An Integer HTTP status code.
|
163
|
+
#
|
164
|
+
# Examples
|
165
|
+
#
|
166
|
+
# res.status = 200
|
167
|
+
#
|
168
|
+
# Signature
|
169
|
+
#
|
170
|
+
# status=(status)
|
171
|
+
#
|
172
|
+
# Inherited by Syro::Response.
|
173
|
+
|
174
|
+
# Public: Appends +str+ to the response body and updates the
|
175
|
+
# +Content-Length+ header.
|
176
|
+
#
|
177
|
+
# str - Any object that responds to +to_s+.
|
178
|
+
#
|
179
|
+
# Examples
|
180
|
+
#
|
181
|
+
# res.body # => []
|
182
|
+
#
|
183
|
+
# res.write("foo")
|
184
|
+
# res.write("bar")
|
185
|
+
#
|
186
|
+
# res.body
|
187
|
+
# # => ["foo", "bar"]
|
188
|
+
#
|
189
|
+
# res["Content-Length"]
|
190
|
+
# # => 6
|
191
|
+
#
|
192
|
+
# Signature
|
193
|
+
#
|
194
|
+
# write(str)
|
195
|
+
#
|
196
|
+
# Inherited by Syro::Response.
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
data/lib/ruter/core.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require "rack"
|
2
|
+
require "syro"
|
3
|
+
require_relative "core/request"
|
4
|
+
require_relative "core/response"
|
5
|
+
|
6
|
+
class Ruter
|
7
|
+
# Include Syro's API directly instead of using the plugin
|
8
|
+
# system to be able to override any of its methods.
|
9
|
+
include Syro::Deck::API
|
10
|
+
|
11
|
+
# Internal: Handles Syro integration.
|
12
|
+
module Core
|
13
|
+
module ClassMethods
|
14
|
+
# Public: Sets the application handler.
|
15
|
+
#
|
16
|
+
# Examples
|
17
|
+
#
|
18
|
+
# class Users < Ruter
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# Users.define do
|
22
|
+
# on("/users") do
|
23
|
+
# get do
|
24
|
+
# res.write("GET /users")
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# post do
|
28
|
+
# res.write("POST /users")
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
def define(&block)
|
34
|
+
build_app(Syro.new(self, &block))
|
35
|
+
end
|
36
|
+
|
37
|
+
private def build_app(syro)
|
38
|
+
@_app = syro
|
39
|
+
end
|
40
|
+
|
41
|
+
# Internal: Required by the Syro API.
|
42
|
+
def implement(&code) # :nodoc:
|
43
|
+
Class.new(self) do
|
44
|
+
define_method(:dispatch!, code)
|
45
|
+
|
46
|
+
private :dispatch!
|
47
|
+
|
48
|
+
define_method(:inspect) do
|
49
|
+
self.class.superclass.inspect
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Internal: Required by the Rack API.
|
55
|
+
def call(env) # :nodoc:
|
56
|
+
@_app.call(env)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Internal: Used for internal testing.
|
60
|
+
def reset! # :nodoc:
|
61
|
+
@_app = nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
module InstanceMethods
|
66
|
+
def request_class # :nodoc:
|
67
|
+
Ruter::Core::Request
|
68
|
+
end
|
69
|
+
|
70
|
+
def response_class # :nodoc:
|
71
|
+
Ruter::Core::Response
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Ruter
|
2
|
+
# Public: Ruter's middleware system.
|
3
|
+
module Middleware
|
4
|
+
module ClassMethods
|
5
|
+
# Public: Adds given Rack +middleware+ to the stack.
|
6
|
+
#
|
7
|
+
# Examples
|
8
|
+
#
|
9
|
+
# require "rack/common_logger"
|
10
|
+
# require "rack/show_exceptions"
|
11
|
+
#
|
12
|
+
# Ruter.use(Rack::CommonLogger)
|
13
|
+
# Ruter.use(Rack::ShowExceptions)
|
14
|
+
#
|
15
|
+
def use(middleware, *args, &block)
|
16
|
+
self.middleware << proc { |app| middleware.new(app, *args, &block) }
|
17
|
+
end
|
18
|
+
|
19
|
+
# Internal: Returns middleware stack.
|
20
|
+
def middleware # :nodoc:
|
21
|
+
@_middleware ||= []
|
22
|
+
end
|
23
|
+
|
24
|
+
# Internal: Used for internal testing.
|
25
|
+
def reset! # :nodoc:
|
26
|
+
super
|
27
|
+
@_middleware = []
|
28
|
+
end
|
29
|
+
|
30
|
+
# Internal: Overrides app composition from core.
|
31
|
+
private def build_app(syro)
|
32
|
+
@_app = if middleware.empty?
|
33
|
+
syro
|
34
|
+
else
|
35
|
+
middleware.reverse.inject(syro) { |a, m| m.call(a) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/ruter/plugin.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
class Ruter
|
2
|
+
# Public: Ruter's plugin system.
|
3
|
+
module Plugin
|
4
|
+
# Public: Loads given +plugin+ into the application.
|
5
|
+
#
|
6
|
+
# Examples
|
7
|
+
#
|
8
|
+
# require "ruter"
|
9
|
+
# require "ruter/protection"
|
10
|
+
# require "ruter/session"
|
11
|
+
#
|
12
|
+
# # Use some standard plugins
|
13
|
+
#
|
14
|
+
# Ruter.plugin(Ruter::Protection)
|
15
|
+
# Ruter.plugin(Ruter::Session, secret: "__a_random_secret_key__")
|
16
|
+
#
|
17
|
+
# # Make your own custom plugin:
|
18
|
+
#
|
19
|
+
# require "redcarpet"
|
20
|
+
#
|
21
|
+
# class MarkdownPlugin
|
22
|
+
# def self.setup(app, options = {})
|
23
|
+
# app.settings[:markdown_options] = options
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# module ClassMethods
|
27
|
+
# def markdown_renderer
|
28
|
+
# @_markdown_renderer ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, markdown_options)
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# def markdown_options
|
32
|
+
# settings[:markdown_options]
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# module InstanceMethods
|
37
|
+
# def markdown(text)
|
38
|
+
# res.write(markdown_renderer.render(text))
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# Ruter.plugin(MarkdownPlugin, fenced_code_blocks: true)
|
44
|
+
#
|
45
|
+
# Ruter.define do
|
46
|
+
# root do
|
47
|
+
# get do
|
48
|
+
# markdown("This is *bongos*, indeed.")
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
def plugin(plugin, *args, &block)
|
54
|
+
if defined?(plugin::InstanceMethods)
|
55
|
+
include(plugin::InstanceMethods)
|
56
|
+
end
|
57
|
+
|
58
|
+
if defined?(plugin::ClassMethods)
|
59
|
+
extend(plugin::ClassMethods)
|
60
|
+
end
|
61
|
+
|
62
|
+
if plugin.respond_to?(:setup)
|
63
|
+
plugin.setup(self, *args, &block)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
class Ruter
|
2
|
+
# Public: It provides a settings API for Ruter applications.
|
3
|
+
#
|
4
|
+
# Examples
|
5
|
+
#
|
6
|
+
# require "ruter"
|
7
|
+
#
|
8
|
+
# module AppName
|
9
|
+
# def self.setup(app, app_name)
|
10
|
+
# app.settings[:app_name] = app_name
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# module ClassMethods
|
14
|
+
# def app_name
|
15
|
+
# return settings[:app_name]
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Ruter.plugin(AppName, "MyApp")
|
21
|
+
#
|
22
|
+
# Ruter.app_name
|
23
|
+
# # => "MyApp"
|
24
|
+
#
|
25
|
+
module Settings
|
26
|
+
# Internal: Returns a deep copy of a Hash.
|
27
|
+
def self.deepclone(hash) # :nodoc:
|
28
|
+
default_proc, hash.default_proc = hash.default_proc, nil
|
29
|
+
|
30
|
+
Marshal.load(Marshal.dump(hash))
|
31
|
+
ensure
|
32
|
+
hash.default_proc = default_proc
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
# Internal: Copies settings into the subclass.
|
37
|
+
# If a setting is not found, checks parent's settings.
|
38
|
+
def inherited(subclass)
|
39
|
+
subclass.settings.replace(Ruter::Settings.deepclone(settings))
|
40
|
+
subclass.settings.default_proc = proc { |h, k| h[k] = settings[k] }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Public: Sets an +option+ to the given +value+.
|
44
|
+
#
|
45
|
+
# Examples
|
46
|
+
#
|
47
|
+
# Ruter.set(:environment, :staging)
|
48
|
+
#
|
49
|
+
# Ruter.environment
|
50
|
+
# # => :staging
|
51
|
+
#
|
52
|
+
def set(option, value)
|
53
|
+
settings[option] = value
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns a Hash with the application settings.
|
57
|
+
#
|
58
|
+
# Examples
|
59
|
+
#
|
60
|
+
# Ruter.set(:environment, :development)
|
61
|
+
#
|
62
|
+
# Ruter.settings
|
63
|
+
# # => { :environment => :development }
|
64
|
+
#
|
65
|
+
def settings
|
66
|
+
@settings ||= {}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
module InstanceMethods
|
71
|
+
# Returns a Hash with the application settings.
|
72
|
+
#
|
73
|
+
# Examples
|
74
|
+
#
|
75
|
+
# Ruter.set(:environment, :development)
|
76
|
+
#
|
77
|
+
# Ruter.define do
|
78
|
+
# get do
|
79
|
+
# res.write(settings[:environment])
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# GET / # => 200 "development"
|
84
|
+
#
|
85
|
+
def settings
|
86
|
+
self.class.settings
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/ruter/test.rb
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
class Ruter
|
2
|
+
# Public: A simple helper class to simulate requests to your application.
|
3
|
+
#
|
4
|
+
# Examples
|
5
|
+
#
|
6
|
+
# require "ruter"
|
7
|
+
# require "ruter/test"
|
8
|
+
#
|
9
|
+
# Ruter.define do
|
10
|
+
# root do
|
11
|
+
# res.write("hei")
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# app = Ruter::Test.new
|
16
|
+
# app.get("/")
|
17
|
+
#
|
18
|
+
# app.res.status # => 200
|
19
|
+
# app.res.body # => "hei"
|
20
|
+
#
|
21
|
+
class Test
|
22
|
+
# Public: Initializes a new Ruter::Test object.
|
23
|
+
#
|
24
|
+
# app - The application class to test (default: Ruter).
|
25
|
+
#
|
26
|
+
# Examples
|
27
|
+
#
|
28
|
+
# class API < Ruter
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# app = Ruter::Test.new(API)
|
32
|
+
# app.get("/json")
|
33
|
+
#
|
34
|
+
def initialize(app = Ruter)
|
35
|
+
@app = app
|
36
|
+
end
|
37
|
+
|
38
|
+
# Internal: Returns the application class that handles the
|
39
|
+
# mock requests. Required by Ruter::Test::InstanceMethods.
|
40
|
+
attr_reader :app
|
41
|
+
|
42
|
+
# Internal: This module provides the Ruter::Test API methods.
|
43
|
+
# If you don't like the stand-alone version, you can integrate
|
44
|
+
# this module to your preferred testing environment.
|
45
|
+
#
|
46
|
+
# The following example uses Minitest:
|
47
|
+
#
|
48
|
+
# class HomeTest < Minitest::Test
|
49
|
+
# include Ruter::Test::InstanceMethods
|
50
|
+
#
|
51
|
+
# def app
|
52
|
+
# return Ruter
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# def test_home
|
56
|
+
# get("/")
|
57
|
+
#
|
58
|
+
# assert_equal 200, res.status
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
module InstanceMethods
|
63
|
+
# Public: Returns the current request object or +nil+ if no requests
|
64
|
+
# have been issued yet.
|
65
|
+
#
|
66
|
+
# Examples
|
67
|
+
#
|
68
|
+
# app = Ruter::Test.new
|
69
|
+
# app.get("/", {}, { "HTTP_USER_AGENT" => "Ruter::Test" })
|
70
|
+
#
|
71
|
+
# app.req.get?
|
72
|
+
# # => true
|
73
|
+
#
|
74
|
+
# app.req.env["HTTP_USER_AGENT"]
|
75
|
+
# # => "Ruter::Test"
|
76
|
+
#
|
77
|
+
# The returned object is an instance of
|
78
|
+
# {Rack::Request}[http://www.rubydoc.info/gems/rack/Rack/Request].
|
79
|
+
#
|
80
|
+
def req
|
81
|
+
@__req
|
82
|
+
end
|
83
|
+
|
84
|
+
# Public: Returns the current response object or +nil+ if no requests
|
85
|
+
# have been issued yet.
|
86
|
+
#
|
87
|
+
# Examples
|
88
|
+
#
|
89
|
+
# app = Ruter::Test.new
|
90
|
+
# app.get("/", name: "alice")
|
91
|
+
#
|
92
|
+
# app.res.status
|
93
|
+
# # => 200
|
94
|
+
#
|
95
|
+
# app.res.body
|
96
|
+
# # => "Hello alice!"
|
97
|
+
#
|
98
|
+
# The returned object is an instance of
|
99
|
+
# {Rack::MockResponse}[http://www.rubydoc.info/gems/rack/Rack/MockResponse]
|
100
|
+
#
|
101
|
+
def res
|
102
|
+
@__res
|
103
|
+
end
|
104
|
+
|
105
|
+
# Public: Issues a GET request for the given +path+ with the given
|
106
|
+
# +params+ and Rack environment.
|
107
|
+
#
|
108
|
+
# Examples
|
109
|
+
#
|
110
|
+
# app = Ruter::Test.new
|
111
|
+
# app.get("/search", name: "alice")
|
112
|
+
#
|
113
|
+
def get(path, params = {}, env = {})
|
114
|
+
request(path, env.merge(method: Rack::GET, params: params))
|
115
|
+
end
|
116
|
+
|
117
|
+
# Public: Issues a POST request for the given +path+ with the given
|
118
|
+
# +params+ and Rack environment.
|
119
|
+
#
|
120
|
+
# Examples
|
121
|
+
#
|
122
|
+
# app = Ruter::Test.new
|
123
|
+
# app.post("/signup", username: "alice", password: "secret")
|
124
|
+
#
|
125
|
+
def post(path, params = {}, env = {})
|
126
|
+
request(path, env.merge(method: "POST".freeze, params: params))
|
127
|
+
end
|
128
|
+
|
129
|
+
# Public: Issues a PUT request for the given +path+ with the given
|
130
|
+
# +params+ and Rack environment.
|
131
|
+
#
|
132
|
+
# Examples
|
133
|
+
#
|
134
|
+
# app = Ruter::Test.new
|
135
|
+
# app.put("/users/1", username: "bob", name: "Bob")
|
136
|
+
#
|
137
|
+
def put(path, params = {}, env = {})
|
138
|
+
request(path, env.merge(method: "PUT".freeze, params: params))
|
139
|
+
end
|
140
|
+
|
141
|
+
# Public: Issues a PATCH request for the given +path+ with the given
|
142
|
+
# +params+ and Rack environment.
|
143
|
+
#
|
144
|
+
# Examples
|
145
|
+
#
|
146
|
+
# app = Ruter::Test.new
|
147
|
+
# app.patch("/users/1", username: "alice")
|
148
|
+
#
|
149
|
+
def patch(path, params = {}, env = {})
|
150
|
+
request(path, env.merge(method: "PATCH".freeze, params: params))
|
151
|
+
end
|
152
|
+
|
153
|
+
# Public: Issues a DELETE request for the given +path+ with the given
|
154
|
+
# +params+ and Rack environment.
|
155
|
+
#
|
156
|
+
# Examples
|
157
|
+
#
|
158
|
+
# app = Ruter::Test.new
|
159
|
+
# app.delete("/users/1")
|
160
|
+
#
|
161
|
+
def delete(path, params = {}, env = {})
|
162
|
+
request(path, env.merge(method: "DELETE".freeze, params: params))
|
163
|
+
end
|
164
|
+
|
165
|
+
# Public: Issues a HEAD request for the given +path+ with the given
|
166
|
+
# +params+ and Rack environment.
|
167
|
+
#
|
168
|
+
# Examples
|
169
|
+
#
|
170
|
+
# app = Ruter::Test.new
|
171
|
+
# app.head("/users/1")
|
172
|
+
#
|
173
|
+
def head(path, params = {}, env = {})
|
174
|
+
request(path, env.merge(method: Rack::HEAD, params: params))
|
175
|
+
end
|
176
|
+
|
177
|
+
# Public: Issues a OPTIONS request for the given +path+ with the given
|
178
|
+
# +params+ and Rack environment.
|
179
|
+
#
|
180
|
+
# Examples
|
181
|
+
#
|
182
|
+
# app = Ruter::Test.new
|
183
|
+
# app.options("/users")
|
184
|
+
#
|
185
|
+
def options(path, params = {}, env = {})
|
186
|
+
request(path, env.merge(method: "OPTIONS".freeze, params: params))
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def request(path, opts = {})
|
192
|
+
@__req = Rack::Request.new(Rack::MockRequest.env_for(path, opts))
|
193
|
+
@__res = Rack::MockResponse.new(*app.call(@__req.env))
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
include InstanceMethods
|
198
|
+
end
|
199
|
+
end
|
data/lib/ruter.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative "ruter/version"
|
2
|
+
require_relative "ruter/plugin"
|
3
|
+
require_relative "ruter/core"
|
4
|
+
require_relative "ruter/middleware"
|
5
|
+
require_relative "ruter/settings"
|
6
|
+
|
7
|
+
class Ruter
|
8
|
+
extend Ruter::Plugin
|
9
|
+
|
10
|
+
# Internal: Core plugins.
|
11
|
+
plugin(Ruter::Core)
|
12
|
+
plugin(Ruter::Middleware)
|
13
|
+
plugin(Ruter::Settings)
|
14
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
class CoreTest < Minitest::Test
|
4
|
+
setup do
|
5
|
+
Ruter.reset!
|
6
|
+
end
|
7
|
+
|
8
|
+
test "hello" do
|
9
|
+
Ruter.define do
|
10
|
+
get do
|
11
|
+
res.write("hello")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
app = Ruter::Test.new
|
16
|
+
app.get("/")
|
17
|
+
|
18
|
+
assert_equal 200, app.res.status
|
19
|
+
assert_equal "hello", app.res.body
|
20
|
+
end
|
21
|
+
|
22
|
+
test "methods" do
|
23
|
+
[:get, :post, :put, :patch, :delete].each do |method|
|
24
|
+
Ruter.define do
|
25
|
+
send(method) { res.write "" }
|
26
|
+
end
|
27
|
+
|
28
|
+
app = Ruter::Test.new
|
29
|
+
app.send(method, "/")
|
30
|
+
|
31
|
+
assert_equal 200, app.res.status
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
test "captures" do
|
36
|
+
Ruter.define do
|
37
|
+
on :foo do
|
38
|
+
on :bar do
|
39
|
+
get do
|
40
|
+
res.write(sprintf("%s:%s", inbox[:foo], inbox[:bar]))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
app = Ruter::Test.new
|
47
|
+
app.get("/foo/bar")
|
48
|
+
|
49
|
+
assert_equal 200, app.res.status
|
50
|
+
assert_equal "foo:bar", app.res.body
|
51
|
+
end
|
52
|
+
|
53
|
+
test "composition" do
|
54
|
+
nested = Class.new(Ruter)
|
55
|
+
|
56
|
+
nested.define do
|
57
|
+
get do
|
58
|
+
res.write(inbox[:foo])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Ruter.define do
|
63
|
+
on "foo" do
|
64
|
+
run(nested, foo: 42)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
app = Ruter::Test.new
|
69
|
+
app.get("/foo")
|
70
|
+
|
71
|
+
assert_equal 200, app.res.status
|
72
|
+
assert_equal "42", app.res.body
|
73
|
+
end
|
74
|
+
|
75
|
+
test "use own request and response classes" do
|
76
|
+
Ruter.define do
|
77
|
+
get do
|
78
|
+
res.write(request_class.name)
|
79
|
+
res.write(response_class.name)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
app = Ruter::Test.new
|
84
|
+
app.get("/")
|
85
|
+
|
86
|
+
assert_equal 200, app.res.status
|
87
|
+
assert_match Ruter::Core::Request.name, app.res.body
|
88
|
+
assert_match Ruter::Core::Response.name, app.res.body
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
class MiddlewareTest < Minitest::Test
|
4
|
+
class ReverseBody
|
5
|
+
def initialize(app)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
status, headers, body = @app.call(env)
|
11
|
+
|
12
|
+
[status, headers, body.reverse]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
setup do
|
17
|
+
Ruter.reset!
|
18
|
+
end
|
19
|
+
|
20
|
+
test "middleware in main application" do
|
21
|
+
Ruter.use(ReverseBody)
|
22
|
+
|
23
|
+
Ruter.define do
|
24
|
+
get do
|
25
|
+
res.write("1")
|
26
|
+
res.write("2")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
app = Ruter::Test.new
|
31
|
+
app.get("/")
|
32
|
+
|
33
|
+
assert_equal 200, app.res.status
|
34
|
+
assert_equal "21", app.res.body
|
35
|
+
end
|
36
|
+
|
37
|
+
test "middleware with composition" do
|
38
|
+
Ruter.use(ReverseBody)
|
39
|
+
|
40
|
+
api = Class.new(Ruter) do
|
41
|
+
define do
|
42
|
+
get do
|
43
|
+
res.write("1")
|
44
|
+
res.write("2")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Ruter.define do
|
50
|
+
on "api" do
|
51
|
+
run(api)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
app = Ruter::Test.new
|
56
|
+
app.get("/api")
|
57
|
+
|
58
|
+
assert_equal 200, app.res.status
|
59
|
+
assert_equal "21", app.res.body
|
60
|
+
end
|
61
|
+
|
62
|
+
test "middleware only in child application" do
|
63
|
+
api = Class.new(Ruter) do
|
64
|
+
use(ReverseBody)
|
65
|
+
|
66
|
+
define do
|
67
|
+
get do
|
68
|
+
res.write("1")
|
69
|
+
res.write("2")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Ruter.define do
|
75
|
+
on "api" do
|
76
|
+
run(api)
|
77
|
+
end
|
78
|
+
|
79
|
+
get do
|
80
|
+
res.write("not_reversed")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
app = Ruter::Test.new
|
85
|
+
app.get("/api")
|
86
|
+
|
87
|
+
assert_equal 200, app.res.status
|
88
|
+
assert_equal "21", app.res.body
|
89
|
+
|
90
|
+
app.get("/")
|
91
|
+
|
92
|
+
assert_equal 200, app.res.status
|
93
|
+
assert_equal "not_reversed", app.res.body
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
require "redcarpet"
|
3
|
+
|
4
|
+
class MarkdownPlugin
|
5
|
+
def self.setup(app, options = {})
|
6
|
+
app.settings[:markdown_options] = options
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def markdown_renderer
|
11
|
+
@_markdown_renderer ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, markdown_options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def markdown_options
|
15
|
+
settings[:markdown_options]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module InstanceMethods
|
20
|
+
def markdown(text)
|
21
|
+
res.write(self.class.markdown_renderer.render(text))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class MarkdownApp < Ruter
|
27
|
+
plugin(MarkdownPlugin, no_intra_emphasis: true)
|
28
|
+
|
29
|
+
define do
|
30
|
+
root do
|
31
|
+
get do
|
32
|
+
markdown("This is *bongos*, indeed.")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class PluginTest < Minitest::Test
|
39
|
+
test "setup" do
|
40
|
+
refute_nil(MarkdownApp.settings[:markdown_options])
|
41
|
+
end
|
42
|
+
|
43
|
+
test "class methods" do
|
44
|
+
assert_instance_of(Redcarpet::Markdown, MarkdownApp.markdown_renderer)
|
45
|
+
end
|
46
|
+
|
47
|
+
test "instance methods" do
|
48
|
+
app = Ruter::Test.new(MarkdownApp)
|
49
|
+
app.get("/")
|
50
|
+
|
51
|
+
assert_equal 200, app.res.status
|
52
|
+
assert_match "<p>This is <em>bongos</em>, indeed.</p>", app.res.body
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
class SettingsTest < MiniTest::Test
|
4
|
+
setup do
|
5
|
+
Ruter.reset!
|
6
|
+
Ruter.settings.clear
|
7
|
+
end
|
8
|
+
|
9
|
+
test "set and get setting" do
|
10
|
+
Ruter.set(:environment, "development")
|
11
|
+
|
12
|
+
assert_equal "development", Ruter.settings[:environment]
|
13
|
+
end
|
14
|
+
|
15
|
+
test "get setting inside handler" do
|
16
|
+
Ruter.set(:environment, "development")
|
17
|
+
|
18
|
+
Ruter.define do
|
19
|
+
get do
|
20
|
+
res.write(settings[:environment])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
app = Ruter::Test.new
|
25
|
+
app.get("/")
|
26
|
+
|
27
|
+
assert_equal 200, app.res.status
|
28
|
+
assert_equal "development", app.res.body
|
29
|
+
end
|
30
|
+
|
31
|
+
test "inheritance" do
|
32
|
+
Ruter.set(:foo, "foo")
|
33
|
+
Ruter.set(:bar, "bar")
|
34
|
+
|
35
|
+
inherited = Class.new(Ruter)
|
36
|
+
inherited.set(:bar, "rab")
|
37
|
+
inherited.set(:baz, "baz")
|
38
|
+
|
39
|
+
assert_equal "foo", Ruter.settings[:foo]
|
40
|
+
assert_equal "bar", Ruter.settings[:bar]
|
41
|
+
assert_nil Ruter.settings[:baz]
|
42
|
+
|
43
|
+
assert_equal "foo", inherited.settings[:foo]
|
44
|
+
assert_equal "rab", inherited.settings[:bar]
|
45
|
+
assert_equal "baz", inherited.settings[:baz]
|
46
|
+
end
|
47
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Francesco Rodriguez
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-08-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: syro
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: tilt
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: erubi
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.10'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.10'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '5.8'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.8'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest-sugar
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.1'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.1'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '13.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '13.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: standard
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.2'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.2'
|
125
|
+
description: "Another Rack based web framework \U0001F937\U0001F3FD♂️"
|
126
|
+
email: frodsan@me.com
|
127
|
+
executables: []
|
128
|
+
extensions: []
|
129
|
+
extra_rdoc_files: []
|
130
|
+
files:
|
131
|
+
- LICENSE
|
132
|
+
- README.md
|
133
|
+
- lib/ruter.rb
|
134
|
+
- lib/ruter/core.rb
|
135
|
+
- lib/ruter/core/request.rb
|
136
|
+
- lib/ruter/core/response.rb
|
137
|
+
- lib/ruter/middleware.rb
|
138
|
+
- lib/ruter/plugin.rb
|
139
|
+
- lib/ruter/settings.rb
|
140
|
+
- lib/ruter/test.rb
|
141
|
+
- lib/ruter/version.rb
|
142
|
+
- test/ruter/core_test.rb
|
143
|
+
- test/ruter/middleware_test.rb
|
144
|
+
- test/ruter/plugin_test.rb
|
145
|
+
- test/ruter/settings_test.rb
|
146
|
+
- test/test_helper.rb
|
147
|
+
homepage: https://github.com/frodsan/ruter
|
148
|
+
licenses:
|
149
|
+
- MIT
|
150
|
+
metadata: {}
|
151
|
+
post_install_message:
|
152
|
+
rdoc_options: []
|
153
|
+
require_paths:
|
154
|
+
- lib
|
155
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
requirements: []
|
166
|
+
rubygems_version: 3.2.26
|
167
|
+
signing_key:
|
168
|
+
specification_version: 4
|
169
|
+
summary: "Another Rack based web framework \U0001F937\U0001F3FD♂️"
|
170
|
+
test_files:
|
171
|
+
- test/ruter/core_test.rb
|
172
|
+
- test/ruter/middleware_test.rb
|
173
|
+
- test/ruter/plugin_test.rb
|
174
|
+
- test/ruter/settings_test.rb
|
175
|
+
- test/test_helper.rb
|