halcyon 0.5.0 → 0.5.1
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/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
|