deas 0.31.0 → 0.32.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2e01bef9b6af4303f73139d7163cffe10e365422
4
+ data.tar.gz: 72a8a94d809478d18b0977d6f08db810a4801547
5
+ SHA512:
6
+ metadata.gz: d911b586a2a5550d68b1213da0928c9660bded2411454543f838d5aa882652412d7bc3717c526fd9b53349c5250ce37c66c0feffb5105e8c65ea7382bb0ebf9a
7
+ data.tar.gz: 29061f4db02882144065819d5f86c720cf9859eb100972f88c070ce23c90257b65bf8f52a0cc6c973f3c94b2a6c7746656aa20613916d2be4a2049526ce321da
data/Gemfile CHANGED
@@ -2,6 +2,6 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rake'
5
+ gem 'rake', "~> 10.4.0"
6
6
  gem 'pry', "~> 0.9.0"
7
7
  gem 'rack-test'
@@ -16,4 +16,6 @@ module Deas
16
16
  end
17
17
  end
18
18
 
19
+ HandlerProxyNotFound = Class.new(Error)
20
+
19
21
  end
@@ -0,0 +1,41 @@
1
+ require 'deas/exceptions'
2
+ require 'deas/sinatra_runner'
3
+
4
+ module Deas
5
+
6
+ class HandlerProxy
7
+
8
+ attr_reader :handler_class_name, :handler_class
9
+
10
+ def initialize(handler_class_name)
11
+ @handler_class_name = handler_class_name
12
+ end
13
+
14
+ def validate!
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def run(sinatra_call)
19
+ runner = SinatraRunner.new(self.handler_class, {
20
+ :sinatra_call => sinatra_call,
21
+ :request => sinatra_call.request,
22
+ :response => sinatra_call.response,
23
+ :session => sinatra_call.session,
24
+ :params => sinatra_call.params,
25
+ :logger => sinatra_call.settings.logger,
26
+ :router => sinatra_call.settings.router,
27
+ :template_source => sinatra_call.settings.template_source
28
+ })
29
+
30
+ sinatra_call.request.env.tap do |env|
31
+ env['deas.params'] = runner.params
32
+ env['deas.handler_class_name'] = self.handler_class.name
33
+ env['deas.logging'].call " Handler: #{env['deas.handler_class_name']}"
34
+ env['deas.logging'].call " Params: #{env['deas.params'].inspect}"
35
+ end
36
+ runner.run
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -1,9 +1,10 @@
1
+ require 'deas/handler_proxy'
1
2
  require 'deas/url'
2
3
  require 'deas/view_handler'
3
4
 
4
5
  module Deas
5
6
 
6
- class RedirectProxy
7
+ class RedirectProxy < HandlerProxy
7
8
 
8
9
  attr_reader :handler_class_name, :handler_class
9
10
 
data/lib/deas/route.rb CHANGED
@@ -1,39 +1,29 @@
1
- require 'deas/sinatra_runner'
1
+ require 'deas/exceptions'
2
2
 
3
3
  module Deas
4
4
 
5
5
  class Route
6
6
 
7
- attr_reader :method, :path, :route_proxy, :handler_class
7
+ attr_reader :method, :path, :handler_proxies
8
8
 
9
- def initialize(method, path, route_proxy)
10
- @method, @path, @route_proxy = method, path, route_proxy
9
+ def initialize(method, path, handler_proxies)
10
+ @method, @path, @handler_proxies = method, path, handler_proxies
11
11
  end
12
12
 
13
13
  def validate!
14
- @route_proxy.validate!
15
- @handler_class = @route_proxy.handler_class
14
+ @handler_proxies.each do |request_type_name, proxy|
15
+ proxy.validate!
16
+ end
16
17
  end
17
18
 
18
19
  def run(sinatra_call)
19
- runner = SinatraRunner.new(self.handler_class, {
20
- :sinatra_call => sinatra_call,
21
- :request => sinatra_call.request,
22
- :response => sinatra_call.response,
23
- :session => sinatra_call.session,
24
- :params => sinatra_call.params,
25
- :logger => sinatra_call.settings.logger,
26
- :router => sinatra_call.settings.router,
27
- :template_source => sinatra_call.settings.template_source
28
- })
29
-
30
- sinatra_call.request.env.tap do |env|
31
- env['deas.params'] = runner.params
32
- env['deas.handler_class_name'] = self.handler_class.name
33
- env['deas.logging'].call " Handler: #{env['deas.handler_class_name']}"
34
- env['deas.logging'].call " Params: #{env['deas.params'].inspect}"
20
+ type = sinatra_call.settings.router.request_type_name(sinatra_call.request)
21
+ proxy = begin
22
+ @handler_proxies[type]
23
+ rescue HandlerProxyNotFound
24
+ sinatra_call.halt(404)
35
25
  end
