georgi-kontrol 0.1 → 0.1.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.
- data/README.md +160 -47
- data/examples/git_app.ru +12 -0
- data/examples/hello_world.ru +11 -0
- data/examples/nested.ru +23 -0
- data/examples/pages/index.md +5 -0
- data/examples/routing.ru +15 -0
- data/examples/templates.ru +11 -0
- data/examples/templates/layout.rhtml +5 -0
- data/examples/templates/page.rhtml +2 -0
- data/lib/kontrol.rb +2 -1
- data/lib/kontrol/application.rb +33 -16
- metadata +11 -1
data/README.md
CHANGED
@@ -2,22 +2,50 @@ Kontrol - a micro framework
|
|
2
2
|
===========================
|
3
3
|
|
4
4
|
Kontrol is a small web framework written in Ruby, which runs directly
|
5
|
-
on Rack. It provides a simple pattern matching algorithm for routing
|
5
|
+
on [Rack][5]. It provides a simple pattern matching algorithm for routing
|
6
6
|
and uses GitStore as data storage.
|
7
7
|
|
8
|
+
All examples can be found in the [examples folder][3] of the kontrol
|
9
|
+
project, which is hosted on [this github page][4].
|
10
|
+
|
8
11
|
## Quick Start
|
9
12
|
|
10
|
-
Create a
|
13
|
+
Create a file named `hello_world.ru`:
|
11
14
|
|
12
15
|
require 'kontrol'
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
|
17
|
+
class HelloWorld < Kontrol::Application
|
18
|
+
map do
|
19
|
+
get '/' do
|
20
|
+
"Hello World!"
|
21
|
+
end
|
17
22
|
end
|
18
23
|
end
|
24
|
+
|
25
|
+
run HelloWorld.new
|
26
|
+
|
27
|
+
Now run:
|
28
|
+
|
29
|
+
rackup hello_world.ru
|
30
|
+
|
31
|
+
Browse to `http://localhost:9292` and you will see "Hello World".
|
19
32
|
|
20
|
-
|
33
|
+
|
34
|
+
## Features
|
35
|
+
|
36
|
+
Kontrol is just a thin layer on top of Rack. It provides a routing
|
37
|
+
algorithm, a simple template mechanism and some convenience stuff to
|
38
|
+
work with [GitStore][1].
|
39
|
+
|
40
|
+
A Kontrol application is a class, which provides some context to the
|
41
|
+
defined actions. You will probably use these methods:
|
42
|
+
|
43
|
+
* request: the Rack request object
|
44
|
+
* response: the Rack response object
|
45
|
+
* params: union of GET and POST parameters
|
46
|
+
* cookies: shortcut to request.cookies
|
47
|
+
* session: shortcut to `request.env['rack.session']`
|
48
|
+
* redirect(path): renders a redirect response to specified path
|
21
49
|
|
22
50
|
|
23
51
|
## Routing
|
@@ -25,51 +53,82 @@ Now run `rackup` and browse to `http://localhost:9292` you will see the "Hello W
|
|
25
53
|
Routing is just as simple as using regular expressions with
|
26
54
|
groups. Each group will be provided as argument to the block.
|
27
55
|
|
28
|
-
|
56
|
+
Create a file named `routing.ru`:
|
29
57
|
|
30
58
|
require 'kontrol'
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
59
|
+
|
60
|
+
class Routing < Kontrol::Application
|
61
|
+
map do
|
62
|
+
get '/pages/(.*)' do |name|
|
63
|
+
"This is the page #{name}!"
|
64
|
+
end
|
65
|
+
|
66
|
+
get '/(\d*)/(\d*)' do |year, month|
|
67
|
+
"Archive for #{year}/#{month}"
|
68
|
+
end
|
39
69
|
end
|
40
70
|
end
|
71
|
+
|
72
|
+
run Routing.new
|
73
|
+
|
74
|
+
Now run this application:
|
75
|
+
|
76
|
+
rackup routing.ru
|
41
77
|
|
42
|
-
|
43
|
-
|
78
|
+
|
79
|
+
You will now see, how regex groups and parameters are related. For
|
80
|
+
example if you browse to `localhost:9292/2008/12`, the app will
|
81
|
+
display `Archive for 2008/12`.
|
44
82
|
|
45
83
|
|
46
84
|
## Nested Routes
|
47
85
|
|
48
|
-
|
86
|
+
Routes can be nested. This way you can avoid repeating patterns and
|
87
|
+
define handlers for a set of HTTP verbs. Each handler will be called
|
88
|
+
with the same arguments.
|
49
89
|
|
50
90
|
require 'kontrol'
|
51
|
-
|
52
|
-
|
53
|
-
map
|
54
|
-
|
55
|
-
|
91
|
+
|
92
|
+
class Nested < Kontrol::Application
|
93
|
+
map do
|
94
|
+
map '/blog' do
|
95
|
+
get '/archives' do
|
96
|
+
"The archives!"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
map '/(.*)' do
|
101
|
+
get do |path|
|
102
|
+
"<form method='post'><input type='submit'/></form>"
|
103
|
+
end
|
104
|
+
|
105
|
+
post do |path|
|
106
|
+
"You posted to #{path}"
|
107
|
+
end
|
56
108
|
end
|
57
109
|
end
|
58
110
|
end
|
111
|
+
|
112
|
+
run Nested.new
|
59
113
|
|
60
|
-
|
114
|
+
Now run this app like:
|
61
115
|
|
116
|
+
rackup nested.ru
|
117
|
+
|
118
|
+
The second route catches all paths except the `/blog` route. Inside
|
119
|
+
the second route there are two different handlers for `GET` and `POST`
|
120
|
+
actions.
|
62
121
|
|
63
|
-
|
122
|
+
So if you browse to `/something`, you will see a submit button. After
|
123
|
+
submitting you will see the result of the second handler.
|
64
124
|
|
65
|
-
|
66
|
-
developing small scale apps. The whole repository is loaded into the
|
67
|
-
memory and any change in the repository is reflected immediately in
|
68
|
-
you in-memory copy.
|
125
|
+
## Templates
|
69
126
|
|
70
|
-
|
127
|
+
Rendering templates is as simple as calling a template file with some
|
128
|
+
parameters, which are accessible inside the template as instance
|
129
|
+
variables. Additionally you will need a layout template.
|
71
130
|
|
72
|
-
|
131
|
+
Create a template named `templates/layout.rhtml`:
|
73
132
|
|
74
133
|
<html>
|
75
134
|
<body>
|
@@ -82,32 +141,86 @@ And now another template named `templates/page.rhtml`:
|
|
82
141
|
<h1><%= @title %></h1>
|
83
142
|
<%= @body %>
|
84
143
|
|
85
|
-
|
144
|
+
Create a templates.ru file:
|
86
145
|
|
87
|
-
|
146
|
+
require 'kontrol'
|
147
|
+
|
148
|
+
class Templates < Kontrol::Application
|
149
|
+
map do
|
150
|
+
get '/(.*)' do |name|
|
151
|
+
render "page.rhtml", :title => name.capitalize, :body => "This is the body!"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
run Templates.new
|
88
157
|
|
158
|
+
Now run this example:
|
89
159
|
|
90
|
-
|
160
|
+
rackup templates.ru
|
91
161
|
|
92
|
-
|
162
|
+
If you browse to any path on `localhost:9292`, you will see the
|
163
|
+
rendered template. Note that the title and body parameters have been
|
164
|
+
passed to the `render` call.
|
165
|
+
|
166
|
+
|
167
|
+
## Using GitStore
|
168
|
+
|
169
|
+
[GitStore][1] is another library, which allows you to store code and
|
170
|
+
data in a convenient way in a git repository. The repository is
|
171
|
+
checked out into memory and any data may be saved back into the
|
172
|
+
repository.
|
173
|
+
|
174
|
+
Install [GitStore][1] and [Grit][2] by:
|
175
|
+
|
176
|
+
$ gem sources -a http://gems.github.com (you only have to do this once)
|
177
|
+
$ sudo gem install mojombo-grit georgi-git_store
|
93
178
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
179
|
+
We create a Markdown file name `pages/index.md`:
|
180
|
+
|
181
|
+
Hello World
|
182
|
+
===========
|
183
|
+
|
184
|
+
This is the **Index** page!
|
185
|
+
|
186
|
+
We have now a simple page, which should be rendered as response. We
|
187
|
+
create a simple app in a file `git_app.ru`:
|
188
|
+
|
189
|
+
require 'kontrol'
|
190
|
+
require 'bluecloth'
|
191
|
+
|
192
|
+
class GitApp < Kontrol::Application
|
193
|
+
map do
|
194
|
+
get '/(.*)' do |name|
|
195
|
+
BlueCloth.new(store['pages', name + '.md']).to_html
|
196
|
+
end
|
98
197
|
end
|
99
198
|
end
|
199
|
+
|
200
|
+
run GitApp.new
|
100
201
|
|
101
202
|
Add all these files to your repo:
|
102
203
|
|
103
|
-
git
|
104
|
-
git add templates/page.rhtml
|
204
|
+
git init
|
105
205
|
git add pages/index.md
|
106
|
-
git
|
107
|
-
|
206
|
+
git commit -m 'init'
|
207
|
+
|
208
|
+
Run the app:
|
209
|
+
|
210
|
+
rackup git_app.ru
|
211
|
+
|
212
|
+
Browse to `http://localhost:9292/index` and you will see the rendered
|
213
|
+
page generated from the markdown file.
|
108
214
|
|
109
|
-
|
215
|
+
This application runs straight from the git repository. You can delete
|
216
|
+
all files except the rackup file and the app will still serve the page
|
217
|
+
from your repo.
|
110
218
|
|
111
|
-
You will see the rendered template with the inserted content of the
|
112
|
-
Markdown file.
|
113
219
|
|
220
|
+
[1]: http://github.com/georgi/git_store
|
221
|
+
[2]: http://github.com/mojombo/grit
|
222
|
+
[3]: http://github.com/georgi/kontrol/tree/master/examples
|
223
|
+
[4]: http://github.com/georgi/kontrol
|
224
|
+
[5]: http://github.com/chneukirchen/rack
|
225
|
+
[6]: http://github.com/chneukirchen/rack/tree/master/lib/rack/request.rb
|
226
|
+
[7]: http://github.com/chneukirchen/rack/tree/master/lib/rack/response.rb
|
data/examples/git_app.ru
ADDED
data/examples/nested.ru
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'kontrol'
|
2
|
+
|
3
|
+
class Nested < Kontrol::Application
|
4
|
+
map do
|
5
|
+
map '/blog' do
|
6
|
+
get '/archives' do
|
7
|
+
"The archives!"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
map '(.*)' do
|
12
|
+
get do |path|
|
13
|
+
"<form method='post'><input type='submit'/></form>"
|
14
|
+
end
|
15
|
+
|
16
|
+
post do |path|
|
17
|
+
"You called #{path}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
run Nested.new
|
data/examples/routing.ru
ADDED
data/lib/kontrol.rb
CHANGED
data/lib/kontrol/application.rb
CHANGED
@@ -18,7 +18,7 @@ module Kontrol
|
|
18
18
|
|
19
19
|
config_reader 'assets.yml', :javascript_files, :stylesheet_files
|
20
20
|
|
21
|
-
def initialize(options = {}
|
21
|
+
def initialize(options = {})
|
22
22
|
options.each do |k, v|
|
23
23
|
send "#{k}=", v
|
24
24
|
end
|
@@ -26,11 +26,14 @@ module Kontrol
|
|
26
26
|
@mtime = {}
|
27
27
|
@last_mtime = Time.now
|
28
28
|
@path = File.expand_path('.')
|
29
|
-
|
29
|
+
|
30
|
+
initialize_repo if defined?(GitStore)
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize_repo
|
30
34
|
@store = GitStore.new(path)
|
31
35
|
@store.load
|
32
|
-
|
33
|
-
map(&block) if block
|
36
|
+
rescue Grit::InvalidGitRepositoryError
|
34
37
|
end
|
35
38
|
|
36
39
|
def assets
|
@@ -77,14 +80,14 @@ module Kontrol
|
|
77
80
|
end
|
78
81
|
end
|
79
82
|
|
80
|
-
def camelize(str)
|
81
|
-
str.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
|
82
|
-
end
|
83
|
-
|
84
83
|
# Render template with given variables.
|
85
84
|
def render_template(file, vars)
|
86
|
-
|
87
|
-
|
85
|
+
if store
|
86
|
+
template = templates[file] or raise "template #{file} not found"
|
87
|
+
else
|
88
|
+
template = ERB.new(File.read("#{path}/templates/#{file}"))
|
89
|
+
end
|
90
|
+
Template.render(template, self, file, vars)
|
88
91
|
end
|
89
92
|
|
90
93
|
def render_layout(vars)
|
@@ -154,21 +157,35 @@ module Kontrol
|
|
154
157
|
MIME_TYPES[ext] || 'text/html'
|
155
158
|
end
|
156
159
|
|
157
|
-
|
158
|
-
|
160
|
+
class << self
|
161
|
+
|
162
|
+
def map(&block)
|
163
|
+
@map = Builder.new(&block)
|
164
|
+
end
|
165
|
+
|
166
|
+
def get_map
|
167
|
+
@map
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
def find_map
|
173
|
+
if store and store['map.rb']
|
174
|
+
store['map.rb']
|
175
|
+
else
|
176
|
+
self.class.get_map
|
177
|
+
end
|
159
178
|
end
|
160
179
|
|
161
180
|
def call(env)
|
162
181
|
Thread.current['request'] = Rack::Request.new(env)
|
163
182
|
Thread.current['response'] = Rack::Response.new([], nil, { 'Content-Type' => '' })
|
164
183
|
|
165
|
-
check_reload
|
184
|
+
check_reload if store
|
166
185
|
|
167
186
|
env['kontrol.app'] = self
|
168
187
|
|
169
|
-
|
170
|
-
|
171
|
-
status, header, body = map.call(env)
|
188
|
+
status, header, body = find_map.call(env)
|
172
189
|
|
173
190
|
response.status = status if response.status.nil?
|
174
191
|
response.header.merge!(header)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: georgi-kontrol
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthias Georgi
|
@@ -32,6 +32,16 @@ files:
|
|
32
32
|
- lib/kontrol/router.rb
|
33
33
|
- lib/kontrol/template.rb
|
34
34
|
- test/application_spec.rb
|
35
|
+
- examples/routing.ru
|
36
|
+
- examples/pages
|
37
|
+
- examples/pages/index.md
|
38
|
+
- examples/git_app.ru
|
39
|
+
- examples/templates.ru
|
40
|
+
- examples/templates
|
41
|
+
- examples/templates/page.rhtml
|
42
|
+
- examples/templates/layout.rhtml
|
43
|
+
- examples/nested.ru
|
44
|
+
- examples/hello_world.ru
|
35
45
|
has_rdoc: true
|
36
46
|
homepage: http://github.com/georgi/kontrol
|
37
47
|
post_install_message:
|