rory 0.3.10 → 0.3.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,6 +4,7 @@ require 'yaml'
4
4
  require 'sequel'
5
5
  require 'rory/application'
6
6
  require 'rory/dispatcher'
7
+ require 'rory/route'
7
8
  require 'rory/support'
8
9
  require 'rory/controller'
9
10
 
@@ -1,9 +1,12 @@
1
- require_relative 'renderer'
1
+ require 'rory/renderer'
2
+ require 'rory/path_generation'
2
3
 
3
4
  module Rory
4
5
  # Interface for Controller class. Subclass this to create controllers
5
6
  # with actions that will be called by the Dispatcher when a route matches.
6
7
  class Controller
8
+ include PathGeneration
9
+
7
10
  attr_accessor :locals
8
11
 
9
12
  def initialize(request, routing, app = nil)
@@ -27,19 +30,23 @@ module Rory
27
30
  end
28
31
 
29
32
  def route_template
30
- "#{@route[:controller]}/#{@route[:action]}"
33
+ "#{@route.controller}/#{@route.action}"
31
34
  end
32
35
 
33
36
  def layout
34
37
  nil
35
38
  end
36
39
 
40
+ def base_path
41
+ @request.script_name
42
+ end
43
+
37
44
  def default_renderer_options
38
45
  {
39
46
  :layout => layout,
40
47
  :locals => locals,
41
48
  :app => @app,
42
- :base_url => @request.script_name
49
+ :base_path => base_path
43
50
  }
44
51
  end
45
52
 
@@ -69,7 +76,7 @@ module Rory
69
76
 
70
77
  def present
71
78
  # if a method exists on the controller for the requested action, call it.
72
- action = @route[:action]
79
+ action = @route.action
73
80
  before_action
74
81
  self.send(action) if self.respond_to?(action)
75
82
  after_action
@@ -21,16 +21,6 @@ module Rory
21
21
  end
22
22
  end
23
23
 
24
- def method
25
- override_method = @request.params.delete('_method')
26
- method = if override_method && ['put', 'patch', 'delete'].include?(override_method.downcase)
27
- override_method
28
- else
29
- @request.request_method
30
- end
31
- method.downcase
32
- end
33
-
34
24
  def redirect(path = '/')
35
25
  unless path =~ /\:\/\//
36
26
  path = "#{@request.scheme}://#{@request.host_with_port}#{path}"
@@ -53,30 +43,25 @@ module Rory
53
43
 
54
44
  def controller_class
55
45
  if route
56
- controller_name = Rory::Support.camelize("#{route[:controller]}_controller")
57
- if route[:module]
58
- controller_name.prepend "#{Rory::Support.camelize("#{route[:module]}")}/"
46
+ controller_name = Rory::Support.camelize("#{route.controller}_controller")
47
+ if route.module
48
+ controller_name.prepend "#{Rory::Support.camelize("#{route.module}")}/"
59
49
  end
60
50
  Rory::Support.constantize(controller_name)
61
51
  end
62
52
  end
63
53
 
64
54
  def get_route
65
- match = nil
66
- mapped_route = route_map.detect do |route_hash|
67
- path_name = @request.path_info[1..-1] || ''
68
- match = route_hash[:regex].match(path_name)
69
- methods = route_hash[:methods] || []
70
- match && (methods.empty? || methods.include?(method.to_sym))
55
+ mapped_route = all_routes.detect do |route|
56
+ route.matches_request?(@request)
71
57
  end
72
58
  if mapped_route
73
- symbolized_param_names = match.names.map { |name| name.to_sym }
74
- @request.params.merge! Hash[symbolized_param_names.zip(match.captures)]
59
+ @request.params.merge! mapped_route.path_params(@request)
75
60
  end
76
61
  mapped_route
77
62
  end
78
63
 
79
- def route_map
64
+ def all_routes
80
65
  @app ? @app.routes : []
81
66
  end
82
67
  end