36
- runner.run
26
+ proxy.run(sinatra_call)
37
27
  end
38
28
 
39
29
  end
@@ -1,18 +1,22 @@
1
1
  require 'deas/exceptions'
2
- require 'deas/view_handler'
2
+ require 'deas/handler_proxy'
3
3
 
4
4
  module Deas
5
- class RouteProxy
6
5
 
7
- attr_reader :handler_class_name, :handler_class
6
+ class RouteProxy < HandlerProxy
8
7
 
9
- def initialize(handler_class_name)
10
- @handler_class_name = handler_class_name
8
+ def initialize(handler_class_name, view_handler_ns = nil)
9
+ raise(NoHandlerClassError.new(handler_class_name)) if handler_class_name.nil?
10
+
11
+ if view_handler_ns && !(handler_class_name =~ /^::/)
12
+ handler_class_name = "#{view_handler_ns}::#{handler_class_name}"
13
+ end
14
+ super(handler_class_name)
11
15
  end
12
16
 
13
17
  def validate!
14
- @handler_class = constantize(@handler_class_name).tap do |handler_class|
15
- raise(NoHandlerClassError.new(@handler_class_name)) if !handler_class
18
+ @handler_class = constantize(self.handler_class_name).tap do |handler_class|
19
+ raise(NoHandlerClassError.new(self.handler_class_name)) if !handler_class
16
20
  end
17
21
  end
18
22
 
@@ -27,4 +31,5 @@ module Deas
27
31
  end
28
32
 
29
33
  end
34
+
30
35
  end
data/lib/deas/router.rb CHANGED
@@ -1,15 +1,21 @@
1
+ require 'deas/exceptions'
1
2
  require 'deas/redirect_proxy'
2
3
  require 'deas/route'
3
4
  require 'deas/route_proxy'
4
5
  require 'deas/url'
5
6
 
6
7
  module Deas
8
+
7
9
  class Router
8
10
 
9
- attr_accessor :urls, :routes
11
+ DEFAULT_REQUEST_TYPE_NAME = 'default'
12
+
13
+ attr_reader :request_types, :urls, :routes
10
14
 
11
15
  def initialize(&block)
16
+ @request_types = []
12
17
  @urls, @routes = {}, []
18
+ default_request_type_name(DEFAULT_REQUEST_TYPE_NAME)
13
19
  self.instance_eval(&block) if !block.nil?
14
20
  end
15
21
 
@@ -41,21 +47,42 @@ module Deas
41
47
  prepend_base_url(url.path_for(*args))
42
48
  end
43
49
 
44
- def get(path, handler_name); self.route(:get, path, handler_name); end
45
- def post(path, handler_name); self.route(:post, path, handler_name); end
46
- def put(path, handler_name); self.route(:put, path, handler_name); end
47
- def patch(path, handler_name); self.route(:patch, path, handler_name); end
48
- def delete(path, handler_name); self.route(:delete, path, handler_name); end
50
+ def default_request_type_name(value = nil)
51
+ @default_request_type = RequestType.new(value) if !value.nil?
52
+ @default_request_type.name
53
+ end
54
+
55
+ def add_request_type(name, &proc)
56
+ @request_types << RequestType.new(name, proc)
57
+ end
58
+
59
+ # ideally someday the request should just *know* its request type
60
+ def request_type_name(request)
61
+ (self.request_types.detect{ |rt| rt.proc.call(request) } || @default_request_type).name
62
+ end
49
63
 
