Permalink
Browse files

Modified the helper Ramaze::Helper::Layout so that it allows you to c…

…all set_layout multiple times as well as setting layouts for multiple methods. A good example is the following:

    set_layout 'my_layout' => [:index, :edit]
    set_layout 'default'   => [:add]

Please note that Ramaze::Helper::Layout#set_layout_except is deprecated and will issue a warning, you should use set_layout instead.
  • Loading branch information...
YorickPeterse
YorickPeterse committed Apr 6, 2011
1 parent 4a8c10e commit 0d15a29c960e22761456180a6be7b88c3809eba8
Showing with 113 additions and 84 deletions.
  1. +96 −69 lib/ramaze/helper/layout.rb
  2. +12 −15 spec/ramaze/helper/layout.rb
  3. +5 −0 spec/ramaze/helper/layout/alternative.xhtml
View
@@ -1,97 +1,124 @@
module Ramaze
module Helper
##
# Provides wrapper methods for a higher-level approach than the core layout
# method. These are useful for simpler layout needs, particularly:
# method. The layout() method that comes with Innate/Ramaze is fairly basic as it only
# allows you to specify a single layout to always use or a block giving you some extra
# flexibility. The latter however is still a bit of a pain when dealing with many
# custom layouts in a single controller. Meet the Layout helper. This helper provides
# a single method (since April 2011, it used to provide more) called "set_layout".
# This method allows you to specify a number of layouts and the methods for which
# these layouts should be used.
#
# == Examples
#
# The most basic example is simply setting a layout as you would do with the layout()
# method:
#
# * layout all actions
# * layout a whitelist of actions
# * layout all but a blacklist of actions
# set_layout 'default'
#
# As with the core layout method, the layout rules apply only to the
# controller on which they are applied. Furthermore, multiple layout
# definitions are not combined; only the last definition will be used.
# This of course is very boring, time to add some more spices to our code:
#
# This helper is one of the default helpers, so no explicit helper call
# is necessary before using it in your controllers.
# set_layout 'default' => [:index]
#
# Usage:
# Woah! What just happened? It's quite easy actually, we merely defined that the
# layout called "default" should be used for the index method *only*. Pretty sweet
# huh? It gets even better:
#
# class MainController < Controller
# # Apply the default layout (e.g. ./layout/default.xhtml) to all
# # three actions.
# set_layout 'default'
# def action1; end
# def action2; end
# def action3; end
# end
# set_layout 'default' => [:index, :edit], 'alternative' => [:add, :process]
#
# class MainController < Controller
# # These two layout definitions accomplish the same thing. The
# # first uses a whitelist, the second uses a blacklist.
# set_layout 'default' => [:laid_out1, :laid_out2]
# set_layout_except 'default' => [:not_laid_out1, :not_laid_out2]
# A few things changed. First of all there are now two key/value groups. Each group
# defines a layout (the key) and a set of methods (the value) for which each layout
# should be used. In this case the layout "default" will be used for index() and edit()
# but the layout "alternative" will be used for add() and process().
#
# def laid_out1; end
# def laid_out2; end
# Last but not least, multiple calls to set_layout will no longer override any
# existing settings *unless* you actually specify the same method with a different
# layout. This is possible because the set_layout method stores all these details in
# an instance variable called "_ramaze_layouts".
#
# @author Yorick Peterse
# @author Michael Fellinger
# @author Pistos
#
# def not_laid_out1; end
# def not_laid_out2; end
# end
module Layout
##
# Extends the class that included this module so that the methods that this helper
# provides can be called outside of instance of class methods.
#
# @param [Object] into The class that included this module.
# @author Michael Fellinger
# @author Pistos
#
def self.included(into)
into.extend SingletonMethods
end
module SingletonMethods
# @param [String Hash] Either a layout name, or a single-element Hash
# which maps a layout name to an Array containing a whitelist of
# action names
# @see set_layout_except Innate::Node::layout
# @author Pistos, manveru
# @example Use a layout named 'default' on all actions of the controller:
# set_layout 'default'
# @example Use a layout named 'default' on just the index and admin actions:
# set_layout 'default' => [ :index, :admin ]
def set_layout(hash_or_the_layout)
if hash_or_the_layout.respond_to?(:to_hash)
f = hash_or_the_layout.to_hash.find{|k,v| k && v }
the_layout = f[0]
whitelist = f[1].map{|action| action.to_s }
else
the_layout = hash_or_the_layout
end
##
# The set_layout method allows you to specify a number of methods and their
# layout. This allows you to use layout A for methods 1, 2 and 3 but layout B for
# method 4.
#
# @example
# # The key is the layout, the value an array of methods
# set_layout 'default' => [:method_1], 'alternative' => [:method_2]
#
# # We can combine this method with layout()
# layout 'default'
# set_layout 'alternative' => [:method_1]
#
# # This is also perfectly fine
# set_layout 'default'
#
# @author Yorick Peterse
# @author Michael Fellinger
# @author Pistos
# @param [Hash/String] hash_or_layout Can either be a string or a hash. In case
# it's a string it will directly be used as the layout. When setting a hash this
# hash should have it's keys set to the layouts and it's values to an array of
# methods that use the specific layout. For more information see the examples.
#
def set_layout(hash_or_layout)
@_ramaze_layouts ||= {}
layout do |path, wish|
if whitelist.nil? || whitelist.include?(path.to_s)
the_layout
# Extract the layout to use
if hash_or_layout.respond_to?(:to_hash)
# Invert the method/layout hash and save them so they don't get lost
hash_or_layout.to_hash.each do |layout, methods|
# Dirty but it works
methods.each do |m|
@_ramaze_layouts[m.to_s] = layout.to_s
end
end
end
end
# @param [String Hash] Either a layout name, or a single-element Hash
# which maps a layout name to an Array containing a blacklist of
# action names
# @see set_layout Innate::Node::layout
# @author Pistos, manveru
# @example Use a layout named 'default' on all actions except the user_data action:
# set_layout_except 'default' => [ :user_data ]
def set_layout_except(hash_or_the_layout)
if hash_or_the_layout.respond_to?(:to_hash)
f = hash_or_the_layout.to_hash.find{|k,v| k && v }
the_layout = f[0]
blacklist = f[1].map{|action| action.to_s }
else
the_layout = hash_or_the_layout
end
# Only use the layout for the current method
layout do |path|
path = path.to_s
layout do |path, wish|
if blacklist.nil? || !blacklist.include?(path.to_s)
the_layout
if @_ramaze_layouts.key?(path)
@_ramaze_layouts[path]
end
end
else
# This is pretty easy isn't it?
layout do |path|
hash_or_layout
end
end
end
# People might get confused when all of a sudden set_layout_except is gone. This
# warning should clear things up for them. This method can be removed a release
# after (or later) this modified helper has been introduced.
def set_layout_except(hash_or_layout)
Ramaze.deprecated('set_layout_except', 'set_layout')
end
end
end
end
end
@@ -22,18 +22,16 @@ def laid_out2; end
def not_laid_out; end
end
class LayoutHelper < Ramaze::Controller
class LayoutHelperThree < Ramaze::Controller
map '/three'
set_layout_except 'default' => [:not_laid_out1, :not_laid_out2]
set_layout 'default' => [:laid_out1], 'alternative' => [:laid_out2]
set_layout 'default' => [:laid_out3]
def laid_out1; end
def laid_out2; end
def not_laid_out1; end
def not_laid_out2; end
def laid_out3; end
end
describe Ramaze::Helper::Layout do
behaves_like :rack_test
@@ -61,19 +59,18 @@ def not_laid_out2; end
last_response.body.should.not.match /laid out/
end
it 'lays out all actions except a blacklist' do
it 'Define a set of method specific layouts' do
get '/three/laid_out1'
last_response.status.should == 200
last_response.status.should === 200
last_response.body.should.match /laid out/
get '/three/laid_out2'
last_response.status.should == 200
last_response.status.should === 200
last_response.body.should.match /alternative/
get '/three/laid_out3'
last_response.status.should === 200
last_response.body.should.match /laid out/
get '/three/not_laid_out1'
last_response.status.should == 200
last_response.body.should.not.match /laid out/
get '/three/not_laid_out2'
last_response.status.should == 200
last_response.body.should.not.match /laid out/
end
end
@@ -0,0 +1,5 @@
<em>alternative</em>
<div id="content">
#@content
</div>

1 comment on commit 0d15a29

@godfat

This comment has been minimized.

Show comment
Hide comment
@godfat

godfat Apr 7, 2011

Thank you!
Then I don't have to use layout do |path, wish| ... anymore.

godfat commented on 0d15a29 Apr 7, 2011

Thank you!
Then I don't have to use layout do |path, wish| ... anymore.

Please sign in to comment.