nyny 1.0.0.pre1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +5 -0
- data/Performance.md +8 -6
- data/README.md +116 -55
- data/Rakefile +5 -0
- data/benchmarks/filters/{frankie.rb → nyny.rb} +2 -2
- data/benchmarks/helpers/{frankie.rb → nyny.rb} +2 -2
- data/benchmarks/simple/{frankie.rb → nyny.rb} +2 -2
- data/benchmarks/url_pattern/{frankie.rb → nyny.rb} +2 -2
- data/examples/active_record/server.rb +2 -2
- data/examples/data_mapper/Gemfile +7 -0
- data/examples/data_mapper/database.rb +7 -0
- data/examples/data_mapper/models/shout.rb +7 -0
- data/examples/data_mapper/server.rb +41 -0
- data/examples/json_api.rb +2 -2
- data/examples/templates/server.rb +5 -4
- data/examples/web_sockets/server.rb +4 -4
- data/lib/nyny.rb +4 -2
- data/lib/nyny/app.rb +46 -47
- data/lib/nyny/middleware_chain.rb +14 -0
- data/lib/nyny/request_scope.rb +3 -9
- data/lib/nyny/route_signature.rb +11 -11
- data/lib/nyny/router.rb +44 -0
- data/lib/nyny/runner.rb +18 -0
- data/lib/nyny/version.rb +1 -1
- data/nyny.gemspec +2 -2
- data/spec/app_spec.rb +34 -24
- data/spec/primitives_spec.rb +11 -4
- data/spec/request_scope_spec.rb +12 -2
- data/spec/route_signature_spec.rb +9 -0
- data/spec/runner_spec.rb +23 -0
- data/spec/spec_helper.rb +14 -3
- metadata +23 -15
- data/.ruby-gemset +0 -1
- data/lib/nyny/class_level_api.rb +0 -40
- data/spec/class_level_api_spec.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d06702b70c5c8ae2b5b41dec0c6cdddd867e2cc
|
4
|
+
data.tar.gz: 771e4872192c8727b722181153822df8dd379985
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20c1401e48e5dd9a690c084ac040bdf705db169f765ea4203ed7bcc9cc63149f2153d4a1f8a96bb6b0d12d4c3007ed39c36f4e353fcb5da7318814580347e163
|
7
|
+
data.tar.gz: 9bdd755fcd18570974ce27564a605618f8dd3ea944111d74c55268b86879a85e320c9672be7738d1d99a9edcfeb390ee398adcb0a9fcffd1afdcbb40d77c8f7c
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/Performance.md
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
#
|
1
|
+
# NYNY vs Sinatra performance test
|
2
2
|
|
3
3
|
Note: all the tests below were made using Thin as a webserver. Httperf was
|
4
4
|
choosen as the tool to do that. Bench settings: `--num-conns 10000`
|
5
5
|
|
6
6
|
Hardware: Intel(R) Core(TM) i7-2620M CPU @ 2.70GHz, 6 GB DDR3
|
7
7
|
|
8
|
+
If you have a clue how to make proper benchmarks (because, frankly, I don't), I am open to suggestions.
|
9
|
+
|
8
10
|
## Results
|
9
11
|
|
10
|
-
| Benchmark |
|
12
|
+
| Benchmark | NYNY (req/s) | Sinatra (req/s) |
|
11
13
|
|-----------|:---------------:|:---------------:|
|
12
14
|
| Simple |__5012__ |2534 |
|
13
15
|
| UrlPattern|__4564__ |2338 |
|
@@ -19,21 +21,21 @@ See below the code for each benchmark
|
|
19
21
|
## Code
|
20
22
|
### Simple
|
21
23
|
|
22
|
-
class App <
|
24
|
+
class App < NYNY::App #(or Sinatra::Base)
|
23
25
|
get '/' do
|
24
26
|
'Hello World!'
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
28
30
|
### UrlPattern
|
29
|
-
class App <
|
31
|
+
class App < NYNY::App #(or Sinatra::Base)
|
30
32
|
get '/hello/:name' do
|
31
33
|
"Hello #{params[:name]}!"
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
37
|
### Filters
|
36
|
-
class App <
|
38
|
+
class App < NYNY::App #(or Sinatra::Base)
|
37
39
|
before do
|
38
40
|
request
|
39
41
|
end
|
@@ -54,7 +56,7 @@ See below the code for each benchmark
|
|
54
56
|
end
|
55
57
|
end
|
56
58
|
|
57
|
-
class App <
|
59
|
+
class App < NYNY::App #(or Sinatra::Base)
|
58
60
|
helpers Dude
|
59
61
|
|
60
62
|
get '/' do
|
data/README.md
CHANGED
@@ -1,10 +1,35 @@
|
|
1
1
|
# New York, New York.
|
2
|
-
Sinatra
|
2
|
+
(very) small Sinatra clone.
|
3
3
|
|
4
|
-
|
4
|
+
![alt text](https://api.travis-ci.org/alisnic/nyny.png "build status")
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/alisnic/nyny/badge.png)](https://coveralls.io/r/alisnic/nyny)
|
6
|
+
[![Code Climate](https://codeclimate.com/repos/521b7ee513d637348712864a/badges/60e3637788bbac94f1cb/gpa.png)](https://codeclimate.com/repos/521b7ee513d637348712864a/feed)
|
7
|
+
|
8
|
+
# myapp.rb
|
9
|
+
|
10
|
+
require 'nyny'
|
11
|
+
class App < NYNY::App
|
12
|
+
get '/' do
|
13
|
+
'Hello world!'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
App.run!
|
18
|
+
|
19
|
+
Install the gem:
|
20
|
+
|
21
|
+
gem install nyny --pre
|
22
|
+
|
23
|
+
Run the file
|
24
|
+
|
25
|
+
ruby myapp.rb
|
26
|
+
|
27
|
+
Open the browser at [http://localhost:9292]()
|
28
|
+
|
29
|
+
- [TOP](#new-york-new-york)
|
5
30
|
- [Motivation](#motivation)
|
6
31
|
- [Philosophy](#philosophy)
|
7
|
-
- [Why use NYNY instead of Sinatra](#why-use-
|
32
|
+
- [Why use NYNY instead of Sinatra](#why-use-nyny-instead-of-sinatra)
|
8
33
|
- [Usage](#usage)
|
9
34
|
- [Running](#running)
|
10
35
|
- [Defining routes](#defining-routes)
|
@@ -16,22 +41,27 @@ Sinatra's little brother.
|
|
16
41
|
- [Contributing](#contributing)
|
17
42
|
|
18
43
|
# Motivation
|
19
|
-
My efforts to write __NYNY__ started when I wanted to understand how __Sinatra__
|
20
|
-
|
21
|
-
|
44
|
+
My efforts to write __NYNY__ started when I wanted to understand how __Sinatra__
|
45
|
+
works, and stumbled upon the [base.rb][0]. The majority of the classes that
|
46
|
+
are used by sinatra are in one single file, which makes it nearly impossible
|
47
|
+
for a new person to grasp.
|
22
48
|
|
23
|
-
I wanted to understand how sinatra works, but the code was pretty challenging.
|
49
|
+
I wanted to understand how sinatra works, but the code was pretty challenging.
|
50
|
+
So I decided I should re-implement the basic things Sinatra has.
|
51
|
+
Thus, __NYNY__ was born.
|
24
52
|
|
25
53
|
# Philosophy
|
26
54
|
NYNY should have only the bare minimum to write basic web servers comfortably,
|
27
|
-
everything else should be in a extension
|
28
|
-
trivial to use
|
55
|
+
everything else should be in a extension. It is also
|
56
|
+
trivial to use NYNY to build large and complex apps, by writing multiple sub
|
29
57
|
apps and using Rack to mount them, or by using those sub apps in the "main" app
|
30
58
|
as middleware.
|
31
59
|
|
32
60
|
# Why use NYNY instead of Sinatra
|
33
|
-
- It's very small (
|
34
|
-
- Sinatra is a drop-in replacement for NYNY. Anytime you feel that you need more,
|
61
|
+
- It's very small (<300 LOC), which is just a little overhead on top of Rack.
|
62
|
+
- Sinatra is a drop-in replacement for NYNY. Anytime you feel that you need more,
|
63
|
+
you can just change your app to inherit from `Sinatra::Base`, your code will
|
64
|
+
still work, and you will be able to use any of the Sinatra features.
|
35
65
|
- It's __~2 times faster__ than Sinatra (see [Performance][performance] for details)
|
36
66
|
- You want to dig into the source code and change to your needs (NYNY's source code is more welcoming)
|
37
67
|
- Each NYNY app is a Rack middleware, so it can be used inside of Sinatra, Rails, or any other Rack-based app.
|
@@ -49,91 +79,120 @@ A NYNY app must _always_ be in a class which inherits from `NYNY::App`.
|
|
49
79
|
## Running
|
50
80
|
There are two ways to run a NYNY app __directly__ [[?]](#middleware):
|
51
81
|
|
52
|
-
-
|
82
|
+
- by requiring it in a `config.ru` file, and then passing it as argument to the
|
53
83
|
Rack's `run` function:
|
54
84
|
|
55
85
|
#config.ru
|
56
86
|
require 'app'
|
57
87
|
run App.new
|
58
|
-
|
88
|
+
|
59
89
|
- by using the `run!` method directly on the app class:
|
60
90
|
|
61
91
|
#app.rb
|
62
92
|
#...App class definition...
|
63
|
-
|
93
|
+
|
64
94
|
App.run!
|
65
|
-
|
66
|
-
`run!` takes the port number as optional argument (the default port is 9292).
|
95
|
+
|
96
|
+
`run!` takes the port number as optional argument (the default port is 9292).
|
97
|
+
Also the `run!` method will include 2 default middlewares to make the
|
98
|
+
development easier: Rack::CommonLogger and Rack::ShowExceptions.
|
99
|
+
This will show all requests in the log, and will provide useful details
|
100
|
+
in the case a error occurs during a request.
|
67
101
|
|
68
102
|
|
69
103
|
## Defining routes
|
70
104
|
|
71
|
-
NYNY supports the following verbs for defining a route: delete, get, head,
|
105
|
+
NYNY supports the following verbs for defining a route: delete, get, head,
|
106
|
+
options, patch, post, put and trace.
|
72
107
|
|
73
108
|
class App < NYNY::App
|
74
|
-
|
75
|
-
|
76
|
-
|
109
|
+
post '/' do
|
110
|
+
'You Posted, dude!'
|
111
|
+
end
|
77
112
|
end
|
78
113
|
|
79
114
|
NYNY also suports basic URL patterns:
|
80
115
|
|
81
116
|
class App < NYNY::App
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
117
|
+
get '/greet/:first_name/:last_name' do
|
118
|
+
# The last expression in the block is _always_ considered the response body.
|
119
|
+
"Hello #{params[:first_name]} #{params[:last_name]}!"
|
120
|
+
end
|
86
121
|
end
|
87
122
|
|
88
|
-
|
123
|
+
you can also tell NYNY to match a regex for a path:
|
124
|
+
|
125
|
+
class App < NYNY::App
|
126
|
+
get /html/ do
|
127
|
+
'Your URL contains html!'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
Each block that is passed to a route definition is evaluated in the context of
|
132
|
+
a request scope. See below what methods are available there.
|
89
133
|
|
90
134
|
## Request scope
|
91
|
-
As was said above, when you pass a block to a route definition,
|
135
|
+
As was said above, when you pass a block to a route definition,
|
136
|
+
that block is evaluated in the context of a [RequestScope][2].
|
137
|
+
This means that several methods/objects available inside that block:
|
92
138
|
|
93
|
-
- `request` - A `Rack::Request` object which encapsulates the request
|
139
|
+
- `request` - A `Rack::Request` object which encapsulates the request
|
140
|
+
to that route. (see [Rack::Request documentation][3] for more info)
|
94
141
|
- `params` - a hash which contains both POST body params and GET querystring params.
|
95
|
-
- `headers` - allows you to read/add headers to the response
|
142
|
+
- `headers` - allows you to read/add headers to the response
|
143
|
+
(ex: `headers 'Content-Type' => 'text/html'`)
|
96
144
|
- `status` - allows you to set the status of the response (ex: `status 403`)
|
97
|
-
- `redirect_to` - sets the response to redirect
|
98
|
-
|
99
|
-
- `
|
145
|
+
- `redirect_to` - sets the response to redirect
|
146
|
+
(ex: `redirect_to 'http://google.com'`)
|
147
|
+
- `cookies` - a hash which allows you to access/modify/remove cookies
|
148
|
+
(ex: `cookies[:foo] = 'bar'`)
|
149
|
+
- `session` - a hash which allows you to access/modify/remove session variables
|
150
|
+
(ex: `session[:foo] = 'bar'`)
|
100
151
|
|
101
152
|
## Filters
|
102
153
|
|
103
|
-
Unlike Sinatra, NYNY supports only "generic" before and after filters.
|
154
|
+
Unlike Sinatra, NYNY supports only "generic" before and after filters.
|
155
|
+
This means that you can't declare a filter to execute depending on a URL pattern.
|
156
|
+
However, you can obtain the same effect by calling next in a before block
|
157
|
+
if the request.path matches a pattern.
|
104
158
|
|
105
159
|
class App < NYNY::App
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
160
|
+
before do
|
161
|
+
next unless /html/ =~ request.path
|
162
|
+
headers 'Content-Type' => 'text/html'
|
163
|
+
end
|
164
|
+
|
165
|
+
after do
|
166
|
+
puts response.inspect
|
167
|
+
end
|
168
|
+
|
169
|
+
get '/' do
|
170
|
+
'hello'
|
171
|
+
end
|
117
172
|
end
|
118
173
|
|
119
|
-
Before and after filters are also evaluated in a RequestScope context.
|
174
|
+
Before and after filters are also evaluated in a RequestScope context.
|
175
|
+
A little exception are the after filters, which can access
|
176
|
+
the __response__ object ([Rack::Response][4]).
|
120
177
|
|
121
178
|
## Middleware
|
122
179
|
|
123
|
-
A
|
180
|
+
A NYNY app is a Rack middleware, which means that it can be used inside
|
181
|
+
Sinatra, Rails, or any other Rack-based app:
|
124
182
|
|
125
183
|
class MyApp < Sinatra::Base
|
126
|
-
|
184
|
+
use MyNYNYApp
|
127
185
|
end
|
128
186
|
|
129
|
-
NYNY also supports middleware itself, and that means you can use Rack middleware
|
187
|
+
NYNY also supports middleware itself, and that means you can use Rack middleware
|
188
|
+
(or a Sinatra app) inside a NYNY app:
|
130
189
|
|
131
190
|
class App < NYNY::App
|
132
|
-
|
133
|
-
|
134
|
-
|
191
|
+
#this will serve all the files in the "public" folder
|
192
|
+
use Rack::Static :url => ['public']
|
193
|
+
use SinatraApp
|
135
194
|
end
|
136
|
-
|
195
|
+
|
137
196
|
I recommend looking at [the list of Rack middlewares][rack-middleware]
|
138
197
|
|
139
198
|
## Helpers
|
@@ -141,10 +200,12 @@ I recommend looking at [the list of Rack middlewares][rack-middleware]
|
|
141
200
|
NYNY supports helpers as Sinatra does:
|
142
201
|
|
143
202
|
class App < NYNY::App
|
144
|
-
|
203
|
+
helpers MyHelperModule
|
145
204
|
end
|
146
205
|
|
147
|
-
Using a helper implies that the helper module is included in the [RequestScope][2],
|
206
|
+
Using a helper implies that the helper module is included in the [RequestScope][2],
|
207
|
+
and that all the methods in that module will be available inside a route
|
208
|
+
definition block.
|
148
209
|
|
149
210
|
# F. A. Q.
|
150
211
|
TBD.
|
@@ -160,8 +221,8 @@ TBD.
|
|
160
221
|
|
161
222
|
[0]: https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb
|
162
223
|
[1]: https://github.com/sinatra/sinatra/pull/716
|
163
|
-
[2]: https://github.com/alisnic/
|
224
|
+
[2]: https://github.com/alisnic/nyny/blob/master/lib/nyny/request_scope.rb
|
164
225
|
[3]: http://rack.rubyforge.org/doc/classes/Rack/Request.html
|
165
226
|
[4]: http://rack.rubyforge.org/doc/classes/Rack/Response.html
|
166
|
-
[performance]: https://github.com/alisnic/
|
227
|
+
[performance]: https://github.com/alisnic/nyny/blob/master/Performance.md
|
167
228
|
[rack-middleware]: https://github.com/rack/rack/wiki/List-of-Middleware
|
data/Rakefile
CHANGED
@@ -6,14 +6,14 @@ require 'rubygems'
|
|
6
6
|
require 'bundler'
|
7
7
|
Bundler.setup(:default, ENV['RACK_ENV'].to_sym)
|
8
8
|
|
9
|
-
require '
|
9
|
+
require 'nyny'
|
10
10
|
require_relative 'database'
|
11
11
|
|
12
12
|
#Require all models
|
13
13
|
Dir[File.dirname(__FILE__) + "/models/*.rb"].each {|file| require file }
|
14
14
|
TEMPLATE = DATA.read.freeze
|
15
15
|
|
16
|
-
class App <
|
16
|
+
class App < NYNY::App
|
17
17
|
get '/' do
|
18
18
|
shouts = Shout.all.reverse
|
19
19
|
ERB.new(TEMPLATE).result(binding)
|