nyny 1.0.0.pre1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|
+

|
5
|
+
[](https://coveralls.io/r/alisnic/nyny)
|
6
|
+
[](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)
|