rack-app 7.3.2 → 7.7.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 +5 -5
- data/.github/ISSUE_TEMPLATE/bug_report.md +31 -0
- data/.ruby-version +1 -1
- data/.travis.yml +6 -8
- data/README.md +94 -34
- data/VERSION +1 -1
- data/assets/rack-app-logo.png +0 -0
- data/lib/rack/app/endpoint.rb +3 -0
- data/lib/rack/app/endpoint/builder.rb +17 -5
- data/lib/rack/app/endpoint/catcher.rb +4 -1
- data/lib/rack/app/file_server.rb +38 -12
- data/lib/rack/app/instance_methods/serve_file.rb +4 -4
- data/lib/rack/app/middlewares/params/validator.rb +8 -10
- data/lib/rack/app/middlewares/set_path_params.rb +7 -5
- data/lib/rack/app/payload/parser/builder/formats.rb +12 -12
- data/lib/rack/app/router/tree/leaf.rb +0 -1
- data/lib/rack/app/router/tree/vein.rb +3 -3
- data/lib/rack/app/singleton_methods/mounting.rb +2 -2
- data/lib/rack/app/streamer/scheduler/null.rb +2 -2
- data/lib/rack/app/test.rb +34 -5
- data/rack-app.gemspec +16 -17
- metadata +10 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bf6acb7c4c89bd038387d214bd7379ade393a3f0b48088f4b7542b6a0c6f05ca
|
4
|
+
data.tar.gz: e084eaa3c611498a98bbdb7cb1a8ccbcdc81cc893e1c08848a515db4b9e536f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '09f143bdb3a084226e0f51f9f8c471dff28b06ab99f4f52c0895abd3541673152ef3949f34711a5eb67fc53ce1544c0bfd0acf6d000b30cf803c5b28f96ce1c1'
|
7
|
+
data.tar.gz: 6667a98608f80d53984ec9147373e370edecec9b5b525b74c3ff0c354f0843ea685deb2b96b57cae354039f56b1d1ab8104ae20bb1cf884bfba98c36b741c537
|
@@ -0,0 +1,31 @@
|
|
1
|
+
---
|
2
|
+
name: Bug report
|
3
|
+
about: Create a report to help us improve
|
4
|
+
title: ''
|
5
|
+
labels: bug
|
6
|
+
assignees: adamluzsi
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
**Describe the bug**
|
11
|
+
A clear and concise description of what the bug is.
|
12
|
+
|
13
|
+
**To Reproduce**
|
14
|
+
Steps to reproduce the behavior:
|
15
|
+
1. Go to '...'
|
16
|
+
2. Click on '....'
|
17
|
+
3. Scroll down to '....'
|
18
|
+
4. See error
|
19
|
+
|
20
|
+
**Expected behavior**
|
21
|
+
A clear and concise description of what you expected to happen.
|
22
|
+
|
23
|
+
**ruby interpreter**
|
24
|
+
ruby interpreter implementation like Mruby, Jruby, ...
|
25
|
+
|
26
|
+
**ruby version**
|
27
|
+
|
28
|
+
**rack-app version**
|
29
|
+
|
30
|
+
**Additional context**
|
31
|
+
Add any other context about the problem here.
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.6.3
|
data/.travis.yml
CHANGED
@@ -6,16 +6,14 @@ install:
|
|
6
6
|
- bundle install
|
7
7
|
|
8
8
|
rvm:
|
9
|
-
- 1.9
|
10
|
-
- 2.0.0
|
11
|
-
- 2.1.1
|
12
|
-
- 2.1.2
|
13
|
-
- 2.2.2
|
14
|
-
- 2.3.1
|
15
|
-
- jruby-19mode
|
16
|
-
|
17
9
|
- ruby-head
|
18
10
|
- jruby-head
|
11
|
+
- jruby-19mode
|
12
|
+
- 1.9
|
13
|
+
- 2.3.8
|
14
|
+
- 2.4.6
|
15
|
+
- 2.5.5
|
16
|
+
- 2.6.3
|
19
17
|
|
20
18
|
matrix:
|
21
19
|
allow_failures:
|
data/README.md
CHANGED
@@ -4,7 +4,9 @@
|
|
4
4
|
[travis-link]: https://travis-ci.org/rack-app/rack-app
|
5
5
|
[travis-home]: http://travis-ci.org/
|
6
6
|
|
7
|
-
|
7
|
+

|
8
|
+
|
9
|
+
Your next favorite rack-based micro-framework that is totally addition free!
|
8
10
|
Have a cup of awesomeness with your sadistically minimalist framework!
|
9
11
|
|
10
12
|
The idea behind is simple.
|
@@ -14,24 +16,41 @@ that will do nothing more than what you defined.
|
|
14
16
|
|
15
17
|
The Routing can handle any amount of endpoints that can fit in the memory,
|
16
18
|
so if you that crazy to use more than 10k endpoint,
|
17
|
-
you still
|
19
|
+
you still don't have to worry about response speed.
|
18
20
|
|
19
21
|
It was inspirited by sinatra, grape, and the pure use form of rack.
|
20
22
|
It's in production, powering Back Ends on Heroku
|
21
23
|
|
24
|
+
## Development Status
|
25
|
+
|
26
|
+
The framework considered stable.
|
27
|
+
I don't have the plan to feature creep the framework without real-life use-cases,
|
28
|
+
since most of the custom edge cases can be resolved with composition.
|
29
|
+
|
30
|
+
The next time it will receive further updates,
|
31
|
+
when rack provides a finalized support for http2.
|
32
|
+
|
33
|
+
If you have an issue, I weekly check the issues tab,
|
34
|
+
answer and reply, or implement a fix for it.
|
35
|
+
|
36
|
+
Since the framework's only dependency is the `rack` gem,
|
37
|
+
I don't have to update the code base to often.
|
38
|
+
|
39
|
+
Cheers and Happy Coding!
|
40
|
+
|
22
41
|
## Concerns
|
23
42
|
|
24
|
-
If you want see fancy magic, you are in a bad place buddy!
|
43
|
+
If you want to see fancy magic, you are in a bad place buddy!
|
25
44
|
|
26
45
|
This also implies that the framework does not include extensions that monkey patch the whole world to give you nice features.
|
27
|
-
|
46
|
+
Clean architecture defines that a web framework should only provide an external interface to the web, and nothing more.
|
28
47
|
|
29
48
|
If you use rack-app, one thing is sure.
|
30
49
|
|
31
50
|
You either love it or will be able to remove it from the project even after years of development because,
|
32
51
|
it will not vendor-lock your application business entities and business use cases to this framework.
|
33
52
|
|
34
|
-
And it's
|
53
|
+
And it's totally fine for us. We don't want everyone to be tied to our solutions, we only want to build clean and well-designed software for the developer happiness.
|
35
54
|
|
36
55
|
## Installation
|
37
56
|
|
@@ -52,7 +71,7 @@ Or install it yourself as:
|
|
52
71
|
|
53
72
|
## Is it Production ready?
|
54
73
|
|
55
|
-
Yes,
|
74
|
+
Yes, it's already powering Heroku hosted micro-services.
|
56
75
|
|
57
76
|
## Principles
|
58
77
|
|
@@ -60,18 +79,18 @@ Yes, in fact it's already powering heroku hosted micro-services.
|
|
60
79
|
* No Code bloat
|
61
80
|
* No on run time processing, or keep at the bare minimum
|
62
81
|
* Fully BDD (Behaviour Driven Design)
|
63
|
-
*
|
82
|
+
* built-in test module to ease the development with easy to use tests
|
64
83
|
* Easy to Learn
|
65
84
|
* rack-app use well known and easy to understand conventions, such as sinatra like DSL
|
66
85
|
* Principle Of Least Surprise
|
67
86
|
* Modular design
|
68
|
-
* Only dependency is rack, nothing more
|
87
|
+
* the Only dependency is rack, nothing more
|
69
88
|
* Open development
|
70
|
-
* Try to create Examples for every feature
|
89
|
+
* Try to create Examples for every feature
|
71
90
|
|
72
91
|
## Features
|
73
92
|
|
74
|
-
*
|
93
|
+
* Easy to understand syntax
|
75
94
|
* module method level endpoint definition inspirited heavily by the Sinatra DSL
|
76
95
|
* unified error handling
|
77
96
|
* syntax sugar for default header definitions
|
@@ -80,20 +99,26 @@ Yes, in fact it's already powering heroku hosted micro-services.
|
|
80
99
|
* App mounting so you can create separated controllers for different task
|
81
100
|
* Streaming
|
82
101
|
* O(log(n)) lookup routing
|
83
|
-
* allows as many endpoint
|
84
|
-
* only basic sets for instance method
|
85
|
-
*
|
102
|
+
* allows as many endpoint registrations to you as you want, without impact on route lookup speed
|
103
|
+
* only basic sets for instance method level for the must need tools, such as params, payload
|
104
|
+
* Simple to use class level response serializer
|
86
105
|
* so you can choose what type of serialization you want without any enforced convention
|
87
|
-
* static file serving so you can mount even filesystem
|
88
|
-
* built
|
106
|
+
* static file serving so you can mount even filesystem-based endpoints too
|
107
|
+
* built-in testing module so your app can be easily written with BDD approach
|
89
108
|
* made with minimalism in mind so your app can't rely on the framework when you implement business logic
|
90
|
-
* if you need something, you should implement it without any dependency on a
|
109
|
+
* if you need something, you should implement it without any dependency on a web framework, rack-app only mean to be to provide you with easy to use interface to the web layer, nothing less and nothing more
|
91
110
|
* per endpoint middleware definitions
|
92
|
-
* you can define middleware stack before endpoints and it will only
|
93
|
-
* File Upload and file download
|
94
|
-
* note that this is not only memory friendly way pure rack solution, but also 2x faster than the
|
111
|
+
* you can define middleware stack before endpoints and it will only apply to them, similar like protected method workflow
|
112
|
+
* File Upload and file download efficiently and elegantly with minimal memory consuming
|
113
|
+
* note that this is not only memory friendly way pure rack solution, but also 2x faster than the usual solution which includes buffering in memory
|
95
114
|
* params validation with ease
|
96
115
|
|
116
|
+
## Under the hood
|
117
|
+
|
118
|
+
rack-app's router relies on a tree structure which makes heavy use of *common prefixes*,
|
119
|
+
it is basically a *compact* [*prefix tree*](https://en.wikipedia.org/wiki/Trie) (or just [*Radix tree*](https://en.wikipedia.org/wiki/Radix_tree)).
|
120
|
+
Nodes with a common prefix also share a common parent.
|
121
|
+
|
97
122
|
## Contributors
|
98
123
|
|
99
124
|
* **[Daniel Nagy](https://github.com/thilonel)**
|
@@ -112,12 +137,14 @@ Yes, in fact it's already powering heroku hosted micro-services.
|
|
112
137
|
|
113
138
|
* [wrote an awesome article](https://www.sitepoint.com/rack-app-a-performant-and-pragmatic-web-microframework/) about the project
|
114
139
|
|
140
|
+
* **[TheSmartnik](https://github.com/TheSmartnik)**
|
141
|
+
|
142
|
+
* Clarify examples in the documentation
|
143
|
+
|
115
144
|
## [Contributing](CONTRIBUTING.md)
|
116
145
|
|
117
146
|
## Usage
|
118
147
|
|
119
|
-
config.ru
|
120
|
-
|
121
148
|
#### basic
|
122
149
|
|
123
150
|
```ruby
|
@@ -143,8 +170,6 @@ require 'rack/app'
|
|
143
170
|
|
144
171
|
class App < Rack::App
|
145
172
|
|
146
|
-
apply_extensions :front_end
|
147
|
-
|
148
173
|
mount SomeAppClass
|
149
174
|
|
150
175
|
headers 'Access-Control-Allow-Origin' => '*',
|
@@ -158,11 +183,12 @@ class App < Rack::App
|
|
158
183
|
validate_params do
|
159
184
|
required 'words', :class => Array, :of => String, :desc => 'some word', :example => ['pug']
|
160
185
|
optional 'word', :class => String, :desc => 'one word', :example => 'pug'
|
186
|
+
optional 'boolean', :class => :boolean, :desc => 'boolean value', :example => true
|
161
187
|
end
|
162
188
|
get '/hello' do
|
163
|
-
puts(
|
189
|
+
puts(params['words'])
|
164
190
|
|
165
|
-
|
191
|
+
'Hello World!'
|
166
192
|
end
|
167
193
|
|
168
194
|
namespace '/users' do
|
@@ -202,9 +228,43 @@ end
|
|
202
228
|
```
|
203
229
|
|
204
230
|
you can access Rack::Request with the request method and
|
205
|
-
Rack::Response as response method.
|
231
|
+
Rack::Response as a response method.
|
232
|
+
|
233
|
+
By default, if you don't write anything to the response 'body' the endpoint block logic return will be used
|
234
|
+
|
235
|
+
### Frontend Example
|
236
|
+
|
237
|
+
if you don't mind extending your dependency list then you can use the front_end extension for creating template-based web applications.
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
require 'rack/app'
|
241
|
+
require 'rack/app/front_end' # You need to add `gem 'rack-app-front_end'` to your Gemfile
|
242
|
+
|
243
|
+
class App < Rack::App
|
244
|
+
|
245
|
+
apply_extensions :front_end
|
246
|
+
|
247
|
+
helpers do
|
248
|
+
|
249
|
+
def method_that_can_be_used_in_template
|
250
|
+
'hello world!'
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
# use ./app/layout.html.erb as layout, this is optionable
|
256
|
+
layout 'layout.html.erb'
|
257
|
+
|
258
|
+
# at '/' the endpoint will serve (render)
|
259
|
+
# the ./app/index.html content as response body and wrap around with layout if the layout is given
|
260
|
+
get '/' do
|
261
|
+
render 'index.html'
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
```
|
206
266
|
|
207
|
-
|
267
|
+
this example expects an "app" folder next to the "app.rb" file that included templates being used such as layout.html.erb and index.html.
|
208
268
|
|
209
269
|
## Testing
|
210
270
|
|
@@ -223,7 +283,7 @@ describe App do
|
|
223
283
|
|
224
284
|
describe '/hello' do
|
225
285
|
# example for params and headers and payload use
|
226
|
-
subject{ get(url: '/hello', params: {'dog' => 'meat'}, headers: {'X-Cat' => 'fur'}, payload: 'some string') }
|
286
|
+
subject { get(url: '/hello', params: {'dog' => 'meat'}, headers: {'X-Cat' => 'fur'}, payload: 'some string') }
|
227
287
|
|
228
288
|
it { expect(subject.status).to eq 200 }
|
229
289
|
|
@@ -232,7 +292,7 @@ describe App do
|
|
232
292
|
|
233
293
|
describe '/users/:user_id' do
|
234
294
|
# restful endpoint example
|
235
|
-
subject{ get(url: '/users/1234') }
|
295
|
+
subject { get(url: '/users/1234') }
|
236
296
|
|
237
297
|
it { expect(subject.body).to eq 'hello 1234!'}
|
238
298
|
|
@@ -242,7 +302,7 @@ describe App do
|
|
242
302
|
|
243
303
|
describe '/make_error' do
|
244
304
|
# error handled example
|
245
|
-
subject{ get(url: '/make_error') }
|
305
|
+
subject { get(url: '/make_error') }
|
246
306
|
|
247
307
|
it { expect(subject.body).to eq '{:error=>"error block rescued"}' }
|
248
308
|
end
|
@@ -254,19 +314,19 @@ end
|
|
254
314
|
|
255
315
|
## Example Apps To start with
|
256
316
|
|
257
|
-
* [Official website How To examples](http://rack-app.com/)
|
317
|
+
* [Official website How To examples](http://www.rack-app.com/)
|
258
318
|
|
259
319
|
* [Rack::App Team Github repositories](https://github.com/rack-app)
|
260
320
|
|
261
321
|
* [Basic](https://github.com/rack-app/rack-app-example-basic)
|
262
|
-
* bare
|
322
|
+
* bare-bone simple example app
|
263
323
|
|
264
324
|
* [Escher Authorized Api](https://github.com/rack-app/rack-app-example-escher)
|
265
|
-
* complex authorization for corporal level
|
325
|
+
* complex authorization for corporal level API use
|
266
326
|
|
267
327
|
## [Benchmarking](https://github.com/rack-app/rack-app-benchmark)
|
268
328
|
|
269
|
-
This is a repo that used for measure Rack::App project speed in order keep an eye on the performance in every release.
|
329
|
+
This is a repo that used for measure Rack::App project speed in order to keep an eye on the performance in every release.
|
270
330
|
|
271
331
|
the benchmarking was taken on the following hardware specification:
|
272
332
|
* Processor: 2,7 GHz Intel Core i5
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
7.
|
1
|
+
7.7.0
|
Binary file
|
data/lib/rack/app/endpoint.rb
CHANGED
@@ -28,6 +28,9 @@ class Rack::App::Endpoint
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def to_app
|
31
|
+
# TODO: fix this to cache it, but to that you need to resolve the problem when middlewares added,
|
32
|
+
# old endpoints are not refreshed by the middleware configs
|
33
|
+
# router.reset must be checked
|
31
34
|
self.class::Builder.new(@config).to_app
|
32
35
|
end
|
33
36
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'rack/builder'
|
3
4
|
class Rack::App::Endpoint::Builder
|
4
5
|
def initialize(config)
|
@@ -33,17 +34,28 @@ class Rack::App::Endpoint::Builder
|
|
33
34
|
end
|
34
35
|
builder.use(Rack::App::Middlewares::Configuration, @config)
|
35
36
|
|
36
|
-
|
37
|
+
apply_catcher_on_need(builder)
|
38
|
+
@config.ancestor_apps.reverse_each do |app_class|
|
39
|
+
apply_hook_middlewares(app_class, builder)
|
40
|
+
end
|
37
41
|
end
|
38
42
|
|
39
|
-
def
|
40
|
-
|
43
|
+
def apply_catcher_on_need(builder)
|
44
|
+
at_least_one_hook_requested = @config.ancestor_apps.any? do |app_class|
|
45
|
+
app_class.before.length + app_class.after.length > 0
|
46
|
+
end
|
47
|
+
|
48
|
+
if at_least_one_hook_requested
|
41
49
|
builder.use(Rack::App::Endpoint::Catcher, @config)
|
42
50
|
end
|
43
|
-
|
51
|
+
end
|
52
|
+
|
53
|
+
def apply_hook_middlewares(app_class, builder)
|
54
|
+
app_class.before.each do |before_block|
|
44
55
|
builder.use(Rack::App::Middlewares::Hooks::Before, before_block)
|
45
56
|
end
|
46
|
-
|
57
|
+
|
58
|
+
app_class.after.each do |after_block|
|
47
59
|
builder.use(Rack::App::Middlewares::Hooks::After, after_block)
|
48
60
|
end
|
49
61
|
end
|
@@ -6,11 +6,14 @@ class Rack::App::Endpoint::Catcher
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def call(env)
|
9
|
-
handle_rack_response do
|
9
|
+
resp = handle_rack_response do
|
10
10
|
handle_response_body(env) do
|
11
11
|
@app.call(env)
|
12
12
|
end
|
13
13
|
end
|
14
|
+
return resp.finish if resp.is_a?(Rack::Response)
|
15
|
+
|
16
|
+
resp
|
14
17
|
end
|
15
18
|
|
16
19
|
protected
|
data/lib/rack/app/file_server.rb
CHANGED
@@ -1,10 +1,24 @@
|
|
1
1
|
class Rack::App::FileServer
|
2
|
+
attr_accessor :relative_file_paths
|
2
3
|
|
3
|
-
def
|
4
|
-
|
4
|
+
def self.serve_file(env, file_path)
|
5
|
+
dir_path = File.dirname(file_path)
|
6
|
+
basename = File.basename(file_path)
|
7
|
+
file_server = new(dir_path, map_relative_file_paths: false)
|
8
|
+
env = env.dup
|
9
|
+
env[::Rack::App::Constants::ENV::REQUEST_METHOD] = 'GET'
|
10
|
+
env[::Rack::App::Constants::ENV::PATH_INFO] = basename
|
11
|
+
file_server.call(env)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(root_folder, opts = {})
|
5
15
|
@root_folder = root_folder
|
6
|
-
@relative_file_paths =
|
16
|
+
@relative_file_paths = []
|
7
17
|
@rack_file_server = ::Rack::File.new(@root_folder, {})
|
18
|
+
|
19
|
+
if map_relative_file_paths?(opts)
|
20
|
+
map_relative_paths!
|
21
|
+
end
|
8
22
|
end
|
9
23
|
|
10
24
|
def call(env)
|
@@ -12,7 +26,7 @@ class Rack::App::FileServer
|
|
12
26
|
|
13
27
|
@relative_file_paths.each do |relative_file_path|
|
14
28
|
if path_info =~ /#{Regexp.escape(relative_file_path)}$/
|
15
|
-
env[::Rack::App::Constants::ENV::PATH_INFO]= relative_file_path
|
29
|
+
env[::Rack::App::Constants::ENV::PATH_INFO] = relative_file_path
|
16
30
|
break
|
17
31
|
end
|
18
32
|
end
|
@@ -20,19 +34,31 @@ class Rack::App::FileServer
|
|
20
34
|
@rack_file_server.call(env)
|
21
35
|
end
|
22
36
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
37
|
+
protected
|
38
|
+
|
39
|
+
def map_relative_file_paths?(opts = {})
|
40
|
+
unless opts.key?(:map_relative_file_paths)
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
|
44
|
+
opts[:map_relative_file_paths]
|
29
45
|
end
|
30
46
|
|
31
|
-
|
47
|
+
def opts_set_defaults(opts)
|
48
|
+
unless opts.key?(:map_relative_file_paths)
|
49
|
+
opts[:map_relative_file_paths] = true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def map_relative_paths!
|
54
|
+
@relative_file_paths = Dir.glob(File.join(@root_folder, '**', '*'))
|
55
|
+
.map { |file_path| file_path.sub(@root_folder, '') }
|
56
|
+
.sort_by { |str| str.length }
|
57
|
+
.reverse
|
58
|
+
end
|
32
59
|
|
33
60
|
def clean_path_info(env)
|
34
61
|
path_info = ::Rack::Utils.unescape(env[::Rack::App::Constants::ENV::PATH_INFO])
|
35
62
|
::Rack::Utils.clean_path_info(path_info)
|
36
63
|
end
|
37
|
-
|
38
64
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module Rack::App::InstanceMethods::ServeFile
|
2
2
|
|
3
3
|
def serve_file(file_path)
|
4
|
-
|
5
|
-
response.status =
|
6
|
-
response.headers.merge!(
|
7
|
-
response.body =
|
4
|
+
rack_resp = Rack::App::FileServer.serve_file(request.env, file_path)
|
5
|
+
response.status = rack_resp[0]
|
6
|
+
response.headers.merge!(rack_resp[1])
|
7
|
+
response.body = rack_resp[2]
|
8
8
|
finish!
|
9
9
|
end
|
10
10
|
|
@@ -37,22 +37,20 @@ class Rack::App::Middlewares::Params::Validator
|
|
37
37
|
|
38
38
|
def validate_required_params(env, params)
|
39
39
|
@descriptor[:required].each do |key, properties|
|
40
|
-
validate_key(key,properties,params)
|
40
|
+
validate_key(key, properties, params)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
def validate_optional_params(env, params)
|
45
45
|
@descriptor[:optional].each do |key, properties|
|
46
|
-
next unless params.
|
46
|
+
next unless params.key?(key)
|
47
47
|
|
48
|
-
validate_key(key,properties,params)
|
48
|
+
validate_key(key, properties, params)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
def validate_key(key,properties,params)
|
53
|
-
unless params.
|
54
|
-
missing_key_error(key, properties[:class])
|
55
|
-
end
|
52
|
+
def validate_key(key, properties, params)
|
53
|
+
missing_key_error(key, properties[:class]) unless params.key?(key)
|
56
54
|
|
57
55
|
if properties[:of]
|
58
56
|
validate_array(properties[:class], properties[:of], key, *params[key])
|
@@ -69,7 +67,7 @@ class Rack::App::Middlewares::Params::Validator
|
|
69
67
|
end
|
70
68
|
|
71
69
|
def validate_array(type, elements_type, key, *elements)
|
72
|
-
values = elements.map{ |str| parse(elements_type, str) }
|
70
|
+
values = elements.map { |str| parse(elements_type, str) }
|
73
71
|
|
74
72
|
if values.include?(nil)
|
75
73
|
invalid_type_of_error(key, type, elements_type)
|
@@ -92,11 +90,11 @@ class Rack::App::Middlewares::Params::Validator
|
|
92
90
|
error "invalid key: #{key}"
|
93
91
|
end
|
94
92
|
|
95
|
-
def invalid_type_error(key,klass)
|
93
|
+
def invalid_type_error(key, klass)
|
96
94
|
error "invalid type for #{key}: #{klass} expected"
|
97
95
|
end
|
98
96
|
|
99
|
-
def invalid_type_of_error(key,klass,of)
|
97
|
+
def invalid_type_of_error(key, klass, of)
|
100
98
|
error "invalid type for #{key}: #{klass} of #{of} expected"
|
101
99
|
end
|
102
100
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class Rack::App::Middlewares::SetPathParams
|
2
2
|
|
3
|
-
def initialize(app,
|
4
|
-
@
|
3
|
+
def initialize(app, build_env)
|
4
|
+
@build_env = build_env
|
5
5
|
@app = app
|
6
6
|
end
|
7
7
|
|
@@ -16,19 +16,21 @@ class Rack::App::Middlewares::SetPathParams
|
|
16
16
|
protected
|
17
17
|
|
18
18
|
def populate_path_params(env)
|
19
|
-
@
|
19
|
+
@build_env.params.each do |index, key|
|
20
20
|
env[E::PATH_SEGMENTS_PARAMS][key] = env[E::SPLITTED_PATH_INFO][index]
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
def correct_last_value_from_extensions(env)
|
25
|
+
return if @build_env.endpoint.config.serializer.extnames.empty?
|
25
26
|
last_index = env[E::SPLITTED_PATH_INFO].length - 1
|
26
|
-
return if @
|
27
|
-
extless(env[E::PATH_SEGMENTS_PARAMS][@
|
27
|
+
return if @build_env.params[last_index].nil?
|
28
|
+
extless(env[E::PATH_SEGMENTS_PARAMS][@build_env.params[last_index]])
|
28
29
|
end
|
29
30
|
|
30
31
|
def extless(value)
|
31
32
|
extname = File.extname(value)
|
33
|
+
return unless @build_env.endpoint.config.serializer.extnames.include?(extname)
|
32
34
|
value.slice!(/#{Regexp.escape(extname)}$/) unless extname.empty?
|
33
35
|
end
|
34
36
|
|
@@ -2,11 +2,11 @@ module Rack::App::Payload::Parser::Builder::Formats
|
|
2
2
|
extend(self)
|
3
3
|
|
4
4
|
JSON_CONTENT_TYPES = [
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
'application/json',
|
6
|
+
'application/x-javascript',
|
7
|
+
'text/javascript',
|
8
|
+
'text/x-javascript',
|
9
|
+
'text/x-json'
|
10
10
|
].freeze
|
11
11
|
|
12
12
|
JSON_PARSER = proc do |io|
|
@@ -28,9 +28,9 @@ module Rack::App::Payload::Parser::Builder::Formats
|
|
28
28
|
end
|
29
29
|
|
30
30
|
JSON_STREAM_CONTENT_TYPES = [
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
'application/jsonstream',
|
32
|
+
'application/stream+json',
|
33
|
+
'application/x-json-stream'
|
34
34
|
].freeze
|
35
35
|
|
36
36
|
JSON_STREAM_PARSER = proc do |io|
|
@@ -62,8 +62,8 @@ module Rack::App::Payload::Parser::Builder::Formats
|
|
62
62
|
# end
|
63
63
|
|
64
64
|
FORM_CONTENT_TYPES = [
|
65
|
-
|
66
|
-
|
65
|
+
'application/x-www-form-urlencoded',
|
66
|
+
# 'multipart/form-data'
|
67
67
|
].freeze
|
68
68
|
|
69
69
|
FORM_SEP_CHAR = '&'.freeze
|
@@ -76,7 +76,7 @@ module Rack::App::Payload::Parser::Builder::Formats
|
|
76
76
|
lambda do |form|
|
77
77
|
::Rack::Utils.parse_nested_query(form, FORM_SEP_CHAR)
|
78
78
|
end
|
79
|
-
|
79
|
+
end
|
80
80
|
|
81
81
|
NULL_END_CHAR = /#{"\u0000"}$/
|
82
82
|
|
@@ -102,7 +102,7 @@ module Rack::App::Payload::Parser::Builder::Formats
|
|
102
102
|
last_name = form_name
|
103
103
|
unless respond_to?(form_name)
|
104
104
|
raise(NotImplementedError, "unknown formatter: #{last_name}")
|
105
|
-
end
|
105
|
+
end
|
106
106
|
__send__ form_name, builder
|
107
107
|
end
|
108
108
|
end
|
@@ -21,12 +21,12 @@ class Rack::App::Router::Tree::Vein < ::Hash
|
|
21
21
|
|
22
22
|
def create_app(env)
|
23
23
|
app = env.endpoint.to_app
|
24
|
-
env.params.empty? ? app : wrap(app, env
|
24
|
+
env.params.empty? ? app : wrap(app, env)
|
25
25
|
end
|
26
26
|
|
27
|
-
def wrap(app,
|
27
|
+
def wrap(app, env)
|
28
28
|
builder = Rack::Builder.new
|
29
|
-
builder.use(Rack::App::Middlewares::SetPathParams,
|
29
|
+
builder.use(Rack::App::Middlewares::SetPathParams, env)
|
30
30
|
builder.run(app)
|
31
31
|
builder.to_app
|
32
32
|
end
|
@@ -46,8 +46,8 @@ module Rack::App::SingletonMethods::Mounting
|
|
46
46
|
nil
|
47
47
|
end
|
48
48
|
|
49
|
-
def serve_files_from(
|
50
|
-
file_server = Rack::App::FileServer.new(Rack::App::Utils.expand_path(
|
49
|
+
def serve_files_from(dir_path, options={})
|
50
|
+
file_server = Rack::App::FileServer.new(Rack::App::Utils.expand_path(dir_path))
|
51
51
|
request_path = Rack::App::Utils.join(options[:to], Rack::App::Constants::PATH::MOUNT_POINT)
|
52
52
|
add_route(::Rack::App::Constants::HTTP::METHOD::ANY, request_path, file_server)
|
53
53
|
nil
|
data/lib/rack/app/test.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'uri'
|
2
|
+
require 'rack/mock'
|
3
3
|
module Rack::App::Test
|
4
|
-
|
5
4
|
require 'rack/app/test/utils'
|
6
5
|
require 'rack/app/test/singleton_methods'
|
7
6
|
|
@@ -16,12 +15,12 @@ module Rack::App::Test
|
|
16
15
|
url = args.detect { |e| e.is_a?(String) } || properties.delete(:url)
|
17
16
|
mock_request = Rack::MockRequest.new(rack_app)
|
18
17
|
request_env = Rack::App::Test::Utils.env_by(url, properties)
|
19
|
-
|
18
|
+
@last_response = mock_request.request(request_method.to_s.upcase, url, request_env)
|
20
19
|
end
|
21
20
|
|
22
21
|
Rack::App::Constants::HTTP::METHODS.each do |request_method_type|
|
23
22
|
define_method(request_method_type.to_s.downcase) do |*args|
|
24
|
-
|
23
|
+
__send_rack_app_request__(request_method_type, *args)
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
@@ -38,4 +37,34 @@ module Rack::App::Test
|
|
38
37
|
block.is_a?(Proc) ? @rack_app.instance_exec(&block) : @rack_app
|
39
38
|
end
|
40
39
|
|
40
|
+
def mount(app_class, options)
|
41
|
+
path_prefix = options.fetch(:to)
|
42
|
+
|
43
|
+
selector = lambda do |e|
|
44
|
+
if e.config.type == :endpoint
|
45
|
+
e.config.app_class == app_class
|
46
|
+
else
|
47
|
+
e.config.callable == app_class
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
endpoints = rack_app.router.endpoints.select(&selector)
|
52
|
+
|
53
|
+
request_paths_that_has_prefix = lambda do |e|
|
54
|
+
e.request_path.start_with?(path_prefix)
|
55
|
+
end
|
56
|
+
|
57
|
+
matching_endpoints = endpoints.select(&request_paths_that_has_prefix)
|
58
|
+
|
59
|
+
if matching_endpoints.empty?
|
60
|
+
raise("Can't find any path that fullfill the requirement")
|
61
|
+
end
|
62
|
+
|
63
|
+
return unless app_class.is_a?(Class) && app_class <= Rack::App
|
64
|
+
app_owned_endpoints = app_class.router.endpoints.select(&selector)
|
65
|
+
|
66
|
+
if matching_endpoints.length != app_owned_endpoints.length
|
67
|
+
raise('endpoint count not matching')
|
68
|
+
end
|
69
|
+
end
|
41
70
|
end
|
data/rack-app.gemspec
CHANGED
@@ -1,28 +1,27 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
Gem::Specification.new do |spec|
|
3
3
|
|
4
|
-
spec.name
|
5
|
-
spec.version
|
6
|
-
spec.authors
|
7
|
-
spec.email
|
4
|
+
spec.name = 'rack-app'
|
5
|
+
spec.version = File.read(File.join(File.dirname(__FILE__), 'VERSION')).strip
|
6
|
+
spec.authors = ['Adam Luzsi']
|
7
|
+
spec.email = ['adamluzsi@gmail.com']
|
8
8
|
|
9
|
-
|
10
|
-
spec.
|
9
|
+
summary = 'Minimalist rack application interface building framework.'
|
10
|
+
spec.summary = summary
|
11
|
+
spec.description = summary
|
11
12
|
|
12
|
-
spec.homepage
|
13
|
+
spec.homepage = 'http://www.rack-app.com/'
|
13
14
|
|
14
|
-
spec.files
|
15
|
-
spec.require_paths = [
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.require_paths = ['lib']
|
16
17
|
|
17
|
-
spec.bindir
|
18
|
-
spec.executables
|
18
|
+
spec.bindir = 'bin'
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
20
|
|
20
|
-
spec.license
|
21
|
+
spec.license = 'Apache License 2.0'
|
21
22
|
|
22
|
-
spec.add_development_dependency
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.
|
25
|
-
|
26
|
-
spec.add_dependency "rack"
|
23
|
+
spec.add_development_dependency 'bundler'
|
24
|
+
spec.add_development_dependency 'rspec'
|
25
|
+
spec.add_dependency 'rack'
|
27
26
|
|
28
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-app
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.
|
4
|
+
version: 7.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Luzsi
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-12-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - '='
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 10.4.2
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - '='
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 10.4.2
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: rspec
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,8 +52,7 @@ dependencies:
|
|
66
52
|
- - ">="
|
67
53
|
- !ruby/object:Gem::Version
|
68
54
|
version: '0'
|
69
|
-
description:
|
70
|
-
free! Have a cup of awesomeness with your to performance designed framework!
|
55
|
+
description: Minimalist rack application interface building framework.
|
71
56
|
email:
|
72
57
|
- adamluzsi@gmail.com
|
73
58
|
executables:
|
@@ -75,6 +60,7 @@ executables:
|
|
75
60
|
extensions: []
|
76
61
|
extra_rdoc_files: []
|
77
62
|
files:
|
63
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
78
64
|
- ".gitignore"
|
79
65
|
- ".rspec"
|
80
66
|
- ".rubocop.yml"
|
@@ -89,6 +75,7 @@ files:
|
|
89
75
|
- VERSION
|
90
76
|
- Vagrantfile
|
91
77
|
- _config.yml
|
78
|
+
- assets/rack-app-logo.png
|
92
79
|
- bin/rack-app
|
93
80
|
- dev/console
|
94
81
|
- dev/rack-app
|
@@ -210,7 +197,7 @@ homepage: http://www.rack-app.com/
|
|
210
197
|
licenses:
|
211
198
|
- Apache License 2.0
|
212
199
|
metadata: {}
|
213
|
-
post_install_message:
|
200
|
+
post_install_message:
|
214
201
|
rdoc_options: []
|
215
202
|
require_paths:
|
216
203
|
- lib
|
@@ -225,9 +212,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
212
|
- !ruby/object:Gem::Version
|
226
213
|
version: '0'
|
227
214
|
requirements: []
|
228
|
-
|
229
|
-
|
230
|
-
signing_key:
|
215
|
+
rubygems_version: 3.0.3
|
216
|
+
signing_key:
|
231
217
|
specification_version: 4
|
232
|
-
summary:
|
218
|
+
summary: Minimalist rack application interface building framework.
|
233
219
|
test_files: []
|