nyny 3.0.0 → 3.0.1
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 +4 -4
- data/.gitignore +20 -20
- data/.rspec +2 -2
- data/.ruby-version +1 -1
- data/.travis.yml +11 -11
- data/CHANGELOG +45 -40
- data/Gemfile +7 -8
- data/LICENSE.txt +22 -22
- data/Performance.md +41 -46
- data/README.md +423 -423
- data/Rakefile +6 -6
- data/benchmark.rb +116 -125
- data/lib/nyny.rb +33 -33
- data/lib/nyny/app.rb +79 -79
- data/lib/nyny/core-ext/runner.rb +19 -19
- data/lib/nyny/core-ext/templates.rb +20 -20
- data/lib/nyny/primitives.rb +25 -25
- data/lib/nyny/request_scope.rb +43 -43
- data/lib/nyny/route.rb +40 -40
- data/lib/nyny/router.rb +46 -44
- data/lib/nyny/version.rb +3 -3
- data/nyny.gemspec +29 -27
- data/spec/app_spec.rb +248 -248
- data/spec/inheritance_spec.rb +76 -75
- data/spec/nyny_spec.rb +11 -11
- data/spec/primitives_spec.rb +33 -33
- data/spec/request_scope_spec.rb +103 -103
- data/spec/router_spec.rb +29 -21
- data/spec/runner_spec.rb +23 -23
- data/spec/spec_helper.rb +61 -61
- data/spec/templates_spec.rb +52 -52
- data/spec/views/layout.erb +6 -6
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1377196ade715ab3d114440cf120a5596c81f67
|
4
|
+
data.tar.gz: 186f4d5433cb0171a41c07a0b686e40382622f95
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d7cf903b0dfda2ea397680ac6cb8326e9e1a042733629452d9cb9576312da507eb10a54696afebf7b3c473337a88638eaafef60e15b72b92b90256db3f4ed25
|
7
|
+
data.tar.gz: 03ca191d2113dfc7bae9d674db8f75889127911df2ec38c1d3fedca30bb242739f6c16e7549e1b5e3c1c01ecb1c8d4d3d074161fba49b8dc1b7b4cd0a884489d
|
data/.gitignore
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
*.gem
|
2
|
-
*.rbc
|
3
|
-
.bundle
|
4
|
-
.config
|
5
|
-
.yardoc
|
6
|
-
*.sqlite3
|
7
|
-
*.sublime-project
|
8
|
-
*.sublime-workspace
|
9
|
-
Gemfile.lock
|
10
|
-
InstalledFiles
|
11
|
-
_yardoc
|
12
|
-
coverage
|
13
|
-
doc/
|
14
|
-
lib/bundler/man
|
15
|
-
pkg
|
16
|
-
rdoc
|
17
|
-
spec/reports
|
18
|
-
test/tmp
|
19
|
-
test/version_tmp
|
20
|
-
tmp
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
*.sqlite3
|
7
|
+
*.sublime-project
|
8
|
+
*.sublime-workspace
|
9
|
+
Gemfile.lock
|
10
|
+
InstalledFiles
|
11
|
+
_yardoc
|
12
|
+
coverage
|
13
|
+
doc/
|
14
|
+
lib/bundler/man
|
15
|
+
pkg
|
16
|
+
rdoc
|
17
|
+
spec/reports
|
18
|
+
test/tmp
|
19
|
+
test/version_tmp
|
20
|
+
tmp
|
data/.rspec
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
--color
|
2
|
-
--order rand
|
1
|
+
--color
|
2
|
+
--order rand
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0.0
|
1
|
+
2.0.0
|
data/.travis.yml
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
---
|
2
|
-
rvm:
|
3
|
-
- 1.9.2
|
4
|
-
- 1.9.3
|
5
|
-
- 2.0.0
|
6
|
-
- jruby-19mode
|
7
|
-
- jruby-20mode
|
8
|
-
|
9
|
-
branches:
|
10
|
-
only:
|
11
|
-
- master
|
1
|
+
---
|
2
|
+
rvm:
|
3
|
+
- 1.9.2
|
4
|
+
- 1.9.3
|
5
|
+
- 2.0.0
|
6
|
+
- jruby-19mode
|
7
|
+
- jruby-20mode
|
8
|
+
|
9
|
+
branches:
|
10
|
+
only:
|
11
|
+
- master
|
data/CHANGELOG
CHANGED
@@ -1,40 +1,45 @@
|
|
1
|
-
3.0.
|
2
|
-
-
|
3
|
-
|
4
|
-
|
5
|
-
-
|
6
|
-
-
|
7
|
-
-
|
8
|
-
-
|
9
|
-
-
|
10
|
-
|
11
|
-
|
12
|
-
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
-
|
24
|
-
-
|
25
|
-
|
26
|
-
-
|
27
|
-
-
|
28
|
-
|
29
|
-
|
30
|
-
-
|
31
|
-
-
|
32
|
-
-
|
33
|
-
|
34
|
-
|
35
|
-
-
|
36
|
-
|
37
|
-
|
38
|
-
-
|
39
|
-
|
40
|
-
|
1
|
+
3.0.1
|
2
|
+
- File SystemStackError when accessing missing param (@holies)
|
3
|
+
|
4
|
+
3.0.0
|
5
|
+
- Use Rack builder to shorten and simplify the code
|
6
|
+
- Add support for namespaces by using the builder
|
7
|
+
- Add ruby-prof as a development dependency
|
8
|
+
- NYNY will return a Rack-like response on each request ([status, headers, body])
|
9
|
+
- headers behave like a hash
|
10
|
+
- cookies behave like a hash
|
11
|
+
- added sprockets integration example
|
12
|
+
- improved documentation
|
13
|
+
- Fixed inheritance behaviour for App (routes, filters, helpers, middlewares
|
14
|
+
will be passed down the inheritance chain)
|
15
|
+
|
16
|
+
2.2.1
|
17
|
+
- Added support for templates
|
18
|
+
|
19
|
+
2.1.1
|
20
|
+
- After blocks will now be evaluated even if the request was halted
|
21
|
+
|
22
|
+
2.1.0
|
23
|
+
- Add ability to define helpers with a block
|
24
|
+
- Remove benchmark folder, and create a single benchmark file which can be
|
25
|
+
executed easily
|
26
|
+
- Simplified and optimized routing logic
|
27
|
+
- Fixed root path processing when a NYNY app is mounted
|
28
|
+
- Added Rails interop example
|
29
|
+
- Added session example
|
30
|
+
- Added NYNY.root
|
31
|
+
- Added NYNY.env
|
32
|
+
- NYNY will not show exceptions in production env
|
33
|
+
|
34
|
+
2.0.0
|
35
|
+
- Simplified and improved RouteSignature implementation
|
36
|
+
- Simplified and improved RequestScope implementation
|
37
|
+
- Made response object available in RequestScope
|
38
|
+
- removed .use_protection! (the rack-protection middleware can be easily
|
39
|
+
used manually)
|
40
|
+
- added support for extensions (using .register, which works the same way as in sinatra)
|
41
|
+
|
42
|
+
1.0.2
|
43
|
+
- Add rack to runtime deps (@etehtsea)
|
44
|
+
|
45
|
+
1.0.0 Initial release
|
data/Gemfile
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
gemspec
|
4
|
-
|
5
|
-
group :test do
|
6
|
-
gem 'coveralls', :require => false
|
7
|
-
|
8
|
-
end
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :test do
|
6
|
+
gem 'coveralls', :require => false
|
7
|
+
end
|
data/LICENSE.txt
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
Copyright (c) 2013 Andrei Lisnic
|
2
|
-
|
3
|
-
MIT License
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
-
a copy of this software and associated documentation files (the
|
7
|
-
"Software"), to deal in the Software without restriction, including
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
the following conditions:
|
12
|
-
|
13
|
-
The above copyright notice and this permission notice shall be
|
14
|
-
included in all copies or substantial portions of the Software.
|
15
|
-
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
1
|
+
Copyright (c) 2013 Andrei Lisnic
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Performance.md
CHANGED
@@ -1,46 +1,41 @@
|
|
1
|
-
This output was generated by running benchmark.rb in repo root
|
2
|
-
```
|
3
|
-
Comparing NYNY
|
4
|
-
|
5
|
-
Test:
|
6
|
-
user system total real
|
7
|
-
nyny: 0.
|
8
|
-
sinatra: 0.
|
9
|
-
NYNY is
|
10
|
-
|
11
|
-
Test:
|
12
|
-
user system total real
|
13
|
-
nyny: 0.
|
14
|
-
sinatra: 0.
|
15
|
-
NYNY is 2.
|
16
|
-
|
17
|
-
Test:
|
18
|
-
user system total real
|
19
|
-
nyny: 0.
|
20
|
-
sinatra: 0.
|
21
|
-
NYNY is 2.
|
22
|
-
|
23
|
-
Test:
|
24
|
-
user system total real
|
25
|
-
nyny: 0.
|
26
|
-
sinatra: 0.
|
27
|
-
NYNY is 2.
|
28
|
-
|
29
|
-
Test:
|
30
|
-
user system total real
|
31
|
-
nyny: 0.
|
32
|
-
sinatra: 0.
|
33
|
-
NYNY is 2.
|
34
|
-
|
35
|
-
Test: A lot
|
36
|
-
user system total real
|
37
|
-
nyny: 0.
|
38
|
-
sinatra: 0.
|
39
|
-
NYNY is 2.
|
40
|
-
|
41
|
-
|
42
|
-
user system total real
|
43
|
-
nyny: 0.130000 0.000000 0.130000 ( 0.125386)
|
44
|
-
sinatra: 0.280000 0.010000 0.290000 ( 0.291068)
|
45
|
-
NYNY is 2.32x faster than Sinatra in this test
|
46
|
-
```
|
1
|
+
This output was generated by running benchmark.rb in repo root
|
2
|
+
```
|
3
|
+
Comparing NYNY 3.0.0 with Sinatra 1.4.4
|
4
|
+
|
5
|
+
Test: hello world
|
6
|
+
user system total real
|
7
|
+
nyny: 0.110000 0.000000 0.110000 ( 0.108916)
|
8
|
+
sinatra: 0.260000 0.010000 0.270000 ( 0.273225)
|
9
|
+
NYNY is 2.51x faster than Sinatra in this test
|
10
|
+
|
11
|
+
Test: filters
|
12
|
+
user system total real
|
13
|
+
nyny: 0.120000 0.000000 0.120000 ( 0.118976)
|
14
|
+
sinatra: 0.250000 0.010000 0.260000 ( 0.264279)
|
15
|
+
NYNY is 2.22x faster than Sinatra in this test
|
16
|
+
|
17
|
+
Test: helpers
|
18
|
+
user system total real
|
19
|
+
nyny: 0.100000 0.000000 0.100000 ( 0.105290)
|
20
|
+
sinatra: 0.240000 0.000000 0.240000 ( 0.249585)
|
21
|
+
NYNY is 2.37x faster than Sinatra in this test
|
22
|
+
|
23
|
+
Test: Url patterns
|
24
|
+
user system total real
|
25
|
+
nyny: 0.120000 0.000000 0.120000 ( 0.113535)
|
26
|
+
sinatra: 0.260000 0.020000 0.280000 ( 0.277098)
|
27
|
+
NYNY is 2.44x faster than Sinatra in this test
|
28
|
+
|
29
|
+
Test: A lot o Plain routes
|
30
|
+
user system total real
|
31
|
+
nyny: 0.120000 0.000000 0.120000 ( 0.113001)
|
32
|
+
sinatra: 0.250000 0.000000 0.250000 ( 0.262890)
|
33
|
+
NYNY is 2.33x faster than Sinatra in this test
|
34
|
+
|
35
|
+
Test: A lot of Pattern routes
|
36
|
+
user system total real
|
37
|
+
nyny: 0.130000 0.000000 0.130000 ( 0.133590)
|
38
|
+
sinatra: 0.270000 0.010000 0.280000 ( 0.284605)
|
39
|
+
NYNY is 2.13x faster than Sinatra in this test
|
40
|
+
|
41
|
+
```
|
data/README.md
CHANGED
@@ -1,423 +1,423 @@
|
|
1
|
-
# New York, New York.
|
2
|
-
(very) small Sinatra clone.
|
3
|
-
|
4
|
-
[](https://travis-ci.org/alisnic/nyny)
|
5
|
-
[](https://coveralls.io/r/alisnic/nyny)
|
6
|
-
[](https://codeclimate.com/repos/521b7ee513d637348712864a/feed)
|
7
|
-
[](https://gemnasium.com/alisnic/nyny)
|
8
|
-
[](http://badge.fury.io/rb/nyny)
|
9
|
-
|
10
|
-
```ruby
|
11
|
-
# myapp.rb
|
12
|
-
|
13
|
-
require 'nyny'
|
14
|
-
class App < NYNY::App
|
15
|
-
get '/' do
|
16
|
-
'Hello world!'
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
App.run!
|
21
|
-
```
|
22
|
-
|
23
|
-
Install the gem:
|
24
|
-
|
25
|
-
```bash
|
26
|
-
gem install nyny
|
27
|
-
```
|
28
|
-
|
29
|
-
Run the file:
|
30
|
-
|
31
|
-
```bash
|
32
|
-
ruby myapp.rb
|
33
|
-
```
|
34
|
-
|
35
|
-
Open the browser at [http://localhost:9292](http://localhost:9292)
|
36
|
-
|
37
|
-
- [TOP](#new-york-new-york)
|
38
|
-
- [Motivation](#motivation)
|
39
|
-
- [Philosophy](#philosophy)
|
40
|
-
- [Why use NYNY instead of Sinatra](#why-use-nyny-instead-of-sinatra)
|
41
|
-
- [Usage](#usage)
|
42
|
-
- [Environment](#environment)
|
43
|
-
- [Running](#running)
|
44
|
-
- [Defining routes](#defining-routes)
|
45
|
-
- [Namespaces](#namespaces)
|
46
|
-
- [Templates](#templates)
|
47
|
-
- [Request scope](#request-scope)
|
48
|
-
- [Filters](#filters)
|
49
|
-
- [Middleware](#middleware)
|
50
|
-
- [Helpers](#helpers)
|
51
|
-
- [Extensions](#extensions)
|
52
|
-
- [FAQ](#f-a-q)
|
53
|
-
- [Contributing](#contributing)
|
54
|
-
|
55
|
-
# Motivation
|
56
|
-
My efforts to write __NYNY__ started when I wanted to understand how __Sinatra__
|
57
|
-
works, and stumbled upon the [base.rb][0]. The majority of the classes that
|
58
|
-
are used by Sinatra are in one single file, which makes it nearly impossible
|
59
|
-
for a new person to grasp.
|
60
|
-
|
61
|
-
I wanted to understand how sinatra works, but the code was pretty challenging.
|
62
|
-
So I decided I should re-implement the basic things Sinatra has.
|
63
|
-
Thus, __NYNY__ was born.
|
64
|
-
|
65
|
-
# Philosophy
|
66
|
-
NYNY should have only the bare minimum to write basic web servers comfortably,
|
67
|
-
everything else should be in a extension. It is also
|
68
|
-
trivial to use NYNY to build large and complex apps, by writing multiple sub
|
69
|
-
apps and using Rack to mount them, or by using those sub apps in the "main" app
|
70
|
-
as middleware.
|
71
|
-
|
72
|
-
# Why use NYNY instead of Sinatra
|
73
|
-
- It's very small (~300 LOC), which is just a little overhead on top of Rack.
|
74
|
-
- Sinatra is a drop-in replacement for NYNY. Anytime you feel that you need more,
|
75
|
-
you can just change your app to inherit from `Sinatra::Base`, your code will
|
76
|
-
still work, and you will be able to use any of the Sinatra features.
|
77
|
-
- It's __~2 times faster__ than Sinatra (see [Performance][performance] for details)
|
78
|
-
- You want to dig into the source code and change to your needs (NYNY's source code is more welcoming)
|
79
|
-
- Each NYNY app is a Rack middleware, so it can be used inside of Sinatra, Rails, or any other Rack-based app.
|
80
|
-
|
81
|
-
# Usage
|
82
|
-
|
83
|
-
A NYNY app must _always_ be in a class which inherits from `NYNY::App`:
|
84
|
-
|
85
|
-
```ruby
|
86
|
-
class App < NYNY::App
|
87
|
-
get '/' do
|
88
|
-
'Hello, World'
|
89
|
-
end
|
90
|
-
end
|
91
|
-
```
|
92
|
-
|
93
|
-
## Environment
|
94
|
-
To get the directory in which your app is running use `NYNY.root`
|
95
|
-
|
96
|
-
```ruby
|
97
|
-
#/some/folder/server.rb
|
98
|
-
require 'nyny'
|
99
|
-
puts NYNY.root #=> /some/folder/
|
100
|
-
```
|
101
|
-
|
102
|
-
To get NYNY's environment, use `NYNY.env`
|
103
|
-
|
104
|
-
```ruby
|
105
|
-
#env.rb
|
106
|
-
require 'nyny'
|
107
|
-
puts NYNY.env
|
108
|
-
puts NYNY.env.production?
|
109
|
-
```
|
110
|
-
|
111
|
-
```bash
|
112
|
-
$ ruby env.rb
|
113
|
-
development
|
114
|
-
false
|
115
|
-
|
116
|
-
$ ruby env.rb RACK_ENV=production
|
117
|
-
production
|
118
|
-
true
|
119
|
-
```
|
120
|
-
|
121
|
-
## Running
|
122
|
-
There are two ways to run a NYNY app __directly__ [[?]](#middleware):
|
123
|
-
|
124
|
-
- by requiring it in a `config.ru` file, and then passing it as argument to the
|
125
|
-
Rack's `run` function:
|
126
|
-
|
127
|
-
```ruby
|
128
|
-
# config.ru
|
129
|
-
|
130
|
-
require 'app'
|
131
|
-
run App.new
|
132
|
-
```
|
133
|
-
- by using the `run!` method directly on the app class:
|
134
|
-
|
135
|
-
```ruby
|
136
|
-
# app.rb
|
137
|
-
|
138
|
-
# ...app class definition...
|
139
|
-
|
140
|
-
App.run!
|
141
|
-
```
|
142
|
-
|
143
|
-
`run!` takes the port number as optional argument (the default port is 9292).
|
144
|
-
Also the `run!` method will include 2 default middlewares to make the
|
145
|
-
development easier: Rack::CommonLogger and Rack::ShowExceptions.
|
146
|
-
This will show all requests in the log, and will provide useful details
|
147
|
-
in the case a error occurs during a request.
|
148
|
-
|
149
|
-
## Defining routes
|
150
|
-
|
151
|
-
NYNY supports the following verbs for defining a route: delete, get, head,
|
152
|
-
options, patch, post, put and trace.
|
153
|
-
|
154
|
-
```ruby
|
155
|
-
class App < NYNY::App
|
156
|
-
post '/' do
|
157
|
-
'You Posted, dude!'
|
158
|
-
end
|
159
|
-
end
|
160
|
-
```
|
161
|
-
|
162
|
-
NYNY also suports basic URL patterns:
|
163
|
-
|
164
|
-
```ruby
|
165
|
-
class App < NYNY::App
|
166
|
-
get '/greet/:first_name/:last_name' do
|
167
|
-
# the last expression in the block is _always_ considered the response body.
|
168
|
-
"Hello #{params[:first_name]} #{params[:last_name]}!"
|
169
|
-
end
|
170
|
-
end
|
171
|
-
```
|
172
|
-
|
173
|
-
you can also tell NYNY to match a regex for a path:
|
174
|
-
|
175
|
-
```ruby
|
176
|
-
class App < NYNY::App
|
177
|
-
get /html/ do
|
178
|
-
'Your URL contains html!'
|
179
|
-
end
|
180
|
-
end
|
181
|
-
```
|
182
|
-
|
183
|
-
Each block that is passed to a route definition is evaluated in the context of
|
184
|
-
a request scope. See below what methods are available there.
|
185
|
-
|
186
|
-
## Namespaces
|
187
|
-
You can define namespaces for routes in NYNY. Each namespace is an isolated
|
188
|
-
app, which means that you can use the same api that you use in your top app there:
|
189
|
-
|
190
|
-
```ruby
|
191
|
-
class App < NYNY::App
|
192
|
-
get '/' do
|
193
|
-
'Hello'
|
194
|
-
end
|
195
|
-
|
196
|
-
namespace '/nested' do
|
197
|
-
use SomeMiddleware
|
198
|
-
helpers SomeHelpers
|
199
|
-
|
200
|
-
get '/' do # this will be accessible at '/nested'
|
201
|
-
'Hello from namespace!'
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
```
|
206
|
-
|
207
|
-
## Templates
|
208
|
-
NYNY can render templates, all you need is to call the `render` function:
|
209
|
-
```ruby
|
210
|
-
class App < NYNY::App
|
211
|
-
get '/' do
|
212
|
-
render 'index.erb'
|
213
|
-
end
|
214
|
-
end
|
215
|
-
```
|
216
|
-
There are 2 ways to pass data to the template:
|
217
|
-
|
218
|
-
Via a instance variable:
|
219
|
-
```ruby
|
220
|
-
class App < NYNY::App
|
221
|
-
get '/' do
|
222
|
-
@foo = 'bar' #access it as @foo in template
|
223
|
-
render 'index.erb'
|
224
|
-
end
|
225
|
-
end
|
226
|
-
```
|
227
|
-
|
228
|
-
Or via a local variable:
|
229
|
-
```ruby
|
230
|
-
class App < NYNY::App
|
231
|
-
get '/' do
|
232
|
-
render 'index.erb', :foo => 'bar' #access it as foo in template
|
233
|
-
end
|
234
|
-
end
|
235
|
-
```
|
236
|
-
|
237
|
-
To render a template with a layout, you need to render both files. It's best
|
238
|
-
to create a helper for that:
|
239
|
-
```ruby
|
240
|
-
class App < NYNY::App
|
241
|
-
helpers do
|
242
|
-
def render_with_layout *args
|
243
|
-
render 'layout.erb' do
|
244
|
-
render *args
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
get '/' do
|
250
|
-
render_with_layout 'index.erb'
|
251
|
-
end
|
252
|
-
end
|
253
|
-
```
|
254
|
-
NYNY uses [Tilt][tilt] for templating, so the list of supported engines is pretty complete.
|
255
|
-
|
256
|
-
## Request scope
|
257
|
-
As was said above, when you pass a block to a route definition,
|
258
|
-
that block is evaluated in the context of a [RequestScope][2].
|
259
|
-
This means that several methods/objects available inside that block:
|
260
|
-
|
261
|
-
- `request` - A `Rack::Request` object which encapsulates the request
|
262
|
-
to that route. (see [Rack::Request documentation][3] for more info)
|
263
|
-
- `response` - A `Rack::Response` object which encapsulates the response.
|
264
|
-
Additionally, NYNY's response exposes 2 more methods in addition to Rack's ones.
|
265
|
-
(see [primitives.rb][primitivesrb])
|
266
|
-
- `params` - a hash which contains both POST body params and GET querystring params.
|
267
|
-
- `headers` - a hash with the response headers
|
268
|
-
(ex: `headers['Content-Type'] = 'text/html'`)
|
269
|
-
- `status` - allows you to set the status of the response (ex: `status 403`)
|
270
|
-
- `redirect_to` - sets the response to redirect
|
271
|
-
(ex: `redirect_to 'http://google.com'`)
|
272
|
-
- `cookies` - a hash which allows you to access/modify/remove cookies
|
273
|
-
(ex: `cookies[:foo] = 'bar'` or `cookies.delete[:foo]`)
|
274
|
-
- `session` - a hash which allows you to access/modify/remove session variables
|
275
|
-
(ex: `session[:foo] = 'bar'`)
|
276
|
-
- `halt` - allows you to instantly return a response, interrupting current
|
277
|
-
handler execution (see [halt][halt-definition])
|
278
|
-
|
279
|
-
## Filters
|
280
|
-
|
281
|
-
Unlike Sinatra, NYNY supports only "generic" before and after filters.
|
282
|
-
This means that you can't declare a filter to execute depending on a URL pattern.
|
283
|
-
However, you can obtain the same effect by calling next in a before block
|
284
|
-
if the request.path matches a pattern.
|
285
|
-
|
286
|
-
```ruby
|
287
|
-
class App < NYNY::App
|
288
|
-
before do
|
289
|
-
next unless /html/ =~ request.path
|
290
|
-
headers['Content-Type'] = 'text/html'
|
291
|
-
end
|
292
|
-
|
293
|
-
after do
|
294
|
-
puts response.inspect
|
295
|
-
end
|
296
|
-
|
297
|
-
get '/' do
|
298
|
-
'hello'
|
299
|
-
end
|
300
|
-
end
|
301
|
-
```
|
302
|
-
|
303
|
-
## Middleware
|
304
|
-
|
305
|
-
A NYNY app is a Rack middleware, which means that it can be used inside
|
306
|
-
Sinatra, Rails, or any other Rack-based app:
|
307
|
-
|
308
|
-
```ruby
|
309
|
-
class MyApp < Sinatra::Base
|
310
|
-
use MyNYNYApp
|
311
|
-
end
|
312
|
-
```
|
313
|
-
|
314
|
-
NYNY also supports middleware itself, and that means you can use Rack middleware
|
315
|
-
(or a Sinatra app) inside a NYNY app:
|
316
|
-
|
317
|
-
```ruby
|
318
|
-
class App < NYNY::App
|
319
|
-
# this will serve all the files in the "public" folder
|
320
|
-
use Rack::Static :url => ['public']
|
321
|
-
use SinatraApp
|
322
|
-
end
|
323
|
-
```
|
324
|
-
|
325
|
-
I recommend looking at [the list of Rack middlewares][rack-middleware]
|
326
|
-
|
327
|
-
## Helpers
|
328
|
-
|
329
|
-
NYNY supports helpers as Sinatra does:
|
330
|
-
|
331
|
-
```ruby
|
332
|
-
class App < NYNY::App
|
333
|
-
helpers MyHelperModule
|
334
|
-
helpers do
|
335
|
-
def using_a_block_to_define_helper
|
336
|
-
true
|
337
|
-
end
|
338
|
-
end
|
339
|
-
end
|
340
|
-
```
|
341
|
-
|
342
|
-
|
343
|
-
Using a helper implies that the helper module is included in the [RequestScope][2],
|
344
|
-
and that all the methods in that module will be available inside a route
|
345
|
-
definition block.
|
346
|
-
|
347
|
-
## Extensions
|
348
|
-
|
349
|
-
Since version 2.0.0, NYNY added support for extensions.
|
350
|
-
This makes possible to include helpers, middlewares and custom app class
|
351
|
-
methods inside a single module:
|
352
|
-
|
353
|
-
```ruby
|
354
|
-
module MyKewlExtension
|
355
|
-
class Middleware
|
356
|
-
def initialize app
|
357
|
-
@app = app
|
358
|
-
end
|
359
|
-
|
360
|
-
def call env
|
361
|
-
env['KEWL'] = true
|
362
|
-
@app.call(env) if @app
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
module Helpers
|
367
|
-
def the_ultimate_answer
|
368
|
-
42
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
def get_or_post route, &block
|
373
|
-
get route, &block
|
374
|
-
post route, &block
|
375
|
-
end
|
376
|
-
|
377
|
-
def self.registered app
|
378
|
-
app.use Middleware
|
379
|
-
app.helpers Helpers
|
380
|
-
|
381
|
-
app.get_or_post '/' do
|
382
|
-
"After many years of hard computation, the answer is #{the_ultimate_answer}"
|
383
|
-
end
|
384
|
-
end
|
385
|
-
end
|
386
|
-
|
387
|
-
class App < NYNY::App
|
388
|
-
register MyKewlExtension
|
389
|
-
end
|
390
|
-
|
391
|
-
App.run!
|
392
|
-
```
|
393
|
-
|
394
|
-
By default, the App class will `extend` the provided extension module.
|
395
|
-
Optionally, an extension can add a `registered` method, which will be invoked
|
396
|
-
once the extension is registered. That method will be called with the app class
|
397
|
-
as a parameter.
|
398
|
-
|
399
|
-
Since NYNY has the same extension interface as Sinatra, some Sinatra extensions
|
400
|
-
might work with NYNY, although that is not guaranteed. However, an extension
|
401
|
-
written for NYNY will always work with Sinatra. (Forward compatible)
|
402
|
-
|
403
|
-
# F. A. Q.
|
404
|
-
TBD.
|
405
|
-
|
406
|
-
# Contributing
|
407
|
-
|
408
|
-
1. Fork it
|
409
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
410
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
411
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
412
|
-
5. Create new Pull Request
|
413
|
-
|
414
|
-
[0]: https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb
|
415
|
-
[1]: https://github.com/sinatra/sinatra/pull/716
|
416
|
-
[2]: https://github.com/alisnic/nyny/blob/master/lib/nyny/request_scope.rb
|
417
|
-
[3]: http://rack.rubyforge.org/doc/classes/Rack/Request.html
|
418
|
-
[4]: http://rack.rubyforge.org/doc/classes/Rack/Response.html
|
419
|
-
[performance]: https://github.com/alisnic/nyny/blob/master/Performance.md
|
420
|
-
[rack-middleware]: https://github.com/rack/rack/wiki/List-of-Middleware
|
421
|
-
[halt-definition]: https://github.com/alisnic/nyny/blob/master/lib/nyny/request_scope.rb#L36
|
422
|
-
[primitivesrb]: https://github.com/alisnic/nyny/blob/master/lib/nyny/primitives.rb
|
423
|
-
[tilt]: https://github.com/rtomayko/tilt
|
1
|
+
# New York, New York.
|
2
|
+
(very) small Sinatra clone.
|
3
|
+
|
4
|
+
[](https://travis-ci.org/alisnic/nyny)
|
5
|
+
[](https://coveralls.io/r/alisnic/nyny)
|
6
|
+
[](https://codeclimate.com/repos/521b7ee513d637348712864a/feed)
|
7
|
+
[](https://gemnasium.com/alisnic/nyny)
|
8
|
+
[](http://badge.fury.io/rb/nyny)
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
# myapp.rb
|
12
|
+
|
13
|
+
require 'nyny'
|
14
|
+
class App < NYNY::App
|
15
|
+
get '/' do
|
16
|
+
'Hello world!'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
App.run!
|
21
|
+
```
|
22
|
+
|
23
|
+
Install the gem:
|
24
|
+
|
25
|
+
```bash
|
26
|
+
gem install nyny
|
27
|
+
```
|
28
|
+
|
29
|
+
Run the file:
|
30
|
+
|
31
|
+
```bash
|
32
|
+
ruby myapp.rb
|
33
|
+
```
|
34
|
+
|
35
|
+
Open the browser at [http://localhost:9292](http://localhost:9292)
|
36
|
+
|
37
|
+
- [TOP](#new-york-new-york)
|
38
|
+
- [Motivation](#motivation)
|
39
|
+
- [Philosophy](#philosophy)
|
40
|
+
- [Why use NYNY instead of Sinatra](#why-use-nyny-instead-of-sinatra)
|
41
|
+
- [Usage](#usage)
|
42
|
+
- [Environment](#environment)
|
43
|
+
- [Running](#running)
|
44
|
+
- [Defining routes](#defining-routes)
|
45
|
+
- [Namespaces](#namespaces)
|
46
|
+
- [Templates](#templates)
|
47
|
+
- [Request scope](#request-scope)
|
48
|
+
- [Filters](#filters)
|
49
|
+
- [Middleware](#middleware)
|
50
|
+
- [Helpers](#helpers)
|
51
|
+
- [Extensions](#extensions)
|
52
|
+
- [FAQ](#f-a-q)
|
53
|
+
- [Contributing](#contributing)
|
54
|
+
|
55
|
+
# Motivation
|
56
|
+
My efforts to write __NYNY__ started when I wanted to understand how __Sinatra__
|
57
|
+
works, and stumbled upon the [base.rb][0]. The majority of the classes that
|
58
|
+
are used by Sinatra are in one single file, which makes it nearly impossible
|
59
|
+
for a new person to grasp.
|
60
|
+
|
61
|
+
I wanted to understand how sinatra works, but the code was pretty challenging.
|
62
|
+
So I decided I should re-implement the basic things Sinatra has.
|
63
|
+
Thus, __NYNY__ was born.
|
64
|
+
|
65
|
+
# Philosophy
|
66
|
+
NYNY should have only the bare minimum to write basic web servers comfortably,
|
67
|
+
everything else should be in a extension. It is also
|
68
|
+
trivial to use NYNY to build large and complex apps, by writing multiple sub
|
69
|
+
apps and using Rack to mount them, or by using those sub apps in the "main" app
|
70
|
+
as middleware.
|
71
|
+
|
72
|
+
# Why use NYNY instead of Sinatra
|
73
|
+
- It's very small (~300 LOC), which is just a little overhead on top of Rack.
|
74
|
+
- Sinatra is a drop-in replacement for NYNY. Anytime you feel that you need more,
|
75
|
+
you can just change your app to inherit from `Sinatra::Base`, your code will
|
76
|
+
still work, and you will be able to use any of the Sinatra features.
|
77
|
+
- It's __~2 times faster__ than Sinatra (see [Performance][performance] for details)
|
78
|
+
- You want to dig into the source code and change to your needs (NYNY's source code is more welcoming)
|
79
|
+
- Each NYNY app is a Rack middleware, so it can be used inside of Sinatra, Rails, or any other Rack-based app.
|
80
|
+
|
81
|
+
# Usage
|
82
|
+
|
83
|
+
A NYNY app must _always_ be in a class which inherits from `NYNY::App`:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
class App < NYNY::App
|
87
|
+
get '/' do
|
88
|
+
'Hello, World'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
## Environment
|
94
|
+
To get the directory in which your app is running use `NYNY.root`
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
#/some/folder/server.rb
|
98
|
+
require 'nyny'
|
99
|
+
puts NYNY.root #=> /some/folder/
|
100
|
+
```
|
101
|
+
|
102
|
+
To get NYNY's environment, use `NYNY.env`
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
#env.rb
|
106
|
+
require 'nyny'
|
107
|
+
puts NYNY.env
|
108
|
+
puts NYNY.env.production?
|
109
|
+
```
|
110
|
+
|
111
|
+
```bash
|
112
|
+
$ ruby env.rb
|
113
|
+
development
|
114
|
+
false
|
115
|
+
|
116
|
+
$ ruby env.rb RACK_ENV=production
|
117
|
+
production
|
118
|
+
true
|
119
|
+
```
|
120
|
+
|
121
|
+
## Running
|
122
|
+
There are two ways to run a NYNY app __directly__ [[?]](#middleware):
|
123
|
+
|
124
|
+
- by requiring it in a `config.ru` file, and then passing it as argument to the
|
125
|
+
Rack's `run` function:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
# config.ru
|
129
|
+
|
130
|
+
require 'app'
|
131
|
+
run App.new
|
132
|
+
```
|
133
|
+
- by using the `run!` method directly on the app class:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
# app.rb
|
137
|
+
|
138
|
+
# ...app class definition...
|
139
|
+
|
140
|
+
App.run!
|
141
|
+
```
|
142
|
+
|
143
|
+
`run!` takes the port number as optional argument (the default port is 9292).
|
144
|
+
Also the `run!` method will include 2 default middlewares to make the
|
145
|
+
development easier: Rack::CommonLogger and Rack::ShowExceptions.
|
146
|
+
This will show all requests in the log, and will provide useful details
|
147
|
+
in the case a error occurs during a request.
|
148
|
+
|
149
|
+
## Defining routes
|
150
|
+
|
151
|
+
NYNY supports the following verbs for defining a route: delete, get, head,
|
152
|
+
options, patch, post, put and trace.
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
class App < NYNY::App
|
156
|
+
post '/' do
|
157
|
+
'You Posted, dude!'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
```
|
161
|
+
|
162
|
+
NYNY also suports basic URL patterns:
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
class App < NYNY::App
|
166
|
+
get '/greet/:first_name/:last_name' do
|
167
|
+
# the last expression in the block is _always_ considered the response body.
|
168
|
+
"Hello #{params[:first_name]} #{params[:last_name]}!"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
you can also tell NYNY to match a regex for a path:
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
class App < NYNY::App
|
177
|
+
get /html/ do
|
178
|
+
'Your URL contains html!'
|
179
|
+
end
|
180
|
+
end
|
181
|
+
```
|
182
|
+
|
183
|
+
Each block that is passed to a route definition is evaluated in the context of
|
184
|
+
a request scope. See below what methods are available there.
|
185
|
+
|
186
|
+
## Namespaces
|
187
|
+
You can define namespaces for routes in NYNY. Each namespace is an isolated
|
188
|
+
app, which means that you can use the same api that you use in your top app there:
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
class App < NYNY::App
|
192
|
+
get '/' do
|
193
|
+
'Hello'
|
194
|
+
end
|
195
|
+
|
196
|
+
namespace '/nested' do
|
197
|
+
use SomeMiddleware
|
198
|
+
helpers SomeHelpers
|
199
|
+
|
200
|
+
get '/' do # this will be accessible at '/nested'
|
201
|
+
'Hello from namespace!'
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
```
|
206
|
+
|
207
|
+
## Templates
|
208
|
+
NYNY can render templates, all you need is to call the `render` function:
|
209
|
+
```ruby
|
210
|
+
class App < NYNY::App
|
211
|
+
get '/' do
|
212
|
+
render 'index.erb'
|
213
|
+
end
|
214
|
+
end
|
215
|
+
```
|
216
|
+
There are 2 ways to pass data to the template:
|
217
|
+
|
218
|
+
Via a instance variable:
|
219
|
+
```ruby
|
220
|
+
class App < NYNY::App
|
221
|
+
get '/' do
|
222
|
+
@foo = 'bar' #access it as @foo in template
|
223
|
+
render 'index.erb'
|
224
|
+
end
|
225
|
+
end
|
226
|
+
```
|
227
|
+
|
228
|
+
Or via a local variable:
|
229
|
+
```ruby
|
230
|
+
class App < NYNY::App
|
231
|
+
get '/' do
|
232
|
+
render 'index.erb', :foo => 'bar' #access it as foo in template
|
233
|
+
end
|
234
|
+
end
|
235
|
+
```
|
236
|
+
|
237
|
+
To render a template with a layout, you need to render both files. It's best
|
238
|
+
to create a helper for that:
|
239
|
+
```ruby
|
240
|
+
class App < NYNY::App
|
241
|
+
helpers do
|
242
|
+
def render_with_layout *args
|
243
|
+
render 'layout.erb' do
|
244
|
+
render *args
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
get '/' do
|
250
|
+
render_with_layout 'index.erb'
|
251
|
+
end
|
252
|
+
end
|
253
|
+
```
|
254
|
+
NYNY uses [Tilt][tilt] for templating, so the list of supported engines is pretty complete.
|
255
|
+
|
256
|
+
## Request scope
|
257
|
+
As was said above, when you pass a block to a route definition,
|
258
|
+
that block is evaluated in the context of a [RequestScope][2].
|
259
|
+
This means that several methods/objects available inside that block:
|
260
|
+
|
261
|
+
- `request` - A `Rack::Request` object which encapsulates the request
|
262
|
+
to that route. (see [Rack::Request documentation][3] for more info)
|
263
|
+
- `response` - A `Rack::Response` object which encapsulates the response.
|
264
|
+
Additionally, NYNY's response exposes 2 more methods in addition to Rack's ones.
|
265
|
+
(see [primitives.rb][primitivesrb])
|
266
|
+
- `params` - a hash which contains both POST body params and GET querystring params.
|
267
|
+
- `headers` - a hash with the response headers
|
268
|
+
(ex: `headers['Content-Type'] = 'text/html'`)
|
269
|
+
- `status` - allows you to set the status of the response (ex: `status 403`)
|
270
|
+
- `redirect_to` - sets the response to redirect
|
271
|
+
(ex: `redirect_to 'http://google.com'`)
|
272
|
+
- `cookies` - a hash which allows you to access/modify/remove cookies
|
273
|
+
(ex: `cookies[:foo] = 'bar'` or `cookies.delete[:foo]`)
|
274
|
+
- `session` - a hash which allows you to access/modify/remove session variables
|
275
|
+
(ex: `session[:foo] = 'bar'`)
|
276
|
+
- `halt` - allows you to instantly return a response, interrupting current
|
277
|
+
handler execution (see [halt][halt-definition])
|
278
|
+
|
279
|
+
## Filters
|
280
|
+
|
281
|
+
Unlike Sinatra, NYNY supports only "generic" before and after filters.
|
282
|
+
This means that you can't declare a filter to execute depending on a URL pattern.
|
283
|
+
However, you can obtain the same effect by calling next in a before block
|
284
|
+
if the request.path matches a pattern.
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
class App < NYNY::App
|
288
|
+
before do
|
289
|
+
next unless /html/ =~ request.path
|
290
|
+
headers['Content-Type'] = 'text/html'
|
291
|
+
end
|
292
|
+
|
293
|
+
after do
|
294
|
+
puts response.inspect
|
295
|
+
end
|
296
|
+
|
297
|
+
get '/' do
|
298
|
+
'hello'
|
299
|
+
end
|
300
|
+
end
|
301
|
+
```
|
302
|
+
|
303
|
+
## Middleware
|
304
|
+
|
305
|
+
A NYNY app is a Rack middleware, which means that it can be used inside
|
306
|
+
Sinatra, Rails, or any other Rack-based app:
|
307
|
+
|
308
|
+
```ruby
|
309
|
+
class MyApp < Sinatra::Base
|
310
|
+
use MyNYNYApp
|
311
|
+
end
|
312
|
+
```
|
313
|
+
|
314
|
+
NYNY also supports middleware itself, and that means you can use Rack middleware
|
315
|
+
(or a Sinatra app) inside a NYNY app:
|
316
|
+
|
317
|
+
```ruby
|
318
|
+
class App < NYNY::App
|
319
|
+
# this will serve all the files in the "public" folder
|
320
|
+
use Rack::Static :url => ['public']
|
321
|
+
use SinatraApp
|
322
|
+
end
|
323
|
+
```
|
324
|
+
|
325
|
+
I recommend looking at [the list of Rack middlewares][rack-middleware]
|
326
|
+
|
327
|
+
## Helpers
|
328
|
+
|
329
|
+
NYNY supports helpers as Sinatra does:
|
330
|
+
|
331
|
+
```ruby
|
332
|
+
class App < NYNY::App
|
333
|
+
helpers MyHelperModule
|
334
|
+
helpers do
|
335
|
+
def using_a_block_to_define_helper
|
336
|
+
true
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
```
|
341
|
+
|
342
|
+
|
343
|
+
Using a helper implies that the helper module is included in the [RequestScope][2],
|
344
|
+
and that all the methods in that module will be available inside a route
|
345
|
+
definition block.
|
346
|
+
|
347
|
+
## Extensions
|
348
|
+
|
349
|
+
Since version 2.0.0, NYNY added support for extensions.
|
350
|
+
This makes possible to include helpers, middlewares and custom app class
|
351
|
+
methods inside a single module:
|
352
|
+
|
353
|
+
```ruby
|
354
|
+
module MyKewlExtension
|
355
|
+
class Middleware
|
356
|
+
def initialize app
|
357
|
+
@app = app
|
358
|
+
end
|
359
|
+
|
360
|
+
def call env
|
361
|
+
env['KEWL'] = true
|
362
|
+
@app.call(env) if @app
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
module Helpers
|
367
|
+
def the_ultimate_answer
|
368
|
+
42
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def get_or_post route, &block
|
373
|
+
get route, &block
|
374
|
+
post route, &block
|
375
|
+
end
|
376
|
+
|
377
|
+
def self.registered app
|
378
|
+
app.use Middleware
|
379
|
+
app.helpers Helpers
|
380
|
+
|
381
|
+
app.get_or_post '/' do
|
382
|
+
"After many years of hard computation, the answer is #{the_ultimate_answer}"
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
class App < NYNY::App
|
388
|
+
register MyKewlExtension
|
389
|
+
end
|
390
|
+
|
391
|
+
App.run!
|
392
|
+
```
|
393
|
+
|
394
|
+
By default, the App class will `extend` the provided extension module.
|
395
|
+
Optionally, an extension can add a `registered` method, which will be invoked
|
396
|
+
once the extension is registered. That method will be called with the app class
|
397
|
+
as a parameter.
|
398
|
+
|
399
|
+
Since NYNY has the same extension interface as Sinatra, some Sinatra extensions
|
400
|
+
might work with NYNY, although that is not guaranteed. However, an extension
|
401
|
+
written for NYNY will always work with Sinatra. (Forward compatible)
|
402
|
+
|
403
|
+
# F. A. Q.
|
404
|
+
TBD.
|
405
|
+
|
406
|
+
# Contributing
|
407
|
+
|
408
|
+
1. Fork it
|
409
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
410
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
411
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
412
|
+
5. Create new Pull Request
|
413
|
+
|
414
|
+
[0]: https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb
|
415
|
+
[1]: https://github.com/sinatra/sinatra/pull/716
|
416
|
+
[2]: https://github.com/alisnic/nyny/blob/master/lib/nyny/request_scope.rb
|
417
|
+
[3]: http://rack.rubyforge.org/doc/classes/Rack/Request.html
|
418
|
+
[4]: http://rack.rubyforge.org/doc/classes/Rack/Response.html
|
419
|
+
[performance]: https://github.com/alisnic/nyny/blob/master/Performance.md
|
420
|
+
[rack-middleware]: https://github.com/rack/rack/wiki/List-of-Middleware
|
421
|
+
[halt-definition]: https://github.com/alisnic/nyny/blob/master/lib/nyny/request_scope.rb#L36
|
422
|
+
[primitivesrb]: https://github.com/alisnic/nyny/blob/master/lib/nyny/primitives.rb
|
423
|
+
[tilt]: https://github.com/rtomayko/tilt
|