kenji 0.7 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +33 -11
- data/bin/{kenji-init → kenji} +9 -1
- data/inited/lib/README.md +2 -0
- data/lib/kenji/version.rb +1 -1
- data/lib/kenji.rb +39 -18
- data/spec/5/controllers/main.rb +10 -0
- data/spec/kenji_spec.rb +29 -2
- metadata +7 -9
- data/inited/configuration/README +0 -1
- data/inited/lib/README +0 -0
- data/inited/models/README +0 -1
- data/inited/scripts/README +0 -1
- data/inited/tmp/README +0 -1
data/README.md
CHANGED
@@ -5,23 +5,37 @@ Kenji is a lightweight backend framework for Ruby.
|
|
5
5
|
|
6
6
|
## Rationale
|
7
7
|
|
8
|
-
Kenji believes that a traditional web application should be divided into two
|
8
|
+
Kenji believes that a traditional web application should be divided into two
|
9
|
+
parts: an client application running in the browser (HTML/JS/CSS), and
|
10
|
+
a backend API with which it communicates. Kenji is the backend side of the
|
11
|
+
equation, while the front-end architecture is left up to the user. (Popular
|
12
|
+
options are [backbone][] and [spine][].)
|
9
13
|
|
10
14
|
[backbone]: http://documentcloud.github.com/backbone/
|
11
15
|
[spine]: http://spinejs.com/
|
12
16
|
|
13
|
-
Kenji believes that in order to keep clean and organized code, routes should be
|
17
|
+
Kenji believes that in order to keep clean and organized code, routes should be
|
18
|
+
defined inline with their code.
|
14
19
|
|
15
|
-
Kenji believes that an app should be usable as a library from scripts or from
|
20
|
+
Kenji believes that an app should be usable as a library from scripts or from
|
21
|
+
the command line. An app should be automatable and testable.
|
16
22
|
|
17
|
-
Lastly, Kenji is opinionated, but only about things that directly pertain to
|
23
|
+
Lastly, Kenji is opinionated, but only about things that directly pertain to
|
24
|
+
routing and code architecture. Kenji believes in being a ligthweight module
|
25
|
+
that only solves the problem it focuses on. Everything else is left up to the
|
26
|
+
user. (ORM, data store, web server, message queue, front-end framework,
|
27
|
+
deployment process, etc.)
|
18
28
|
|
19
29
|
|
20
30
|
### Routing
|
21
31
|
|
22
|
-
Kenji wants you to organize your code into logical units of code, aka.
|
32
|
+
Kenji wants you to organize your code into logical units of code, aka.
|
33
|
+
controllers. The controllers will automatically be selected based on the url
|
34
|
+
requested, and the rest of the route is defined inline in the controller, with
|
35
|
+
a domain-specific-language.
|
23
36
|
|
24
|
-
The canonical Hello World example for the URL `/hello/world` in Kenji would
|
37
|
+
The canonical Hello World example for the URL `/hello/world` in Kenji would
|
38
|
+
look like this, in `controller/hello.rb`:
|
25
39
|
|
26
40
|
```ruby
|
27
41
|
class HelloController < Kenji::Controller
|
@@ -55,7 +69,8 @@ end
|
|
55
69
|
|
56
70
|
### Data Transport
|
57
71
|
|
58
|
-
JSON is used as the singular data transport for Kenji. Requests are assumed to
|
72
|
+
JSON is used as the singular data transport for Kenji. Requests are assumed to
|
73
|
+
have:
|
59
74
|
|
60
75
|
Content-Type: application/json; charset=utf-8
|
61
76
|
Accept: application/json; charset=utf-8
|
@@ -63,10 +78,11 @@ JSON is used as the singular data transport for Kenji. Requests are assumed to h
|
|
63
78
|
|
64
79
|
## Usage
|
65
80
|
|
66
|
-
Getting started with Kenji could not be any easier. All it takes is a few lines
|
81
|
+
Getting started with Kenji could not be any easier. All it takes is a few lines
|
82
|
+
and a terminal:
|
67
83
|
|
68
84
|
$ gem install kenji # (once kenji is on the rubygems main source)
|
69
|
-
$ kenji
|
85
|
+
$ kenji init app_name; cd app_name
|
70
86
|
$ rackup # launch the webserver
|
71
87
|
|
72
88
|
And already, your app is ready to go:
|
@@ -78,12 +94,18 @@ And already, your app is ready to go:
|
|
78
94
|
## Requirements & Assumptions
|
79
95
|
|
80
96
|
- Requires RubyGems and Bundler.
|
81
|
-
- Requires Rack
|
82
|
-
- Requires Ruby 1.9.
|
97
|
+
- Requires Rack ~> 1.5.3.
|
98
|
+
- Requires Ruby >= 1.9.3.
|
83
99
|
|
84
100
|
|
85
101
|
## Changelog
|
86
102
|
|
103
|
+
#### 0.7
|
104
|
+
|
105
|
+
- Pass can now contain variables, that get set as @ivars on the controller.
|
106
|
+
Thanks @nicotaing.
|
107
|
+
- Accessors for `response_headers`
|
108
|
+
|
87
109
|
#### 0.6.5
|
88
110
|
|
89
111
|
- Automatically handle CORS / Access-Control.
|
data/bin/{kenji-init → kenji}
RENAMED
@@ -1,6 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
|
4
|
+
unless ARGV.first == 'init'
|
5
|
+
puts 'Usage: kenji init [project-name]'
|
6
|
+
Process.exit
|
7
|
+
end
|
8
|
+
|
9
|
+
puts 'Initializing a new Kenji project... :)'
|
10
|
+
|
11
|
+
path = File.expand_path('.' << '/' << (ARGV[1] || '.'))
|
4
12
|
app_name = File.basename(path)
|
5
13
|
|
6
14
|
Dir.mkdir(path) unless File.directory?(path)
|
data/lib/kenji/version.rb
CHANGED
data/lib/kenji.rb
CHANGED
@@ -27,6 +27,11 @@ module Kenji
|
|
27
27
|
#
|
28
28
|
# - :auto_cors => true | false # automatically deal with
|
29
29
|
# CORS / Access-Control
|
30
|
+
# - :root_controller => Object # when set, Kenji will not attempt to
|
31
|
+
# discover controllers based on
|
32
|
+
# convention, but rather will always
|
33
|
+
# use this controller. use `pass` to
|
34
|
+
# build a controller hierarchy
|
30
35
|
#
|
31
36
|
def initialize(env, root, options = {})
|
32
37
|
@headers = {
|
@@ -38,7 +43,8 @@ module Kenji
|
|
38
43
|
@env = env
|
39
44
|
|
40
45
|
@options = {
|
41
|
-
auto_cors: true
|
46
|
+
auto_cors: true,
|
47
|
+
root_controller: nil
|
42
48
|
}.merge(options)
|
43
49
|
end
|
44
50
|
|
@@ -57,21 +63,28 @@ module Kenji
|
|
57
63
|
|
58
64
|
|
59
65
|
# new routing code
|
66
|
+
method = @env['REQUEST_METHOD'].downcase.to_sym
|
67
|
+
|
60
68
|
segments = path.split('/')
|
61
|
-
segments = segments.
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
segments = segments.unshift('') unless segments.first == '' # ensure existence of leading /'s empty segment
|
70
|
+
|
71
|
+
if @options[:root_controller]
|
72
|
+
controller = controller_instance(@options[:root_controller])
|
73
|
+
subpath = segments.join('/')
|
74
|
+
out = controller.call(method, subpath).to_json
|
75
|
+
success = true
|
76
|
+
else
|
77
|
+
acc = ''; out = '', success = false
|
78
|
+
while head = segments.shift
|
79
|
+
acc = "#{acc}/#{head}"
|
80
|
+
if controller = controller_for(acc) # if we have a valid controller
|
81
|
+
begin
|
82
|
+
subpath = '/'+segments.join('/')
|
83
|
+
out = controller.call(method, subpath).to_json
|
84
|
+
end
|
85
|
+
success = true
|
86
|
+
break
|
72
87
|
end
|
73
|
-
success = true
|
74
|
-
break
|
75
88
|
end
|
76
89
|
end
|
77
90
|
|
@@ -137,8 +150,7 @@ module Kenji
|
|
137
150
|
response = { # default structure. TODO: figure out if i really want to keep this
|
138
151
|
:status => code,
|
139
152
|
:message => message
|
140
|
-
}
|
141
|
-
hash.each { |k,v| response[k]=v }
|
153
|
+
}.merge(hash)
|
142
154
|
throw(:KenjiRespondControlFlowInterrupt, [@status, @headers, [response.to_json]])
|
143
155
|
end
|
144
156
|
|
@@ -164,7 +176,8 @@ module Kenji
|
|
164
176
|
end
|
165
177
|
end
|
166
178
|
|
167
|
-
# Will attempt to fetch the controller, and verify that it is a implements
|
179
|
+
# Will attempt to fetch the controller, and verify that it is a implements
|
180
|
+
# call.
|
168
181
|
#
|
169
182
|
def controller_for(subpath)
|
170
183
|
subpath = '/_' if subpath == '/'
|
@@ -173,7 +186,15 @@ module Kenji
|
|
173
186
|
require path
|
174
187
|
controller_name = subpath.split('/').last.sub(/^_/, 'Root')
|
175
188
|
controller_class = Object.const_get(controller_name.to_s.to_camelcase+'Controller')
|
176
|
-
|
189
|
+
controller_instance(controller_class)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Attempts to instantiate the controller class, set up as a Kenji
|
193
|
+
# controller.
|
194
|
+
#
|
195
|
+
def controller_instance(controller_class)
|
196
|
+
# ensure protocol compliance
|
197
|
+
return unless controller_class.method_defined?(:call) && controller_class.instance_method(:call).arity == 2
|
177
198
|
controller = controller_class.new
|
178
199
|
controller.kenji = self if controller.respond_to?(:kenji=)
|
179
200
|
return controller if controller
|
data/spec/kenji_spec.rb
CHANGED
@@ -9,9 +9,9 @@ require 'kenji'
|
|
9
9
|
|
10
10
|
# NOTE: these tests make use of the controllers defined in test/controllers.
|
11
11
|
|
12
|
-
def app_for(path)
|
12
|
+
def app_for(path, opts={})
|
13
13
|
lambda do |env|
|
14
|
-
kenji = Kenji::Kenji.new(env, File.dirname(__FILE__)+'/'+path)
|
14
|
+
kenji = Kenji::Kenji.new(env, File.dirname(__FILE__)+'/'+path, opts)
|
15
15
|
kenji.stderr = double(puts: nil)
|
16
16
|
kenji.call
|
17
17
|
end
|
@@ -158,4 +158,31 @@ describe Kenji::Kenji, 'expected reponses' do
|
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
161
|
+
context '5' do
|
162
|
+
before do
|
163
|
+
require File.expand_path('./5/controllers/main.rb', File.dirname(__FILE__))
|
164
|
+
end
|
165
|
+
|
166
|
+
def app; app_for('5', root_controller: Spec5::MainController); end
|
167
|
+
|
168
|
+
it "should use main controller for /" do
|
169
|
+
get '/'
|
170
|
+
expected_response = { :foo => 'bar' }.to_json
|
171
|
+
last_response.body.should == expected_response
|
172
|
+
last_response.status.should == 200
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should use main controller for /path" do
|
176
|
+
get '/path'
|
177
|
+
expected_response = { :baz => 'bar' }.to_json
|
178
|
+
last_response.body.should == expected_response
|
179
|
+
last_response.status.should == 200
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should 404 on main controller" do
|
183
|
+
put '/main/foo/foo_id/pass/pass_id'
|
184
|
+
last_response.status.should == 404
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
161
188
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kenji
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0
|
4
|
+
version: '1.0'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -95,7 +95,7 @@ description: A lightweight Ruby web framework.
|
|
95
95
|
email:
|
96
96
|
- kenneth@ballenegger.com
|
97
97
|
executables:
|
98
|
-
- kenji
|
98
|
+
- kenji
|
99
99
|
extensions: []
|
100
100
|
extra_rdoc_files: []
|
101
101
|
files:
|
@@ -104,20 +104,16 @@ files:
|
|
104
104
|
- LICENSE
|
105
105
|
- README.md
|
106
106
|
- Rakefile
|
107
|
-
- bin/kenji
|
107
|
+
- bin/kenji
|
108
108
|
- inited/.gitignore
|
109
109
|
- inited/Gemfile
|
110
110
|
- inited/README.md
|
111
111
|
- inited/__APP_NAME__
|
112
112
|
- inited/config.ru
|
113
|
-
- inited/configuration/README
|
114
113
|
- inited/controllers/main.rb
|
115
|
-
- inited/lib/README
|
116
|
-
- inited/models/README
|
114
|
+
- inited/lib/README.md
|
117
115
|
- inited/public/humans.txt
|
118
116
|
- inited/public/index.html
|
119
|
-
- inited/scripts/README
|
120
|
-
- inited/tmp/README
|
121
117
|
- inited/tmp/always_restart.txt
|
122
118
|
- kenji.gemspec
|
123
119
|
- lib/kenji.rb
|
@@ -131,6 +127,7 @@ files:
|
|
131
127
|
- spec/4/controllers/bar.rb
|
132
128
|
- spec/4/controllers/main.rb
|
133
129
|
- spec/4/controllers/pass.rb
|
130
|
+
- spec/5/controllers/main.rb
|
134
131
|
- spec/kenji_spec.rb
|
135
132
|
homepage: https://github.com/kballenegger/kenji
|
136
133
|
licenses: []
|
@@ -164,5 +161,6 @@ test_files:
|
|
164
161
|
- spec/4/controllers/bar.rb
|
165
162
|
- spec/4/controllers/main.rb
|
166
163
|
- spec/4/controllers/pass.rb
|
164
|
+
- spec/5/controllers/main.rb
|
167
165
|
- spec/kenji_spec.rb
|
168
166
|
has_rdoc:
|
data/inited/configuration/README
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
This is where configuration goes.
|
data/inited/lib/README
DELETED
File without changes
|
data/inited/models/README
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
This is where models go.
|
data/inited/scripts/README
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
This is where scripts go.
|
data/inited/tmp/README
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
This folder is for Rack & Passenger to use.
|