From: Jean-Philippe Lang Date: Sat, 18 Aug 2012 08:25:22 +0000 (+0000) Subject: Let macros optionally accept a block of text (#3061). X-Git-Tag: 2.1.0~122 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=fc3a09e49a692ce2307e78cd414242abd2c31e7d;p=redmine.git Let macros optionally accept a block of text (#3061). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@10210 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 74032496f..cfa9cb5ab 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -866,10 +866,11 @@ module ApplicationHelper ( \{\{ # opening tag ([\w]+) # macro name - (\((.*?)\))? # optional arguments + (\(([^\n\r]*?)\))? # optional arguments + ([\n\r].*[\n\r])? # optional block of text \}\} # closing tag ) - )/x unless const_defined?(:MACROS_RE) + )/mx unless const_defined?(:MACROS_RE) MACRO_SUB_RE = /( \{\{ @@ -899,9 +900,9 @@ module ApplicationHelper all, index = $1, $2.to_i orig = macros.delete(index) if execute && orig && orig =~ MACROS_RE - esc, all, macro, args = $2, $3, $4.downcase, $6.to_s + esc, all, macro, args, block = $2, $3, $4.downcase, $6.to_s, $7.try(:strip) if esc.nil? - h(exec_macro(macro, obj, args) || all) + h(exec_macro(macro, obj, args, block) || all) else h(all) end diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb index 55bde5e29..16a3239ee 100644 --- a/lib/redmine/wiki_formatting/macros.rb +++ b/lib/redmine/wiki_formatting/macros.rb @@ -24,7 +24,7 @@ module Redmine Redmine::WikiFormatting::Macros.available_macros.key?(name.to_sym) end - def exec_macro(name, obj, args) + def exec_macro(name, obj, args, text) macro_options = Redmine::WikiFormatting::Macros.available_macros[name.to_sym] return unless macro_options @@ -34,7 +34,13 @@ module Redmine end begin - send(method_name, obj, args) if respond_to?(method_name) + if self.class.instance_method(method_name).arity == 3 + send(method_name, obj, args, text) + elsif text + raise "This macro does not accept a block of text" + else + send(method_name, obj, args) + end rescue => e "
Error executing the #{h name} macro (#{h e.to_s})
".html_safe end @@ -55,9 +61,11 @@ module Redmine class << self # Called with a block to define additional macros. - # Macro blocks accept 2 arguments: + # Macro blocks accept 2 or 3 arguments: # * obj: the object that is rendered # * args: macro arguments + # * text: a block of text (if the macro accepts + # 3 arguments) # # Plugins can use this method to define new macros: # @@ -66,7 +74,33 @@ module Redmine # macro :my_macro do |obj, args| # "My macro output" # end + # + # desc "This is my macro that accepts a block of text" + # macro :my_macro do |obj, args, text| + # "My macro output" + # end # end + # + # Macros are invoked in formatted text using the following + # syntax: + # + # No arguments: + # {{my_macro}} + # + # With arguments: + # {{my_macro(arg1, arg2)}} + # + # With a block of text: + # {{my_macro + # multiple lines + # of text + # }} + # + # With arguments and a block of text + # {{my_macro(arg1, arg2) + # multiple lines + # of text + # }} def register(&block) class_eval(&block) if block_given? end @@ -79,7 +113,7 @@ module Redmine # # Examples: # By default, when the macro is invoked, the coma separated list of arguments - # is parsed and passed to the macro block as an array: + # is split and passed to the macro block as an array: # # macro :my_macro do |obj, args| # # args is an array @@ -106,8 +140,11 @@ module Redmine # Builtin macros desc "Sample macro." - macro :hello_world do |obj, args| - h("Hello world! Object: #{obj.class.name}, " + (args.empty? ? "Called with no argument." : "Arguments: #{args.join(', ')}")) + macro :hello_world do |obj, args, text| + h("Hello world! Object: #{obj.class.name}, " + + (args.empty? ? "Called with no argument" : "Arguments: #{args.join(', ')}") + + " and " + (text.present? ? "a #{text.size} bytes long block of text." : "no block of text.") + ) end desc "Displays a list of all available macros, including description if available." diff --git a/test/unit/lib/redmine/wiki_formatting/macros_test.rb b/test/unit/lib/redmine/wiki_formatting/macros_test.rb index b313e8b80..901184909 100644 --- a/test/unit/lib/redmine/wiki_formatting/macros_test.rb +++ b/test/unit/lib/redmine/wiki_formatting/macros_test.rb @@ -65,6 +65,19 @@ class Redmine::WikiFormatting::MacrosTest < ActionView::TestCase assert_equal '

Bar: () (String)

', textilizable("{{bar()}}") end + def test_macro_registration_with_3_args_should_receive_text_argument + Redmine::WikiFormatting::Macros.register do + macro :baz do |obj, args, text| + "Baz: (#{args.join(',')}) (#{text.class.name}) (#{text})" + end + end + + assert_equal "

Baz: () (NilClass) ()

", textilizable("{{baz}}") + assert_equal "

Baz: () (NilClass) ()

", textilizable("{{baz()}}") + assert_equal "

Baz: () (String) (line1\nline2)

", textilizable("{{baz()\nline1\nline2\n}}") + assert_equal "

Baz: (arg1,arg2) (String) (line1\nline2)

", textilizable("{{baz(arg1, arg2)\nline1\nline2\n}}") + end + def test_multiple_macros_on_the_same_line Redmine::WikiFormatting::Macros.macro :foo do |obj, args| args.any? ? "args: #{args.join(',')}" : "no args" @@ -79,14 +92,15 @@ class Redmine::WikiFormatting::MacrosTest < ActionView::TestCase def test_macro_should_receive_the_object_as_argument_when_with_object_and_attribute issue = Issue.find(1) issue.description = "{{hello_world}}" - assert_equal '

Hello world! Object: Issue, Called with no argument.

', textilizable(issue, :description) + assert_equal '

Hello world! Object: Issue, Called with no argument and no block of text.

', textilizable(issue, :description) end def test_macro_should_receive_the_object_as_argument_when_called_with_object_option text = "{{hello_world}}" - assert_equal '

Hello world! Object: Issue, Called with no argument.

', textilizable(text, :object => Issue.find(1)) + assert_equal '

Hello world! Object: Issue, Called with no argument and no block of text.

', textilizable(text, :object => Issue.find(1)) end + def test_macro_exception_should_be_displayed Redmine::WikiFormatting::Macros.macro :exception do |obj, args| raise "My message" @@ -237,14 +251,14 @@ class Redmine::WikiFormatting::MacrosTest < ActionView::TestCase RAW expected = <<-EXPECTED -

Hello world! Object: NilClass, Arguments: foo

+

Hello world! Object: NilClass, Arguments: foo and no block of text.

 {{hello_world(pre)}}
 !{{hello_world(pre)}}
 
-

Hello world! Object: NilClass, Arguments: bar

+

Hello world! Object: NilClass, Arguments: bar and no block of text.

EXPECTED assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(text).gsub(%r{[\r\n\t]}, '') @@ -257,6 +271,6 @@ EXPECTED def test_macros_should_not_mangle_next_macros_outputs text = '{{macro(2)}} !{{macro(2)}} {{hello_world(foo)}}' - assert_equal '

{{macro(2)}} {{macro(2)}} Hello world! Object: NilClass, Arguments: foo

', textilizable(text) + assert_equal '

{{macro(2)}} {{macro(2)}} Hello world! Object: NilClass, Arguments: foo and no block of text.

', textilizable(text) end end