50
- def route(http_method, from_path, handler_class_name)
51
- if self.view_handler_ns && !(handler_class_name =~ /^::/)
52
- handler_class_name = "#{self.view_handler_ns}::#{handler_class_name}"
64
+ def get(path, *args); self.route(:get, path, *args); end
65
+ def post(path, *args); self.route(:post, path, *args); end
66
+ def put(path, *args); self.route(:put, path, *args); end
67
+ def patch(path, *args); self.route(:patch, path, *args); end
68
+ def delete(path, *args); self.route(:delete, path, *args); end
69
+
70
+ def route(http_method, from_path, *args)
71
+ handler_names = args.last.kind_of?(::Hash) ? args.pop : {}
72
+ default_handler_name = args.last
73
+ if !handler_names.key?(self.default_request_type_name) && default_handler_name
74
+ handler_names[self.default_request_type_name] = default_handler_name
75
+ end
76
+
77
+ proxies = handler_names.inject({}) do |proxies, (req_type_name, handler_name)|
78
+ proxies[req_type_name] = Deas::RouteProxy.new(handler_name, self.view_handler_ns)
79
+ proxies
53
80
  end
54
- proxy = Deas::RouteProxy.new(handler_class_name)
55
81
 
56
82
  from_url = self.urls[from_path]
57
83
  from_url_path = from_url.path if from_url
58
- add_route(http_method, prepend_base_url(from_url_path || from_path), proxy)
84
+
85
+ add_route(http_method, prepend_base_url(from_url_path || from_path), proxies)
59
86
  end
60
87
 
61
88
  def redirect(from_path, to_path = nil, &block)
@@ -63,11 +90,14 @@ module Deas
63
90
  if to_path.kind_of?(::Symbol) && to_url.nil?
64
91
  raise ArgumentError, "no url named `#{to_path.inspect}`"
65
92
  end
93
+
66
94
  proxy = Deas::RedirectProxy.new(to_url || to_path, &block)
95
+ proxies = { self.default_request_type_name => proxy }
67
96
 
68
97
  from_url = self.urls[from_path]
69
98
  from_url_path = from_url.path if from_url
70
- add_route(:get, from_url_path || from_path, proxy)
99
+
100
+ add_route(:get, prepend_base_url(from_url_path || from_path), proxies)
71
101
  end
72
102
 
73
103
  private
@@ -76,10 +106,36 @@ module Deas
76
106
  self.urls[name] = Deas::Url.new(name, path)
77
107
  end
78
108
 
79
- def add_route(http_method, path, proxy)
80
- Deas::Route.new(http_method, path, proxy).tap{ |r| self.routes.push(r) }
109
+ def add_route(http_method, path, proxies)
110
+ proxies = HandlerProxies.new(proxies, self.default_request_type_name)
111
+ Deas::Route.new(http_method, path, proxies).tap{ |r| self.routes.push(r) }
81
112
  end
82
113
 
114
+ class HandlerProxies
115
+
116
+ attr_reader :default_type
117
+
118
+ def initialize(proxies, default_name)
119
+ @proxies = proxies
120
+ @default_type = default_name
121
+ end
122
+
123
+ def [](type)
124
+ @proxies[type] || @proxies[@default_type] || raise(HandlerProxyNotFound)
125
+ end
126
+
127
+ def each(&block)
128
+ @proxies.each(&block)
129
+ end
130
+
131
+ def empty?
132
+ @proxies.empty?
133
+ end
134
+
135
+ end
136
+
137
+ RequestType = Struct.new(:name, :proc)
138
+
83
139
  end
84
140
 
85
141
  end
data/lib/deas/server.rb CHANGED
@@ -211,6 +211,10 @@ module Deas::Server
211
211
  def url(*args, &block); self.router.url(*args, &block); end
212
212
  def url_for(*args, &block); self.router.url_for(*args, &block); end
213
213
 
214
+ def default_request_type_name(*args); self.router.default_request_type_name(*args); end
215
+ def add_request_type(*args, &block); self.router.add_request_type(*args, &block); end
216
+ def request_type_name(*args); self.router.request_type_name(*args); end
217
+
214
218
  def get(*args, &block); self.router.get(*args, &block); end
215
219
  def post(*args, &block); self.router.post(*args, &block); end
216
220
  def put(*args, &block); self.router.put(*args, &block); end
data/lib/deas/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Deas
2
- VERSION = "0.31.0"
2
+ VERSION = "0.32.0"
3
3
  end
@@ -19,6 +19,10 @@ class DeasTestServer
19
19
  end
20
20
  end
21
21
 
