Skip to content

Commit

Permalink
Extract an overridable PageFinder class
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-burns committed Sep 26, 2012
1 parent 6eee9b0 commit 8494e51
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 31 deletions.
30 changes: 30 additions & 0 deletions README.md
Expand Up @@ -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
-------

Expand Down
31 changes: 13 additions & 18 deletions app/controllers/high_voltage/pages_controller.rb
@@ -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
Expand All @@ -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
37 changes: 37 additions & 0 deletions lib/high_voltage/page_finder.rb
@@ -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
13 changes: 13 additions & 0 deletions spec/controllers/alternative_finder_controller_spec.rb
@@ -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
9 changes: 0 additions & 9 deletions spec/controllers/subclassed_pages_controller_spec.rb
Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions spec/dummy/app/controllers/alternative_finder_controller.rb
@@ -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
4 changes: 0 additions & 4 deletions spec/dummy/app/controllers/subclassed_pages_controller.rb
@@ -1,7 +1,3 @@
class SubclassedPagesController < HighVoltage::PagesController
layout 'alternate'

def content_path
'other_pages/'
end
end
1 change: 1 addition & 0 deletions spec/dummy/app/views/pages/also_dir/also_nested.html.erb
@@ -0,0 +1 @@
hello <%= 'world' %> from a nested dir
1 change: 1 addition & 0 deletions spec/dummy/app/views/pages/also_exists.html.erb
@@ -0,0 +1 @@
hello <%= 'world' %>
@@ -0,0 +1,2 @@
hello <%= 'world' %>
<%= render 'nonexistent' %>
1 change: 1 addition & 0 deletions spec/dummy/app/views/pages/rot13.html.erb
@@ -0,0 +1 @@
alternative
1 change: 1 addition & 0 deletions spec/dummy/config/routes.rb
@@ -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
53 changes: 53 additions & 0 deletions spec/high_voltage/page_finder_spec.rb
@@ -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.