Skip to content

Commit

Permalink
Modified the helper Ramaze::Helper::Layout so that it allows you to c…
Browse files Browse the repository at this point in the history
…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 committed Apr 6, 2011
1 parent 4a8c10e commit 0d15a29
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 84 deletions.
165 changes: 96 additions & 69 deletions lib/ramaze/helper/layout.rb
@@ -1,97 +1,124 @@
module Ramaze module Ramaze
module Helper module Helper

##
# Provides wrapper methods for a higher-level approach than the core layout # 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 # set_layout 'default'
# * layout a whitelist of actions
# * layout all but a blacklist of actions
# #
# As with the core layout method, the layout rules apply only to the # This of course is very boring, time to add some more spices to our code:
# controller on which they are applied. Furthermore, multiple layout
# definitions are not combined; only the last definition will be used.
# #
# This helper is one of the default helpers, so no explicit helper call # set_layout 'default' => [:index]
# is necessary before using it in your controllers.
# #
# 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 # set_layout 'default' => [:index, :edit], 'alternative' => [:add, :process]
# # 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
# #
# class MainController < Controller # A few things changed. First of all there are now two key/value groups. Each group
# # These two layout definitions accomplish the same thing. The # defines a layout (the key) and a set of methods (the value) for which each layout
# # first uses a whitelist, the second uses a blacklist. # should be used. In this case the layout "default" will be used for index() and edit()
# set_layout 'default' => [:laid_out1, :laid_out2] # but the layout "alternative" will be used for add() and process().
# set_layout_except 'default' => [:not_laid_out1, :not_laid_out2]
# #
# def laid_out1; end # Last but not least, multiple calls to set_layout will no longer override any
# def laid_out2; end # 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 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) def self.included(into)
into.extend SingletonMethods into.extend SingletonMethods
end end


module SingletonMethods 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 # The set_layout method allows you to specify a number of methods and their
# action names # layout. This allows you to use layout A for methods 1, 2 and 3 but layout B for
# @see set_layout_except Innate::Node::layout # method 4.
# @author Pistos, manveru #
# @example Use a layout named 'default' on all actions of the controller: # @example
# set_layout 'default' # # The key is the layout, the value an array of methods
# @example Use a layout named 'default' on just the index and admin actions: # set_layout 'default' => [:method_1], 'alternative' => [:method_2]
# set_layout 'default' => [ :index, :admin ] #
def set_layout(hash_or_the_layout) # # We can combine this method with layout()
if hash_or_the_layout.respond_to?(:to_hash) # layout 'default'
f = hash_or_the_layout.to_hash.find{|k,v| k && v } # set_layout 'alternative' => [:method_1]
the_layout = f[0] #
whitelist = f[1].map{|action| action.to_s } # # This is also perfectly fine
else # set_layout 'default'
the_layout = hash_or_the_layout #
end # @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| # Extract the layout to use
if whitelist.nil? || whitelist.include?(path.to_s) if hash_or_layout.respond_to?(:to_hash)
the_layout # 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
end


# @param [String Hash] Either a layout name, or a single-element Hash # Only use the layout for the current method
# which maps a layout name to an Array containing a blacklist of layout do |path|
# action names path = path.to_s
# @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


layout do |path, wish| if @_ramaze_layouts.key?(path)
if blacklist.nil? || !blacklist.include?(path.to_s) @_ramaze_layouts[path]
the_layout end
end

else
# This is pretty easy isn't it?
layout do |path|
hash_or_layout
end end
end 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

end end
end end
27 changes: 12 additions & 15 deletions spec/ramaze/helper/layout.rb
Expand Up @@ -22,18 +22,16 @@ def laid_out2; end
def not_laid_out; end def not_laid_out; end
end end


class LayoutHelper < Ramaze::Controller class LayoutHelperThree < Ramaze::Controller
map '/three' 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_out1; end
def laid_out2; end def laid_out2; end

def laid_out3; end
def not_laid_out1; end
def not_laid_out2; end
end end



describe Ramaze::Helper::Layout do describe Ramaze::Helper::Layout do
behaves_like :rack_test behaves_like :rack_test


Expand Down Expand Up @@ -61,19 +59,18 @@ def not_laid_out2; end
last_response.body.should.not.match /laid out/ last_response.body.should.not.match /laid out/
end end


it 'lays out all actions except a blacklist' do it 'Define a set of method specific layouts' do
get '/three/laid_out1' get '/three/laid_out1'
last_response.status.should == 200 last_response.status.should === 200
last_response.body.should.match /laid out/ last_response.body.should.match /laid out/

get '/three/laid_out2' 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/ 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


end end
5 changes: 5 additions & 0 deletions spec/ramaze/helper/layout/alternative.xhtml
@@ -0,0 +1,5 @@
<em>alternative</em>

<div id="content">
#@content
</div>

1 comment on commit 0d15a29

@godfat
Copy link

@godfat godfat commented on 0d15a29 Apr 7, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Please sign in to comment.