22
+ default_request_type_name 'desktop'
23
+ add_request_type('regular'){ |r| r.path_info =~ /regular/ }
24
+ add_request_type('mobile'){ |r| r.path_info =~ /mobile/ }
25
+
22
26
  get '/show', 'ShowHandler'
23
27
  get '/show.html', 'ShowHtmlHandler'
24
28
  get '/show.json', 'ShowJsonHandler'
@@ -26,6 +30,9 @@ class DeasTestServer
26
30
  get '/show-text', 'ShowTextHandler'
27
31
  get '/show-headers-text', 'ShowHeadersTextHandler'
28
32
 
33
+ get '/req-type-show/:type', 'regular' => 'ShowHandler',
34
+ 'mobile' => 'ShowMobileHandler'
35
+
29
36
  get '/halt', 'HaltHandler'
30
37
  get '/error', 'ErrorHandler'
31
38
  get '/redirect', 'RedirectHandler'
@@ -71,6 +78,21 @@ class ShowHandler
71
78
 
72
79
  end
73
80
 
81
+ class ShowMobileHandler
82
+ include Deas::ViewHandler
83
+
84
+ attr_reader :message
85
+
86
+ def init!
87
+ @message = "[MOBILE] #{params['message']}"
88
+ end
89
+
90
+ def run!
91
+ @message
92
+ end
93
+
94
+ end
95
+
74
96
  class ShowHtmlHandler
75
97
  include Deas::ViewHandler
76
98
 
@@ -1,7 +1,8 @@
1
1
  require 'assert'
2
- require 'assert-rack-test'
3
2
  require 'deas'
4
3
 
4
+ require 'assert-rack-test'
5
+
5
6
  module Deas
6
7
 
7
8
  class RackTestsContext < Assert::Context
@@ -20,8 +21,7 @@ module Deas
20
21
  get '/show', 'message' => 'this is a test'
21
22
 
22
23
  assert_equal 200, last_response.status
23
- exp = "this is a test"
24
- assert_equal exp, last_response.body
24
+ assert_equal "this is a test", last_response.body
25
25
  end
26
26
 
27
27
  should "set the content type appropriately" do
@@ -44,6 +44,19 @@ module Deas
44
44
  assert_equal 'text/plain', last_response.headers['Content-Type']
45
45
  end
46
46
 
47
+ should "render different handlers for the same meth/path based on the type" do
48
+ get '/req-type-show/regular', 'message' => 'this is a test request'
49
+ assert_equal 200, last_response.status
50
+ assert_equal "this is a test request", last_response.body
51
+
52
+ get '/req-type-show/mobile', 'message' => 'this is a test request'
53
+ assert_equal 200, last_response.status
54
+ assert_equal "[MOBILE] this is a test request", last_response.body
55
+
56
+ get '/req-type-show/other', 'message' => 'this is a test request'
57
+ assert_equal 404, last_response.status
58
+ end
59
+
47
60
  should "allow halting with a custom response" do
48
61
  get '/halt', 'with' => 234
49
62
 
@@ -115,7 +128,6 @@ module Deas
115
128
  desc "handler"
116
129
  setup do
117
130
  get 'handler/tests?a-param=something'
118
-
119
131
  @data_inspect = last_response.body
120
132
  end
121
133
 
@@ -11,7 +11,7 @@ module Deas
11
11
  assert_kind_of RuntimeError, Deas::Error.new
12
12
  end
13
13
 
14
- should "provide a no handler class exception that subclasses `Error`" do
14
+ should "provide a no handler class exception" do
15
15
  assert Deas::NoHandlerClassError
16
16
 
17
17
  handler_class_name = 'AHandlerClass'
@@ -23,12 +23,12 @@ module Deas
23
23
  assert_equal exp_msg, e.message
24
24
  end
25
25
 
26
- should "provide a server exception that subclasses `Error`" do
26
+ should "provide a server exception" do
27
27
  assert Deas::ServerError
28
28
  assert_kind_of Deas::Error, Deas::ServerError.new
29
29
  end
30
30
 
31
- should "provide a server root exception that subclasses `ServerError`" do
31
+ should "provide a server root exception" do
32
32
  assert Deas::ServerRootError
33
33
 
34
34
  e = Deas::ServerRootError.new
@@ -36,6 +36,11 @@ module Deas
36
36
  assert_equal "server `root` not set but required", e.message
37
37
  end
38
38
 
