halcyon 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +5 -0
- data/lib/halcyon.rb +42 -24
- data/lib/halcyon/application.rb +134 -45
- data/lib/halcyon/application/hooks.rb +38 -0
- data/lib/halcyon/config.rb +252 -0
- data/lib/halcyon/config/file.rb +100 -0
- data/lib/halcyon/config/helpers.rb +180 -0
- data/lib/halcyon/config/paths.rb +73 -0
- data/lib/halcyon/controller.rb +168 -38
- data/lib/halcyon/exceptions.rb +3 -2
- data/lib/halcyon/runner.rb +8 -99
- data/lib/halcyon/runner/commands.rb +3 -4
- data/lib/rack/jsonp.rb +38 -0
- data/spec/halcyon/application_spec.rb +9 -15
- data/spec/halcyon/config_spec.rb +157 -0
- data/spec/halcyon/controller_spec.rb +70 -11
- data/spec/halcyon/halcyon_spec.rb +8 -8
- data/spec/halcyon/router_spec.rb +3 -3
- data/spec/halcyon/runner_spec.rb +10 -26
- data/spec/spec_helper.rb +34 -8
- data/support/generators/halcyon/templates/config/init.rb +42 -0
- data/support/generators/halcyon_flat/templates/app.rb +5 -12
- metadata +17 -5
- data/support/generators/halcyon/templates/config/config.yml +0 -36
- data/support/generators/halcyon/templates/config/init/environment.rb +0 -11
data/lib/halcyon/exceptions.rb
CHANGED
@@ -95,8 +95,9 @@ module Halcyon
|
|
95
95
|
status, body = http_status
|
96
96
|
class_eval <<-"end;"
|
97
97
|
class #{body.gsub(/( |\-)/,'')} < Halcyon::Exceptions::Base
|
98
|
-
def initialize(
|
99
|
-
|
98
|
+
def initialize(body=nil)
|
99
|
+
body = '#{body}' if body.nil?
|
100
|
+
super(#{status}, body)
|
100
101
|
end
|
101
102
|
end
|
102
103
|
end;
|
data/lib/halcyon/runner.rb
CHANGED
@@ -4,6 +4,7 @@ module Halcyon
|
|
4
4
|
# * setting up the logger
|
5
5
|
# * loading initializers
|
6
6
|
# * loading controllers
|
7
|
+
# All of which is done by the call to <tt>Halcyon::Application.boot</tt>.
|
7
8
|
#
|
8
9
|
# The Runner is a full-fledged Rack application, and accepts calls to #call.
|
9
10
|
#
|
@@ -14,70 +15,14 @@ module Halcyon
|
|
14
15
|
# Halcyon::Runner.run!(['start', '-p', '4647'])
|
15
16
|
#
|
16
17
|
# # load the config file and initialize the app
|
17
|
-
# Halcyon::Runner.load_config Halcyon.root/'config'/'config.yml'
|
18
18
|
# Halcyon::Runner.new
|
19
19
|
class Runner
|
20
20
|
|
21
21
|
autoload :Commands, 'halcyon/runner/commands'
|
22
22
|
|
23
|
-
class << self
|
24
|
-
|
25
|
-
# Runs commands from the CLI.
|
26
|
-
# +argv+ the arguments to pass to the commands
|
27
|
-
#
|
28
|
-
# Returns nothing
|
29
|
-
def run!(argv=ARGV)
|
30
|
-
Commands.send(argv.shift, argv)
|
31
|
-
end
|
32
|
-
|
33
|
-
# Returns the path to the configuration file specified, defaulting
|
34
|
-
# to the path for the <tt>config.yml</tt> file.
|
35
|
-
# +file+ the name of the config file path (without the <tt>.yml</tt>
|
36
|
-
# extension)
|
37
|
-
def config_path(file = "config")
|
38
|
-
Halcyon.paths[:config]/"#{file}.yml"
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
23
|
# Initializes the application and application resources.
|
44
|
-
def initialize
|
45
|
-
Halcyon::
|
46
|
-
|
47
|
-
# Load the configuration if none is set already
|
48
|
-
if Halcyon.config.nil?
|
49
|
-
if File.exist?(Halcyon::Runner.config_path)
|
50
|
-
Halcyon.config = Halcyon::Runner.load_config
|
51
|
-
else
|
52
|
-
Halcon.config = Halcyon::Application::DEFAULT_OPTIONS
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# Set application name
|
57
|
-
Halcyon.app = Halcyon.config[:app] || Halcyon.root.split('/').last.camel_case
|
58
|
-
|
59
|
-
# Setup logger
|
60
|
-
if Halcyon.config[:logger]
|
61
|
-
Halcyon.config[:logging] = (Halcyon.config[:logging] || Halcyon::Application::DEFAULT_OPTIONS[:logging]).merge({
|
62
|
-
:type => Halcyon.config[:logger].class.to_s,
|
63
|
-
:logger => Halcyon.config[:logger]
|
64
|
-
})
|
65
|
-
end
|
66
|
-
Halcyon::Logging.set((Halcyon.config[:logging][:type] rescue nil))
|
67
|
-
Halcyon.logger = Halcyon::Logger.setup(Halcyon.config[:logging])
|
68
|
-
|
69
|
-
# Run initializers
|
70
|
-
Dir.glob(Halcyon.paths[:init]/'{requires,hooks,routes,environment,*}.rb').each do |initializer|
|
71
|
-
self.logger.debug "Init: #{File.basename(initializer).chomp('.rb').camel_case}" if
|
72
|
-
require initializer.chomp('.rb')
|
73
|
-
end
|
74
|
-
|
75
|
-
# Setup autoloads for Controllers found in Halcyon.root/'app'
|
76
|
-
Dir.glob(Halcyon.paths[:controller]/'{application,*}.rb').each do |controller|
|
77
|
-
self.logger.debug "Load: #{File.basename(controller).chomp('.rb').camel_case} Controller" if
|
78
|
-
require controller.chomp('.rb')
|
79
|
-
end
|
80
|
-
|
24
|
+
def initialize(&block)
|
25
|
+
Halcyon::Application.boot(&block) unless Halcyon::Application.booted
|
81
26
|
@app = Halcyon::Application.new
|
82
27
|
end
|
83
28
|
|
@@ -91,48 +36,12 @@ module Halcyon
|
|
91
36
|
|
92
37
|
class << self
|
93
38
|
|
94
|
-
#
|
95
|
-
# +
|
96
|
-
#
|
97
|
-
# Examples
|
98
|
-
# Halcyon::Runner.load_config Halcyon.root/'config'/'config.yml'
|
99
|
-
# Halcyon.config #=> {:allow_from => :all, :logging => {...}, ...}.to_mash
|
100
|
-
#
|
101
|
-
# Returns {Symbol:key => String:value}.to_mash
|
102
|
-
def load_config(file=Halcyon::Runner.config_path)
|
103
|
-
if File.exist?(file)
|
104
|
-
require 'yaml'
|
105
|
-
|
106
|
-
# load the config file
|
107
|
-
begin
|
108
|
-
config = YAML.load_file(file).to_mash
|
109
|
-
rescue Errno::EACCES
|
110
|
-
raise LoadError.new("Can't access #{file}, try 'sudo #{$0}'")
|
111
|
-
end
|
112
|
-
else
|
113
|
-
warn "#{file} not found, ensure the path to this file is correct. Ignoring."
|
114
|
-
nil
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# Set the paths for resources to be located.
|
119
|
-
#
|
120
|
-
# Used internally for setting the load paths if not manually overridden
|
121
|
-
# and needed to be set before normal application initialization.
|
122
|
-
#
|
123
|
-
# TODO: Move this to the planned <tt>Halcyon::Config</tt> object.
|
39
|
+
# Runs commands from the CLI.
|
40
|
+
# +argv+ the arguments to pass to the commands
|
124
41
|
#
|
125
|
-
# Returns nothing
|
126
|
-
def
|
127
|
-
|
128
|
-
Halcyon.paths = {
|
129
|
-
:controller => Halcyon.root/'app',
|
130
|
-
:model => Halcyon.root/'app'/'models',
|
131
|
-
:lib => Halcyon.root/'lib',
|
132
|
-
:config => Halcyon.root/'config',
|
133
|
-
:init => Halcyon.root/'config'/'{init,initialize}',
|
134
|
-
:log => Halcyon.root/'log'
|
135
|
-
}.to_mash.merge(Halcyon.paths || {})
|
42
|
+
# Returns nothing
|
43
|
+
def run!(argv=ARGV)
|
44
|
+
Commands.send(argv.shift, argv)
|
136
45
|
end
|
137
46
|
|
138
47
|
end
|
@@ -63,10 +63,9 @@ module Halcyon
|
|
63
63
|
# Set up the application
|
64
64
|
Object.instance_eval do
|
65
65
|
$log = ''
|
66
|
-
Halcyon::Runner.
|
67
|
-
|
68
|
-
|
69
|
-
$app = Halcyon::Runner.new
|
66
|
+
$app = Halcyon::Runner.new do |c|
|
67
|
+
c[:logger] = Logger.new(StringIO.new($log))
|
68
|
+
end
|
70
69
|
$response = nil
|
71
70
|
end
|
72
71
|
|
data/lib/rack/jsonp.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Rack
|
2
|
+
|
3
|
+
# A Rack middleware for providing JSON-P support.
|
4
|
+
#
|
5
|
+
# Full credit to Flinn Mueller (http://actsasflinn.com/) for this contribution.
|
6
|
+
#
|
7
|
+
class JSONP
|
8
|
+
|
9
|
+
def initialize(app)
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
# Proxies the request to the application, stripping out the JSON-P callback
|
14
|
+
# method and padding the response with the appropriate callback format.
|
15
|
+
#
|
16
|
+
# Changes nothing if no <tt>callback</tt> param is specified.
|
17
|
+
#
|
18
|
+
def call(env)
|
19
|
+
status, headers, response = @app.call(env)
|
20
|
+
request = Rack::Request.new(env)
|
21
|
+
response = pad(request.params.delete('callback'), response) if request.params.include?('callback')
|
22
|
+
[status, headers, response]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Pads the response with the appropriate callback format according to the
|
26
|
+
# JSON-P spec/requirements.
|
27
|
+
#
|
28
|
+
# The Rack response spec indicates that it should be enumerable. The method
|
29
|
+
# of combining all of the data into a sinle string makes sense since JSON
|
30
|
+
# is returned as a full string.
|
31
|
+
#
|
32
|
+
def pad(callback, response, body = "")
|
33
|
+
response.each{ |s| body << s }
|
34
|
+
"#{callback}(#{body})"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -3,10 +3,9 @@ describe "Halcyon::Application" do
|
|
3
3
|
before do
|
4
4
|
@log = ''
|
5
5
|
@logger = Logger.new(StringIO.new(@log))
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
Halcyon.config = @config
|
6
|
+
Halcyon.config.use do |c|
|
7
|
+
c[:logger] = @logger
|
8
|
+
end
|
10
9
|
@app = Halcyon::Runner.new
|
11
10
|
end
|
12
11
|
|
@@ -17,7 +16,7 @@ describe "Halcyon::Application" do
|
|
17
16
|
|
18
17
|
it "should dispatch methods according to their respective routes" do
|
19
18
|
Rack::MockRequest.new(@app).get("/hello/Matt")
|
20
|
-
|
19
|
+
$hello.should == "Matt"
|
21
20
|
end
|
22
21
|
|
23
22
|
it "should handle requests and respond with JSON" do
|
@@ -26,13 +25,6 @@ describe "Halcyon::Application" do
|
|
26
25
|
body['body'].should == "Found"
|
27
26
|
end
|
28
27
|
|
29
|
-
it "should handle requests with param values in the URL" do
|
30
|
-
body = JSON.parse(Rack::MockRequest.new(@app).get("/hello/Matt?test=value").body)
|
31
|
-
body['status'].should == 200
|
32
|
-
body['body'].should == "Hello Matt"
|
33
|
-
@log.split("\n").last.should =~ /"test"=>"value"/
|
34
|
-
end
|
35
|
-
|
36
28
|
it "should not dispatch private methods" do
|
37
29
|
body = JSON.parse(Rack::MockRequest.new(@app).get("/specs/undispatchable_private_method").body)
|
38
30
|
body['status'].should == 404
|
@@ -47,12 +39,14 @@ describe "Halcyon::Application" do
|
|
47
39
|
|
48
40
|
it "should log activity" do
|
49
41
|
Halcyon.logger.is_a?(Logger).should.be.true?
|
50
|
-
Rack::MockRequest.new(@app).get("/lolcats/r/cute")
|
51
|
-
@log.should =~ / INFO \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] \(\d+\) Specs :: \[404\] \/lolcats\/r\/cute \(.+\)\n/
|
42
|
+
# Rack::MockRequest.new(@app).get("/lolcats/r/cute")
|
43
|
+
# @log.should =~ / INFO \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] \(\d+\) Specs :: \[404\] \/lolcats\/r\/cute \(.+\)\n/
|
44
|
+
# Halcyon.logger.debug "Testing"
|
45
|
+
# @log.should =~ /Testing/
|
52
46
|
end
|
53
47
|
|
54
48
|
it "should allow all requests by default" do
|
55
|
-
Halcyon.config[:allow_from].should == :all
|
49
|
+
Halcyon.config[:allow_from].to_sym.should == :all
|
56
50
|
end
|
57
51
|
|
58
52
|
it "should handle exceptions gracefully" do
|
@@ -0,0 +1,157 @@
|
|
1
|
+
describe "Halcyon::Config" do
|
2
|
+
|
3
|
+
before do
|
4
|
+
Halcyon.config = Halcyon::Config.new(:environment => :test)
|
5
|
+
# @log = ''
|
6
|
+
# @logger = Logger.new(StringIO.new(@log))
|
7
|
+
# @config = $config.dup
|
8
|
+
# @config[:logger] = @logger
|
9
|
+
# @config[:app] = 'Specs'
|
10
|
+
# Halcyon.config = @config
|
11
|
+
# @app = Halcyon::Runner.new
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should provide the path of the application root directory" do
|
15
|
+
Halcyon.root.should == Dir.pwd
|
16
|
+
Halcyon.config[:root] = Dir.pwd
|
17
|
+
Halcyon.root.should == Halcyon.config[:root]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should provide numerous ways to retrieve configuration values" do
|
21
|
+
Halcyon.config[:foo] = :bar
|
22
|
+
|
23
|
+
Halcyon.config[:foo].should == :bar
|
24
|
+
Halcyon.config.foo.should == :bar
|
25
|
+
Halcyon.config.get(:foo).should == :bar
|
26
|
+
Halcyon.config.use {|c| c[:foo].should == :bar }
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should provide numerous ways to set configuration values" do
|
30
|
+
Halcyon.config[:foo] = :a; Halcyon.config[:foo].should == :a
|
31
|
+
Halcyon.config.foo = :b; Halcyon.config[:foo].should == :b
|
32
|
+
Halcyon.config.put(:foo, :c); Halcyon.config[:foo].should == :c
|
33
|
+
Halcyon.config.put(:foo => :d); Halcyon.config[:foo].should == :d
|
34
|
+
Halcyon.config.use {|c| c[:foo] = :e }; Halcyon.config[:foo].should == :e
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should access to major config values through Halcyon.<attr> accessors" do
|
38
|
+
Halcyon.config.use do |c|
|
39
|
+
c[:app] = "Specr"
|
40
|
+
c[:root] = Dir.pwd
|
41
|
+
c[:paths] = Halcyon::Config::Paths.new
|
42
|
+
c[:db] = Mash.new(:test => Mash.new)
|
43
|
+
c[:environment] = :test
|
44
|
+
end
|
45
|
+
|
46
|
+
Halcyon.app.should == Halcyon.config[:app]
|
47
|
+
Halcyon.root.should == (Halcyon.config[:root] || Dir.pwd)
|
48
|
+
Halcyon.paths.should == Halcyon.config[:paths]
|
49
|
+
Halcyon.db.should == Halcyon.config[:db]
|
50
|
+
Halcyon.environment.should == Halcyon.config[:environment]
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should provide custom Halcyon.<attr> accessors interfacing config values" do
|
54
|
+
Halcyon.configurable_attr(:foo)
|
55
|
+
Halcyon.foo = true
|
56
|
+
Halcyon.foo.should == Halcyon.config[:foo]
|
57
|
+
|
58
|
+
Halcyon.configurable_reader(:bar) do
|
59
|
+
Halcyon.config[:bar].to_sym
|
60
|
+
end
|
61
|
+
Halcyon.config[:bar] = "foo"
|
62
|
+
Halcyon.bar.should == :foo
|
63
|
+
|
64
|
+
Halcyon.configurable_reader(:baz, "Halcyon.config[%s].to_sym")
|
65
|
+
Halcyon.config[:baz] = "bar"
|
66
|
+
Halcyon.baz.should == :bar
|
67
|
+
|
68
|
+
Halcyon.configurable_writer(:bing) do |value|
|
69
|
+
Halcyon.config[:bing] = value.to_sym
|
70
|
+
end
|
71
|
+
Halcyon.bing = "foo"
|
72
|
+
Halcyon.config[:bing].should == :foo
|
73
|
+
|
74
|
+
Halcyon.configurable_writer(:bong, "Halcyon.config[%s] = value.to_sym")
|
75
|
+
Halcyon.bong = "bar"
|
76
|
+
Halcyon.config[:bong].should == :bar
|
77
|
+
end
|
78
|
+
|
79
|
+
# it "should ..." do
|
80
|
+
# #
|
81
|
+
# end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "Halcyon::Config::Paths" do
|
86
|
+
|
87
|
+
before do
|
88
|
+
@paths = Halcyon::Config::Paths.new
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should be able to look up paths by name" do
|
92
|
+
@paths.for(:config).should == Halcyon.root/'config'
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should be able to define new paths" do
|
96
|
+
@paths.define(:foo => Halcyon.root/'bar', :bar => Halcyon.root/'foo')
|
97
|
+
@paths.for(:foo).should == Halcyon.root/'bar'
|
98
|
+
@paths.for(:bar).should == Halcyon.root/'foo'
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should be able to define new paths by name" do
|
102
|
+
@paths.define(:foo, Halcyon.root/'baz')
|
103
|
+
@paths.for(:foo).should == Halcyon.root/'baz'
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should provide a shortcut to look up paths by name" do
|
107
|
+
@paths[:config].should == @paths.for(:config)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should provide a shortcut to define new paths by name" do
|
111
|
+
@paths[:config] = Halcyon.root/'gifnoc'
|
112
|
+
@paths.for(:config).should == Halcyon.root/'gifnoc'
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should raise an ArgumentError if a nonexistent path is queried for" do
|
116
|
+
should.raise(ArgumentError) { @paths.for(:nonexistent_path) }
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
require 'tmpdir'
|
122
|
+
require 'yaml'
|
123
|
+
describe "Halcyon::Config::File" do
|
124
|
+
|
125
|
+
before do
|
126
|
+
@config = {
|
127
|
+
:allow_from => "all",
|
128
|
+
:logging => {
|
129
|
+
:type => "Logger",
|
130
|
+
:level => "debug"
|
131
|
+
},
|
132
|
+
:root => Dir.pwd,
|
133
|
+
:app => "Specr",
|
134
|
+
:environment => "development"
|
135
|
+
}.to_mash
|
136
|
+
File.open(Dir.tmpdir/'config.yaml', 'w+'){|f| f << @config.to_yaml }
|
137
|
+
File.open(Dir.tmpdir/'config.json', 'w+'){|f| f << @config.to_json }
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should load the configuration from the YAML config file" do
|
141
|
+
Halcyon::Config::File.new(Dir.tmpdir/'config.yaml').to_hash.should == @config
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should load the configuration from the JSON config file" do
|
145
|
+
Halcyon::Config::File.new(Dir.tmpdir/'config.json').to_hash(:from_json).should == @config
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should provide shortcuts for loading configuration files" do
|
149
|
+
Halcyon::Config::File.load(Dir.tmpdir/'config.yaml').should == @config
|
150
|
+
Halcyon::Config::File.load_from_json(Dir.tmpdir/'config.json')
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should throw an ArgumentError when the config file doesn't exist" do
|
154
|
+
should.raise(ArgumentError) { Halcyon::Config::File.load('/path/to/nonexistent/file.yalm') }
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
@@ -3,22 +3,39 @@ describe "Halcyon::Controller" do
|
|
3
3
|
before do
|
4
4
|
@log = ''
|
5
5
|
@logger = Logger.new(StringIO.new(@log))
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
Halcyon.config = @config
|
6
|
+
Halcyon.config.use do |c|
|
7
|
+
c[:logger] = @logger
|
8
|
+
end
|
10
9
|
@app = Halcyon::Runner.new
|
11
10
|
end
|
12
11
|
|
13
12
|
it "should provide various shorthand methods for simple responses but take custom response values" do
|
14
13
|
controller = Specs.new(Rack::MockRequest.env_for('/'))
|
15
14
|
|
16
|
-
response = {:status => 200, :body => 'OK'}
|
15
|
+
response = {:status => 200, :body => 'OK', :headers => {}}
|
17
16
|
controller.ok.should == response
|
18
17
|
controller.success.should == response
|
19
18
|
|
20
|
-
controller.ok('').should == {:status => 200, :body => ''}
|
21
|
-
controller.ok(['OK', 'Sure Thang', 'Correcto']).should == {:status => 200, :body => ['OK', 'Sure Thang', 'Correcto']}
|
19
|
+
controller.ok('').should == {:status => 200, :body => '', :headers => {}}
|
20
|
+
controller.ok(['OK', 'Sure Thang', 'Correcto']).should == {:status => 200, :body => ['OK', 'Sure Thang', 'Correcto'], :headers => {}}
|
21
|
+
|
22
|
+
headers = {'Date' => Time.now.strftime("%a, %d %h %Y %H:%I:%S %Z"), 'Test' => 'FooBar'}
|
23
|
+
controller.ok('OK', headers).should == {:status => 200, :body => 'OK', :headers => headers}
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should provide extensive responders" do
|
27
|
+
controller = Specs.new(Rack::MockRequest.env_for('/'))
|
28
|
+
|
29
|
+
should.raise(Halcyon::Exceptions::UnprocessableEntity) { controller.status(:unprocessable_entity) }
|
30
|
+
response = Rack::MockRequest.new(@app).get("/specs/unprocessable_entity_test")
|
31
|
+
response.body.should =~ %r{Unprocessable Entity}
|
32
|
+
|
33
|
+
should.raise(Halcyon::Exceptions::UnprocessableEntity) { controller.status(:unprocessable_entity) }
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should indicate service is unavailable if an status specified is not found" do
|
37
|
+
controller = Specs.new(Rack::MockRequest.env_for('/'))
|
38
|
+
should.raise(Halcyon::Exceptions::ServiceUnavailable) { controller.status(:this_state_does_not_exist) }
|
22
39
|
end
|
23
40
|
|
24
41
|
it "should provide a quick way to find out what method the request was performed using" do
|
@@ -52,17 +69,59 @@ describe "Halcyon::Controller" do
|
|
52
69
|
controller = Specs.new(Rack::MockRequest.env_for(""))
|
53
70
|
controller.uri.should == '/'
|
54
71
|
end
|
55
|
-
|
56
|
-
it
|
72
|
+
|
73
|
+
it "should provide url accessor for resource index route" do
|
57
74
|
controller = Resources.new(Rack::MockRequest.env_for("/resources"))
|
58
75
|
controller.uri.should == controller.url(:resources)
|
59
76
|
end
|
60
|
-
|
61
|
-
it
|
77
|
+
|
78
|
+
it "should provide url accessor for resource show route" do
|
62
79
|
resource = Model.new
|
63
80
|
resource.id = 1
|
64
81
|
controller = Resources.new(Rack::MockRequest.env_for("/resources/1"))
|
65
82
|
controller.uri.should == controller.url(:resource, resource)
|
66
83
|
end
|
67
84
|
|
85
|
+
it "should accept response headers" do
|
86
|
+
controller = Specs.new(Rack::MockRequest.env_for(""))
|
87
|
+
headers = {'Date' => Time.now.strftime("%a, %d %h %Y %H:%I:%S %Z"), 'Foo' => 'Bar'}
|
88
|
+
controller.ok('OK', headers).should == {:status => 200, :body => 'OK', :headers => headers}
|
89
|
+
controller.ok('OK').should == {:status => 200, :body => 'OK', :headers => {}}
|
90
|
+
|
91
|
+
response = Rack::MockRequest.new(@app).get("/goob")
|
92
|
+
response['Date'].should == Time.now.strftime("%a, %d %h %Y %H:%I:%S %Z")
|
93
|
+
response['Content-Language'].should == 'en'
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should handle return values from actions not from the response helpers" do
|
97
|
+
{
|
98
|
+
'OK' => {'status' => 200, 'body' => 'OK'},
|
99
|
+
[200, {}, 'OK'] => {'status' => 200, 'body' => 'OK'},
|
100
|
+
[1, 2, 3] => {'status' => 200, 'body' => [1, 2, 3]},
|
101
|
+
{'foo' => 'bar'} => {'status' => 200, 'body' => {'foo' => 'bar'}}
|
102
|
+
}.each do |(value, expected)|
|
103
|
+
$return_value_for_gaff = value
|
104
|
+
response = JSON.parse(Rack::MockRequest.new(@app).get("/gaff").body).should == expected
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should run filters before or after actions" do
|
109
|
+
response = Rack::MockRequest.new(@app).get("/index")
|
110
|
+
response.body.should =~ %r{Found}
|
111
|
+
|
112
|
+
# The Accepted exception is raised if +cause_exception_in_filter+ is set
|
113
|
+
response = Rack::MockRequest.new(@app).get("/index?cause_exception_in_filter=true")
|
114
|
+
response.body.should =~ %r{Accepted}
|
115
|
+
|
116
|
+
response = Rack::MockRequest.new(@app).get("/foobar")
|
117
|
+
response.body.should =~ %r{fubr}
|
118
|
+
|
119
|
+
# The Created exception is raised if +cause_exception_in_filter+ is set
|
120
|
+
response = Rack::MockRequest.new(@app).get("/foobar?cause_exception_in_filter=true")
|
121
|
+
response.body.should =~ %r{Created}
|
122
|
+
|
123
|
+
response = Rack::MockRequest.new(@app).get("/hello/Matt?cause_exception_in_filter_block=true")
|
124
|
+
response.body.should =~ %r{Not Found}
|
125
|
+
end
|
126
|
+
|
68
127
|
end
|