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 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 config.ru file and try this little "Hello World" app:
13
+ Create a file named `hello_world.ru`:
11
14
 
12
15
  require 'kontrol'
13
-
14
- run Kontrol::Application.new do
15
- get '/' do
16
- "Hello World!"
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
- Now run `rackup` and browse to `http://localhost:9292` you will see the "Hello World".
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
- Some examples:
56
+ Create a file named `routing.ru`:
29
57
 
30
58
  require 'kontrol'
31
-
32
- run Kontrol::Application.new do
33
- get '/pages/(.*)' do |name|
34
- "This is the page #{name}!"
35
- end
36
-
37
- get '/(\d*)/(\d*)', :content_type => 'text/html' do |year, month|
38
- "Archive for #{year} #{month}"
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
- The second route has the requirement, that the `content-type` header
43
- should be 'text/html'.
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
- You may nest your routes like you want:
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
- run Kontrol::Application.new do
53
- map '/blog' do
54
- get '/archives' do
55
- "The archives!"
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
- This app can be reached at '/blog/archives'.
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
- ## Storing your data in a git repository
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
- Using GitStore for your code and data is a convenient way for
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
- Just init a new repo: `git init`
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
- Now we create a template named `templates/layout.rhtml`:
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
- Now we create a Markdown file name `pages/index.md`:
144
+ Create a templates.ru file:
86
145
 
87
- Hello World from **Markdown** !
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
- Create a config.ru file:
160
+ rackup templates.ru
91
161
 
92
- require 'kontrol'
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
- run Kontrol::Application.new do
95
- get '/(.*)' do |name|
96
- body = store["pages/#{name}.md"]
97
- render "page.rhtml", :title => name.capitalize, :body => body
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 add templates/layout.rhtml
104
- git add templates/page.rhtml
204
+ git init
105
205
  git add pages/index.md
106
- git add config.ru
107
- git commit -m 'added templates and config.ru'
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
- Now just run `rackup` and browse to `http://localhost:9292/index`
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
@@ -0,0 +1,12 @@
1
+ require 'kontrol'
2
+ require 'bluecloth'
3
+
4
+ class GitApp < Kontrol::Application
5
+ map do
6
+ get '/(.*)' do |name|
7
+ BlueCloth.new(store['pages', name + '.md']).to_html
8
+ end
9
+ end
10
+ end
11
+
12
+ run GitApp.new
@@ -0,0 +1,11 @@
1
+ require 'kontrol'
2
+
3
+ class HelloWorld < Kontrol::Application
4
+ map do
5
+ get '/' do
6
+ "Hello World!"
7
+ end
8
+ end
9
+ end
10
+
11
+ run HelloWorld.new
@@ -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
@@ -0,0 +1,5 @@
1
+ Hello World
2
+ ===========
3
+
4
+ This is the **Index** page!
5
+
@@ -0,0 +1,15 @@
1
+ require 'kontrol'
2
+
3
+ class Routing < Kontrol::Application
4
+ map do
5
+ get '/pages/(.*)' do |name|
6
+ "This is the page #{name}!"
7
+ end
8
+
9
+ get '/(\d*)/(\d*)' do |year, month|
10
+ "Archive for #{year}/#{month}"
11
+ end
12
+ end
13
+ end
14
+
15
+ run Routing.new
@@ -0,0 +1,11 @@
1
+ require 'kontrol'
2
+
3
+ class Templates < Kontrol::Application
4
+ map do
5
+ get '/(.*)' do |name|
6
+ render "page.rhtml", :title => name.capitalize, :body => "This is the body!"
7
+ end
8
+ end
9
+ end
10
+
11
+ run Templates.new
@@ -0,0 +1,5 @@
1
+ <html>
2
+ <body>
3
+ <%= @content %>
4
+ </body>
5
+ </html>
@@ -0,0 +1,2 @@
1
+ <h1><%= @title %></h1>
2
+ <%= @body %>
data/lib/kontrol.rb CHANGED
@@ -3,7 +3,8 @@ require 'rack'
3
3
  require 'erb'
4
4
  require 'yaml'
5
5
  require 'logger'
6
- require 'git_store'
6
+
7
+ begin; require 'git_store'; rescue LoadError; end
7
8
 
8
9
  require 'kontrol/helpers'
9
10
  require 'kontrol/template'
@@ -18,7 +18,7 @@ module Kontrol
18
18
 
19
19
  config_reader 'assets.yml', :javascript_files, :stylesheet_files
20
20
 
21
- def initialize(options = {}, &block)
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
- templates[file] or raise "template #{file} not found"
87
- Template.render(templates[file], self, file, vars)
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
- def map(&block)
158
- @map = Builder.new(&block)
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
- map = @map || store['map.rb'] or raise "no map defined"
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: "0.1"
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: