deas 0.2.1 → 0.3.0

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/lib/deas.rb CHANGED
@@ -36,4 +36,12 @@ module Deas
36
36
  option :routes_file, Pathname, :default => ENV['DEAS_ROUTES_FILE']
37
37
  end
38
38
 
39
+ class NullLogger
40
+ require 'logger'
41
+
42
+ ::Logger::Severity.constants.each do |name|
43
+ define_method(name.downcase){|*args| } # no-op
44
+ end
45
+ end
46
+
39
47
  end
@@ -0,0 +1,35 @@
1
+ module Deas
2
+
3
+ class ErrorHandler
4
+
5
+ def self.run(*args)
6
+ self.new(*args).run
7
+ end
8
+
9
+ def initialize(exception, sinatra_call, error_procs)
10
+ @exception = exception
11
+ @sinatra_call = sinatra_call
12
+
13
+ @error_procs = [*error_procs].compact
14
+ end
15
+
16
+ def run
17
+ response = nil
18
+ @error_procs.each do |error_proc|
19
+ begin
20
+ result = @sinatra_call.instance_exec(@exception, &error_proc)
21
+ response = result if result
22
+ rescue Exception => proc_exception
23
+ @exception = proc_exception
24
+ # reset the response if an exception occurs while evaulating the
25
+ # error procs -- a new exception will now be handled by the
26
+ # remaining procs
27
+ response = nil
28
+ end
29
+ end
30
+ response
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,126 @@
1
+ require 'benchmark'
2
+ require 'sinatra/base'
3
+
4
+ module Deas
5
+
6
+ module Logging
7
+ def self.middleware(verbose)
8
+ verbose ? VerboseLogging : SummaryLogging
9
+ end
10
+ end
11
+
12
+ class BaseLogging
13
+
14
+ def initialize(app)
15
+ @app = app
16
+ @logger = Deas.app.settings.logger
17
+ end
18
+
19
+ # The Rack call interface. The receiver acts as a prototype and runs
20
+ # each request in a clone object unless the +rack.run_once+ variable is
21
+ # set in the environment. Ripped from:
22
+ # http://github.com/rtomayko/rack-cache/blob/master/lib/rack/cache/context.rb
23
+ def call(env)
24
+ if env['rack.run_once']
25
+ call! env
26
+ else
27
+ clone.call! env
28
+ end
29
+ end
30
+
31
+ # The real Rack call interface.
32
+ # This is the common behavior for both the verbose and summary logging
33
+ # middlewares. It times the response and returns it as is.
34
+ def call!(env)
35
+ status, headers, body = nil, nil, nil
36
+ benchmark = Benchmark.measure do
37
+ status, headers, body = @app.call(env)
38
+ end
39
+ log_error(env['sinatra.error'])
40
+ env['deas.time_taken'] = RoundedTime.new(benchmark.real)
41
+ [ status, headers, body ]
42
+ end
43
+
44
+ def log(message)
45
+ @logger.info "[Deas] #{message}"
46
+ end
47
+
48
+ def log_error(exception)
49
+ return if !exception || exception.kind_of?(Sinatra::NotFound)
50
+ log "#{exception.class}: #{exception.message}\n" \
51
+ "#{exception.backtrace.join("\n")}"
52
+ end
53
+
54
+ end
55
+
56
+ class VerboseLogging < BaseLogging
57
+
58
+ RESPONSE_STATUS_NAMES = {
59
+ 200 => 'OK',
60
+ 400 => 'BAD REQUEST' ,
61
+ 401 => 'UNAUTHORIZED',
62
+ 403 => 'FORBIDDEN',
63
+ 404 => 'NOT FOUND',
64
+ 408 => 'TIMEOUT',
65
+ 500 => 'ERROR'
66
+ }
67
+
68
+ # This the real Rack call interface. It adds logging before and after
69
+ # super-ing to the common logging behavior.
70
+ def call!(env)
71
+ log "===== Received request ====="
72
+ Rack::Request.new(env).tap do |request|
73
+ log " Method: #{request.request_method.inspect}"
74
+ log " Path: #{request.path.inspect}"
75
+ end
76
+ env['deas.logging'] = Proc.new{ |msg| log(msg) }
77
+ status, headers, body = super(env)
78
+ log "===== Completed in #{env['deas.time_taken']}ms (#{response_display(status)}) ====="
79
+ [ status, headers, body ]
80
+ end
81
+
82
+ def response_display(status)
83
+ [ status, RESPONSE_STATUS_NAMES[status.to_i] ].compact.join(', ')
84
+ end
85
+
86
+ end
87
+
88
+ class SummaryLogging < BaseLogging
89
+
90
+ # This the real Rack call interface. It adds logging after super-ing to the
91
+ # common logging behavior.
92
+ def call!(env)
93
+ env['deas.logging'] = Proc.new{ |msg| } # no-op
94
+ status, headers, body = super(env)
95
+ request = Rack::Request.new(env)
96
+ log SummaryLine.new({
97
+ 'method' => request.request_method,
98
+ 'path' => request.path,
99
+ 'handler' => env['deas.handler_class'],
100
+ 'params' => env['sinatra.params'],
101
+ 'time' => env['deas.time_taken'],
102
+ 'status' => status
103
+ })
104
+ [ status, headers, body ]
105
+ end
106
+
107
+ end
108
+
109
+ module SummaryLine
110
+ def self.keys
111
+ %w{time status method path handler params}
112
+ end
113
+ def self.new(line_attrs)
114
+ self.keys.map{ |k| "#{k}=#{line_attrs[k].inspect}" }.join(' ')
115
+ end
116
+ end
117
+
118
+ module RoundedTime
119
+ ROUND_PRECISION = 2
120
+ ROUND_MODIFIER = 10 ** ROUND_PRECISION
121
+ def self.new(time_in_seconds)
122
+ (time_in_seconds * 1000 * ROUND_MODIFIER).to_i / ROUND_MODIFIER.to_f
123
+ end
124
+ end
125
+
126
+ end
data/lib/deas/route.rb CHANGED
@@ -17,8 +17,14 @@ module Deas
17
17
  raise(NoHandlerClassError.new(handler_class_name)) if !@handler_class
