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...
1 parent 4a8c10e commit 0d15a29c960e22761456180a6be7b88c3809eba8 YorickPeterse committed Apr 6, 2011
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
@@ -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
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.