kenji 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
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: