kenji 0.4 → 0.5

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/Gemfile CHANGED
@@ -2,4 +2,9 @@ gem 'inifile'
2
2
  gem 'json'
3
3
  gem 'rack'
4
4
 
5
+ group :test do
6
+ gem 'rspec'
7
+ gem 'rack-test'
8
+ end
9
+
5
10
  source :rubygems
data/Rakefile CHANGED
@@ -1,2 +1,7 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
+ require 'rspec/core'
4
+ require 'rspec/core/rake_task'
5
+ task :default => :spec
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
@@ -68,12 +68,46 @@ module Kenji
68
68
  nil # void method
69
69
  end
70
70
 
71
+ # This lets us pass the routing down to another controller for a sub-path.
72
+ #
73
+ # class MyController < Kenji::Controller
74
+ # pass '/admin/*', AdminController
75
+ # # regular routes
76
+ # end
77
+ #
78
+ def self.pass(path, controller)
79
+ node = (@passes ||= {})
80
+ segments = path.split('/')
81
+ segments = segments.drop(1) if segments.first == '' # discard leading /'s empty segment
82
+ segments.each do |segment|
83
+ node = (node[segment.to_sym] ||= {})
84
+ break if segment == '*'
85
+ end
86
+ node[:@controller] = controller
87
+ end
88
+
71
89
 
72
90
  # Most likely only used by Kenji itself.
73
91
  # Override to implement your own routing, if you'd like.
92
+ #
74
93
  def call(method, path)
75
94
  segments = path.split('/')
76
95
  segments = segments.drop(1) if segments.first == '' # discard leading /'s empty segment
96
+
97
+ # check for passes
98
+ node = self.class.passes
99
+ remaining_segments = segments.dup
100
+ while s = remaining_segments.shift
101
+ next unless node[s.to_sym]
102
+ node = node[s.to_sym]
103
+ break
104
+ end
105
+ if node[:@controller]
106
+ instance = node[:@controller].new
107
+ return instance.call(method, remaining_segments.join('/'))
108
+ end
109
+
110
+ # regular routing
77
111
  node = self.class.routes[method]
78
112
  variables = []
79
113
  searching = true
@@ -114,6 +148,9 @@ module Kenji
114
148
  def self.routes
115
149
  @routes || {}
116
150
  end
151
+ def self.passes
152
+ @passes || {}
153
+ end
117
154
  end
118
155
  end
119
156
 
data/lib/kenji/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Kenji
3
- VERSION = '0.4'
3
+ VERSION = '0.5'
4
4
  end
5
5
 
data/lib/kenji.rb CHANGED
@@ -8,6 +8,13 @@ module Kenji
8
8
 
9
9
  attr_reader :env, :root
10
10
 
11
+ # Setting `kenji.status = 203` will affect the status code of the response.
12
+ attr_accessor :status
13
+
14
+ # Methods for rack!
15
+
16
+ # Constructor...
17
+ #
11
18
  def initialize(env, root)
12
19
  @headers = {
13
20
  'Content-Type' => 'application/json'
@@ -17,6 +24,8 @@ module Kenji
17
24
  @env = env
18
25
  end
19
26
 
27
+ # This method does all the work!
28
+ #
20
29
  def call
21
30
  path = @env['PATH_INFO']
22
31
 
@@ -28,6 +37,7 @@ module Kenji
28
37
  # new routing code
29
38
  segments = path.split('/')
30
39
  segments = segments.drop(1) if segments.first == '' # discard leading /'s empty segment
40
+ segments.unshift('')
31
41
 
32
42
  acc = ''; out = 'null'
33
43
  while head = segments.shift
@@ -56,6 +66,7 @@ module Kenji
56
66
  # Sets one or multiple headers, as named arametres. eg.
57
67
  #
58
68
  # kenji.header 'Content-Type' => 'hello/world'
69
+ #
59
70
  def header(hash={})
60
71
  hash.each do |key, value|
61
72
  @headers[key] = value
@@ -64,19 +75,21 @@ module Kenji
64
75
 
65
76
  # Fetch (and cache) the json input to the request
66
77
  # Return a Hash
78
+ #
67
79
  def input_as_json
68
80
  return @json_input if @json_input
69
81
  require 'json'
70
82
  raw = @env['rack.input'].read if @env['rack.input']
71
83
  begin
72
84
  return @json_input = JSON.parse(raw)
73
- rescue JSON::ParserError => e
85
+ rescue JSON::ParserError
74
86
  end if raw
75
87
  {} # default return value
76
88
  end
77
89
 
78
90
  # Respond to the request
79
- def respond code, message, hash={}
91
+ #
92
+ def respond(code, message, hash={})
80
93
  @status = code
81
94
  response = { # default structure. TODO: figure out if i really want to keep this
82
95
  :status => code,
@@ -89,13 +102,16 @@ module Kenji
89
102
 
90
103
 
91
104
  # Private methods
105
+ private
92
106
 
93
107
  # Will attempt to fetch the controller, and verify that it is a implements call
94
- def controller_for subpath
108
+ #
109
+ def controller_for(subpath)
110
+ subpath = '/_' if subpath == '/'
95
111
  path = "#{@root}controllers#{subpath}.rb"
96
112
  return nil unless File.exists?(path)
97
113
  require path
98
- controller_name = subpath.split('/').last
114
+ controller_name = subpath.split('/').last.sub(/^_/, 'Root')
99
115
  controller_class = Object.const_get(controller_name.to_s.to_camelcase+'Controller')
100
116
  return unless controller_class.method_defined?(:call) && controller_class.instance_method(:call).arity == 2 # ensure protocol compliance
101
117
  controller = controller_class.new
@@ -0,0 +1,19 @@
1
+
2
+ class MainController < Kenji::Controller
3
+
4
+ get '/hello' do
5
+ {status: 200, hello: :world}
6
+ end
7
+
8
+ post '/' do
9
+ {status:1337}
10
+ end
11
+
12
+ put '/' do
13
+ {status:1337}
14
+ end
15
+
16
+ delete '/' do
17
+ {status:1337}
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+
2
+ require File.expand_path(File.dirname(__FILE__)+'/child.rb')
3
+
4
+ class RootController < Kenji::Controller
5
+ get '/' do
6
+ {status: 200, controller_used: :root}
7
+ end
8
+ pass '/child', ChildController
9
+ end
@@ -0,0 +1,8 @@
1
+
2
+
3
+ class ChildController < Kenji::Controller
4
+
5
+ get '/foo' do
6
+ {status: 200, foo: :bar}
7
+ end
8
+ end
@@ -0,0 +1,65 @@
1
+
2
+ require 'rack'
3
+ require 'rack/test'
4
+ require 'rspec'
5
+
6
+ require 'kenji'
7
+
8
+
9
+ # NOTE: these tests make use of the controllers defined in test/controllers.
10
+
11
+ def app_for(path)
12
+ lambda do |env|
13
+ Kenji::Kenji.new(env, File.dirname(__FILE__)+'/'+path).call
14
+ end
15
+ end
16
+
17
+ describe Kenji do
18
+
19
+ include Rack::Test::Methods
20
+ def app; app_for('1'); end
21
+
22
+
23
+ it 'should return "null" for unknown routes' do
24
+ get '/sdlkjhb'
25
+ last_response.body.should == 'null'
26
+ end
27
+
28
+ it 'should route a GET call to a defined get call' do
29
+ get '/main/hello'
30
+ expected_response = {status: 200, hello: :world}.to_json
31
+ last_response.body.should == expected_response
32
+ end
33
+
34
+ [:post, :put, :delete].each do |method|
35
+
36
+ it "should route a #{method.to_s.upcase} to a defined #{method.to_s} call" do
37
+ send(method, '/main')
38
+ expected_response = {status: 1337}.to_json
39
+ last_response.body.should == expected_response
40
+ end
41
+ end
42
+
43
+ it 'should return "null" for unsupported methods' do
44
+ post '/main/hello'
45
+ last_response.body.should == 'null'
46
+ end
47
+
48
+ end
49
+
50
+ describe Kenji do
51
+ include Rack::Test::Methods
52
+ def app; app_for('2'); end
53
+
54
+ it 'should use root controller' do
55
+ get '/'
56
+ expected_response = {status: 200, controller_used: :root}.to_json
57
+ last_response.body.should == expected_response
58
+ end
59
+
60
+ it 'should pass routing down to child controllers' do
61
+ get '/child/foo'
62
+ expected_response = {status: 200, foo: :bar}.to_json
63
+ last_response.body.should == expected_response
64
+ end
65
+ end
metadata CHANGED
@@ -1,57 +1,56 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: kenji
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 4
8
- version: "0.4"
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.5'
5
+ prerelease:
9
6
  platform: ruby
10
- authors:
7
+ authors:
11
8
  - Kenneth Ballenegger
12
9
  autorequire:
13
10
  bindir: bin
14
11
  cert_chain: []
15
-
16
- date: 2012-04-05 00:00:00 -07:00
17
- default_executable:
18
- dependencies:
19
- - !ruby/object:Gem::Dependency
12
+ date: 2012-04-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
20
15
  name: json
21
- prerelease: false
22
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
23
17
  none: false
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 0
29
- version: "0"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
30
22
  type: :runtime
31
- version_requirements: *id001
32
- - !ruby/object:Gem::Dependency
33
- name: rack
34
23
  prerelease: false
35
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
36
25
  none: false
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- segments:
41
- - 0
42
- version: "0"
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rack
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
43
38
  type: :runtime
44
- version_requirements: *id002
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
45
46
  description: A lightweight Ruby web framework.
46
- email:
47
+ email:
47
48
  - kenneth@ballenegger.com
48
- executables:
49
+ executables:
49
50
  - kenji-init
50
51
  extensions: []
51
-
52
52
  extra_rdoc_files: []
53
-
54
- files:
53
+ files:
55
54
  - .gitignore
56
55
  - Gemfile
57
56
  - LICENSE
@@ -77,37 +76,37 @@ files:
77
76
  - lib/kenji/controller.rb
78
77
  - lib/kenji/string_extensions.rb
79
78
  - lib/kenji/version.rb
80
- has_rdoc: true
79
+ - spec/1/controllers/main.rb
80
+ - spec/2/controllers/_.rb
81
+ - spec/2/controllers/child.rb
82
+ - spec/kenji_spec.rb
81
83
  homepage: https://github.com/kballenegger/kenji
82
84
  licenses: []
83
-
84
85
  post_install_message:
85
86
  rdoc_options: []
86
-
87
- require_paths:
87
+ require_paths:
88
88
  - lib
89
- required_ruby_version: !ruby/object:Gem::Requirement
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
90
  none: false
91
- requirements:
92
- - - ">="
93
- - !ruby/object:Gem::Version
94
- segments:
95
- - 0
96
- version: "0"
97
- required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
96
  none: false
99
- requirements:
100
- - - ">="
101
- - !ruby/object:Gem::Version
102
- segments:
103
- - 0
104
- version: "0"
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
105
101
  requirements: []
106
-
107
102
  rubyforge_project:
108
- rubygems_version: 1.3.7
103
+ rubygems_version: 1.8.24
109
104
  signing_key:
110
105
  specification_version: 3
111
106
  summary: Kenji
112
- test_files: []
113
-
107
+ test_files:
108
+ - spec/1/controllers/main.rb
109
+ - spec/2/controllers/_.rb
110
+ - spec/2/controllers/child.rb
111
+ - spec/kenji_spec.rb
112
+ has_rdoc: