rory 0.3.10 → 0.3.11

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.
@@ -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