rack-app 7.3.2 → 7.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![rack-app-logo](/assets/rack-app-logo.png)
|
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: []
|