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 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 parts: an client application running in the browser (HTML/JS/CSS), and a backend API with which it communicates. Kenji is the backend side of the equation, while the front-end architecture is left up to the user. (Popular options are [backbone][] and [spine][].)
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 defined inline with their code.
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 the command line. An app should be automatable and testable.
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 routing and code architecture. Kenji believes in being a ligthweight module that only solves the problem it focuses on. Everything else is left up to the user. (ORM, data store, web server, message queue, front-end framework, deployment process, etc.)
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. controllers. The controllers will automatically be selected based on the url requested, and the rest of the route is defined inline in the controller, with a domain-specific-language.
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 look like this, in `controller/hello.rb`:
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 have:
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 and a terminal:
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-init app_name; cd app_name
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.
@@ -1,6 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- path = File.expand_path('.' << '/' << (ARGV.first || '.'))
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)
@@ -0,0 +1,2 @@
1
+ This is where you might put supporting libraries for your Kenji app. The
2
+ structure of this is left up to you.
data/lib/kenji/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Kenji
3
- VERSION = '0.7'
3
+ VERSION = '1.0'
4
4
  end
5
5
 
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.drop(1) if segments.first == '' # discard leading /'s empty segment
62
- segments.unshift('')
63
-
64
- acc = ''; out = '', success = false
65
- while head = segments.shift
66
- acc = "#{acc}/#{head}"
67
- if controller = controller_for(acc) # if we have a valid controller
68
- begin
69
- method = @env['REQUEST_METHOD'].downcase.to_sym
70
- subpath = '/'+segments.join('/')
71
- out = controller.call(method, subpath).to_json
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 call
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
- return unless controller_class.method_defined?(:call) && controller_class.instance_method(:call).arity == 2 # ensure protocol compliance
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
@@ -0,0 +1,10 @@
1
+ module Spec5
2
+ class MainController < Kenji::Controller
3
+ get '/' do
4
+ { :foo => 'bar' }
5
+ end
6
+ get '/path' do
7
+ { :baz => 'bar' }
8
+ end
9
+ end
10
+ end
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.7'
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-04-19 00:00:00.000000000 Z
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-init
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-init
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:
@@ -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.
@@ -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.