18
18
  end
19
19
 
20
- def runner(sinatra_call)
21
- Deas::SinatraRunner.new(@handler_class, sinatra_call)
20
+ def run(sinatra_call)
21
+ sinatra_call.request.env.tap do |env|
22
+ env['sinatra.params'] = sinatra_call.params
23
+ env['deas.handler_class'] = @handler_class
24
+ env['deas.logging'].call " Handler: #{env['deas.handler_class']}"
25
+ env['deas.logging'].call " Params: #{env['sinatra.params'].inspect}"
26
+ end
27
+ Deas::SinatraRunner.run(@handler_class, sinatra_call)
22
28
  end
23
29
 
24
30
  private
data/lib/deas/server.rb CHANGED
@@ -2,8 +2,6 @@ require 'ns-options'
2
2
  require 'ns-options/boolean'
3
3
  require 'pathname'
4
4
  require 'singleton'
5
-
6
- require 'deas/logger'
7
5
  require 'deas/route'
8
6
 
9
7
  module Deas
@@ -22,13 +20,15 @@ module Deas
22
20
  option :public_folder, Pathname
23
21
  option :views_folder, Pathname
24
22
 
25
- option :dump_errors, NsOptions::Boolean, :default => false
26
- option :method_override, NsOptions::Boolean, :default => true
27
- option :sessions, NsOptions::Boolean, :default => true
28
- option :show_exceptions, NsOptions::Boolean, :default => false
29
- option :static_files, NsOptions::Boolean, :default => true
23
+ option :dump_errors, NsOptions::Boolean, :default => false
24
+ option :method_override, NsOptions::Boolean, :default => true
25
+ option :sessions, NsOptions::Boolean, :default => false
26
+ option :show_exceptions, NsOptions::Boolean, :default => false
27
+ option :static_files, NsOptions::Boolean, :default => true
28
+ option :reload_templates, NsOptions::Boolean, :default => false
30
29
 
31
- # Deas specific options
30
+ # server handling options
31
+ option :error_procs, Array, :default => []
32
32
  option :init_proc, Proc, :default => proc{ }
33
33
  option :logger, :default => proc{ Deas::NullLogger.new }
34
34
  option :middlewares, Array, :default => []
@@ -48,9 +48,6 @@ module Deas
48
48
  })
49
49
  end
50
50
 
51
- def runner_logger
52
- Deas::RunnerLogger.new(self.logger, self.verbose_logging)
53
- end
54
51
  end
55
52
 
56
53
  attr_reader :configuration
@@ -59,6 +56,8 @@ module Deas
59
56
  @configuration = Configuration.new
60
57
  end
61
58
 
59
+ # sinatra settings DSL
60
+
62
61
  def env(*args)
63
62
  self.configuration.env *args
64
63
  end
@@ -95,6 +94,16 @@ module Deas
95
94
  self.configuration.static_files *args
96
95
  end
97
96
 
97
+ def reload_templates(*args)
98
+ self.configuration.reload_templates *args
99
+ end
100
+
101
+ # Server handling DSL
102
+
103
+ def error(&block)
104
+ self.configuration.error_procs << block
105
+ end
106
+
98
107
  def init(&block)
99
108
  self.configuration.init_proc = block
100
109
  end
@@ -103,10 +112,6 @@ module Deas
103
112
  self.configuration.logger *args
104
113
  end
105
114
 
106
- def use(*args)
107
- self.configuration.middlewares << args
108
- end
109
-
110
115
  def verbose_logging(*args)
111
116
  self.configuration.verbose_logging *args
112
117
  end
@@ -115,6 +120,10 @@ module Deas
115
120
  self.configuration.view_handler_ns *args
116
121
  end
117
122
 
123
+ def use(*args)
124
+ self.configuration.middlewares << args
125
+ end
126
+
118
127
  def get(path, handler_class_name)
119
128
  self.route(:get, path, handler_class_name)
120
129
  end
@@ -1,4 +1,6 @@
1
1
  require 'sinatra/base'
2
+ require 'deas/error_handler'
3
+ require 'deas/logging'
2
4
 
3
5
  module Deas
4
6
 
@@ -18,36 +20,37 @@ module Deas
18
20
  set :public_folder, server_config.public_folder
19
21
  set :views, server_config.views_folder
20
22
 
21
- set :dump_errors, server_config.dump_errors
23
+ set :dump_errors, server_config.dump_errors
24
+ set :method_override, server_config.method_override
25
+ set :sessions, server_config.sessions
26
+ set :show_exceptions, server_config.show_exceptions
27
+ set :static, server_config.static_files
28
+ set :reload_templates, server_config.reload_templates
22
29
  set :logging, false
23
- set :method_override, server_config.method_override
24
- set :sessions, server_config.sessions
25
- set :show_exceptions, server_config.show_exceptions
26
- set :static, server_config.static_files
27
30
 
28
31
  # custom settings
29
- set :logger, server_config.logger
30
- set :runner_logger, server_config.runner_logger
32
+ set :deas_error_procs, server_config.error_procs
33
+ set :logger, server_config.logger
31
34
 
32
35
  server_config.middlewares.each do |middleware_args|
33
36
  use *middleware_args
34
37
  end
38
+ use Deas::Logging.middleware(server_config.verbose_logging)
35
39
 
36
40
  # routes
37
41
  server_config.routes.each do |route|
38
42
  # defines Sinatra routes like:
39
- # before('/'){ ... }
40
43
  # get('/'){ ... }
41
- # after('/'){ ... }
42
- before(route.path) do
43
- @runner = route.runner(self).setup
44
- end
45
- send(route.method, route.path) do
46
- @runner.run
47
- end
48
- after(route.path) do
49
- @runner.teardown
50
- end
44
+ send(route.method, route.path){ route.run(self) }
45
+ end
46
+
47
+ # error handling
48
+ not_found do
49
+ env['sinatra.error'] ||= Sinatra::NotFound.new
50
+ ErrorHandler.run(env['sinatra.error'], self, settings.deas_error_procs)
51
+ end
52
+ error do
53
+ ErrorHandler.run(env['sinatra.error'], self, settings.deas_error_procs)
51
54
  end
52
55
 
53
56
  end
@@ -5,30 +5,21 @@ module Deas
5
5
 
6
6
  class SinatraRunner < Runner
7
7
 
8
+ def self.run(*args)
9
+ self.new(*args).run
10
+ end
11
+
8
12
  def initialize(handler_class, sinatra_call)
9
13
  @sinatra_call = sinatra_call
10
14
  @handler_class = handler_class
11
15
  @logger = @sinatra_call.settings.logger
12
- @runner_logger = @sinatra_call.settings.runner_logger
13
16
  @params = @sinatra_call.params
14
17
  @request = @sinatra_call.request
15
18
  @response = @sinatra_call.response
16
19
  @session = @sinatra_call.session
17
- @time_taken = nil
18
- @started_at = nil
19
20
  super(handler_class)
20
21
  end
21
22
 
22
- def setup
23
- @started_at = Time.now
24
- log_verbose "===== Received request ====="
25
- log_verbose " Method: #{@request.request_method.inspect}"
26
- log_verbose " Path: #{@request.path.inspect}"
27
- log_verbose " Params: #{@sinatra_call.params.inspect}"
28
- log_verbose " Handler: #{@handler_class}"
29
- self
30
- end
31
-
32
23
  def run
33
24
  run_callbacks @handler_class.before_callbacks
34
25
  @handler.init
@@ -37,42 +28,6 @@ module Deas
37
28
  response_data
38
29
  end
39
30
 
40
- # expects that `setup` has been run; this method is dependent on it
41
- CODE_NAMES = {
42
- 200 => 'OK',
43
- 400 => 'BAD REQUEST' ,
44
- 401 => 'UNAUTHORIZED',
45
- 403 => 'FORBIDDEN',
46
- 404 => 'NOT FOUND',
47
- 408 => 'TIMEOUT',
48
- 500 => 'ERROR'
49
- }
50
- def teardown
51
- @time_taken = RoundedTime.new(Time.now - @started_at)
52
- @response.status.tap do |code|
53
- response_display = [ code, CODE_NAMES[code.to_i] ].compact.join(', ')
54
- log_verbose "===== Completed in #{@time_taken}ms " \
55
- "#{response_display} ====="
56
- end
57
- log_summary SummaryLine.new({
58
- 'status' => @response.status,
59
- 'method' => @request.request_method,
60
- 'path' => @request.path,
61
- 'params' => @params,
62
- 'time' => @time_taken,
63
- 'handler' => @handler_class
64
- })
65
- self
66
- end
67
-
68
- def log_verbose(message, level = :info)
69
- @runner_logger.verbose.send(level, "[Deas] #{message}")
70
- end
71
-
72
- def log_summary(message, level = :info)
73
- @runner_logger.summary.send(level, "[Deas] #{message}")
74
- end
75
-
76
31
  # Helpers
77
32
 
78
33
  def halt(*args)
@@ -100,20 +55,5 @@ module Deas
100
55
  callbacks.each{|proc| @handler.instance_eval(&proc) }
101
56
  end
102
57
 
103
- module RoundedTime
104
- ROUND_PRECISION = 2
105
- ROUND_MODIFIER = 10 ** ROUND_PRECISION
106
- def self.new(time_in_seconds)
107
- (time_in_seconds * 1000 * ROUND_MODIFIER).to_i / ROUND_MODIFIER.to_f
108
- end
109
- end
110
-
111
- module SummaryLine
112
- def self.new(line_attrs)
113
- attr_keys = %w{time status handler method path params}
114
- attr_keys.map{ |k| "#{k}=#{line_attrs[k].inspect}" }.join(' ')
115
- end
116
- end
117
-
118
58
  end
119
59
  end
@@ -1,4 +1,3 @@
1
- require 'deas/logger'
2
1
  require 'deas/runner'
3
2
 
4
3
  module Deas
data/lib/deas/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Deas
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -41,11 +41,6 @@ module Deas
41
41
 
42
42
  protected
43
43
 
44
- def before_init; end
45
- def after_init; end
46
- def before_run; end
47
- def after_run; end
48
-
49
44
  # Helpers
50
45
 
51
46
  def halt(*args); @deas_runner.halt(*args); end
@@ -63,7 +58,9 @@ module Deas
63
58
  def session; @deas_runner.session; end
64
59
 
65
60
  def run_callback(callback)
66
- self.send(callback.to_s)
61
+ (self.class.send("#{callback}_callbacks") || []).each do |callback|
62
+ self.instance_eval(&callback)
63
+ end
67
64
  end
68
65
 
69
66
  module ClassMethods
@@ -84,6 +81,38 @@ module Deas
84
81
  @after_callbacks ||= []
85
82
  end
86
83
 
84
+ def before_init(&block)
85
+ self.before_init_callbacks << block
86
+ end
87
+
88
+ def before_init_callbacks
89
+ @before_init_callbacks ||= []
90
+ end
91
+
92
+ def after_init(&block)
93
+ self.after_init_callbacks << block
94
+ end
95
+
96
+ def after_init_callbacks
97
+ @after_init_callbacks ||= []
98
+ end
99
+
100
+ def before_run(&block)
101
+ self.before_run_callbacks << block
102
+ end
103
+
104
+ def before_run_callbacks
105
+ @before_run_callbacks ||= []
106
+ end
107
+
108
+ def after_run(&block)
109
+ self.after_run_callbacks << block
110
+ end
111
+
112
+ def after_run_callbacks
113
+ @after_run_callbacks ||= []
114
+ end
115
+
87
116
  def layout(*args)
88
117
  @layouts = args unless args.empty?
89
118
  @layouts
@@ -1,4 +1,4 @@
1
- require 'deas/logger'
1
+ require 'deas'
2
2
  require 'ostruct'
3
3
 
4
4
  class FakeApp
@@ -13,9 +13,7 @@ class FakeApp
13
13
  @params = @request.params
14
14
  @session = @request.session
15
15
  @response = FakeResponse.new
16
- @settings = OpenStruct.new({
17
- :runner_logger => Deas::RunnerLogger.new(Deas::NullLogger.new, false)
18
- })
16
+ @settings = OpenStruct.new({ })
19
17
  end
20
18
 
21
19
  def halt(*args)
@@ -9,15 +9,24 @@ class Deas::Server
9
9
  logger Logger.new(File.open(log_file_path, 'w'))
10
10
  verbose_logging true
11
11
 
12
- get '/show', 'ShowHandler'
13
- get '/halt', 'HaltHandler'
14
- get '/error', 'ErrorHandler'
15
- get '/with_layout', 'WithLayoutHandler'
16
- get '/alt_with_layout', 'AlternateWithLayoutHandler'
17
- get '/redirect', 'RedirectHandler'
18
- get '/redirect_to', 'RedirectToHandler'
19
- get '/set_session', 'SetSessionHandler'
20
- get '/use_session', 'UseSessionHandler'
12
+ error do |exception|
13
+ case exception
14
+ when Sinatra::NotFound
15
+ halt 404, "Couldn't be found"
16
+ when Exception
17
+ halt 500, "Oops, something went wrong"
18
+ end
19
+ end
20
+
21
+ get '/show', 'ShowHandler'
22
+ get '/halt', 'HaltHandler'
23
+ get '/error', 'ErrorHandler'
24
+ get '/with_layout', 'WithLayoutHandler'
25
+ get '/alt_with_layout', 'AlternateWithLayoutHandler'
26
+ get '/redirect', 'RedirectHandler'
27
+ get '/redirect_to', 'RedirectToHandler'
28
+ post '/session', 'SetSessionHandler'
29
+ get '/session', 'UseSessionHandler'
21
30
 
22
31
  end
23
32
 
@@ -102,7 +111,7 @@ class SetSessionHandler
102
111
 
103
112
  def run!
104
113
  session[:secret] = 'session_secret'
105
- redirect_to '/use_session'
114
+ redirect_to '/session'
106
115
  end
107
116
 
108
117
  end
@@ -13,21 +13,24 @@ class FlagViewHandler
13
13
 
14
14
  attr_reader :before_init_called, :init_bang_called, :after_init_called,
15
15
  :before_run_called, :run_bang_called, :after_run_called,
16
- :before_hook_called, :after_hook_called
16
+ :before_hook_called, :after_hook_called, :second_before_init_called
17
17
 
18
- def before_init
18
+ before_init do
19
19
  @before_init_called = true
20
20
  end
21
+ before_init do
22
+ @second_before_init_called = true
23
+ end
21
24
 
22
25
  def init!
23
26
  @init_bang_called = true
24
27
  end
25
28
 
26
- def after_init
29
+ after_init do
27
30
  @after_init_called = true
28
31
  end
29
32
 
30
- def before_run
33
+ before_run do
31
34
  @before_run_called = true
32
35
  end
33
36
 
@@ -35,7 +38,7 @@ class FlagViewHandler
35
38
  @run_bang_called = true
36
39
  end
37
40
 
38
- def after_run
41
+ after_run do
39
42
  @after_run_called = true
40
43
  end
41
44
 
@@ -1,78 +1,95 @@
1
1
  require 'assert'
2
2
  require 'rack/test'
3
3
 
4
- class MakingRequestsTests < Assert::Context
5
- include Rack::Test::Methods
4
+ module Deas
6
5
 
7
- desc "Making requests using rack test"
8
- setup do
9
- @app = Deas.app.new
10
- end
6
+ class RackTests < Assert::Context
7
+ include Rack::Test::Methods
11
8
 
12
- should "return a 200 response with a GET to '/show'" do
13
- get '/show', 'message' => 'this is a test'
9
+ desc "Deas' the rack app"
10
+ setup do
11
+ @app = Deas.app.new
12
+ end
14
13
 
15
- expected_body = "show page: this is a test\n" \
16
- "Stuff: Show Info\n"
17
- assert_equal 200, last_response.status
18
- assert_equal expected_body, last_response.body
19
- end
14
+ def app; @app; end
20
15
 
21
- should "allow halting with a custom response" do
22
- get '/halt', 'with' => 234
16
+ should "return a 200 response with a GET to '/show'" do
17
+ get '/show', 'message' => 'this is a test'
23
18
 
24
- assert_equal 234, last_response.status
25
- end
19
+ expected_body = "show page: this is a test\n" \
20
+ "Stuff: Show Info\n"
21
+ assert_equal 200, last_response.status
22
+ assert_equal expected_body, last_response.body
23
+ end
26
24
 
27
- should "return a 404 response with an undefined route" do
28
- get '/not_defined'
25
+ should "allow halting with a custom response" do
26
+ get '/halt', 'with' => 234
29
27
 
30
- assert_equal 404, last_response.status
31
- end
28
+ assert_equal 234, last_response.status
29
+ end
32
30
 
33
- should "return a 500 response with an error route" do
34
- get '/error'
31
+ should "return a 404 response with an undefined route and " \
32
+ "run the defined error procs" do
33
+ get '/not_defined'
35
34
 
36
- assert_equal 500, last_response.status
37
- end
35
+ assert_equal 404, last_response.status
36
+ assert_equal "Couldn't be found", last_response.body
37
+ end
38
38
 
39
- should "return a 200 response and use all the layouts" do
40
- get '/with_layout'
39
+ should "return a 500 response with an error route and " \
40
+ "run the defined error procs" do
41
+ get '/error'
41
42
 
42
- expected_body = "Layout 1\nLayout 2\nLayout 3\nWith Layout\n"
43
- assert_equal 200, last_response.status
44
- assert_equal expected_body, last_response.body
43
+ assert_equal 500, last_response.status
44
+ assert_equal "Oops, something went wrong", last_response.body
45
+ end
45
46
 
46
- get '/alt_with_layout'
47
+ should "return a 200 response and use all the layouts" do
48
+ get '/with_layout'
47
49
 
48
- assert_equal 200, last_response.status
49
- assert_equal expected_body, last_response.body
50
- end
50
+ expected_body = "Layout 1\nLayout 2\nLayout 3\nWith Layout\n"
51
+ assert_equal 200, last_response.status
52
+ assert_equal expected_body, last_response.body
51
53
 
52
- should "return a 302 redirecting to the expected locations" do
53
- get '/redirect'
54
- expected_location = 'http://google.com'
54
+ get '/alt_with_layout'
55
55
 
56
- assert_equal 302, last_response.status
57
- assert_equal expected_location, last_response.headers['Location']
56
+ assert_equal 200, last_response.status
57
+ assert_equal expected_body, last_response.body
58
+ end
58
59
 
59
- get '/redirect_to'
60
- expected_location = 'http://example.org/somewhere'
60
+ should "return a 302 redirecting to the expected locations" do
61
+ get '/redirect'
62
+ expected_location = 'http://google.com'
61
63
 
62
- assert_equal 302, last_response.status
63
- assert_equal expected_location, last_response.headers['Location']
64
- end
64
+ assert_equal 302, last_response.status
65
+ assert_equal expected_location, last_response.headers['Location']
66
+
67
+ get '/redirect_to'
68
+ expected_location = 'http://example.org/somewhere'
65
69
 
66
- should "return a 200 response and the session value" do
67
- get '/set_session'
68
- follow_redirect!
70
+ assert_equal 302, last_response.status
71
+ assert_equal expected_location, last_response.headers['Location']
72
+ end
69
73
 
70
- assert_equal 200, last_response.status
71
- assert_equal 'session_secret', last_response.body
72
74
  end
73
75
 
74
- def app
75
- @app
76
+ class SessionTests < RackTests
77
+ desc "with sessions enabled"
78
+ setup do
79
+ orig_sessions = Deas.app.settings.sessions
80
+ Deas.app.set :sessions, true
81
+ @app = Deas.app.new
82
+ Deas.app.set :sessions, orig_sessions
83
+ end
84
+
85
+ should "return a 200 response and the session value" do
86
+ post '/session'
87
+ follow_redirect!
88
+
89
+ assert_equal 200, last_response.status
90
+ assert_equal 'session_secret', last_response.body
91
+ end
92
+
76
93
  end
77
94
 
78
95
  end
@@ -0,0 +1,104 @@
1
+ require 'assert'
2
+ require 'deas/error_handler'
3
+
4
+ class Deas::ErrorHandler
5
+
6
+ class BaseTests < Assert::Context
7
+ desc "Deas::ErrorHandler"
8
+ setup do
9
+ @exception = RuntimeError.new
10
+ @fake_app = FakeApp.new
11
+ @error_handler = Deas::ErrorHandler.new(@exception, @fake_app, [])
12
+ end
13
+ subject{ @error_handler }
14
+
15
+ should have_instance_methods :run
16
+ should have_class_methods :run
17
+
18
+ end
19
+
20
+ class RunTests < BaseTests
21
+ desc "run"
22
+ setup do
23
+ @error_procs = [ proc do |exception|
24
+ settings.exception_that_occurred = exception
25
+ "my return value"
26
+ end ]
27
+
28
+ @error_handler = Deas::ErrorHandler.new(@exception, @fake_app, @error_procs)
29
+ @response = @error_handler.run
30
+ end
31
+
32
+ should "run the proc in the context of the app" do
33
+ assert_equal @exception, @fake_app.settings.exception_that_occurred
34
+ end
35
+
36
+ should "return whatever the proc returns" do
37
+ assert_equal "my return value", @response
38
+ end
39
+
40
+ end
41
+
42
+ class RunWithMultipleProcsTests < BaseTests
43
+ desc "run with multiple procs"
44
+ setup do
45
+ @error_procs = [
46
+ proc do |exception|
47
+ settings.first_proc_run = true
48
+ 'first'
49
+ end,
50
+ proc do |exception|
51
+ settings.second_proc_run = true
52
+ 'second'
53
+ end,
54
+ proc do |exception|
55
+ settings.third_proc_run = true
56
+ nil
57
+ end
58
+ ]
59
+
60
+ @error_handler = Deas::ErrorHandler.new(@exception, @fake_app, @error_procs)
61
+ @response = @error_handler.run
62
+ end
63
+
64
+ should "run all the error procs" do
65
+ assert_equal true, @fake_app.settings.first_proc_run
66
+ assert_equal true, @fake_app.settings.second_proc_run
67
+ assert_equal true, @fake_app.settings.third_proc_run
68
+ end
69
+
70
+ should "return the last non-nil response" do
71
+ assert_equal 'second', @response
72
+ end
73
+
74
+ end
75
+
76
+ class RunWithProcsThatHaltTests < BaseTests
77
+ desc "run with a proc that halts"
78
+ setup do
79
+ @error_procs = [
80
+ proc do |exception|
81
+ settings.first_proc_run = true
82
+ halt 401
83
+ end,
84
+ proc do |exception|
85
+ settings.second_proc_run = true
86
+ end
87
+ ]
88
+
89
+ @error_handler = Deas::ErrorHandler.new(@exception, @fake_app, @error_procs)
90
+ @response = catch(:halt){ @error_handler.run }
91
+ end
92
+
93
+ should "run error procs until one halts" do
94
+ assert_equal true, @fake_app.settings.first_proc_run
95
+ assert_nil @fake_app.settings.second_proc_run
96
+ end
97
+
98
+ should "return whatever was halted" do
99
+ assert_equal [ 401 ], @response
100
+ end
101
+
102
+ end
103
+
104
+ end
@@ -0,0 +1,72 @@
1
+ require 'assert'
2
+ require 'deas/logging'
3
+
4
+ module Deas::Logging
5
+
6
+ class BaseTests < Assert::Context
7
+ desc "Deas::Logging"
8
+ subject{ Deas::Logging }
9
+
10
+ should have_imeths :middleware
11
+
12
+ end
13
+
14
+ class VerboseLoggingTests < Assert::Context
15
+ desc "Deas::VerboseLogging"
16
+ setup do
17
+ @middleware = Deas::VerboseLogging.new('a rack app goes here')
18
+ end
19
+ subject{ @middleware }
20
+
21
+ should have_imeths :call, :call!
22
+
23
+ should "be a kind of Deas::BaseLogging middleware" do
24
+ assert_kind_of Deas::BaseLogging, subject
25
+ end
26
+
27
+ end
28
+
29
+ class SummaryLoggingTests < Assert::Context
30
+ desc "Deas::SummaryLogging"
31
+ setup do
32
+ @middleware = Deas::SummaryLogging.new('a rack app goes here')
33
+ end
34
+ subject{ @middleware }
35
+
36
+ should have_imeths :call, :call!
37
+
38
+ should "be a kind of Deas::BaseLogging middleware" do
39
+ assert_kind_of Deas::BaseLogging, subject
40
+ end
41
+
42
+ end
43
+
44
+ class SummaryLineTests < Assert::Context
45
+ desc "Deas::SummaryLine"
46
+ subject{ Deas::SummaryLine }
47
+
48
+ should "output its attributes in a specific order" do
49
+ assert_equal %w{time status method path handler params}, subject.keys
50
+ end
51
+
52
+ should "output its attributes in a single line" do
53
+ line_attrs = {
54
+ 'time' => 't',
55
+ 'status' => 's',
56
+ 'method' => 'm',
57
+ 'path' => 'pth',
58
+ 'handler' => 'h',
59
+ 'params' => 'p',
60
+ }
61
+ exp_line = "time=\"t\" "\
62
+ "status=\"s\" "\
63
+ "method=\"m\" "\
64
+ "path=\"pth\" "\
65
+ "handler=\"h\" "\
66
+ "params=\"p\""
67
+ assert_equal exp_line, subject.new(line_attrs)
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -14,7 +14,7 @@ class Deas::Route
14
14
  subject{ @route }
15
15
 
16
16
  should have_instance_methods :method, :path, :handler_class_name,
17
- :handler_class, :runner
17
+ :handler_class, :run
18
18
 
19
19
  should "constantize the handler class with #constantize!" do
20
20
  assert_nil subject.handler_class
@@ -33,11 +33,6 @@ class Deas::Route
33
33
  end
34
34
  end
35
35
 
36
- should "return an instance of the Runner class with supplied variables" do
37
- subject.constantize!
38
- returned = subject.runner(FakeApp.new)
39
- assert_instance_of Deas::SinatraRunner, returned
40
- end
41
36
  end
42
37
 
43
38
  end
@@ -1,5 +1,4 @@
1
1
  require 'assert'
2
- require 'deas/logger'
3
2
  require 'deas/route'
4
3
  require 'deas/server'
5
4
  require 'logger'
@@ -22,8 +21,16 @@ class Deas::Server
22
21
  end
23
22
  subject{ Deas::Server }
24
23
 
25
- should have_instance_methods :configuration, :init, :view_handler_ns,
26
- :get, :post, :put, :patch, :delete, :route, :use
24
+ should have_reader :configuration
25
+
26
+ # DSL for sinatra settings
27
+ should have_imeths :env, :root, :public_folder, :views_folder
28
+ should have_imeths :dump_errors, :method_override, :sessions, :show_exceptions
29
+ should have_imeths :static_files, :reload_templates
30
+
31
+ # DSL for server handling
32
+ should have_imeths :init, :logger, :use, :view_handler_ns, :use
33
+ should have_imeths :get, :post, :put, :patch, :delete, :route
27
34
 
28
35
  should "be a singleton" do
29
36
  assert_includes Singleton, subject.included_modules
@@ -59,6 +66,9 @@ class Deas::Server
59
66
  subject.static_files false
60
67
  assert_equal false, config.static_files
61
68
 
69
+ subject.reload_templates true
70
+ assert_equal true, config.reload_templates
71
+
62
72
  subject.use 'MyMiddleware'
63
73
  assert_equal [ ['MyMiddleware'] ], config.middlewares
64
74
 
@@ -156,10 +166,14 @@ class Deas::Server
156
166
  end
157
167
  subject{ @configuration }
158
168
 
159
- should have_instance_methods :env, :root, :app_file, :public_folder,
160
- :views_folder, :dump_errors, :method_override, :sessions, :static_files,
161
- :init_proc, :logger, :routes, :view_handler_ns, :show_exceptions,
162
- :middlewares
169
+ # sinatra related options
170
+ should have_imeths :env, :root, :app_file, :public_folder, :views_folder
171
+ should have_imeths :dump_errors, :method_override, :sessions, :show_exceptions
172
+ should have_imeths :static_files, :reload_templates
173
+
174
+ # server handling options
175
+ should have_imeths :init_proc, :logger, :verbose_logging, :middlewares
176
+ should have_imeths :routes, :view_handler_ns
163
177
 
164
178
  should "default the env to 'development'" do
165
179
  assert_equal 'development', subject.env
@@ -189,9 +203,10 @@ class Deas::Server
189
203
  should "default the Sinatra flags" do
190
204
  assert_equal false, subject.dump_errors
191
205
  assert_equal true, subject.method_override
206
+ assert_equal false, subject.sessions
192
207
  assert_equal false, subject.show_exceptions
193
- assert_equal true, subject.sessions
194
208
  assert_equal true, subject.static_files
209
+ assert_equal false, subject.reload_templates
195
210
  end
196
211
 
197
212
  should "default the logger to a NullLogger" do
@@ -12,14 +12,15 @@ module Deas::SinatraApp
12
12
  setup do
13
13
  @route = Deas::Route.new(:get, '/something', 'TestViewHandler')
14
14
  @configuration = Deas::Server::Configuration.new.tap do |c|
15
- c.env = 'staging'
16
- c.root = 'path/to/somewhere'
17
- c.dump_errors = true
18
- c.method_override = false
19
- c.sessions = false
20
- c.show_exceptions = true
21
- c.static = true
22
- c.routes = [ @route ]
15
+ c.env = 'staging'
16
+ c.root = 'path/to/somewhere'
17
+ c.dump_errors = true
18
+ c.method_override = false
19
+ c.sessions = false
20
+ c.show_exceptions = true
21
+ c.static = true
22
+ c.reload_templates = true
23
+ c.routes = [ @route ]
23
24
  end
24
25
  @sinatra_app = Deas::SinatraApp.new(@configuration)
25
26
  end
@@ -54,7 +55,7 @@ module Deas::SinatraApp
54
55
  assert_equal false, settings.sessions
55
56
  assert_equal true, settings.show_exceptions
56
57
  assert_equal true, settings.static
57
- assert_instance_of Deas::RunnerLogger, settings.runner_logger
58
+ assert_equal true, settings.reload_templates
58
59
  assert_instance_of Deas::NullLogger, settings.logger
59
60
  end
60
61
  end
@@ -69,11 +69,6 @@ class Deas::SinatraRunner
69
69
  assert_equal expected, return_value
70
70
  end
71
71
 
72
- should "not throw an exception with the setup or teardown methods" do
73
- assert_nothing_raised{ subject.setup }
74
- assert_nothing_raised{ subject.teardown }
75
- end
76
-
77
72
  end
78
73
 
79
74
  class RunTests < BaseTests
@@ -15,8 +15,13 @@ module Deas::ViewHandler
15
15
  subject{ @handler }
16
16
 
17
17
  should have_instance_methods :init, :init!, :run, :run!
18
- should have_class_methods :before, :before_callbacks, :after,
19
- :after_callbacks, :layout, :layouts
18
+ should have_class_methods :before, :before_callbacks
19
+ should have_class_methods :after, :after_callbacks
20
+ should have_class_methods :before_init, :before_init_callbacks
21
+ should have_class_methods :after_init, :after_init_callbacks
22
+ should have_class_methods :before_run, :before_run_callbacks
23
+ should have_class_methods :after_run, :after_run_callbacks
24
+ should have_class_methods :layout, :layouts
20
25
 
