diff --git a/README.md b/README.md index d5af295a..40fb4f99 100644 --- a/README.md +++ b/README.md @@ -538,6 +538,14 @@ Lotus::View.configure do # Argument: Symbol, defaults to nil # layout :application + + # Set modules that you want to include in all views + # Argument: Block + # + prepare do + include MyCustomModule + before { do_something } + end end ``` diff --git a/lib/lotus/view.rb b/lib/lotus/view.rb index fac7dacd..bc07ea7d 100644 --- a/lib/lotus/view.rb +++ b/lib/lotus/view.rb @@ -148,8 +148,9 @@ def self.dupe # # # # 1. Generate MyApp::View # # 2. Generate MyApp::Layout - # # 3. Generate MyApp::Views - # # 4. Configure MyApp::Views as the default namespace for views + # # 3. Generate MyApp::Presenter + # # 4. Generate MyApp::Views + # # 5. Configure MyApp::Views as the default namespace for views # # module MyApp::Views::Dashboard # class Index @@ -227,7 +228,10 @@ def self.dupe def self.duplicate(mod, views = 'Views', &blk) dupe.tap do |duplicated| mod.module_eval %{ module #{ views }; end } if views - mod.module_eval %{ Layout = Lotus::Layout.dup } + mod.module_eval %{ + Layout = Lotus::Layout.dup + Presenter = Lotus::Presenter.dup + } duplicated.configure do namespace [mod, views].compact.join '::' @@ -272,7 +276,7 @@ def self.included(base) self.configuration = conf.duplicate end - + conf.copy!(base) end diff --git a/lib/lotus/view/configuration.rb b/lib/lotus/view/configuration.rb index c48d5d6f..6960f3a9 100644 --- a/lib/lotus/view/configuration.rb +++ b/lib/lotus/view/configuration.rb @@ -32,6 +32,7 @@ class Configuration attr_reader :load_paths attr_reader :views attr_reader :layouts + attr_reader :modules # Return the original configuration of the framework instance associated # with the given class. @@ -236,54 +237,89 @@ def layout(value = nil) end end - # Specify the default modules to be included when `Lotus::View` - # is included. + # Prepare the views. # - # If not set, this option will be ignored. + # The given block will be yielded when `Lotus::View` will be included by + # a view. # - # This is part of a DSL, for this reason when this method is called with - # an argument, it will set the corresponding instance variable. When - # called without, it will return the already set value, or the default. + # This method can be called multiple times. # - # @overload modules(blk) - # Adds the given block - # @param value [Proc] specify the modules to be included + # @param blk [Proc] the code block # - # @overload modules - # Gets the value - # @return [Array] the list of the specified procs + # @return [void] + # + # @raise [ArgumentError] if called without passing a block # # @since 0.3.0 # - # @see Lotus::View#duplicate + # @see Lotus::View.configure + # @see Lotus::View.duplicate # - # @example Getting the value + # @example Including shared utilities # require 'lotus/view' # - # Lotus::View.configuration.modules # => [] + # module UrlHelpers + # def comments_path + # '/' + # end + # end + # + # Lotus::View.configure do + # prepare do + # include UrlHelpers + # end + # end # - # @example Setting the value + # Lotus::View.load! + # + # module Comments + # class New + # # The following include will cause UrlHelpers to be included too. + # # This makes `comments_path` available in the view context + # include Lotus::View + # + # def form + # %(
) + # end + # end + # end + # + # @example Preparing multiple times # require 'lotus/view' # # Lotus::View.configure do - # modules do - # include MyCustomModule + # prepare do + # include UrlHelpers + # end + # + # prepare do + # format :json + # end + # end + # + # Lotus::View.configure do + # prepare do + # include FormattingHelpers # end # end # - # class Articles + # Lotus::View.load! + # + # module Articles # class Index + # # The following include will cause the inclusion of: + # # * UrlHelpers + # # * FormattingHelpers + # # + # # It also sets the view to render only JSON # include Lotus::View - # - # # It includes: - # # * MyCustomModule # end # end - def modules(&blk) + def prepare(&blk) if block_given? @modules.push(blk) else - @modules + raise ArgumentError.new('Please provide a block') end end diff --git a/test/fixtures.rb b/test/fixtures.rb index 8bfe3b53..a0a2d9d9 100644 --- a/test/fixtures.rb +++ b/test/fixtures.rb @@ -234,7 +234,7 @@ module CardDeck namespace CardDeck root __dir__ + '/fixtures/templates/card_deck/app/templates' layout :application - modules do + prepare do include MyCustomModule include MyOtherCustomModule end diff --git a/test/integration/template_name_test.rb b/test/integration/template_name_test.rb index c354359c..a7ff241d 100644 --- a/test/integration/template_name_test.rb +++ b/test/integration/template_name_test.rb @@ -2,6 +2,11 @@ describe 'Template name' do before do + ## + # Reset the configuration + # + Lotus::View.unload! + # # # # # Standalone usage: diff --git a/test/view/configuration_test.rb b/test/view/configuration_test.rb index 1d79c9cf..8b7c28f2 100644 --- a/test/view/configuration_test.rb +++ b/test/view/configuration_test.rb @@ -143,13 +143,48 @@ class LazyLayout end end - describe 'duplicate' do + describe '#prepare' do + before do + module FooRendering + def render + 'foo' + end + end + + class PrepareView + end + end + + after do + Object.__send__(:remove_const, :FooRendering) + Object.__send__(:remove_const, :PrepareView) + end + + it 'allows to set a code block to be yielded when Lotus::View is included' do + Lotus::View.configure do + prepare do + include FooRendering + end + end + + PrepareView.__send__(:include, Lotus::View) + PrepareView.render({format: :html}).must_equal 'foo' + end + + it 'raises error in case of missing block' do + exception = -> { @configuration.prepare }.must_raise(ArgumentError) + exception.message.must_equal('Please provide a block') + end + end + + describe '#duplicate' do before do @configuration.root 'test' @configuration.load_paths << '..' @configuration.layout :application @configuration.add_view(HelloWorldView) @configuration.add_layout(ApplicationLayout) + @configuration.prepare { include Kernel } @config = @configuration.duplicate end @@ -158,6 +193,7 @@ class LazyLayout @config.root.must_equal @configuration.root @config.load_paths.must_equal @configuration.load_paths @config.layout.must_equal @configuration.layout + @config.modules.must_equal @configuration.modules @config.views.must_be_empty @config.layouts.must_be_empty end @@ -168,6 +204,7 @@ class LazyLayout @config.layout :global @config.add_view(RenderView) @config.add_layout(GlobalLayout) + @config.prepare { include Comparable } @config.root.must_equal Pathname.new('.').realpath @@ -178,6 +215,7 @@ class LazyLayout @config.layout.must_equal GlobalLayout @config.views.must_include RenderView @config.layouts.must_include GlobalLayout + @config.modules.size.must_equal 2 @configuration.root.must_equal Pathname.new('test').realpath diff --git a/test/view_test.rb b/test/view_test.rb index 11a99adf..39a72b66 100644 --- a/test/view_test.rb +++ b/test/view_test.rb @@ -201,6 +201,10 @@ class AppLayout assert defined?(Duplicated::Layout), 'Duplicated::Layout expected' end + it 'duplicates Presenter' do + assert defined?(Duplicated::Presenter), 'Duplicated::Presenter expected' + end + it 'optionally accepts a block to configure the generated module' do expected = DuplicatedConfigure::Views::AppLayout DuplicatedConfigure::View.configuration.layout.must_equal expected