halcyon 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/LICENSE +20 -0
- data/README +107 -0
- data/Rakefile +8 -6
- data/bin/halcyon +3 -204
- data/lib/halcyon.rb +55 -42
- data/lib/halcyon/application.rb +247 -0
- data/lib/halcyon/application/router.rb +86 -0
- data/lib/halcyon/client.rb +187 -35
- data/lib/halcyon/client/ssl.rb +38 -0
- data/lib/halcyon/controller.rb +154 -0
- data/lib/halcyon/exceptions.rb +67 -59
- data/lib/halcyon/logging.rb +31 -0
- data/lib/halcyon/logging/analogger.rb +31 -0
- data/lib/halcyon/logging/helpers.rb +37 -0
- data/lib/halcyon/logging/log4r.rb +25 -0
- data/lib/halcyon/logging/logger.rb +20 -0
- data/lib/halcyon/logging/logging.rb +19 -0
- data/lib/halcyon/runner.rb +141 -0
- data/lib/halcyon/runner/commands.rb +141 -0
- data/lib/halcyon/runner/helpers.rb +9 -0
- data/lib/halcyon/runner/helpers/command_helper.rb +71 -0
- data/spec/halcyon/application_spec.rb +70 -0
- data/spec/halcyon/client_spec.rb +63 -0
- data/spec/halcyon/controller_spec.rb +68 -0
- data/spec/halcyon/halcyon_spec.rb +63 -0
- data/spec/halcyon/logging_spec.rb +31 -0
- data/spec/halcyon/router_spec.rb +37 -12
- data/spec/halcyon/runner_spec.rb +54 -0
- data/spec/spec_helper.rb +75 -9
- data/support/generators/halcyon/USAGE +0 -0
- data/support/generators/halcyon/halcyon_generator.rb +52 -0
- data/support/generators/halcyon/templates/README +26 -0
- data/support/generators/halcyon/templates/Rakefile +32 -0
- data/support/generators/halcyon/templates/app/application.rb +43 -0
- data/support/generators/halcyon/templates/config/config.yml +36 -0
- data/support/generators/halcyon/templates/config/init/environment.rb +11 -0
- data/support/generators/halcyon/templates/config/init/hooks.rb +39 -0
- data/support/generators/halcyon/templates/config/init/requires.rb +10 -0
- data/support/generators/halcyon/templates/config/init/routes.rb +50 -0
- data/support/generators/halcyon/templates/lib/client.rb +77 -0
- data/support/generators/halcyon/templates/runner.ru +8 -0
- data/support/generators/halcyon_flat/USAGE +0 -0
- data/support/generators/halcyon_flat/halcyon_flat_generator.rb +52 -0
- data/support/generators/halcyon_flat/templates/README +26 -0
- data/support/generators/halcyon_flat/templates/Rakefile +32 -0
- data/support/generators/halcyon_flat/templates/app.rb +49 -0
- data/support/generators/halcyon_flat/templates/lib/client.rb +17 -0
- data/support/generators/halcyon_flat/templates/runner.ru +8 -0
- metadata +73 -20
- data/lib/halcyon/client/base.rb +0 -261
- data/lib/halcyon/client/exceptions.rb +0 -41
- data/lib/halcyon/client/router.rb +0 -106
- data/lib/halcyon/server.rb +0 -62
- data/lib/halcyon/server/auth/basic.rb +0 -107
- data/lib/halcyon/server/base.rb +0 -774
- data/lib/halcyon/server/exceptions.rb +0 -41
- data/lib/halcyon/server/router.rb +0 -103
- data/spec/halcyon/error_spec.rb +0 -55
- data/spec/halcyon/server_spec.rb +0 -105
@@ -1,41 +0,0 @@
|
|
1
|
-
#--
|
2
|
-
# Created by Matt Todd on 2007-12-14.
|
3
|
-
# Copyright (c) 2007. All rights reserved.
|
4
|
-
#++
|
5
|
-
|
6
|
-
#--
|
7
|
-
# module
|
8
|
-
#++
|
9
|
-
|
10
|
-
module Halcyon
|
11
|
-
class Server
|
12
|
-
class Base
|
13
|
-
module Exceptions #:nodoc:
|
14
|
-
|
15
|
-
#--
|
16
|
-
# Exception classes
|
17
|
-
#++
|
18
|
-
|
19
|
-
Halcyon::Exceptions::HTTP_ERROR_CODES.to_a.each do |http_error|
|
20
|
-
status, body = http_error
|
21
|
-
class_eval(
|
22
|
-
"class #{body.gsub(/( |\-)/,'')} < Halcyon::Exceptions::Base\n"+
|
23
|
-
" def initialize(s=#{status}, e='#{body}')\n"+
|
24
|
-
" super\n"+
|
25
|
-
" end\n"+
|
26
|
-
"end"
|
27
|
-
);
|
28
|
-
end
|
29
|
-
|
30
|
-
#--
|
31
|
-
# Exception Lookup
|
32
|
-
#++
|
33
|
-
|
34
|
-
def self.lookup(status)
|
35
|
-
self.const_get(Halcyon::Exceptions::HTTP_ERROR_CODES[status].gsub(/( |\-)/,''))
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,103 +0,0 @@
|
|
1
|
-
#--
|
2
|
-
# Created by Matt Todd on 2007-12-14.
|
3
|
-
# Copyright (c) 2007. All rights reserved.
|
4
|
-
#++
|
5
|
-
|
6
|
-
#--
|
7
|
-
# dependencies
|
8
|
-
#++
|
9
|
-
|
10
|
-
begin
|
11
|
-
%w(rubygems merb/core_ext merb/router uri).each {|dep|require dep}
|
12
|
-
rescue LoadError => e
|
13
|
-
abort "Merb must be installed for Routing to function. Please install Merb."
|
14
|
-
end
|
15
|
-
|
16
|
-
#--
|
17
|
-
# module
|
18
|
-
#++
|
19
|
-
|
20
|
-
module Halcyon
|
21
|
-
class Server
|
22
|
-
|
23
|
-
# = Routing
|
24
|
-
#
|
25
|
-
# Handles routing.
|
26
|
-
#
|
27
|
-
# == Usage
|
28
|
-
#
|
29
|
-
# class Xy < Halcyon::Server::Base
|
30
|
-
# route do |r|
|
31
|
-
# r.match('/path/to/match').to(:action => 'do_stuff')
|
32
|
-
# {:action => 'not_found'} # the default route
|
33
|
-
# end
|
34
|
-
# def do_stuff(params)
|
35
|
-
# [200, {}, 'OK']
|
36
|
-
# end
|
37
|
-
# end
|
38
|
-
#
|
39
|
-
# == Default Routes
|
40
|
-
#
|
41
|
-
# Supplying a default route if none of the others match is good practice,
|
42
|
-
# but is unnecessary as the predefined route is always, automatically,
|
43
|
-
# going to contain a redirection to the +not_found+ method which already
|
44
|
-
# exists in Halcyon::Server::Base. This method is freely overwritable, and
|
45
|
-
# is recommended for those that wish to handle unroutable requests
|
46
|
-
# themselves.
|
47
|
-
#
|
48
|
-
# In order to set a different default route, simply end the call to +route+
|
49
|
-
# with a hash containing the action (and optionally the module) to run.
|
50
|
-
#
|
51
|
-
# == The Hard Work
|
52
|
-
#
|
53
|
-
# The mechanics of the router are solely from the efforts of the Merb
|
54
|
-
# community. This functionality is completely ripped right out of Merb
|
55
|
-
# and makes it functional. All credit to them, and be sure to check out
|
56
|
-
# their great framework: if Halcyon isn't quite what you need, maybe Merb
|
57
|
-
# is.
|
58
|
-
#
|
59
|
-
# http://merbivore.com/
|
60
|
-
class Router < Merb::Router
|
61
|
-
|
62
|
-
# Retrieves the last value from the +route+ call in Halcyon::Server::Base
|
63
|
-
# and, if it's a Hash, sets it to +@@default_route+ to designate the
|
64
|
-
# failover route. If +route+ is not a Hash, though, the internal default
|
65
|
-
# should be used instead (as the last returned value is probably a Route
|
66
|
-
# object returned by the +r.match().to()+ call).
|
67
|
-
#
|
68
|
-
# Used exclusively internally.
|
69
|
-
def self.default_to route
|
70
|
-
@@default_route = route.is_a?(Hash) ? route : {:action => 'not_found'}
|
71
|
-
end
|
72
|
-
|
73
|
-
# Called internally by the Halcyon::Server::Base#call method to match
|
74
|
-
# the current request against the currently defined routes. Returns the
|
75
|
-
# params list defined in the +to+ routing definition, opting for the
|
76
|
-
# default route if no match is made.
|
77
|
-
def self.route(env)
|
78
|
-
# pull out the path requested (WEBrick keeps the host and port and protocol in REQUEST_URI)
|
79
|
-
# PATH_INFO is failover if REQUEST_URI is blank (like what Rack::MockRequest does)
|
80
|
-
uri = URI.parse(env['REQUEST_URI'] || env['PATH_INFO']).path
|
81
|
-
|
82
|
-
# prepare request
|
83
|
-
path = (uri ? uri.split('?').first : '').sub(/\/+/, '/')
|
84
|
-
path = path[0..-2] if (path[-1] == ?/) && path.size > 1
|
85
|
-
req = Struct.new(:path, :method).new(path, env['REQUEST_METHOD'].downcase.to_sym)
|
86
|
-
|
87
|
-
# perform match
|
88
|
-
route = self.match(req, {})
|
89
|
-
|
90
|
-
# make sure a route is returned even if no match is found
|
91
|
-
if route[0].nil?
|
92
|
-
#return default route
|
93
|
-
env['halcyon.logger'].debug "No route found. Using default." if env['halcyon.logger'].is_a? Logger
|
94
|
-
@@default_route
|
95
|
-
else
|
96
|
-
# params (including action and module if set) for the matching route
|
97
|
-
route[1]
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
data/spec/halcyon/error_spec.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
describe "Halcyon::Server Errors" do
|
2
|
-
|
3
|
-
before do
|
4
|
-
@app = Specr.new :port => 4000
|
5
|
-
end
|
6
|
-
|
7
|
-
it "should provide shorthand methods for errors which should throw an appropriate exception" do
|
8
|
-
begin
|
9
|
-
@app.not_found
|
10
|
-
rescue Halcyon::Exceptions::Base => e
|
11
|
-
e.status.should == 404
|
12
|
-
e.error.should == 'Not Found'
|
13
|
-
end
|
14
|
-
|
15
|
-
begin
|
16
|
-
@app.not_found('Missing')
|
17
|
-
rescue Halcyon::Exceptions::Base => e
|
18
|
-
e.status.should == 404
|
19
|
-
e.error.should == 'Missing'
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
it "supports numerous standard HTTP request error exceptions with lookup by status code" do
|
24
|
-
begin
|
25
|
-
Halcyon::Server::Base::Exceptions::NotFound.new
|
26
|
-
rescue Halcyon::Exceptions::Base => e
|
27
|
-
e.status.should == 404
|
28
|
-
e.error.should == 'Not Found'
|
29
|
-
end
|
30
|
-
|
31
|
-
Halcyon::Exceptions::HTTP_ERROR_CODES.each do |code, error|
|
32
|
-
begin
|
33
|
-
Halcyon::Server::Base::Exceptions.const_get(error.gsub(/( |\-)/,'')).new
|
34
|
-
rescue Halcyon::Exceptions::Base => e
|
35
|
-
e.status.should == code
|
36
|
-
e.error.should == error
|
37
|
-
end
|
38
|
-
begin
|
39
|
-
Halcyon::Server::Base::Exceptions.lookup(code).new
|
40
|
-
rescue Halcyon::Exceptions::Base => e
|
41
|
-
e.status.should == code
|
42
|
-
e.error.should == error
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should have a short inheritence chain to make catching generically simple" do
|
48
|
-
begin
|
49
|
-
Halcyon::Server::Base::Exceptions::NotFound.new
|
50
|
-
rescue Halcon::Exceptions::Base => e
|
51
|
-
e.class.to_s.should == 'NotFound'
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
data/spec/halcyon/server_spec.rb
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
describe "Halcyon::Server" do
|
2
|
-
|
3
|
-
before do
|
4
|
-
@app = Specr.new :port => 4000
|
5
|
-
end
|
6
|
-
|
7
|
-
it "should dispatch methods according to their respective routes" do
|
8
|
-
Rack::MockRequest.new(@app).get("/hello/Matt")
|
9
|
-
last_line = File.new(@app.instance_variable_get("@config")[:log_file]).readlines.last
|
10
|
-
last_line.should =~ /INFO \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] \(\d+\) Specr#test :: \[200\] .* => greeter \(.+\)/
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should provide various shorthand methods for simple responses but take custom response values" do
|
14
|
-
response = {:status => 200, :body => 'OK'}
|
15
|
-
@app.ok.should == response
|
16
|
-
@app.success.should == response
|
17
|
-
@app.standard_response.should == response
|
18
|
-
|
19
|
-
@app.ok('').should == {:status => 200, :body => ''}
|
20
|
-
@app.ok(['OK', 'Sure Thang', 'Correcto']).should == {:status => 200, :body => ['OK', 'Sure Thang', 'Correcto']}
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should handle requests and respond with JSON" do
|
24
|
-
body = JSON.parse(Rack::MockRequest.new(@app).get("/").body)
|
25
|
-
body['status'].should == 200
|
26
|
-
body['body'].should == "Found"
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should handle requests with param values in the URL" do
|
30
|
-
body = JSON.parse(Rack::MockRequest.new(@app).get("/hello/Matt").body)
|
31
|
-
body['status'].should == 200
|
32
|
-
body['body'].should == "Hello Matt"
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should route unmatchable requests to the default route and return JSON with appropriate status" do
|
36
|
-
body = JSON.parse(Rack::MockRequest.new(@app).get("/garbage/request/url").body)
|
37
|
-
body['status'].should == 404
|
38
|
-
body['body'].should == "Not Found"
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should log activity" do
|
42
|
-
prev_line = File.new(@app.instance_variable_get("@config")[:log_file]).readlines.last
|
43
|
-
Rack::MockRequest.new(@app).get("/url/that/will/not/be/found/#{rand}")
|
44
|
-
last_line = File.new(@app.instance_variable_get("@config")[:log_file]).readlines.last
|
45
|
-
last_line.should =~ /INFO \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] \(\d+\) Specr#test :: \[404\] .* => not_found \(.+\)/
|
46
|
-
prev_line.should.not == last_line
|
47
|
-
end
|
48
|
-
|
49
|
-
it "should create a PID file while running with the correct process ID" do
|
50
|
-
pid_file = @app.instance_variable_get("@config")[:pid_file]
|
51
|
-
File.exist?(pid_file).should.be.true?
|
52
|
-
File.open(pid_file){|file|file.read.should == "#{$$}\n"}
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should parse URI query params correctly" do
|
56
|
-
Rack::MockRequest.new(@app).get("/?query=value&lang=en-US")
|
57
|
-
@app.query_params.should == {:query => 'value', :lang => 'en-US'}
|
58
|
-
end
|
59
|
-
|
60
|
-
it "should parse the URI correctly" do
|
61
|
-
Rack::MockRequest.new(@app).get("http://localhost:4000/slaughterhouse/5")
|
62
|
-
@app.uri.should == '/slaughterhouse/5'
|
63
|
-
|
64
|
-
Rack::MockRequest.new(@app).get("/slaughterhouse/5")
|
65
|
-
@app.uri.should == '/slaughterhouse/5'
|
66
|
-
|
67
|
-
Rack::MockRequest.new(@app).get("")
|
68
|
-
@app.uri.should == '/'
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should provide a quick way to find out what method the request was performed using" do
|
72
|
-
Rack::MockRequest.new(@app).get("/#{rand}")
|
73
|
-
@app.method.should == :get
|
74
|
-
|
75
|
-
Rack::MockRequest.new(@app).post("/#{rand}")
|
76
|
-
@app.method.should == :post
|
77
|
-
|
78
|
-
Rack::MockRequest.new(@app).put("/#{rand}")
|
79
|
-
@app.method.should == :put
|
80
|
-
|
81
|
-
Rack::MockRequest.new(@app).delete("/#{rand}")
|
82
|
-
@app.method.should == :delete
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should provide convenient access to GET and POST data" do
|
86
|
-
Rack::MockRequest.new(@app).get("/#{rand}?foo=bar")
|
87
|
-
@app.get[:foo].should == 'bar'
|
88
|
-
|
89
|
-
Rack::MockRequest.new(@app).post("/#{rand}", :input => {:foo => 'bar'}.to_params)
|
90
|
-
@app.post[:foo].should == 'bar'
|
91
|
-
end
|
92
|
-
|
93
|
-
it "should deny all unacceptable requests" do
|
94
|
-
conf = @app.instance_variable_get("@config")
|
95
|
-
conf[:acceptable_requests] = Halcyon::Server::ACCEPTABLE_REQUESTS
|
96
|
-
|
97
|
-
Rack::MockRequest.new(@app).get("/#{rand}")
|
98
|
-
@app.acceptable_request! rescue Halcyon::Exceptions::Base
|
99
|
-
end
|
100
|
-
|
101
|
-
it "should record the correct environment details" do
|
102
|
-
@app.instance_eval { @config[:root].should == Dir.pwd }
|
103
|
-
end
|
104
|
-
|
105
|
-
end
|