little_frankie 1.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +5 -0
  7. data/LICENSE.txt +22 -0
  8. data/Performance.md +65 -0
  9. data/README.md +167 -0
  10. data/Rakefile +1 -0
  11. data/benchmarks/filters/frankie.rb +18 -0
  12. data/benchmarks/filters/sinatra.rb +17 -0
  13. data/benchmarks/helpers/frankie.rb +19 -0
  14. data/benchmarks/helpers/sinatra.rb +18 -0
  15. data/benchmarks/simple/frankie.rb +10 -0
  16. data/benchmarks/simple/sinatra.rb +9 -0
  17. data/benchmarks/url_pattern/frankie.rb +10 -0
  18. data/benchmarks/url_pattern/sinatra.rb +8 -0
  19. data/examples/active_record/.gitignore +1 -0
  20. data/examples/active_record/Gemfile +14 -0
  21. data/examples/active_record/Rakefile +51 -0
  22. data/examples/active_record/config/database.yml +0 -0
  23. data/examples/active_record/database.rb +12 -0
  24. data/examples/active_record/db/migrate/20130606133756_add_shouts.rb +12 -0
  25. data/examples/active_record/models/shout.rb +3 -0
  26. data/examples/active_record/server.rb +43 -0
  27. data/examples/json_api.rb +21 -0
  28. data/examples/templates/server.rb +27 -0
  29. data/examples/templates/views/index.haml +1 -0
  30. data/examples/web_sockets/public/FABridge.js +604 -0
  31. data/examples/web_sockets/public/WebSocketMain.swf +0 -0
  32. data/examples/web_sockets/public/index.html +76 -0
  33. data/examples/web_sockets/public/swfobject.js +4 -0
  34. data/examples/web_sockets/public/web_socket.js +388 -0
  35. data/examples/web_sockets/server.rb +60 -0
  36. data/lib/little_frankie.rb +9 -0
  37. data/lib/little_frankie/app.rb +66 -0
  38. data/lib/little_frankie/class_level_api.rb +40 -0
  39. data/lib/little_frankie/primitives.rb +25 -0
  40. data/lib/little_frankie/request_scope.rb +60 -0
  41. data/lib/little_frankie/route_signature.rb +44 -0
  42. data/lib/little_frankie/version.rb +3 -0
  43. data/little_frankie.gemspec +24 -0
  44. data/spec/app_spec.rb +144 -0
  45. data/spec/class_level_api_spec.rb +39 -0
  46. data/spec/primitives_spec.rb +26 -0
  47. data/spec/request_scope_spec.rb +71 -0
  48. data/spec/spec_helper.rb +42 -0
  49. metadata +138 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9d8d154d7208cae8c066755e72e8b892639cbbed
4
+ data.tar.gz: 22b3c70a5a6032e0e507bcc13a5ff73335e5ec48
5
+ SHA512:
6
+ metadata.gz: 57e1e6c341510d7e85dbc994fd95dbf0d2f30548bc7f291f771ef17bbdbac394bac80cb4942bb285a2c057dbb938859f25371723b809cb10d7c3e6dcb971a445
7
+ data.tar.gz: f88e9ab513a33e867a73ddd231b0d01a6a6c1828911054918ddcb9175e93da9a9cf679fb0707a41e235812678f5a4b0a71c6309f07fcb6ed0b80614318ca7b1c
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --order rand
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ frankie
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rack'
data/LICENSE.txt ADDED
@@ -0,0 +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.
data/Performance.md ADDED
@@ -0,0 +1,65 @@
1
+ # Frankie vs Sinatra performance test
2
+
3
+ Note: all the tests below were made using Thin as a webserver. Httperf was
4
+ choosen as the tool to do that. Bench settings: `--num-conns 10000`
5
+
6
+ Hardware: Intel(R) Core(TM) i7-2620M CPU @ 2.70GHz, 6 GB DDR3
7
+
8
+ ## Results
9
+
10
+ | Benchmark | Frankie (req/s) | Sinatra (req/s) |
11
+ |-----------|:---------------:|:---------------:|
12
+ | Simple |__5012__ |2534 |
13
+ | UrlPattern|__4564__ |2338 |
14
+ | Filters |__4510__ |2465 |
15
+ | Helpers |__4737__ |2663 |
16
+
17
+ See below the code for each benchmark
18
+
19
+ ## Code
20
+ ### Simple
21
+
22
+ class App < Frankie::App #(or Sinatra::Base)
23
+ get '/' do
24
+ 'Hello World!'
25
+ end
26
+ end
27
+
28
+ ### UrlPattern
29
+ class App < Frankie::App #(or Sinatra::Base)
30
+ get '/hello/:name' do
31
+ "Hello #{params[:name]}!"
32
+ end
33
+ end
34
+
35
+ ### Filters
36
+ class App < Frankie::App #(or Sinatra::Base)
37
+ before do
38
+ request
39
+ end
40
+
41
+ after do
42
+ response
43
+ end
44
+
45
+ get '/' do
46
+ 'Hello World!'
47
+ end
48
+ end
49
+
50
+ ### Helpers
51
+ module Dude
52
+ def da_request_man
53
+ request
54
+ end
55
+ end
56
+
57
+ class App < Frankie::App #(or Sinatra::Base)
58
+ helpers Dude
59
+
60
+ get '/' do
61
+ da_request_man
62
+ 'Hello World!'
63
+ end
64
+ end
65
+
data/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # Frankie
2
+ Sinatra's little brother.
3
+
4
+ - [TOP](#frankie)
5
+ - [Motivation](#motivation)
6
+ - [Philosophy](#philosophy)
7
+ - [Why use Frankie instead of Sinatra](#why-use-frankie-instead-of-sinatra)
8
+ - [Usage](#usage)
9
+ - [Running](#running)
10
+ - [Defining routes](#defining-routes)
11
+ - [Request scope](#request-scope)
12
+ - [Filters](#filters)
13
+ - [Middleware](#middleware)
14
+ - [Helpers](#helpers)
15
+ - [FAQ](#f-a-q)
16
+ - [Contributing](#contributing)
17
+
18
+ # Motivation
19
+ My efforts to write __Frankie__ started when I wanted to understand how __Sinatra__ works, and stumbled upon the [base.rb][0]. The majority of the classes that are used by sinatra are in one single file, which makes it nearly impossible for a new person to grasp.
20
+
21
+ [I've tried to change the situation][1], but unfortunately, my initiative was premature for the sinatra project (considering their plans).
22
+
23
+ I wanted to understand how sinatra works, but the code was pretty challenging. So I decided I should re-implement the basic things sinatra has. Thus, __Frankie__ was born.
24
+
25
+ # Philosophy
26
+ Frankie should have only the bare minimum to write basic web servers comfortably,
27
+ everything else should be in a extension (see frankie extensions). It is also
28
+ trivial to use frankie to build large and complex app, by writing multiple sub
29
+ apps and using Rack to mount them, or by using those sub apps in the "main" app
30
+ as middleware.
31
+
32
+ # Why use Frankie instead of Sinatra
33
+ - It's very small (~250 LOC), which is just a little overhead on top of Rack.
34
+ - Sinatra is a drop-in replacement for Frankie. Anytime you feel that you need more, you can just change your app to inherit from `Sinatra::Base`, your code will still work, and you will be able to use any of the Sinatra features.
35
+ - It's __~2 times faster__ than Sinatra (see [Performance][performance] for details)
36
+ - You want to dig into the source code and change to your needs (Frankie's source code is more welcoming)
37
+ - Each Frankie app is a Rack middleware, so it can be used inside of Sinatra, Rails, or any other Rack-based app.
38
+
39
+ # Usage
40
+
41
+ A Frankie app must _always_ be in a class which inherits from `Frankie::App`.
42
+
43
+ class App < Frankie::App
44
+ get '/' do
45
+ 'Hello, World'
46
+ end
47
+ end
48
+
49
+ ## Running
50
+ There are two ways to run a Frankie app __directly__ [[?]](#middleware):
51
+
52
+ - be requiring it in a `config.ru` file, and then passing it as argument to the
53
+ Rack's `run` function:
54
+
55
+ #config.ru
56
+ require 'app'
57
+ run App.new
58
+
59
+ - by using the `run!` method directly on the app class:
60
+
61
+ #app.rb
62
+ #...App class definition...
63
+
64
+ App.run!
65
+
66
+ `run!` takes the port number as optional argument (the default port is 9292). Also the `run!` method will include 2 default middlewares to make the development easier: Rack::CommonLogger and Rack::ShowExceptions. This will show all requests in the log, and will provide useful details in the case a error occurs during a request.
67
+
68
+
69
+ ## Defining routes
70
+
71
+ Frankie supports the following verbs for defining a route: delete, get, head, options, patch, post, put and trace.
72
+
73
+ class App < Frankie::App
74
+ post '/' do
75
+ 'You Posted, dude!'
76
+ end
77
+ end
78
+
79
+ Frankie also suports basic URL patterns:
80
+
81
+ class App < Frankie::App
82
+ get '/greet/:first_name/:last_name' do
83
+ # The last expression in the block is _always_ considered the response body.
84
+ "Hello #{params[:first_name]} #{params[:last_name]}!"
85
+ end
86
+ end
87
+
88
+ Each block that is passed to a route definition is evaluated in the context of a request scope. See below what methods are available there.
89
+
90
+ ## Request scope
91
+ As was said above, when you pass a block to a route definition, that block is evaluated in the context of a [RequestScope][2]. This means that several methods/objects available inside that block:
92
+
93
+ - `request` - A `Rack::Request` object which encapsulates the request to that route. (see [Rack::Request documentation][3] for more info)
94
+ - `params` - a hash which contains both POST body params and GET querystring params.
95
+ - `headers` - allows you to read/add headers to the response (ex: `headers 'Content-Type' => 'text/html'`)
96
+ - `status` - allows you to set the status of the response (ex: `status 403`)
97
+ - `redirect_to` - sets the response to redirect (ex: `redirect_to 'http://google.com'`)
98
+ - `cookies` - a hash which allows you to access/modify/remove cookies (ex: `cookies[:foo] = 'bar'`)
99
+ - `session` - a hash which allows you to access/modify/remove session variables (ex: `session[:foo] = 'bar'`)
100
+
101
+ ## Filters
102
+
103
+ Unlike Sinatra, Frankie supports only "generic" before and after filters. This means that you can't execute a filter depending on a URL pattern.
104
+
105
+ class App < Frankie::App
106
+ before do
107
+ headers 'Content-Type' => 'text/html'
108
+ end
109
+
110
+ after do
111
+ puts response.inspect
112
+ end
113
+
114
+ get '/' do
115
+ 'hello'
116
+ end
117
+ end
118
+
119
+ Before and after filters are also evaluated in a RequestScope context. A little exception are the after filters, which can access the __response__ object ([Rack::Response][4]).
120
+
121
+ ## Middleware
122
+
123
+ A Fankie app is a Rack middleware, which means that it can be used inside of Sinatra, Rails, or any other Rack-based app:
124
+
125
+ class MyApp < Sinatra::Base
126
+ use MyFrankieApp
127
+ end
128
+
129
+ Frankie also supports middleware itself, and that means you can use Rack middleware (or a Sinatra app) inside a Frankie app:
130
+
131
+ class App < Frankie::App
132
+ #this will serve all the files in the "public" folder
133
+ use Rack::Static :url => ['public']
134
+ use SinatraApp
135
+ end
136
+
137
+ I recommend looking at [the list of Rack middlewares][rack-middleware]
138
+
139
+ ## Helpers
140
+
141
+ Frankie supports helpers as Sinatra does:
142
+
143
+ class App < Frankie::App
144
+ helpers MyHelperModule
145
+ end
146
+
147
+ Using a helper implies that the helper module is included in the [RequestScope][2], and that all the methods in that module will be available inside a route definition block.
148
+
149
+ # F. A. Q.
150
+ TBD.
151
+
152
+
153
+ # Contributing
154
+
155
+ 1. Fork it
156
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
157
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
158
+ 4. Push to the branch (`git push origin my-new-feature`)
159
+ 5. Create new Pull Request
160
+
161
+ [0]: https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb
162
+ [1]: https://github.com/sinatra/sinatra/pull/716
163
+ [2]: https://github.com/alisnic/frankie/blob/master/lib/frankie/request_scope.rb
164
+ [3]: http://rack.rubyforge.org/doc/classes/Rack/Request.html
165
+ [4]: http://rack.rubyforge.org/doc/classes/Rack/Response.html
166
+ [performance]: https://github.com/alisnic/frankie/blob/master/Performance.md
167
+ [rack-middleware]: https://github.com/rack/rack/wiki/List-of-Middleware
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,18 @@
1
+ #!ruby -I ../../lib -I lib
2
+ require 'frankie'
3
+
4
+ class App < Frankie::App
5
+ before do
6
+ request
7
+ end
8
+
9
+ after do
10
+ response
11
+ end
12
+
13
+ get '/' do
14
+ 'Hello World!'
15
+ end
16
+ end
17
+
18
+ App.run!
@@ -0,0 +1,17 @@
1
+ #!ruby -I ../../lib -I lib
2
+ require 'sinatra'
3
+
4
+ class App < Sinatra::Base
5
+ before do
6
+ request
7
+ end
8
+
9
+ after do
10
+ response
11
+ end
12
+
13
+ get '/' do
14
+ 'Hello World!'
15
+ end
16
+ end
17
+
@@ -0,0 +1,19 @@
1
+ #!ruby -I ../../lib -I lib
2
+ require 'frankie'
3
+
4
+ module Dude
5
+ def da_request_man
6
+ request
7
+ end
8
+ end
9
+
10
+ class App < Frankie::App
11
+ helpers Dude
12
+
13
+ get '/' do
14
+ da_request_man
15
+ 'Hello World!'
16
+ end
17
+ end
18
+
19
+ App.run!
@@ -0,0 +1,18 @@
1
+ #!ruby -I ../../lib -I lib
2
+ require 'sinatra'
3
+
4
+ module Dude
5
+ def da_request_man
6
+ request
7
+ end
8
+ end
9
+
10
+ class App < Sinatra::Base
11
+ helpers Dude
12
+
13
+ get '/' do
14
+ da_request_man
15
+ 'Hello World!'
16
+ end
17
+ end
18
+
@@ -0,0 +1,10 @@
1
+ #!ruby -I ../../lib -I lib
2
+ require 'frankie'
3
+
4
+ class App < Frankie::App
5
+ get '/' do
6
+ 'Hello World!'
7
+ end
8
+ end
9
+
10
+ App.run!
@@ -0,0 +1,9 @@
1
+ #!ruby -I ../../lib -I lib
2
+ require 'sinatra'
3
+
4
+ class App < Sinatra::Base
5
+ get '/' do
6
+ 'Hello World!'
7
+ end
8
+ end
9
+
@@ -0,0 +1,10 @@
1
+ #!ruby -I ../../lib -I lib
2
+ require 'frankie'
3
+
4
+ class App < Frankie::App
5
+ get '/hello/:name' do
6
+ "Hello #{params[:name]}!"
7
+ end
8
+ end
9
+
10
+ App.run!
@@ -0,0 +1,8 @@
1
+ #!ruby -I ../../lib -I lib
2
+ require 'sinatra'
3
+
4
+ class App < Sinatra::Base
5
+ get '/hello/:name' do
6
+ "Hello #{params[:name]}!"
7
+ end
8
+ end
@@ -0,0 +1 @@
1
+ db/*.sqlite3
@@ -0,0 +1,14 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'activerecord', :require => 'active_record'
4
+ gem 'sqlite3'
5
+ gem 'rack'
6
+ gem 'thin'
7
+
8
+ group :development do
9
+ #
10
+ end
11
+
12
+ group :production do
13
+ #
14
+ end