21
26
  should "raise a NotImplementedError if run! is not overwritten" do
22
27
  assert_raises(NotImplementedError){ subject.run! }
@@ -36,6 +41,34 @@ module Deas::ViewHandler
36
41
  assert_includes after_proc, TestViewHandler.after_callbacks
37
42
  end
38
43
 
44
+ should "store procs in #before_init_callbacks with #before_init" do
45
+ before_init_proc = proc{ }
46
+ TestViewHandler.before_init(&before_init_proc)
47
+
48
+ assert_includes before_init_proc, TestViewHandler.before_init_callbacks
49
+ end
50
+
51
+ should "store procs in #after_init_callbacks with #after_init" do
52
+ after_init_proc = proc{ }
53
+ TestViewHandler.after_init(&after_init_proc)
54
+
55
+ assert_includes after_init_proc, TestViewHandler.after_init_callbacks
56
+ end
57
+
58
+ should "store procs in #before_run_callbacks with #before_run" do
59
+ before_run_proc = proc{ }
60
+ TestViewHandler.before_run(&before_run_proc)
61
+
62
+ assert_includes before_run_proc, TestViewHandler.before_run_callbacks
63
+ end
64
+
65
+ should "store procs in #after_run_callbacks with #after_run" do
66
+ after_run_proc = proc{ }
67
+ TestViewHandler.after_run(&after_run_proc)
68
+
69
+ assert_includes after_run_proc, TestViewHandler.after_run_callbacks
70
+ end
71
+
39
72
  should "allow specifying the layouts using #layout or #layouts" do
40
73
  handler_class = Class.new{ include Deas::ViewHandler }
41
74
 
@@ -55,6 +88,7 @@ module Deas::ViewHandler
55
88
 
56
89
  should "have called `init!` and it's callbacks" do
57
90
  assert_equal true, subject.before_init_called
91
+ assert_equal true, subject.second_before_init_called
58
92
  assert_equal true, subject.init_bang_called
59
93
  assert_equal true, subject.after_init_called
60
94
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deas
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
9
- - 1
10
- version: 0.2.1
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kelly Redding
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2013-05-02 00:00:00 Z
19
+ date: 2013-05-07 00:00:00 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  prerelease: false
@@ -134,7 +134,8 @@ files:
134
134
  - Rakefile
135
135
  - deas.gemspec
136
136
  - lib/deas.rb
137
- - lib/deas/logger.rb
137
+ - lib/deas/error_handler.rb
138
+ - lib/deas/logging.rb
138
139
  - lib/deas/rack_request_fix.rb
139
140
  - lib/deas/route.rb
140
141
  - lib/deas/runner.rb
@@ -159,7 +160,8 @@ files:
159
160
  - test/support/views/with_layout.erb
160
161
  - test/system/making_requests_tests.rb
161
162
  - test/unit/deas_tests.rb
162
- - test/unit/logger_tests.rb
163
+ - test/unit/error_handler_tests.rb
164
+ - test/unit/logging_tests.rb
163
165
  - test/unit/route_tests.rb
164
166
  - test/unit/runner_tests.rb
165
167
  - test/unit/server_tests.rb
@@ -214,7 +216,8 @@ test_files:
214
216
  - test/support/views/with_layout.erb
215
217
  - test/system/making_requests_tests.rb
216
218
  - test/unit/deas_tests.rb
217
- - test/unit/logger_tests.rb
219
+ - test/unit/error_handler_tests.rb
220
+ - test/unit/logging_tests.rb
218
221
  - test/unit/route_tests.rb
219
222
  - test/unit/runner_tests.rb
220
223
  - test/unit/server_tests.rb
data/lib/deas/logger.rb DELETED
@@ -1,23 +0,0 @@
1
- module Deas
2
-
3
- class RunnerLogger
4
- attr_reader :summary, :verbose
5
-
6
- def initialize(logger, verbose = true)
7
- loggers = [ logger, Deas::NullLogger.new ]
8
- loggers.reverse! if !verbose
9
- @verbose, @summary = loggers
10
- end
11
-
12
- end
13
-
14
- class NullLogger
15
- require 'logger'
16
-
17
- ::Logger::Severity.constants.each do |name|
18
- define_method(name.downcase){|*args| } # no-op
19
- end
20
-
21
- end
22
-
23
- end
@@ -1,33 +0,0 @@
1
- require 'assert'
2
-
3
- class Deas::RunnerLogger
4
-
5
- class BaseTests < Assert::Context
6
- desc "Deas::RunnerLogger"
7
- setup do
8
- @logger = Logger.new(File.open("/dev/null", 'w'))
9
- @runner_logger = Deas::RunnerLogger.new(@logger)
10
- end
11
- subject{ @runner_logger }
12
-
13
- should have_instance_methods :verbose, :summary
14
-
15
- should "use the passed logger as #verbose and a null logger as #summary " \
16
- "when passed true as the second arg" do
17
- runner_logger = Deas::RunnerLogger.new(@logger, true)
18
-
19
- assert_equal @logger, runner_logger.verbose
20
- assert_instance_of Deas::NullLogger, runner_logger.summary
21
- end
22
-
23
- should "use the passed logger as #summary and a null logger as #verbose " \
24
- "when passed false as the second arg" do
25
- runner_logger = Deas::RunnerLogger.new(@logger, false)
26
-
27
- assert_instance_of Deas::NullLogger, runner_logger.verbose
28
- assert_equal @logger, runner_logger.summary
29
- end
30
-
31
- end
32
-
33
- end