@@ -0,0 +1,13 @@
1
+ module Rory
2
+ module PathGeneration
3
+ def path_to(route_name, fields = {})
4
+ if route = @app.routes.detect { |r| r.name == route_name }
5
+ path = route.mask.dup.prepend('/').prepend(base_path.to_s)
6
+ fields.each do |key, value|
7
+ path.gsub!(/\:#{key}/, value.to_s)
8
+ end
9
+ path
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,14 +1,17 @@
1
+ require 'rory/path_generation'
2
+
1
3
  module Rory
2
4
  class Renderer
3
5
  class Context
4
- attr_reader :base_url
6
+ include Rory::PathGeneration
7
+ attr_reader :base_path
5
8
 
6
9
  def initialize(options = {})
7
10
  (options[:locals] || {}).each do |key, value|
8
11
  singleton_class.send(:define_method, key) { value }
9
12
  end
10
13
  @app = options[:app]
11
- @base_url = options[:base_url]
14
+ @base_path = options[:base_path]
12
15
  end
13
16
 
14
17
  def get_binding
@@ -16,7 +19,7 @@ module Rory
16
19
  end
17
20
 
18
21
  def render(template_name, opts = {})
19
- opts = { :layout => false, :app => @app, :base_url => @base_url }.merge(opts)
22
+ opts = { :layout => false, :app => @app, :base_path => @base_path }.merge(opts)
20
23
  renderer = Rory::Renderer.new(template_name, opts)
21
24
  renderer.render
22
25
  end
@@ -0,0 +1,66 @@
1
+ module Rory
2
+ class Route
3
+ attr_reader :controller, :action, :mask
4
+
5
+ def initialize(mask, options = {})
6
+ @mask = mask.gsub(/^\//, '')
7
+ @options = options
8
+ @controller, @action = options[:to].split('#')
9
+ end
10
+
11
+ def name
12
+ "#{controller}_#{action}"
13
+ end
14
+
15
+ def ==(other)
16
+ to_h == other.to_h
17
+ end
18
+
19
+ def regex
20
+ /^#{@mask.gsub(/:([\w_]+)/, "(?<\\1>\[\^\\\/\]+)")}$/
21
+ end
22
+
23
+ def module
24
+ @options[:module]
25
+ end
26
+
27
+ def methods
28
+ @options[:methods] || []
29
+ end
30
+
31
+ def matches_request?(request)
32
+ @match = regex.match(request.path_info[1..-1] || '')
33
+ @match &&
34
+ (methods.empty? ||
35
+ methods.include?(method_from_request(request).to_sym))
36
+ end
37
+
38
+ def path_params(request)
39
+ @match ||= regex.match(request.path_info[1..-1] || '')
40
+ symbolized_param_names = @match.names.map { |name| name.to_sym }
41
+ Hash[symbolized_param_names.zip(@match.captures)]
42
+ end
43
+
44
+ def to_h
45
+ {
46
+ :mask => @mask,
47
+ :controller => @controller,
48
+ :action => @action,
49
+ :module => @module,
50
+ :methods => @methods
51
+ }
52
+ end
53
+
54
+ private
55
+
56
+ def method_from_request(request)
57
+ override_method = request.params.delete('_method')
58
+ method = if override_method && ['put', 'patch', 'delete'].include?(override_method.downcase)
59
+ override_method
60
+ else
61
+ request.request_method
62
+ end
63
+ method.downcase
64
+ end
65
+ end
66
+ end
@@ -29,17 +29,7 @@ module Rory
29
29
  def match(mask, options = {})
30
30
  options.merge!(@scope_options)
31
31
  options[:to] ||= mask.split('/').first
32
- mask.gsub!(/^\//, '')
33
- regex = /^#{mask.gsub(/:([\w_]+)/, "(?<\\1>\[\^\\\/\]+)")}$/
34
- controller, action = options[:to].split('#')
35
- route = {
36
- :controller => controller,
37
- :action => action,
38
- :regex => regex
39
- }
40
- route[:module] = options[:module] if options[:module]
41
- route[:methods] = options[:methods] if options[:methods]
42
- @routes << route
32
+ @routes << Route.new(mask, options)
43
33
  end
44
34
  end
45
35
  end
@@ -1,3 +1,3 @@
1
1
  module Rory
2
- VERSION = '0.3.10'
2
+ VERSION = '0.3.11'
3
3
  end
@@ -1,6 +1,6 @@
1
1
  Fixture::Application.set_routes do
2
2
  match 'foo/:id/bar', :to => 'foo#bar', :methods => [:get, :post]
3
- match '/foo', :to => 'monkeys', :methods => [:put]
3
+ match '/foo', :to => 'monkeys', :methods => [:delete]
4
4
  match 'this/:path/is/:very_awesome', :to => 'awesome#rad'
5
5
  scope :module => 'goose' do
6
6
  match 'lumpies/:lump', :to => 'lumpies#show', :methods => [:get]
@@ -1 +1 @@
1
- You came from <%= base_url %>.
1
+ You came from <%= base_path %>.
@@ -66,19 +66,16 @@ describe Rory::Application do
66
66
  end
67
67
 
68
68
  describe ".routes" do
69
- it "generates a routing table from route configuration" do
70
- # note: we're comparing the inspected arrays here because the arrays
71
- # won't be equal, despite appearing the same - this is because the Regexes
72
- # are different objects.
73
- Fixture::Application.routes.inspect.should == [
74
- { :controller => 'foo', :action => 'bar', :regex => /^foo\/(?<id>[^\/]+)\/bar$/, :methods => [:get, :post] },
75
- { :controller => 'monkeys', :action => nil, :regex => /^foo$/, :methods => [:put] },
76
- { :controller => 'awesome', :action => 'rad', :regex => /^this\/(?<path>[^\/]+)\/is\/(?<very_awesome>[^\/]+)$/},
77
- { :controller => 'lumpies', :action => 'show', :regex => /^lumpies\/(?<lump>[^\/]+)$/, :module => 'goose', :methods => [:get] },
78
- { :controller => 'rabbits', :action => 'chew', :regex => /^rabbits\/(?<chew>[^\/]+)$/, :module => 'goose/wombat', :methods => [:get] },
79
- { :controller => 'root', :action => 'vegetable', :regex => /^$/, :methods => [:get] },
80
- { :controller => 'for_reals', :action => 'srsly', :regex => /^for_reals\/(?<parbles>[^\/]+)$/, :methods => [:get] }
81
- ].inspect
69
+ it "generates a collection of routing objects from route configuration" do
70
+ expect(Fixture::Application.routes).to eq [
71
+ Rory::Route.new('foo/:id/bar', :to => 'foo#bar', :methods => [:get, :post]),
72
+ Rory::Route.new('foo', :to => 'monkeys', :methods => [:delete]),
73
+ Rory::Route.new('this/:path/is/:very_awesome', :to => 'awesome#rad'),
74
+ Rory::Route.new('lumpies/:lump', :to => 'lumpies#show', :methods => [:get], :module => 'goose'),
75
+ Rory::Route.new('rabbits/:chew', :to => 'rabbits#chew', :methods => [:get], :module => 'goose/wombat'),
76
+ Rory::Route.new('', :to => 'root#vegetable', :methods => [:get]),
77
+ Rory::Route.new('for_reals/:parbles', :to => 'for_reals#srsly', :methods => [:get])
78
+ ]
82
79
  end
83
80
  end
84
81
 
@@ -1,10 +1,7 @@
1
1
  describe Rory::Controller do
2
2
  before :each do
3
3
  @routing = {
4
- :route => {
5
- :controller => 'test',
6
- :action => 'letsgo'
7
- }
4
+ :route => Rory::Route.new('', :to => 'test#letsgo')
8
5
  }
9
6
 
10
7
  @request = double('Rack::Request', {
@@ -13,6 +10,12 @@ describe Rory::Controller do
13
10
  })
14
11
  end
15
12
 
13
+ it_has_behavior 'path_generation' do
14
+ let(:path_generator) {
15
+ Rory::Controller.new(@request, @routing, Fixture::Application)
16
+ }
17
+ end
18
+
16
19
  describe '#layout' do
17
20
  it 'defaults to nil' do
18
21
  controller = Rory::Controller.new(@request, @routing)
@@ -49,7 +52,7 @@ describe Rory::Controller do
49
52
  :layout => 'pretend',
50
53
  :locals => { :a => 1 },
51
54
  :app => :scooby,
52
- :base_url => 'script_root'
55
+ :base_path => 'script_root'
53
56
  }
54
57
  allow(Rory::Renderer).to receive(:new).
55
58
  with('also/fake', renderer_options).
@@ -76,6 +79,13 @@ describe Rory::Controller do
76
79
  end
77
80
  end
78
81
 
82
+ describe "#base_path" do
83
+ it "returns script_name from request" do
84
+ controller = Rory::Controller.new(@request, @routing)
85
+ expect(controller.base_path).to eq 'script_root'
86
+ end
87
+ end
88
+
79
89
  describe "#present" do
80
90
  it "calls filters and action from route if exists on controller" do
81
91
  controller = Rory::Controller.new(@request, @routing)
@@ -33,7 +33,8 @@ describe Rory::Dispatcher do
33
33
  end
34
34
 
35
35
  it "instantiates a controller with the parsed request and calls present" do
36
- allow(dispatcher).to receive(:get_route).and_return({ :controller => 'stub' })
36
+ route = Rory::Route.new('', :to => 'stub#index')
37
+ allow(dispatcher).to receive(:get_route).and_return(route)
37
38
  dispatcher.dispatch.should == {
38
39
  :whatever => :yay,
39
40
  :present_called => true # see StubController in /spec/fixture_app
@@ -41,9 +42,8 @@ describe Rory::Dispatcher do
41
42
  end
42
43
 
43
44
  it "dispatches properly to a scoped controller" do
44
- allow(dispatcher).to receive(:get_route).and_return({
45
- :controller => 'lumpies', :module => 'goose'
46
- })
45
+ route = Rory::Route.new('', :to => 'lumpies#index', :module => 'goose')
46
+ allow(dispatcher).to receive(:get_route).and_return(route)
47
47
  dispatcher.dispatch.should == {
48
48
  :whatever => :yay,
49
49
  :in_scoped_controller => true # see Goose::LumpiesController in /spec/fixture_app
@@ -51,9 +51,8 @@ describe Rory::Dispatcher do
51
51
  end
52
52
 
53
53
  it "dispatches properly to a nested scoped controller" do
54
- allow(dispatcher).to receive(:get_route).and_return({
55
- :controller => 'rabbits', :module => 'goose/wombat'
56
- })
54
+ route = Rory::Route.new('', :to => 'rabbits#index', :module => 'goose/wombat')
55
+ allow(dispatcher).to receive(:get_route).and_return(route)
57
56
  dispatcher.dispatch.should == {
58
57
  :whatever => :yay,
59
58
  :in_scoped_controller => true # see Goose::Wombat::RabbitsController in /spec/fixture_app
@@ -74,33 +73,35 @@ describe Rory::Dispatcher do
74
73
  end
75
74
 
76
75
  it "matches the path from the request to the routes table" do
77
- @request.stub(:path_info => '/foo', :request_method => 'PUT')
78
- @dispatcher.route.should == {
79
- :controller => 'monkeys',
80
- :action => nil,
81
- :regex => /^foo$/,
82
- :methods => [:put]
83
- }
76
+ @request.stub(:path_info => '/foo/3/bar', :request_method => 'GET')
77
+ expect(@dispatcher.route).to eq Rory::Route.new('/foo/:id/bar', {
78
+ :to => 'foo#bar',
79
+ :methods => [:get, :post]
80
+ })
81
+ end
82
+
83
+ it "uses override method from params if exists" do
84
+ @request.stub(:path_info => '/foo', :params => { '_method' => 'delete' }, :request_method => 'PUT')
85
+ expect(@dispatcher.route).to eq Rory::Route.new('/foo', {
86
+ :to => 'monkeys',
87
+ :methods => [:delete]
88
+ })
84
89
  end
85
90
 
86
91
  it "works with empty path" do
87
92
  @request.stub(:path_info => '', :request_method => 'GET')
88
- @dispatcher.route.should == {
89
- :controller => 'root',
90
- :action => 'vegetable',
91
- :regex => /^$/,
93
+ expect(@dispatcher.route).to eq Rory::Route.new('/', {
94
+ :to => 'root#vegetable',
92
95
  :methods => [:get]
93
- }
96
+ })
94
97
  end
95
98
 
96
99
  it "works with root url represented by slash" do
97
100
  @request.stub(:path_info => '/', :request_method => 'GET')
98
- @dispatcher.route.should == {
99
- :controller => 'root',
100
- :action => 'vegetable',
101
- :regex => /^$/,
101
+ expect(@dispatcher.route).to eq Rory::Route.new('/', {
102
+ :to => 'root#vegetable',
102
103
  :methods => [:get]
103
- }
104
+ })
104
105
  end
105
106
 
106
107
  it "returns nil if no route found" do
@@ -120,38 +121,11 @@ describe Rory::Dispatcher do
120
121
 
121
122
  it "assigns named matches to params hash" do
122
123
  @request.stub(:path_info => '/this/some-thing_or-other/is/wicked', :request_method => 'GET')
123
- @dispatcher.route.inspect.should == {
124
- :controller => 'awesome',
125
- :action => 'rad',
126
- :regex => /^this\/(?<path>[^\/]+)\/is\/(?<very_awesome>[^\/]+)$/,
127
- }.inspect
124
+ expect(@dispatcher.route).to eq Rory::Route.new('/this/:path/is/:very_awesome', {
125
+ :to => 'awesome#rad'
126
+ })
128
127
 
129
128
  @request.params.should == {:path=>"some-thing_or-other", :very_awesome=>"wicked"}
130
129
  end
131
130
  end
132
-
133
- describe '#method' do
134
- it 'returns downcased method from request' do
135
- request = {:whatever => :yay}
136
- request.stub(:path_info => '/', :request_method => 'POST', :params => {})
137
- dispatcher = Rory::Dispatcher.new(request, Fixture::Application)
138
- dispatcher.method.should == 'post'
139
- end
140
-
141
- ['put', 'patch', 'delete'].each do |override_method|
142
- it "overrides request method if _method from params is #{override_method}" do
143
- request = {:whatever => :yay}
144
- request.stub(:path_info => '/', :request_method => 'POST', :params => {'_method' => override_method})
145
- dispatcher = Rory::Dispatcher.new(request, Fixture::Application)
146
- dispatcher.method.should == override_method
147
- end
148
- end
149
-
150
- it 'ignores overriding _method if not valid' do
151
- request = {:whatever => :yay}
152
- request.stub(:path_info => '/', :request_method => 'POST', :params => {'_method' => 'rhubarb'})
153
- dispatcher = Rory::Dispatcher.new(request, Fixture::Application)
154
- dispatcher.method.should == 'post'
155
- end
156
- end
157
131
  end
@@ -1,12 +1,20 @@
1
1
  describe Rory::Renderer::Context do
2
+ it_has_behavior 'path_generation' do
3
+ let(:path_generator) {
4
+ Rory::Renderer::Context.new({
5
+ :app => Fixture::Application
6
+ })
7
+ }
8
+ end
9
+
2
10
  describe "#render" do
3
11
  it "returns sub-renderer output" do
4
12
  renderer_context = Rory::Renderer::Context.new({
5
13
  :app => :an_app,
6
- :base_url => 'yoyo'
14
+ :base_path => 'yoyo'
7
15
  })
8
16
  passed_renderer_options = {
9
- :layout => false, :app => :an_app, :base_url => 'yoyo'
17
+ :layout => false, :app => :an_app, :base_path => 'yoyo'
10
18
  }
11
19
  allow(Rory::Renderer).to receive(:new).
12
20
  with('not/real', passed_renderer_options).
@@ -18,11 +26,11 @@ describe Rory::Renderer::Context do
18
26
  renderer_context = Rory::Renderer::Context.new({
19
27
  :locals => { :thing => :great },
20
28
  :app => :an_app,
21
- :base_url => 'yoyo',
29
+ :base_path => 'yoyo',
22
30
  :layout => 'groooovy'
23
31
  })
24
32
  passed_renderer_options = {
25
- :layout => false, :app => :an_app, :base_url => 'yoyo'
33
+ :layout => false, :app => :an_app, :base_path => 'yoyo'
26
34
  }
27
35
  allow(Rory::Renderer).to receive(:new).
28
36
  with('also/fake', passed_renderer_options).
@@ -26,8 +26,8 @@ describe Rory::Renderer do
26
26
  "Don't Say A Bad Word: Poop!"
27
27
  end
28
28
 
29
- it "exposes base_url to template" do
30
- controller = Rory::Renderer.new('test/a_link', :base_url => 'spoo')
29
+ it "exposes base_path to template" do
30
+ controller = Rory::Renderer.new('test/a_link', :base_path => 'spoo')
31
31
  controller.render.should == 'You came from spoo.'
32
32
  end
33
33
  end
@@ -0,0 +1,8 @@
1
+ describe Rory::Route do
2
+ describe '#name' do
3
+ it 'returns concatenated controller and action' do
4
+ route = described_class.new('/whatever', :to => 'pigeons#index')
5
+ expect(route.name).to eq 'pigeons_index'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,27 @@
1
+ RSpec.configure do |c|
2
+ c.alias_it_should_behave_like_to :it_has_behavior, 'has behavior:'
3
+ end
4
+
5
+ shared_examples 'path_generation' do
6
+ describe '#path_to' do
7
+ it 'returns mask from route with given name prepended with root slash' do
8
+ allow(path_generator).to receive(:base_path).and_return(nil)
9
+ expect(path_generator.path_to('awesome_rad')).
10
+ to eq '/this/:path/is/:very_awesome'
11
+ end
12
+
13
+ it 'prepends base_path to returned mask' do
14
+ allow(path_generator).to receive(:base_path).and_return('/strawminos')
15
+ expect(path_generator.path_to('awesome_rad')).
16
+ to eq '/strawminos/this/:path/is/:very_awesome'
17
+ end
18
+
19
+ it 'substitutes tokens with given fields' do
20
+ allow(path_generator).to receive(:base_path).and_return('/strawminos')
21
+ expect(path_generator.path_to('awesome_rad', :path => 'house', :very_awesome => 352)).
22
+ to eq '/strawminos/this/house/is/352'
23
+ end
24
+ end
25
+ end
26
+
27
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.10
4
+ version: 0.3.11
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-03-03 00:00:00.000000000 Z
12
+ date: 2014-03-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -192,8 +192,10 @@ files:
192
192
  - lib/rory/application.rb
193
193
  - lib/rory/controller.rb
194
194
  - lib/rory/dispatcher.rb
195
+ - lib/rory/path_generation.rb
195
196
  - lib/rory/renderer/context.rb
196
197
  - lib/rory/renderer.rb
198
+ - lib/rory/route.rb
197
199
  - lib/rory/route_mapper.rb
198
200
  - lib/rory/support.rb
199
201
  - lib/rory/tasks.rb
@@ -221,10 +223,12 @@ files:
221
223
  - spec/lib/rory/dispatcher_spec.rb
222
224
  - spec/lib/rory/renderer/context_spec.rb
223
225
  - spec/lib/rory/renderer_spec.rb
226
+ - spec/lib/rory/route_spec.rb
224
227
  - spec/lib/rory/support_spec.rb
225
228
  - spec/lib/rory_spec.rb
226
229
  - spec/requests/controller_spec.rb
227
230
  - spec/spec_helper.rb
231
+ - spec/support/shared_examples/path_generation.rb
228
232
  - LICENSE.txt
229
233
  - Rakefile
230
234
  - README.rdoc