39
+ should "provide a handler proxy not found exception" do
40
+ assert Deas::HandlerProxyNotFound
41
+ assert_kind_of Deas::Error, Deas::HandlerProxyNotFound.new
42
+ end
43
+
39
44
  end
40
45
 
41
46
  end
@@ -0,0 +1,115 @@
1
+ require 'assert'
2
+ require 'deas/handler_proxy'
3
+
4
+ require 'deas/exceptions'
5
+ require 'deas/sinatra_runner'
6
+ require 'test/support/fake_sinatra_call'
7
+ require 'test/support/view_handlers'
8
+
9
+ class Deas::HandlerProxy
10
+
11
+ class UnitTests < Assert::Context
12
+ desc "Deas::HandlerProxy"
13
+ setup do
14
+ @proxy = Deas::HandlerProxy.new('EmptyViewHandler')
15
+ end
16
+ subject{ @proxy }
17
+
18
+ should have_readers :handler_class_name, :handler_class
19
+ should have_imeths :validate!, :run
20
+
21
+ should "know its handler class name" do
22
+ assert_equal 'EmptyViewHandler', subject.handler_class_name
23
+ end
24
+
25
+ should "not implement its validate! method" do
26
+ assert_raises(NotImplementedError){ subject.validate! }
27
+ end
28
+
29
+ end
30
+
31
+ class RunTests < UnitTests
32
+ desc "when run"
33
+ setup do
34
+ @runner_spy = SinatraRunnerSpy.new
35
+ Assert.stub(Deas::SinatraRunner, :new) do |*args|
36
+ @runner_spy.build(*args)
37
+ @runner_spy
38
+ end
39
+
40
+ Assert.stub(@proxy, :handler_class){ EmptyViewHandler }
41
+
42
+ @fake_sinatra_call = FakeSinatraCall.new
43
+ @proxy.run(@fake_sinatra_call)
44
+ end
45
+
46
+ should "build and run a sinatra runner" do
47
+ assert_equal subject.handler_class, @runner_spy.handler_class
48
+
49
+ exp_args = {
50
+ :sinatra_call => @fake_sinatra_call,
51
+ :request => @fake_sinatra_call.request,
52
+ :response => @fake_sinatra_call.response,
53
+ :session => @fake_sinatra_call.session,
54
+ :params => @fake_sinatra_call.params,
55
+ :logger => @fake_sinatra_call.settings.logger,
56
+ :router => @fake_sinatra_call.settings.router,
57
+ :template_source => @fake_sinatra_call.settings.template_source
58
+ }
59
+ assert_equal exp_args, @runner_spy.args
60
+
61
+ assert_true @runner_spy.run_called
62
+ end
63
+
64
+ should "add the runner params to the request env" do
65
+ exp = @runner_spy.params
66
+ assert_equal exp, @fake_sinatra_call.request.env['deas.params']
67
+ end
68
+
69
+ should "add the handler class name to the request env" do
70
+ exp = subject.handler_class.name
71
+ assert_equal exp, @fake_sinatra_call.request.env['deas.handler_class_name']
72
+ end
73
+
74
+ should "log the handler and params" do
75
+ exp_msgs = [
76
+ " Handler: #{subject.handler_class}",
77
+ " Params: #{@runner_spy.params.inspect}"
78
+ ]
79
+ assert_equal exp_msgs, @fake_sinatra_call.request.logging_msgs
80
+ end
81
+
82
+ end
83
+
84
+ class SinatraRunnerSpy
85
+
86
+ attr_reader :run_called
87
+ attr_reader :handler_class, :args
88
+ attr_reader :sinatra_call
89
+ attr_reader :request, :response, :session, :params
90
+ attr_reader :logger, :router, :template_source
91
+
92
+ def initialize
93
+ @run_called = false
94
+ end
95
+
96
+ def build(handler_class, args)
97
+ @handler_class, @args = handler_class, args
98
+
99
+ @sinatra_call = args[:sinatra_call]
100
+ @request = args[:request]
101
+ @response = args[:response]
102
+ @session = args[:session]
103
+ @params = args[:params]
104
+ @logger = args[:logger]
105
+ @router = args[:router]
106
+ @template_source = args[:template_source]
107
+ end
108
+
109
+ def run
110
+ @run_called = true
111
+ end
112
+
113
+ end
114
+
115
+ end