Commit 71015018b67f3a77c8876cace01c60fb581d81f0
1 parent
1f128345
Exists in
master
and in
29 other branches
r222@sede: terceiro | 2007-07-28 15:54:13 -0300
ActionItem0: implementing a better interface for the old flexible_template git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@226 3f533792-8f58-4932-b0fe-aaf55b0a4547
Showing
15 changed files
with
318 additions
and
0 deletions
Show diff stats
| @@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
| 1 | +require 'rake' | ||
| 2 | +require 'rake/testtask' | ||
| 3 | +require 'rake/rdoctask' | ||
| 4 | + | ||
| 5 | +desc 'Default: run unit tests.' | ||
| 6 | +task :default => :test | ||
| 7 | + | ||
| 8 | +desc 'Test the design plugin.' | ||
| 9 | +Rake::TestTask.new(:test) do |t| | ||
| 10 | + t.libs << 'lib' | ||
| 11 | + t.pattern = 'test/**/*_test.rb' | ||
| 12 | + t.verbose = true | ||
| 13 | +end | ||
| 14 | + | ||
| 15 | +desc 'Generate documentation for the design plugin.' | ||
| 16 | +Rake::RDocTask.new(:rdoc) do |rdoc| | ||
| 17 | + rdoc.rdoc_dir = 'rdoc' | ||
| 18 | + rdoc.title = 'Design' | ||
| 19 | + rdoc.options << '--line-numbers' << '--inline-source' | ||
| 20 | + rdoc.rdoc_files.include('README') | ||
| 21 | + rdoc.rdoc_files.include('lib/**/*.rb') | ||
| 22 | +end |
| @@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
| 1 | +require 'design' | ||
| 2 | + | ||
| 3 | +class ActionController::Base | ||
| 4 | + | ||
| 5 | + # Declares that this controller uses design plugin to generate its layout. | ||
| 6 | + # See the plugin README for options that can be passed to this method. | ||
| 7 | + def self.design(config = {}) | ||
| 8 | + if (config.has_key?(:holder) && config.has_key?(:fixed)) || (!config.has_key?(:holder) && !config.has_key?(:fixed)) | ||
| 9 | + raise ArgumentError.new("You must supply either <tt>:holder</tt> or <tt>:fixed</tt> to design.") | ||
| 10 | + end | ||
| 11 | + | ||
| 12 | + @design_plugin_config = config | ||
| 13 | + | ||
| 14 | + include Design | ||
| 15 | + end | ||
| 16 | + | ||
| 17 | + # declares this controller as a design editor, including in it all the | ||
| 18 | + # functionalities to do that (besides those for using a design). Accepts the | ||
| 19 | + # same options as design. | ||
| 20 | + def self.design_editor(config = {}) | ||
| 21 | + self.design(config) | ||
| 22 | + include Design::Editor | ||
| 23 | + end | ||
| 24 | + | ||
| 25 | +end |
| @@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
| 1 | +# Install hook code here |
| @@ -0,0 +1,29 @@ | @@ -0,0 +1,29 @@ | ||
| 1 | +require 'design/fixed_design_holder' | ||
| 2 | +require 'design/proxy_design_holder' | ||
| 3 | + | ||
| 4 | +require 'design/helper' | ||
| 5 | +require 'design/editor' | ||
| 6 | + | ||
| 7 | +module Design | ||
| 8 | + | ||
| 9 | + # gets the Design object for this controller | ||
| 10 | + def design | ||
| 11 | + @design_plugin_data ||= Hash.new | ||
| 12 | + data = @design_plugin_data | ||
| 13 | + | ||
| 14 | + return data[:design] if data.has_key?(:design) | ||
| 15 | + | ||
| 16 | + config = self.class.instance_variable_get("@design_plugin_config") | ||
| 17 | + | ||
| 18 | + if config.has_key?(:holder) | ||
| 19 | + holder_variable_name = config[:holder] | ||
| 20 | + data[:design] = Design::ProxyDesignHolder.new(self.instance_variable_get("@#{holder_variable_name}")) | ||
| 21 | + else | ||
| 22 | + options = (config[:fixed].kind_of? Hash) ? config[:fixed] : {} | ||
| 23 | + data[:design] = Design::FixedDesignHolder.new(options) | ||
| 24 | + end | ||
| 25 | + | ||
| 26 | + data[:design] # redundant, but makes more clear the return value | ||
| 27 | + end | ||
| 28 | + protected :design | ||
| 29 | +end |
| @@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
| 1 | +module Design | ||
| 2 | + | ||
| 3 | + class FixedDesignHolder | ||
| 4 | + attr_reader :template, :theme, :icon_theme, :boxes | ||
| 5 | + def initialize(options = {}) | ||
| 6 | + @template = options[:template] || 'default' | ||
| 7 | + @theme = options[:theme] || 'default' | ||
| 8 | + @icon_theme = options[:icon_theme] || 'default' | ||
| 9 | + @boxes = options[:boxes] || default_boxes | ||
| 10 | + end | ||
| 11 | + | ||
| 12 | + # creates some default boxes | ||
| 13 | + def default_boxes | ||
| 14 | + box1 = Box.new | ||
| 15 | + box2 = Box.new | ||
| 16 | + box2.blocks << MainBlock.new | ||
| 17 | + box3 = Box.new | ||
| 18 | + | ||
| 19 | + [box1, box2, box3] | ||
| 20 | + end | ||
| 21 | + private :default_boxes | ||
| 22 | + end | ||
| 23 | + | ||
| 24 | +end | ||
| 25 | + |
| @@ -0,0 +1,43 @@ | @@ -0,0 +1,43 @@ | ||
| 1 | +module Design | ||
| 2 | + | ||
| 3 | + # This class uses an external holder object to hold the details of the | ||
| 4 | + # design, and proxies all access to the template data to it. This object can | ||
| 5 | + # be any object that responds to the following methods: | ||
| 6 | + # | ||
| 7 | + # * +template+ | ||
| 8 | + # * +template=+ | ||
| 9 | + # * +theme+ | ||
| 10 | + # * +theme=+ | ||
| 11 | + # * +icon_theme+ | ||
| 12 | + # * +icon_theme=+ | ||
| 13 | + # * +boxes+ | ||
| 14 | + # * +boxes=+ | ||
| 15 | + # | ||
| 16 | + # These methods must implement get/set semantics for atrributes with their | ||
| 17 | + # names, and can be implemented with +attr_accessor+, as ActiveRecord | ||
| 18 | + # columns, or event explicity by writing the methods and storing the values | ||
| 19 | + # wherever you want. | ||
| 20 | + # | ||
| 21 | + # +template+, +theme+ and +icon_theme+ must return (and accept in the | ||
| 22 | + # setters) strings, while +boxes+ must be an array of Box objects. | ||
| 23 | + class ProxyDesignHolder | ||
| 24 | + | ||
| 25 | + attr_reader :holder | ||
| 26 | + | ||
| 27 | + # creates a new proxy for +holder+ | ||
| 28 | + def initialize(holder) | ||
| 29 | + @holder = holder | ||
| 30 | + end | ||
| 31 | + | ||
| 32 | + # proxies all calls to +template+, +theme+, +icon_theme+ and +boxes+ (as | ||
| 33 | + # well as their setters counterparts) to the holder object | ||
| 34 | + def method_missing(method_id, *args) | ||
| 35 | + if method_id.to_s =~ /^(template|theme|icon_theme|boxes)=?$/ | ||
| 36 | + holder.send(method_id, *args) | ||
| 37 | + else | ||
| 38 | + raise NoMethodError.new("Design has no method \"#{method_id}\"") | ||
| 39 | + end | ||
| 40 | + end | ||
| 41 | + end | ||
| 42 | + | ||
| 43 | +end |
| @@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
| 1 | +require File.join(File.dirname(__FILE__), 'test_helper') | ||
| 2 | + | ||
| 3 | +class FixedDesignHolderTest < Test::Unit::TestCase | ||
| 4 | + | ||
| 5 | + def test_design_should_include_design_module | ||
| 6 | + assert FixedDesignTestController.included_modules.include?(Design) | ||
| 7 | + end | ||
| 8 | + | ||
| 9 | + def test_design_editor_should_include_design_and_design_editor_module | ||
| 10 | + assert DesignEditorTestController.included_modules.include?(Design) | ||
| 11 | + assert DesignEditorTestController.included_modules.include?(Design::Editor) | ||
| 12 | + end | ||
| 13 | + | ||
| 14 | + def test_should_not_accept_no_holder_and_no_fixed | ||
| 15 | + assert_raise ArgumentError do | ||
| 16 | + DesignEditorTestController.design | ||
| 17 | + end | ||
| 18 | + end | ||
| 19 | + def test_should_not_accept_both_holder_and_fixed | ||
| 20 | + assert_raise ArgumentError do | ||
| 21 | + DesignEditorTestController.design :holder => 'something', :fixed => true end | ||
| 22 | + end | ||
| 23 | + | ||
| 24 | +end |
| @@ -0,0 +1,53 @@ | @@ -0,0 +1,53 @@ | ||
| 1 | +require File.join(File.dirname(__FILE__), 'test_helper') | ||
| 2 | + | ||
| 3 | +class FixedDesignHolderTest < Test::Unit::TestCase | ||
| 4 | + | ||
| 5 | + include Design | ||
| 6 | + | ||
| 7 | + def test_explicit_design | ||
| 8 | + controller = FixedDesignTestController.new | ||
| 9 | + assert_kind_of Design::FixedDesignHolder, controller.design | ||
| 10 | + assert_equal 'some_template', controller.design.template | ||
| 11 | + assert_equal 'some_theme', controller.design.theme | ||
| 12 | + assert_equal 'some_icon_theme', controller.design.icon_theme | ||
| 13 | + assert_equal [FixedDesignTestController::BOX1, FixedDesignTestController::BOX2, FixedDesignTestController::BOX3], controller.design.boxes | ||
| 14 | + end | ||
| 15 | + | ||
| 16 | + def test_explicit_design_should_have_sensible_defaults | ||
| 17 | + controller = FixedDesignDefaultTestController.new | ||
| 18 | + assert_kind_of Design::FixedDesignHolder, controller.design | ||
| 19 | + assert_equal 'default', controller.design.template | ||
| 20 | + assert_equal 'default', controller.design.theme | ||
| 21 | + assert_equal 'default', controller.design.icon_theme | ||
| 22 | + assert_kind_of Array, controller.design.boxes | ||
| 23 | + assert_equal 3, controller.design.boxes.size | ||
| 24 | + end | ||
| 25 | + | ||
| 26 | + def test_should_not_be_able_to_assign_template | ||
| 27 | + # FixedDesignHolder does not implement assigment, on purpose | ||
| 28 | + assert_raise NoMethodError do | ||
| 29 | + FixedDesignHolder.new.template = 'break' | ||
| 30 | + end | ||
| 31 | + end | ||
| 32 | + | ||
| 33 | + def test_should_not_be_able_to_assign_theme | ||
| 34 | + # FixedDesignHolder does not implement assigment, on purpose | ||
| 35 | + assert_raise NoMethodError do | ||
| 36 | + FixedDesignHolder.new.theme = 'break' | ||
| 37 | + end | ||
| 38 | + end | ||
| 39 | + | ||
| 40 | + def test_should_not_be_able_to_assign_icon_theme | ||
| 41 | + assert_raise NoMethodError do | ||
| 42 | + FixedDesignHolder.new.icon_theme = 'break' | ||
| 43 | + end | ||
| 44 | + end | ||
| 45 | + | ||
| 46 | + def test_should_not_be_able_to_assign_boxes | ||
| 47 | + assert_raise NoMethodError do | ||
| 48 | + FixedDesignHolder.new.boxes = [] | ||
| 49 | + end | ||
| 50 | + end | ||
| 51 | + | ||
| 52 | + | ||
| 53 | +end |
| @@ -0,0 +1,32 @@ | @@ -0,0 +1,32 @@ | ||
| 1 | +require File.join(File.dirname(__FILE__), 'test_helper') | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +class ProxyDesignHolderTest < Test::Unit::TestCase | ||
| 5 | + | ||
| 6 | + # FIXME: rewrite this test with mocha | ||
| 7 | + def test_design_should_interact_with_sample_holder | ||
| 8 | + design = Design::ProxyDesignHolder.new(SampleHolderForTestingProxyDesignHolder.new) | ||
| 9 | + design.template = 'bli' | ||
| 10 | + assert_equal 'bli', design.template | ||
| 11 | + design.theme = 'bli' | ||
| 12 | + assert_equal 'bli', design.theme | ||
| 13 | + design.icon_theme = 'bli' | ||
| 14 | + assert_equal 'bli', design.icon_theme | ||
| 15 | + design.boxes = [] | ||
| 16 | + assert_equal [], design.boxes | ||
| 17 | + end | ||
| 18 | + | ||
| 19 | + def test_design_user_controller_should_get_a_proper_design | ||
| 20 | + controller = ProxyDesignHolderTestController.new | ||
| 21 | + design = controller.send(:design) | ||
| 22 | + design.template = 'bli' | ||
| 23 | + assert_equal 'bli', design.template | ||
| 24 | + design.theme = 'bli' | ||
| 25 | + assert_equal 'bli', design.theme | ||
| 26 | + design.icon_theme = 'bli' | ||
| 27 | + assert_equal 'bli', design.icon_theme | ||
| 28 | + design.boxes = [] | ||
| 29 | + assert_equal [], design.boxes | ||
| 30 | + end | ||
| 31 | + | ||
| 32 | +end |
| @@ -0,0 +1,44 @@ | @@ -0,0 +1,44 @@ | ||
| 1 | +ENV["RAILS_ENV"] = "test" | ||
| 2 | +require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment") | ||
| 3 | + | ||
| 4 | +require 'test/unit' | ||
| 5 | + | ||
| 6 | +######################## | ||
| 7 | +# test clases below here | ||
| 8 | +######################## | ||
| 9 | + | ||
| 10 | +class FixedDesignTestController < ActionController::Base | ||
| 11 | + | ||
| 12 | + BOX1 = Box.new | ||
| 13 | + BOX2 = Box.new | ||
| 14 | + BOX3 = Box.new | ||
| 15 | + | ||
| 16 | + design :fixed => { | ||
| 17 | + :template => 'some_template', | ||
| 18 | + :theme => 'some_theme', | ||
| 19 | + :icon_theme => 'some_icon_theme', | ||
| 20 | + :boxes => [ BOX1, BOX2, BOX3 ], | ||
| 21 | + } | ||
| 22 | +end | ||
| 23 | + | ||
| 24 | +class FixedDesignDefaultTestController < ActionController::Base | ||
| 25 | + design :fixed => true | ||
| 26 | +end | ||
| 27 | + | ||
| 28 | +class SampleHolderForTestingProxyDesignHolder | ||
| 29 | + attr_accessor :template, :theme, :icon_theme, :boxes | ||
| 30 | +end | ||
| 31 | + | ||
| 32 | +class ProxyDesignHolderTestController < ActionController::Base | ||
| 33 | + design :holder => 'sample_object' | ||
| 34 | + def initialize | ||
| 35 | + @sample_object = SampleHolderForTestingProxyDesignHolder.new | ||
| 36 | + end | ||
| 37 | +end | ||
| 38 | + | ||
| 39 | +class DesignEditorTestController < ActionController::Base | ||
| 40 | + design_editor :holder => 'sample_object' | ||
| 41 | + def initialize | ||
| 42 | + @sample_object = SampleHolderForTestingProxyDesignHolder.new | ||
| 43 | + end | ||
| 44 | +end |
| @@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
| 1 | +# Uninstall hook code here |