Permalink
Browse files

Extract an overridable PageFinder class

  • Loading branch information...
1 parent 6eee9b0 commit 8494e51b59ea3b73405401a268ce206a440cfeeb @mike-burns mike-burns committed Sep 26, 2012
View
@@ -121,6 +121,36 @@ Then modify it to subclass from High Voltage, adding whatever you need:
end
end
+Custom finding
+--------------
+
+You can further control the algorithm used to find pages by overriding
+the `page_finder_factory` method:
+
+ class PagesController < HighVoltage::PagesController
+ private
+
+ def page_finder_factory
+ Rot13PageFinder
+ end
+ end
+
+The easiest thing is to subclass `HighVoltage::PageFinder`, which
+provides you with `page_id`:
+
+ class Rot13PageFinder < HighVoltage::PageFinder
+ def find
+ paths = super.split('/')
+ directory = paths[0..-2]
+ filename = paths[-1].tr('a-z','n-za-m')
+
+ File.join(*directory, filename)
+ end
+ end
+
+Use this to create a custom file mapping, clean filenames for your file
+system, A/B test, and so on.
+
Testing
-------
@@ -1,11 +1,11 @@
-class HighVoltage::PagesController < ApplicationController
- VALID_CHARACTERS = "a-zA-Z0-9~!@$%^&*()#`_+-=<>\"{}|[];',?".freeze
+require 'high_voltage/page_finder'
+class HighVoltage::PagesController < ApplicationController
unloadable
layout Proc.new { |_| HighVoltage.layout }
rescue_from ActionView::MissingTemplate do |exception|
- if exception.message =~ %r{Missing template #{content_path}}
+ if exception.message =~ %r{Missing template #{page_finder.content_path}}
raise ActionController::RoutingError, "No such page: #{params[:id]}"
else
raise exception
@@ -16,22 +16,17 @@ def show
render :template => current_page
end
- protected
+ private
- def current_page
- "#{content_path}#{clean_path}"
- end
-
- def clean_path
- path = Pathname.new("/#{clean_id}")
- path.cleanpath.to_s[1..-1]
- end
+ def current_page
+ page_finder.find
+ end
- def content_path
- HighVoltage.content_path
- end
+ def page_finder
+ page_finder_factory.new(params[:id])
+ end
- def clean_id
- params[:id].tr("^#{VALID_CHARACTERS}", '')
- end
+ def page_finder_factory
+ HighVoltage::PageFinder
+ end
end
@@ -0,0 +1,37 @@
+module HighVoltage
+ # A command for finding pages by id. This encapsulates the concepts of
+ # mapping page names to file names.
+ class PageFinder
+ VALID_CHARACTERS = "a-zA-Z0-9~!@$%^&*()#`_+-=<>\"{}|[];',?".freeze
+
+ def initialize(page_id)
+ @page_id = page_id
+ end
+
+ # Produce a template path to the page, in a format understood by
+ # `render :template => find`
+ def find
+ "#{content_path}#{clean_path}"
+ end
+
+ def content_path
+ HighVoltage.content_path
+ end
+
+ protected
+
+ # The raw page id passed in by the user
+ attr_reader :page_id
+
+ private
+
+ def clean_path
+ path = Pathname.new("/#{clean_id}")
+ path.cleanpath.to_s[1..-1]
+ end
+
+ def clean_id
+ @page_id.tr("^#{VALID_CHARACTERS}", '')
+ end
+ end
+end
@@ -0,0 +1,13 @@
+require 'spec_helper'
+
+describe AlternativeFinderController do
+
+ render_views
+
+ it 'renders the file from the alternative directory' do
+ get :show, :id => 'ebg13'
+
+ response.should be_success
+ response.should render_template('rot13')
+ end
+end
@@ -18,15 +18,6 @@
end
end
- describe "on GET to /subclassed_pages/also_dir/nested" do
- before { get :show, :id => 'also_dir/also_nested' }
-
- it "should respond with success and render template" do
- response.should be_success
- response.should render_template('other_pages/also_dir/also_nested')
- end
- end
-
it "should raise a routing error for an invalid page" do
lambda { get :show, :id => "invalid" }.should raise_error(ActionController::RoutingError)
end
@@ -0,0 +1,14 @@
+class AlternativeFinderController < HighVoltage::PagesController
+ private
+
+ def page_finder_factory
+ Rot13PageFinder
+ end
+
+ class Rot13PageFinder < HighVoltage::PageFinder
+ def find
+ paths = super.split('/')
+ "#{paths[0..-2].join('/')}/#{paths[-1].tr('a-z','n-za-m')}"
+ end
+ end
+end
@@ -1,7 +1,3 @@
class SubclassedPagesController < HighVoltage::PagesController
layout 'alternate'
-
- def content_path
- 'other_pages/'
- end
end
@@ -0,0 +1 @@
+hello <%= 'world' %> from a nested dir
@@ -0,0 +1 @@
+hello <%= 'world' %>
@@ -0,0 +1,2 @@
+hello <%= 'world' %>
+<%= render 'nonexistent' %>
@@ -0,0 +1 @@
+alternative
@@ -1,3 +1,4 @@
Dummy::Application.routes.draw do
match "/subclassed_pages/*id" => 'subclassed_pages#show', :format => false
+ match "/alternative_finder/*id" => 'alternative_finder#show', :format => false
end
@@ -0,0 +1,53 @@
+require 'spec_helper'
+require 'high_voltage/page_finder'
+
+describe HighVoltage::PageFinder do
+ it 'produces the name of an existing template' do
+ find('existing').should == 'pages/existing'
+ end
+
+ it 'produces the name of a nested template' do
+ find('dir/nested').should == 'pages/dir/nested'
+ end
+
+ it 'uses a custom content path' do
+ with_content_path('other_pages/') do
+ find('also_exists').should == 'other_pages/also_exists'
+ end
+ end
+
+ it 'exposes the content path' do
+ with_content_path('another_thing/') do
+ page_finder.content_path.should == 'another_thing/'
+ end
+ end
+
+ it 'provides the page_id' do
+ subclass = Class.new(HighVoltage::PageFinder) do
+ def page_name
+ "the page is #{page_id}"
+ end
+ end
+
+ subclass.new('sweet page').page_name.should == 'the page is sweet page'
+ end
+
+ private
+
+ def find(page_id)
+ page_finder(page_id).find
+ end
+
+ def page_finder(page_id = 'whatever')
+ HighVoltage::PageFinder.new(page_id)
+ end
+
+ def with_content_path(path)
+ original_content_path = HighVoltage.content_path
+ HighVoltage.content_path = path
+
+ yield
+
+ HighVoltage.content_path = original_content_path
+ end
+end

0 comments on commit 8494e51

Please sign in to comment.