From 4289559b5fc7cad22d14d4f567e75e1a7b5f807a Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 26 Apr 2011 12:42:17 -0700 Subject: [PATCH 01/22] [#604] Require the liquid gem --- Gemfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Gemfile b/Gemfile index 49d96fb1..2bb6fb48 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,7 @@ gem "coderay", "~> 0.9.7" gem "i18n", "~> 0.4.2" gem "rubytree", "~> 0.5.2", :require => 'tree' gem "rdoc", ">= 2.4.2" +gem "liquid", "~> 2.3.0" # Needed only on RUBY_VERSION = 1.8, ruby 1.9+ compatible interpreters should bring their csv gem "fastercsv", "~> 1.5.0", :platforms => [:ruby_18, :jruby, :mingw_18] From 7261622196470f8a36c34c5e1b3ce944df9670fa Mon Sep 17 00:00:00 2001 From: Holger Just Date: Sat, 19 Nov 2011 23:31:58 +0100 Subject: [PATCH 02/22] [#604] Add base drop --- app/drops/base_drop.rb | 23 +++++++++++++++++++++++ config/environment.rb | 3 +++ 2 files changed, 26 insertions(+) create mode 100644 app/drops/base_drop.rb diff --git a/app/drops/base_drop.rb b/app/drops/base_drop.rb new file mode 100644 index 00000000..18355cc1 --- /dev/null +++ b/app/drops/base_drop.rb @@ -0,0 +1,23 @@ +class BaseDrop < Liquid::Drop + def initialize(object) + @object = object unless object.respond_to?(:visible?) && !object.visible? + end + + # Defines a Liquid method on the drop that is allowed to call the + # Ruby method directly. Best used for attributes. + # + # Based on Module#liquid_methods + def self.allowed_methods(*allowed_methods) + class_eval do + allowed_methods.each do |sym| + define_method sym do + if @object.respond_to?(:public_send) + @object.public_send(sym) rescue nil + else + @object.send(sym) rescue nil + end + end + end + end + end +end diff --git a/config/environment.rb b/config/environment.rb index 3c174193..0ae61ffe 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -49,6 +49,9 @@ Rails::Initializer.run do |config| # (by default production uses :info, the others :debug) # config.log_level = :debug + # Liquid drops + config.autoload_paths += %W( #{RAILS_ROOT}/app/drops ) + # Enable page/fragment caching by setting a file-based store # (remember to create the caching directory and make it readable to the application) # config.action_controller.cache_store = :file_store, "#{RAILS_ROOT}/tmp/cache" From 91914cb877497417dea72af676752f878f75bde4 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 26 Apr 2011 13:17:18 -0700 Subject: [PATCH 03/22] [#604] Add simple Liquid drops for Projects and Principals --- app/drops/principal_drop.rb | 3 +++ app/drops/project_drop.rb | 3 +++ app/models/principal.rb | 4 +++ app/models/project.rb | 9 +++++++ test/unit/principal_drop_test.rb | 15 ++++++++++++ test/unit/project_drop_test.rb | 42 ++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+) create mode 100644 app/drops/principal_drop.rb create mode 100644 app/drops/project_drop.rb create mode 100644 test/unit/principal_drop_test.rb create mode 100644 test/unit/project_drop_test.rb diff --git a/app/drops/principal_drop.rb b/app/drops/principal_drop.rb new file mode 100644 index 00000000..24a94ea9 --- /dev/null +++ b/app/drops/principal_drop.rb @@ -0,0 +1,3 @@ +class PrincipalDrop < BaseDrop + allowed_methods :name +end diff --git a/app/drops/project_drop.rb b/app/drops/project_drop.rb new file mode 100644 index 00000000..f14a7799 --- /dev/null +++ b/app/drops/project_drop.rb @@ -0,0 +1,3 @@ +class ProjectDrop < BaseDrop + allowed_methods :name, :identifier +end diff --git a/app/models/principal.rb b/app/models/principal.rb index 00207f5e..3c390bb2 100644 --- a/app/models/principal.rb +++ b/app/models/principal.rb @@ -31,6 +31,10 @@ class Principal < ActiveRecord::Base before_create :set_default_empty_values + def to_liquid + PrincipalDrop.new(self) + end + def name(formatter = nil) to_s end diff --git a/app/models/project.rb b/app/models/project.rb index 5fe6a8b8..299d7017 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -83,6 +83,10 @@ class Project < ActiveRecord::Base named_scope :all_public, { :conditions => { :is_public => true } } named_scope :visible, lambda { { :conditions => Project.visible_by(User.current) } } + def to_liquid + ProjectDrop.new(self) + end + def initialize(attributes = nil) super @@ -131,6 +135,11 @@ class Project < ActiveRecord::Base end end + # Is the project visible to the current user + def visible? + User.current.allowed_to?(:view_project, self) + end + def self.allowed_to_condition(user, permission, options={}) base_statement = "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}" if perm = Redmine::AccessControl.permission(permission) diff --git a/test/unit/principal_drop_test.rb b/test/unit/principal_drop_test.rb new file mode 100644 index 00000000..b19adfd0 --- /dev/null +++ b/test/unit/principal_drop_test.rb @@ -0,0 +1,15 @@ +require File.expand_path('../../test_helper', __FILE__) + +class PrincipalDropTest < ActiveSupport::TestCase + def setup + @principal = Principal.generate! + @drop = @principal.to_liquid + end + + + context "#name" do + should "return the name" do + assert_equal @principal.name, @drop.name + end + end +end diff --git a/test/unit/project_drop_test.rb b/test/unit/project_drop_test.rb new file mode 100644 index 00000000..677bda04 --- /dev/null +++ b/test/unit/project_drop_test.rb @@ -0,0 +1,42 @@ +require File.expand_path('../../test_helper', __FILE__) + +class ProjectDropTest < ActiveSupport::TestCase + def setup + @project = Project.generate! + User.current = @user = User.generate! + @role = Role.generate! + Member.generate!(:principal => @user, :project => @project, :roles => [@role]) + @drop = @project.to_liquid + end + + context "drop" do + should "be a ProjectDrop" do + assert @drop.is_a?(ProjectDrop), "drop is not a ProjectDrop" + end + end + + + context "#name" do + should "return the project name" do + assert_equal @project.name, @drop.name + end + end + + context "#identifier" do + should "return the project identifier" do + assert_equal @project.identifier, @drop.identifier + end + end + + should "only load an object if it's visible to the current user" do + assert User.current.logged? + assert @project.visible? + + @private_project = Project.generate!(:is_public => false) + + assert !@private_project.visible?, "Project is visible" + @private_drop = ProjectDrop.new(@private_project) + assert_equal nil, @private_drop.instance_variable_get("@object") + assert_equal nil, @private_drop.name + end +end From 6f8d8c410591d7a8598163b3ff13505c34d74b86 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 3 May 2011 13:25:41 -0700 Subject: [PATCH 04/22] [#604] Add basic WikiPageDrop --- app/drops/wiki_page_drop.rb | 3 +++ app/models/wiki_page.rb | 4 ++++ test/unit/wiki_page_drop_test.rb | 40 ++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 app/drops/wiki_page_drop.rb create mode 100644 test/unit/wiki_page_drop_test.rb diff --git a/app/drops/wiki_page_drop.rb b/app/drops/wiki_page_drop.rb new file mode 100644 index 00000000..27c9be4f --- /dev/null +++ b/app/drops/wiki_page_drop.rb @@ -0,0 +1,3 @@ +class WikiPageDrop < BaseDrop + allowed_methods :title +end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 16566f05..d2208dfa 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -53,6 +53,10 @@ class WikiPage < ActiveRecord::Base end end + def to_liquid + WikiPageDrop.new(self) + end + def visible?(user=User.current) !user.nil? && user.allowed_to?(:view_wiki_pages, project) end diff --git a/test/unit/wiki_page_drop_test.rb b/test/unit/wiki_page_drop_test.rb new file mode 100644 index 00000000..5093c22a --- /dev/null +++ b/test/unit/wiki_page_drop_test.rb @@ -0,0 +1,40 @@ +require File.expand_path('../../test_helper', __FILE__) + +class WikiPageDropTest < ActiveSupport::TestCase + def setup + @project = Project.generate! + @wiki = Wiki.generate(:project => @project) + @wiki_page = WikiPage.generate!(:wiki => @wiki) + User.current = @user = User.generate! + @role = Role.generate!(:permissions => [:view_wiki_pages]) + Member.generate!(:principal => @user, :project => @project, :roles => [@role]) + @drop = @wiki_page.to_liquid + end + + context "drop" do + should "be a WikiPageDrop" do + assert @drop.is_a?(WikiPageDrop), "drop is not a WikiPageDrop" + end + end + + + context "#title" do + should "return the title of the wiki page" do + assert_equal @wiki_page.title, @drop.title + end + end + + should "only load an object if it's visible to the current user" do + assert User.current.logged? + assert @wiki_page.visible? + + @private_project = Project.generate!(:is_public => false) + @private_wiki = Wiki.generate!(:project => @private_project) + @private_wiki_page = WikiPage.generate!(:wiki => @private_wiki) + + assert !@private_wiki_page.visible?, "WikiPage is visible" + @private_drop = WikiPageDrop.new(@private_wiki_page) + assert_equal nil, @private_drop.instance_variable_get("@object") + assert_equal nil, @private_drop.title + end +end From 7906afe6b9ebfa2c9af031503ba5dfb27b0d707f Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 3 May 2011 16:36:44 -0700 Subject: [PATCH 05/22] [#604] Add an IssueDrop with custom field support --- app/drops/issue_drop.rb | 65 +++++++++++++++++++++ app/drops/issue_status_drop.rb | 3 + app/drops/tracker_drop.rb | 3 + app/models/issue.rb | 4 ++ app/models/issue_status.rb | 4 ++ app/models/tracker.rb | 4 ++ test/unit/issue_drop_test.rb | 89 +++++++++++++++++++++++++++++ test/unit/issue_status_drop_test.rb | 21 +++++++ test/unit/tracker_drop_test.rb | 20 +++++++ 9 files changed, 213 insertions(+) create mode 100644 app/drops/issue_drop.rb create mode 100644 app/drops/issue_status_drop.rb create mode 100644 app/drops/tracker_drop.rb create mode 100644 test/unit/issue_drop_test.rb create mode 100644 test/unit/issue_status_drop_test.rb create mode 100644 test/unit/tracker_drop_test.rb diff --git a/app/drops/issue_drop.rb b/app/drops/issue_drop.rb new file mode 100644 index 00000000..40d3f572 --- /dev/null +++ b/app/drops/issue_drop.rb @@ -0,0 +1,65 @@ +class IssueDrop < BaseDrop + allowed_methods :id + allowed_methods :subject + allowed_methods :description + allowed_methods :project + allowed_methods :tracker + allowed_methods :status + allowed_methods :due_date + allowed_methods :category + allowed_methods :assigned_to + allowed_methods :priority + allowed_methods :fixed_version + allowed_methods :author + allowed_methods :created_on + allowed_methods :updated_on + allowed_methods :start_date + allowed_methods :done_ratio + allowed_methods :estimated_hours + allowed_methods :parent + + def custom_field(name) + return '' unless name.present? + custom_field = IssueCustomField.find_by_name(name.strip) + return '' unless custom_field.present? + custom_value = @object.custom_value_for(custom_field) + if custom_value.present? + return custom_value.value + else + return '' + end + end + + # TODO: both required, method_missing for Ruby and before_method for Liquid + + # Allows accessing custom fields by their name: + # + # - issue.the_name_of_player => CustomField(:name => "The name Of Player") + # + def before_method(method_sym) + if custom_field_with_matching_name = has_custom_field_with_matching_name?(method_sym) + custom_field(custom_field_with_matching_name.name) + else + super + end + end + + # Allows accessing custom fields by their name: + # + # - issue.the_name_of_player => CustomField(:name => "The name Of Player") + # + def method_missing(method_sym, *arguments, &block) + if custom_field_with_matching_name = has_custom_field_with_matching_name?(method_sym) + custom_field(custom_field_with_matching_name.name) + else + super + end + end + +private + def has_custom_field_with_matching_name?(method_sym) + custom_field_with_matching_name = @object.available_custom_fields.detect {|custom_field| + custom_field.name.downcase.underscore.gsub(' ','_') == method_sym.to_s + } + end +end diff --git a/app/drops/issue_status_drop.rb b/app/drops/issue_status_drop.rb new file mode 100644 index 00000000..88d1a9dc --- /dev/null +++ b/app/drops/issue_status_drop.rb @@ -0,0 +1,3 @@ +class IssueStatusDrop < BaseDrop + allowed_methods :name +end diff --git a/app/drops/tracker_drop.rb b/app/drops/tracker_drop.rb new file mode 100644 index 00000000..3bcf4a0e --- /dev/null +++ b/app/drops/tracker_drop.rb @@ -0,0 +1,3 @@ +class TrackerDrop < BaseDrop + allowed_methods :name +end diff --git a/app/models/issue.rb b/app/models/issue.rb index cc754014..233e2bb1 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -103,6 +103,10 @@ class Issue < ActiveRecord::Base (usr || User.current).allowed_to?(:view_issues, self.project) end + def to_liquid + IssueDrop.new(self) + end + def after_initialize if new_record? # set default values for new records only diff --git a/app/models/issue_status.rb b/app/models/issue_status.rb index 7078237d..637aaafb 100644 --- a/app/models/issue_status.rb +++ b/app/models/issue_status.rb @@ -28,6 +28,10 @@ class IssueStatus < ActiveRecord::Base IssueStatus.update_all("is_default=#{connection.quoted_false}", ['id <> ?', id]) if self.is_default? end + def to_liquid + IssueStatusDrop.new(self) + end + # Returns the default status for new issues def self.default find(:first, :conditions =>["is_default=?", true]) diff --git a/app/models/tracker.rb b/app/models/tracker.rb index 353645f7..94b75845 100644 --- a/app/models/tracker.rb +++ b/app/models/tracker.rb @@ -35,6 +35,10 @@ class Tracker < ActiveRecord::Base name <=> tracker.name end + def to_liquid + TrackerDrop.new(self) + end + def self.all find(:all, :order => 'position') end diff --git a/test/unit/issue_drop_test.rb b/test/unit/issue_drop_test.rb new file mode 100644 index 00000000..b3c034a2 --- /dev/null +++ b/test/unit/issue_drop_test.rb @@ -0,0 +1,89 @@ +require File.expand_path('../../test_helper', __FILE__) + +class IssueDropTest < ActiveSupport::TestCase + include ApplicationHelper + + def setup + @project = Project.generate! + @issue = Issue.generate_for_project!(@project) + User.current = @user = User.generate! + @role = Role.generate!(:permissions => [:view_issues]) + Member.generate!(:principal => @user, :project => @project, :roles => [@role]) + @drop = @issue.to_liquid + end + + context "drop" do + should "be a IssueDrop" do + assert @drop.is_a?(IssueDrop), "drop is not a IssueDrop" + end + end + + + [ + :tracker, + :project, + :subject, + :description, + :due_date, + :category, + :status, + :assigned_to, + :priority, + :fixed_version, + :author, + :created_on, + :updated_on, + :start_date, + :done_ratio, + :estimated_hours, + :parent + ].each do |attribute| + + should "IssueDrop##{attribute} should return the actual #{attribute} attribute" do + assert @issue.respond_to?(attribute), "Issue does not have an #{attribute} method" + assert @drop.respond_to?(attribute), "IssueDrop does not have an #{attribute} method" + + assert_equal @issue.send(attribute), @drop.send(attribute) + end + end + + context "custom fields" do + setup do + @field = IssueCustomField.generate!(:name => 'The Name', :field_format => 'string', :is_for_all => true, :trackers => @project.trackers) + @field_name_conflict = IssueCustomField.generate!(:name => 'Subject', :field_format => 'string', :is_for_all => true, :trackers => @project.trackers) + @issue.custom_fields = [{'id' => @field.id, 'value' => 'Custom field value'}, + {'id' => @field_name_conflict.id, 'value' => 'Second subject'}] + assert @issue.save + assert_equal "Custom field value", @issue.reload.custom_value_for(@field).value + assert_equal "Second subject", @issue.reload.custom_value_for(@field_name_conflict).value + @drop = @issue.to_liquid + end + + should "be accessible under #custom_field(name)" do + assert_equal @issue.reload.custom_value_for(@field).value, @drop.custom_field('The Name') + end + + should "be accessible under the custom field name (lowercase, underscored)" do + assert_equal @issue.reload.custom_value_for(@field).value, @drop.the_name + + assert textilizable("{{issue.the_name}}").include?("Custom field value") + end + + should "not be accessible under the custom field name if it conflict with an existing drop method" do + assert_equal @issue.subject, @drop.subject # no confict + end + end + + should "only load an object if it's visible to the current user" do + assert User.current.logged? + assert @issue.visible? + + @private_project = Project.generate!(:is_public => false) + @private_issue = Issue.generate_for_project!(@private_project) + + assert !@private_issue.visible?, "Issue is visible" + @private_drop = IssueDrop.new(@private_issue) + assert_equal nil, @private_drop.instance_variable_get("@object") + assert_equal nil, @private_drop.subject + end +end \ No newline at end of file diff --git a/test/unit/issue_status_drop_test.rb b/test/unit/issue_status_drop_test.rb new file mode 100644 index 00000000..83cbe24e --- /dev/null +++ b/test/unit/issue_status_drop_test.rb @@ -0,0 +1,21 @@ +require File.expand_path('../../test_helper', __FILE__) + +class IssueStatusDropTest < ActiveSupport::TestCase + def setup + @issue_status = IssueStatus.generate! + @drop = @issue_status.to_liquid + end + + context "drop" do + should "be a IssueStatusDrop" do + assert @drop.is_a?(IssueStatusDrop), "drop is not a IssueStatusDrop" + end + end + + + context "#name" do + should "return the name" do + assert_equal @issue_status.name, @drop.name + end + end +end diff --git a/test/unit/tracker_drop_test.rb b/test/unit/tracker_drop_test.rb new file mode 100644 index 00000000..ff619d72 --- /dev/null +++ b/test/unit/tracker_drop_test.rb @@ -0,0 +1,20 @@ +require File.expand_path('../../test_helper', __FILE__) + +class TrackerDropTest < ActiveSupport::TestCase + def setup + @tracker = Tracker.generate! + @drop = @tracker.to_liquid + end + + context "drop" do + should "be a TrackerDrop" do + assert @drop.is_a?(TrackerDrop), "drop is not a TrackerDrop" + end + end + + context "#name" do + should "return the name" do + assert_equal @tracker.name, @drop.name + end + end +end From 981143f78fa66e4c4357ec7cbb35675710abeb40 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 26 Apr 2011 12:41:57 -0700 Subject: [PATCH 06/22] [#604] Disable classic ChiliProject wiki macros --- lib/redmine/wiki_formatting.rb | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/lib/redmine/wiki_formatting.rb b/lib/redmine/wiki_formatting.rb index cf5f4516..ac9ae734 100644 --- a/lib/redmine/wiki_formatting.rb +++ b/lib/redmine/wiki_formatting.rb @@ -41,7 +41,7 @@ module Redmine end def to_html(format, text, options = {}, &block) - text = if Setting.cache_formatted_text? && text.size > 2.kilobyte && cache_store && cache_key = cache_key_for(format, options[:object], options[:attribute]) + if Setting.cache_formatted_text? && text.size > 2.kilobyte && cache_store && cache_key = cache_key_for(format, options[:object], options[:attribute]) # Text retrieved from the cache store may be frozen # We need to dup it so we can do in-place substitutions with gsub! cache_store.fetch cache_key do @@ -50,10 +50,6 @@ module Redmine else formatter_for(format).new(text).to_html end - if block_given? - execute_macros(text, block) - end - text end # Returns a cache key for the given text +format+, +object+ and +attribute+ or nil if no caching should be done @@ -67,33 +63,6 @@ module Redmine def cache_store ActionController::Base.cache_store end - - MACROS_RE = / - (!)? # escaping - ( - \{\{ # opening tag - ([\w]+) # macro name - (\(([^\}]*)\))? # optional arguments - \}\} # closing tag - ) - /x unless const_defined?(:MACROS_RE) - - # Macros substitution - def execute_macros(text, macros_runner) - text.gsub!(MACROS_RE) do - esc, all, macro = $1, $2, $3.downcase - args = ($5 || '').split(',').each(&:strip) - if esc.nil? - begin - macros_runner.call(macro, args) - rescue => e - "
Error executing the #{macro} macro (#{e})
" - end || all - else - all - end - end - end end end end From 72fa3ff920eb26f542328a121a429840dc848771 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 26 Apr 2011 12:44:02 -0700 Subject: [PATCH 07/22] [#604] Run the output of the WikiFormatted text into Liquid The current view's instance variables are sent to liquid dynamically --- app/helpers/application_helper.rb | 43 ++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 5e24410f..a089d9e5 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -461,7 +461,29 @@ module ApplicationHelper project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) only_path = options.delete(:only_path) == false ? false : true - text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) } + begin + text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) } + liquid_template = Liquid::Template.parse(text) + liquid_variables = get_view_instance_variables_for_liquid + liquid_variables.merge!({'current_user' => User.current}) + liquid_variables.merge!({'toc' => '{{toc}}'}) # Pass toc through to replace later + liquid_variables.merge!(ChiliProject::Liquid::Variables.macro_backwards_compatibility) + # Pass :view in a register so this view (with helpers) can be used inside of a tag + text = liquid_template.render(liquid_variables, :registers => {:view => self}) + + # Add Liquid errors to the log + if Rails.logger && Rails.logger.debug? + msg = "" + liquid_template.errors.each do |exception| + msg << "[Liquid Error] #{exception.message}\n:\n#{exception.backtrace.join("\n")}" + msg << "\n\n" + end + Rails.logger.debug msg + end + text + rescue Liquid::SyntaxError + # Skip Liquid if there is a syntax error + end @parsed_headings = [] text = parse_non_pre_blocks(text) do |text| @@ -1006,4 +1028,23 @@ module ApplicationHelper def link_to_content_update(text, url_params = {}, html_options = {}) link_to(text, url_params, html_options) end + + def get_view_instance_variables_for_liquid + self.instance_variables.reject do |ivar| + ivar.match(/@_/) || # Rails "internal" variables: @_foo + ivar.match(/@template/) || + ivar == '@output_buffer' || + ivar == '@cookies' || + ivar == '@helpers' || + ivar == '@real_format' || + ivar == '@assigns_added' || + ivar == '@assigns' || + ivar == '@view_paths' || + ivar == '@controller' + end.inject({}) do |acc,ivar| + acc[ivar.sub('@','')] = instance_variable_get(ivar) + acc + end + end + end From 82432f3f991f4c4534ce8747d765fa553a7999a5 Mon Sep 17 00:00:00 2001 From: Holger Just Date: Fri, 9 Sep 2011 23:35:24 +0200 Subject: [PATCH 08/22] [#604] Evaluate Liquid before Textile-to-HTML transformation. This changes how the liquid integration works. It now integrates the Textile conversion step. This was necessary because if you first convert the snippets inside of loops and conditionals from Textile to HTML, you loose some important context information which is required to e.g. build proper lists in textile. We expect the standard case that Liquid tags return Textile markup instead of HTML. Thus, we can convert the final textile markup to HTML as a very last step. To allow existing and new macros (or tags) to return HTML for advanced usage, we save their respective output into the context and put a placeholder string into the generated markup. After the transformation to HTML, we insert the previously generated HTML into the string using search+replace in lib/chili_project/liquid/template.rb. Tags have to be registered using :html => true for this special treatment. --- app/helpers/application_helper.rb | 11 +-- lib/chili_project/liquid.rb | 7 ++ lib/chili_project/liquid/liquid_ext.rb | 7 ++ .../liquid/liquid_ext/context.rb | 29 ++++++ lib/chili_project/liquid/tags.rb | 32 +++++++ lib/chili_project/liquid/template.rb | 96 +++++++++++++++++++ 6 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 lib/chili_project/liquid.rb create mode 100644 lib/chili_project/liquid/liquid_ext.rb create mode 100644 lib/chili_project/liquid/liquid_ext/context.rb create mode 100644 lib/chili_project/liquid/tags.rb create mode 100644 lib/chili_project/liquid/template.rb diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a089d9e5..7b2d50e4 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -462,14 +462,14 @@ module ApplicationHelper only_path = options.delete(:only_path) == false ? false : true begin - text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) } - liquid_template = Liquid::Template.parse(text) + liquid_template = ChiliProject::Liquid::Template.parse(text) liquid_variables = get_view_instance_variables_for_liquid liquid_variables.merge!({'current_user' => User.current}) liquid_variables.merge!({'toc' => '{{toc}}'}) # Pass toc through to replace later liquid_variables.merge!(ChiliProject::Liquid::Variables.macro_backwards_compatibility) + # Pass :view in a register so this view (with helpers) can be used inside of a tag - text = liquid_template.render(liquid_variables, :registers => {:view => self}) + text = liquid_template.render(liquid_variables, :registers => {:view => self, :object => obj, :attribute => attr}) # Add Liquid errors to the log if Rails.logger && Rails.logger.debug? @@ -480,7 +480,6 @@ module ApplicationHelper end Rails.logger.debug msg end - text rescue Liquid::SyntaxError # Skip Liquid if there is a syntax error end @@ -962,7 +961,7 @@ module ApplicationHelper # Expands the current menu item using JavaScript based on the params def expand_current_menu current_menu_class = - case + case when params[:controller] == "timelog" "reports" when params[:controller] == 'projects' && params[:action] == 'changelog' @@ -981,7 +980,7 @@ module ApplicationHelper params[:controller] end - + javascript_tag("jQuery.menu_expand({ menuItem: '.#{current_menu_class}' });") end diff --git a/lib/chili_project/liquid.rb b/lib/chili_project/liquid.rb new file mode 100644 index 00000000..e9aeffd3 --- /dev/null +++ b/lib/chili_project/liquid.rb @@ -0,0 +1,7 @@ +require 'chili_project/liquid/liquid_ext' +require 'chili_project/liquid/tags' + +module ChiliProject + module Liquid + end +end diff --git a/lib/chili_project/liquid/liquid_ext.rb b/lib/chili_project/liquid/liquid_ext.rb new file mode 100644 index 00000000..b35798a9 --- /dev/null +++ b/lib/chili_project/liquid/liquid_ext.rb @@ -0,0 +1,7 @@ +module ChiliProject + module Liquid + module LiquidExt + ::Liquid::Context.send(:include, Context) + end + end +end diff --git a/lib/chili_project/liquid/liquid_ext/context.rb b/lib/chili_project/liquid/liquid_ext/context.rb new file mode 100644 index 00000000..777f820f --- /dev/null +++ b/lib/chili_project/liquid/liquid_ext/context.rb @@ -0,0 +1,29 @@ +module ChiliProject + module Liquid + module LiquidExt + module Context + def self.included(base) + base.send(:include, InstanceMethods) + end + + module InstanceMethods + def html_result(html) + key = nil + while key.nil? || html_results.has_key?(key) + random = ActiveSupport::SecureRandom.hex(10) + # This string must be passed untouched through Liquid and textile + # It mustn't be changed in any way by any rendering stage. + key = "!!html_results.#{random}!!" + end + html_results[key] = html + key + end + + def html_results + registers[:html_results] ||= {} + end + end + end + end + end +end \ No newline at end of file diff --git a/lib/chili_project/liquid/tags.rb b/lib/chili_project/liquid/tags.rb new file mode 100644 index 00000000..af58c33d --- /dev/null +++ b/lib/chili_project/liquid/tags.rb @@ -0,0 +1,32 @@ +module ChiliProject::Liquid + module Tags + class TagError < StandardError; end + + def self.register_tag(name, klass, options={}) + if options[:html] + html_class = Class.new do + def render(context) + result = @tag.render(context) + context.html_result(result) + end + + def method_missing(*args, &block) + @tag.send(*args, &block) + end + end + html_class.send :define_method, :initialize do |*args| + @tag = klass.new(*args) + end + ::Liquid::Template.register_tag(name, html_class) + else + ::Liquid::Template.register_tag(name, klass) + end + end + + # TODO: reimplement old macros as tags and register them here + # child_pages + # hello_world + # include + # macro_list + end +end diff --git a/lib/chili_project/liquid/template.rb b/lib/chili_project/liquid/template.rb new file mode 100644 index 00000000..955cbf32 --- /dev/null +++ b/lib/chili_project/liquid/template.rb @@ -0,0 +1,96 @@ +module ChiliProject + module Liquid + class Template < ::Liquid::Template + # creates a new Template object from liquid source code + def self.parse(source) + template = self.new + template.parse(source) + template + end + + + def context_from_render_options(*args) + # This method is pulled out straight from the original + # Liquid::Template#render + context = case args.first + when ::Liquid::Context + args.shift + when Hash + ::Liquid::Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors) + when nil + ::Liquid::Context.new(assigns, instance_assigns, registers, @rethrow_errors) + else + raise ArgumentError, "Expect Hash or Liquid::Context as parameter" + end + + case args.last + when Hash + options = args.pop + + if options[:registers].is_a?(Hash) + self.registers.merge!(options[:registers]) + end + + if options[:filters] + context.add_filters(options[:filters]) + end + + when Module + context.add_filters(args.pop) + when Array + context.add_filters(args.pop) + end + context + end + + # Render takes a hash with local variables. + # + # if you use the same filters over and over again consider registering them globally + # with Template.register_filter + # + # Following options can be passed: + # + # * filters : array with local filters + # * registers : hash with register variables. Those can be accessed from + # filters and tags and might be useful to integrate liquid more with its host application + # + def render(*args) + return '' if @root.nil? + + context = context_from_render_options(*args) + context.registers[:html_results] ||= {} + + # ENTER THE RENDERING STAGE + + # 1. Render the input as Liquid + # Some tags might register final HTML output in this stage. + begin + # for performance reasons we get a array back here. join will make a string out of it + result = @root.render(context) + result.respond_to?(:join) ? result.join : result + ensure + @errors = context.errors + end + + # 2. Perform the Wiki markup transformation (e.g. Textile) + obj = context.registers[:object] + attr = context.registers[:attribute] + result = Redmine::WikiFormatting.to_html(Setting.text_formatting, result, :object => obj, :attribute => attr) + + # 3. Now finally, replace the captured raw HTML bits in the final content + length = nil + # replace HTML results until we can find no additional variables + while length != context.registers[:html_results].length do + length = context.registers[:html_results].length + context.registers[:html_results].delete_if do |key, value| + # We use the block variant to avoid the evaluation of escaped + # characters in +value+ during substitution. + result.sub!(key) { |match| value } + end + end + + result + end + end + end +end From 81ca15c52c84380618dd18de26e3c18205ee6569 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Wed, 11 May 2011 10:11:24 -0700 Subject: [PATCH 09/22] [#604] Add ability to support legacy macros --- app/helpers/application_helper.rb | 1 + lib/chili_project/liquid.rb | 2 +- lib/chili_project/liquid/legacy.rb | 57 +++++++++++++++++++++++++++ lib/chili_project/liquid/variables.rb | 14 +++++++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 lib/chili_project/liquid/legacy.rb create mode 100644 lib/chili_project/liquid/variables.rb diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 7b2d50e4..a4eabcb4 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -462,6 +462,7 @@ module ApplicationHelper only_path = options.delete(:only_path) == false ? false : true begin + ChiliProject::Liquid::Legacy.run_macros(text) liquid_template = ChiliProject::Liquid::Template.parse(text) liquid_variables = get_view_instance_variables_for_liquid liquid_variables.merge!({'current_user' => User.current}) diff --git a/lib/chili_project/liquid.rb b/lib/chili_project/liquid.rb index e9aeffd3..9dae8d24 100644 --- a/lib/chili_project/liquid.rb +++ b/lib/chili_project/liquid.rb @@ -4,4 +4,4 @@ require 'chili_project/liquid/tags' module ChiliProject module Liquid end -end +end \ No newline at end of file diff --git a/lib/chili_project/liquid/legacy.rb b/lib/chili_project/liquid/legacy.rb new file mode 100644 index 00000000..c2a23768 --- /dev/null +++ b/lib/chili_project/liquid/legacy.rb @@ -0,0 +1,57 @@ +module ChiliProject + module Liquid + # Legacy is used to support older Redmine style macros by converting + # them to Liquid objects (tags, filters) on the fly by doing basic + # string substitution. This is done before the Liquid processing + # so the converted macros work like normal + # + module Legacy + # Holds the list of legacy macros + # + # @param [Regexp] :match The regex to match on the legacy macro + # @param [String] :replace The string to replace with. E.g. "%" converts + # "{{ }}" to "{% %}" + # @param [String] :new_name The new name of the Liquid object + def self.macros + @macros ||= {} + end + + # "Runs" legacy macros by doing a gsub of their values to the new Liquid ones + # + # @param [String] content The pre-Liquid content + def self.run_macros(content) + macros.each do |macro_name, macro| + next unless macro[:match].present? && macro[:replace].present? + content.gsub!(macro[:match]) do |match| + # Use block form so $1 and $2 are set properly + "{#{macro[:replace]} #{macro[:new_name]} '#{$2}' #{macro[:replace]}}" + end + end + end + + # Add support for a legacy macro syntax that was converted to liquid + # + # @param [String] name The legacy macro name + # @param [Symbol] liquid_type The type of Liquid object to use. Supported: :tag + # @param [optional, String] new_name The new name of the liquid object, used + # to rename a macro + def self.add(name, liquid_type, new_name=nil) + new_name = name unless new_name.present? + case liquid_type + when :tag + + macros[name.to_s] = { + # Example values the regex matches + # {{name}} + # {{ name }} + # {{ name 'arg' }} + # {{ name('arg') }} + :match => Regexp.new(/\{\{(#{name})(?:\(([^\}]*)\))?\}\}/), + :replace => "%", + :new_name => new_name + } + end + end + end + end +end diff --git a/lib/chili_project/liquid/variables.rb b/lib/chili_project/liquid/variables.rb new file mode 100644 index 00000000..ad23da38 --- /dev/null +++ b/lib/chili_project/liquid/variables.rb @@ -0,0 +1,14 @@ +module ChiliProject + module Liquid + module Variables + # Liquid "variables" that are used for backwards compatability with macros + # + # Variables are used in liquid like {{var}} + def self.macro_backwards_compatibility + { + 'macro_list' => "Use the '{% variable_list %}' tag to see all Liquid variables and '{% tag_list %}' to see all of the Liquid tags." + } + end + end + end +end From 29fe8569162b1b9ee5a39869ecb5e64447b805bd Mon Sep 17 00:00:00 2001 From: Holger Just Date: Sat, 19 Nov 2011 21:09:42 +0100 Subject: [PATCH 10/22] [#604] Add base tag --- lib/chili_project/liquid/tags.rb | 2 +- lib/chili_project/liquid/tags/tag.rb | 4 ++++ lib/chili_project/liquid/variables.rb | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 lib/chili_project/liquid/tags/tag.rb diff --git a/lib/chili_project/liquid/tags.rb b/lib/chili_project/liquid/tags.rb index af58c33d..9aa8b7f8 100644 --- a/lib/chili_project/liquid/tags.rb +++ b/lib/chili_project/liquid/tags.rb @@ -29,4 +29,4 @@ module ChiliProject::Liquid # include # macro_list end -end +end \ No newline at end of file diff --git a/lib/chili_project/liquid/tags/tag.rb b/lib/chili_project/liquid/tags/tag.rb new file mode 100644 index 00000000..4b7783dd --- /dev/null +++ b/lib/chili_project/liquid/tags/tag.rb @@ -0,0 +1,4 @@ +module ChiliProject::Liquid::Tags + class Tag < ::Liquid::Tag + end +end diff --git a/lib/chili_project/liquid/variables.rb b/lib/chili_project/liquid/variables.rb index ad23da38..28766ec6 100644 --- a/lib/chili_project/liquid/variables.rb +++ b/lib/chili_project/liquid/variables.rb @@ -6,7 +6,6 @@ module ChiliProject # Variables are used in liquid like {{var}} def self.macro_backwards_compatibility { - 'macro_list' => "Use the '{% variable_list %}' tag to see all Liquid variables and '{% tag_list %}' to see all of the Liquid tags." } end end From 7778ff2f83cc9e992ba5b54c96bbe7cfbbf2d0fe Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 26 Apr 2011 14:30:30 -0700 Subject: [PATCH 11/22] [#604] Port hello_world macro to liquid --- lib/chili_project/liquid/tags.rb | 8 ++++++-- lib/chili_project/liquid/tags/hello_world.rb | 11 +++++++++++ lib/redmine/wiki_formatting/macros.rb | 5 ----- 3 files changed, 17 insertions(+), 7 deletions(-) create mode 100644 lib/chili_project/liquid/tags/hello_world.rb diff --git a/lib/chili_project/liquid/tags.rb b/lib/chili_project/liquid/tags.rb index 9aa8b7f8..56dc342d 100644 --- a/lib/chili_project/liquid/tags.rb +++ b/lib/chili_project/liquid/tags.rb @@ -25,8 +25,12 @@ module ChiliProject::Liquid # TODO: reimplement old macros as tags and register them here # child_pages - # hello_world + register_tag('hello_world', HelloWorld) # include # macro_list end -end \ No newline at end of file +end + +# FIXME: remove the deprecated syntax for 4.0, provide a way to migrate +# existing pages to the new syntax. +ChiliProject::Liquid::Legacy.add('hello_world', :tag) diff --git a/lib/chili_project/liquid/tags/hello_world.rb b/lib/chili_project/liquid/tags/hello_world.rb new file mode 100644 index 00000000..7eff7654 --- /dev/null +++ b/lib/chili_project/liquid/tags/hello_world.rb @@ -0,0 +1,11 @@ +module ChiliProject::Liquid::Tags + class HelloWorld < Tag + def initialize(tag_name, markup, tokens) + super + end + + def render(context) + "Hello world!" + end + end +end \ No newline at end of file diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb index 8c01eac0..df03ce59 100644 --- a/lib/redmine/wiki_formatting/macros.rb +++ b/lib/redmine/wiki_formatting/macros.rb @@ -68,11 +68,6 @@ module Redmine end # Builtin macros - desc "Sample macro." - macro :hello_world do |obj, args| - "Hello world! Object: #{obj.class.name}, " + (args.empty? ? "Called with no argument." : "Arguments: #{args.join(', ')}") - end - desc "Displays a list of all available macros, including description if available." macro :macro_list do out = '' From 1e7dfe545e85029de0ded514dc13bf347c6512c7 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 3 May 2011 10:48:51 -0700 Subject: [PATCH 12/22] [#604] Port the macro_list to Liquid: variable_list and tag_list --- lib/chili_project/liquid/tags.rb | 3 ++- lib/chili_project/liquid/tags/tag_list.rb | 14 ++++++++++++++ lib/chili_project/liquid/tags/variable_list.rb | 15 +++++++++++++++ lib/chili_project/liquid/variables.rb | 1 + lib/redmine/wiki_formatting/macros.rb | 10 ---------- 5 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 lib/chili_project/liquid/tags/tag_list.rb create mode 100644 lib/chili_project/liquid/tags/variable_list.rb diff --git a/lib/chili_project/liquid/tags.rb b/lib/chili_project/liquid/tags.rb index 56dc342d..9438213d 100644 --- a/lib/chili_project/liquid/tags.rb +++ b/lib/chili_project/liquid/tags.rb @@ -27,7 +27,8 @@ module ChiliProject::Liquid # child_pages register_tag('hello_world', HelloWorld) # include - # macro_list + register_tag('tag_list', TagList, :html => true) + register_tag('variable_list', VariableList, :html => true) end end diff --git a/lib/chili_project/liquid/tags/tag_list.rb b/lib/chili_project/liquid/tags/tag_list.rb new file mode 100644 index 00000000..e409e8ca --- /dev/null +++ b/lib/chili_project/liquid/tags/tag_list.rb @@ -0,0 +1,14 @@ +module ChiliProject::Liquid::Tags + class TagList < Tag + include ActionView::Helpers::TagHelper + + def render(context) + content_tag('p', "Tags:") + + content_tag('ul', + ::Liquid::Template.tags.keys.sort.collect {|tag_name| + content_tag('li', content_tag('code', h(tag_name))) + }.join('') + ) + end + end +end \ No newline at end of file diff --git a/lib/chili_project/liquid/tags/variable_list.rb b/lib/chili_project/liquid/tags/variable_list.rb new file mode 100644 index 00000000..51b85a48 --- /dev/null +++ b/lib/chili_project/liquid/tags/variable_list.rb @@ -0,0 +1,15 @@ +module ChiliProject::Liquid::Tags + class VariableList < Tag + include ActionView::Helpers::TagHelper + + def render(context) + out = '' + context.environments.first.keys.sort.each do |liquid_variable| + next if liquid_variable == 'text' # internal variable + out << content_tag('li', content_tag('code', h(liquid_variable))) + end if context.environments.present? + + content_tag('p', "Variables:") + content_tag('ul', out) + end + end +end diff --git a/lib/chili_project/liquid/variables.rb b/lib/chili_project/liquid/variables.rb index 28766ec6..ad23da38 100644 --- a/lib/chili_project/liquid/variables.rb +++ b/lib/chili_project/liquid/variables.rb @@ -6,6 +6,7 @@ module ChiliProject # Variables are used in liquid like {{var}} def self.macro_backwards_compatibility { + 'macro_list' => "Use the '{% variable_list %}' tag to see all Liquid variables and '{% tag_list %}' to see all of the Liquid tags." } end end diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb index df03ce59..8b4468a5 100644 --- a/lib/redmine/wiki_formatting/macros.rb +++ b/lib/redmine/wiki_formatting/macros.rb @@ -68,16 +68,6 @@ module Redmine end # Builtin macros - desc "Displays a list of all available macros, including description if available." - macro :macro_list do - out = '' - @@available_macros.keys.collect(&:to_s).sort.each do |macro| - out << content_tag('dt', content_tag('code', macro)) - out << content_tag('dd', textilizable(@@available_macros[macro.to_sym])) - end - content_tag('dl', out) - end - desc "Displays a list of child pages. With no argument, it displays the child pages of the current wiki page. Examples:\n\n" + " !{{child_pages}} -- can be used from a wiki page only\n" + " !{{child_pages(Foo)}} -- lists all children of page Foo\n" + From 71ecdb57edb1853f285606fc5b92c13002199f04 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 3 May 2011 12:04:09 -0700 Subject: [PATCH 13/22] [#604] Port the child_pages to Liquid tag --- lib/chili_project/liquid/tags.rb | 3 +- lib/chili_project/liquid/tags/child_pages.rb | 60 ++++++++++++++++++++ lib/redmine/wiki_formatting/macros.rb | 19 ------- 3 files changed, 62 insertions(+), 20 deletions(-) create mode 100644 lib/chili_project/liquid/tags/child_pages.rb diff --git a/lib/chili_project/liquid/tags.rb b/lib/chili_project/liquid/tags.rb index 9438213d..e44ab0ea 100644 --- a/lib/chili_project/liquid/tags.rb +++ b/lib/chili_project/liquid/tags.rb @@ -24,7 +24,7 @@ module ChiliProject::Liquid end # TODO: reimplement old macros as tags and register them here - # child_pages + register_tag('child_pages', ChildPages, :html => true) register_tag('hello_world', HelloWorld) # include register_tag('tag_list', TagList, :html => true) @@ -34,4 +34,5 @@ end # FIXME: remove the deprecated syntax for 4.0, provide a way to migrate # existing pages to the new syntax. +ChiliProject::Liquid::Legacy.add('child_pages', :tag) ChiliProject::Liquid::Legacy.add('hello_world', :tag) diff --git a/lib/chili_project/liquid/tags/child_pages.rb b/lib/chili_project/liquid/tags/child_pages.rb new file mode 100644 index 00000000..ca373a3e --- /dev/null +++ b/lib/chili_project/liquid/tags/child_pages.rb @@ -0,0 +1,60 @@ +module ChiliProject::Liquid::Tags + class ChildPages < Tag + def initialize(tag_name, markup, tokens) + markup = markup.strip.gsub(/["']/, '') + if markup.present? + tag_args = markup.split(',') + @args, @options = extract_macro_options(tag_args, :parent) + else + @args = [] + @options = {} + end + super + end + + def render(context) + # inside of a project + @project = Project.find(context['project'].identifier) if context['project'].present? + + if @args.present? + page_name = @args.first.to_s + cross_project_page = page_name.include?(':') + + page = Wiki.find_page(page_name, :project => (cross_project_page ? nil : @project)) + # FIXME: :object and :attribute should be variables, not registers + elsif context.registers[:object].is_a?(WikiContent) + page = context.registers[:object].page + page_name = page.title + elsif @project + return render_all_pages(context) + else + raise TagError.new('With no argument, this tag can be called from projects only.') + end + + raise TagError.new("No such page '#{page_name}'") if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project) + pages = ([page] + page.descendants).group_by(&:parent_id) + context.registers[:view].render_page_hierarchy(pages, @options[:parent] ? page.parent_id : page.id) + end + + private + def render_all_pages(context) + return '' unless @project.wiki.present? && @project.wiki.pages.present? + raise TagError.new('Page not found') if !User.current.allowed_to?(:view_wiki_pages, @project) + + context.registers[:view].render_page_hierarchy(@project.wiki.pages.group_by(&:parent_id)) + end + + # @param args [Array, String] An array of strings in "key=value" format + # @param keys [Hash, Symbol] List of keyword args to extract + def extract_macro_options(args, *keys) + options = {} + args.each do |arg| + if arg.to_s.gsub(/["']/,'').strip =~ %r{^(.+)\=(.+)$} && keys.include?($1.downcase.to_sym) + options[$1.downcase.to_sym] = $2 + args.pop + end + end + return [args, options] + end + end +end \ No newline at end of file diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb index 8b4468a5..b343b4f2 100644 --- a/lib/redmine/wiki_formatting/macros.rb +++ b/lib/redmine/wiki_formatting/macros.rb @@ -68,25 +68,6 @@ module Redmine end # Builtin macros - desc "Displays a list of child pages. With no argument, it displays the child pages of the current wiki page. Examples:\n\n" + - " !{{child_pages}} -- can be used from a wiki page only\n" + - " !{{child_pages(Foo)}} -- lists all children of page Foo\n" + - " !{{child_pages(Foo, parent=1)}} -- same as above with a link to page Foo" - macro :child_pages do |obj, args| - args, options = extract_macro_options(args, :parent) - page = nil - if args.size > 0 - page = Wiki.find_page(args.first.to_s, :project => @project) - elsif obj.is_a?(WikiContent) - page = obj.page - else - raise 'With no argument, this macro can be called from wiki pages only.' - end - raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project) - pages = ([page] + page.descendants).group_by(&:parent_id) - render_page_hierarchy(pages, options[:parent] ? page.parent_id : page.id) - end - desc "Include a wiki page. Example:\n\n !{{include(Foo)}}\n\nor to include a page of a specific project wiki:\n\n !{{include(projectname:Foo)}}" macro :include do |obj, args| page = Wiki.find_page(args.first.to_s, :project => @project) From 862c9e0fdebe28c77240acffaad041b124c8046f Mon Sep 17 00:00:00 2001 From: Holger Just Date: Sun, 20 Nov 2011 00:59:52 +0100 Subject: [PATCH 14/22] [#604] Adapt the upstream include mechanism to work with Wiki pages --- lib/chili_project/liquid.rb | 1 + lib/chili_project/liquid/file_system.rb | 18 ++++++ lib/chili_project/liquid/tags.rb | 4 +- lib/chili_project/liquid/tags/include.rb | 82 ++++++++++++++++++++++++ lib/redmine/wiki_formatting/macros.rb | 13 ---- 5 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 lib/chili_project/liquid/file_system.rb create mode 100644 lib/chili_project/liquid/tags/include.rb diff --git a/lib/chili_project/liquid.rb b/lib/chili_project/liquid.rb index 9dae8d24..d9da7d5b 100644 --- a/lib/chili_project/liquid.rb +++ b/lib/chili_project/liquid.rb @@ -3,5 +3,6 @@ require 'chili_project/liquid/tags' module ChiliProject module Liquid + Liquid::Template.file_system = FileSystem.new end end \ No newline at end of file diff --git a/lib/chili_project/liquid/file_system.rb b/lib/chili_project/liquid/file_system.rb new file mode 100644 index 00000000..d6fe60f9 --- /dev/null +++ b/lib/chili_project/liquid/file_system.rb @@ -0,0 +1,18 @@ +module ChiliProject + module Liquid + class FileSystem + def read_template_file(template_name, context) + raise ::Liquid::FileSystemError.new("Page not found") if template_name.blank? + project = Project.find(context['project'].identifier) if context['project'].present? + + cross_project_page = template_name.include?(':') + page = Wiki.find_page(template_name.to_s.strip, :project => (cross_project_page ? nil : project)) + if page.nil? || !page.visible? + raise ::Liquid::FileSystemError.new("No such page '#{template_name}'") + end + + page.content + end + end + end +end \ No newline at end of file diff --git a/lib/chili_project/liquid/tags.rb b/lib/chili_project/liquid/tags.rb index e44ab0ea..41a28f7b 100644 --- a/lib/chili_project/liquid/tags.rb +++ b/lib/chili_project/liquid/tags.rb @@ -23,10 +23,9 @@ module ChiliProject::Liquid end end - # TODO: reimplement old macros as tags and register them here register_tag('child_pages', ChildPages, :html => true) register_tag('hello_world', HelloWorld) - # include + register_tag('include', Include, :html => true) register_tag('tag_list', TagList, :html => true) register_tag('variable_list', VariableList, :html => true) end @@ -36,3 +35,4 @@ end # existing pages to the new syntax. ChiliProject::Liquid::Legacy.add('child_pages', :tag) ChiliProject::Liquid::Legacy.add('hello_world', :tag) +ChiliProject::Liquid::Legacy.add('include', :tag) diff --git a/lib/chili_project/liquid/tags/include.rb b/lib/chili_project/liquid/tags/include.rb new file mode 100644 index 00000000..6de3df92 --- /dev/null +++ b/lib/chili_project/liquid/tags/include.rb @@ -0,0 +1,82 @@ +#-- copyright +# ChiliProject is a project management system. +# +# Copyright (C) 2010-2011 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +module ChiliProject::Liquid::Tags + class Include < ::Liquid::Include + + # This method follows the basic flow of the default include in liquid + # We just add some additional flexibility. This method can be removed once + # https://github.com/Shopify/liquid/pull/78 got accepted + def render(context) + context.stack do + template = _read_template_from_file_system(context) + partial = Liquid::Template.parse _template_source(template) + variable = context[@variable_name || @template_name[1..-2]] + + @attributes.each do |key, value| + context[key] = context[value] + end + + if variable.is_a?(Array) + variable.collect do |variable| + context[@template_name[1..-2]] = variable + _render_partial(partial, template, context) + end + else + context[@template_name[1..-2]] = variable + _render_partial(partial, template, context) + end + end + end + + private + def break_circle(context) + context.registers[:included_pages] ||= [] + + project = context['project'].identifier if context['project'].present? + template_name = context[@template_name] + cross_project_page = template_name.include?(':') + page_title = cross_project_page ? template_name : "#{project}:#{template_name}" + + raise ::Liquid::FileSystemError.new("Circular inclusion detected") if context.registers[:included_pages].include?(page_title) + context.registers[:included_pages] << page_title + + yield + ensure + context.registers[:included_pages].pop + end + + def _template_source(wiki_content) + wiki_content.text + end + + def _render_partial(partial, template, context) + break_circle(context) do + textile = partial.render(context) + + # Call textilizable on the view so all of the helpers are loaded + # based on the view and not this tag + context.registers[:view].textilizable(textile, :attachments => template.page.attachments, :headings => false, :object => template) + end + end + + def _read_template_from_file_system(context) + wiki_content = super + + # Set the new project to that additional includes use the correct + # base project + context['project'] = wiki_content.page.wiki.project + wiki_content + end + end +end diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb index b343b4f2..faef7a8b 100644 --- a/lib/redmine/wiki_formatting/macros.rb +++ b/lib/redmine/wiki_formatting/macros.rb @@ -66,19 +66,6 @@ module Redmine @@desc = txt end end - - # Builtin macros - desc "Include a wiki page. Example:\n\n !{{include(Foo)}}\n\nor to include a page of a specific project wiki:\n\n !{{include(projectname:Foo)}}" - macro :include do |obj, args| - page = Wiki.find_page(args.first.to_s, :project => @project) - raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project) - @included_wiki_pages ||= [] - raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title) - @included_wiki_pages << page.title - out = textilizable(page.content, :text, :attachments => page.attachments, :headings => false) - @included_wiki_pages.pop - out - end end end end From cc0526cb27d6b6a17834a6eb55d6789cd29454d4 Mon Sep 17 00:00:00 2001 From: Holger Just Date: Thu, 1 Sep 2011 01:12:57 +0200 Subject: [PATCH 15/22] [#604] Introduce compatibility layer for third party macros. This be removed with complete macro removal. --- app/helpers/application_helper.rb | 1 - lib/redmine/wiki_formatting/macros.rb | 70 +++++++++++++-------------- 2 files changed, 33 insertions(+), 38 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a4eabcb4..f621138c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -16,7 +16,6 @@ require 'forwardable' require 'cgi' module ApplicationHelper - include Redmine::WikiFormatting::Macros::Definitions include Redmine::I18n include GravatarHelper::PublicMethods diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb index faef7a8b..28ea57d7 100644 --- a/lib/redmine/wiki_formatting/macros.rb +++ b/lib/redmine/wiki_formatting/macros.rb @@ -12,58 +12,54 @@ # See doc/COPYRIGHT.rdoc for more details. #++ +# DECREACATED SINCE 3.0 - TO BE REMOVED IN 4.0 +# The whole macro concept is deprecated. It is to be completely replaced by +# Liquid tags and variables. + +require 'dispatcher' + module Redmine module WikiFormatting module Macros - module Definitions - def exec_macro(name, obj, args) - method_name = "macro_#{name}" - send(method_name, obj, args) if respond_to?(method_name) - end - - def extract_macro_options(args, *keys) - options = {} - while args.last.to_s.strip =~ %r{^(.+)\=(.+)$} && keys.include?($1.downcase.to_sym) - options[$1.downcase.to_sym] = $2 - args.pop - end - return [args, options] - end - end - - @@available_macros = {} + @available_macros = {} class << self - # Called with a block to define additional macros. - # Macro blocks accept 2 arguments: - # * obj: the object that is rendered - # * args: macro arguments - # - # Plugins can use this method to define new macros: - # - # Redmine::WikiFormatting::Macros.register do - # desc "This is my macro" - # macro :my_macro do |obj, args| - # "My macro output" - # end - # end def register(&block) + ActiveSupport::Deprecation.warn("Macros are deprecated. Use Liquid filters and tags instead", caller.drop(3)) class_eval(&block) if block_given? end private + # Sets description for the next macro to be defined + def desc(txt) + @desc = txt + end + # Defines a new macro with the given name and block. def macro(name, &block) name = name.to_sym if name.is_a?(String) - @@available_macros[name] = @@desc || '' - @@desc = nil + @available_macros[name] = @desc || '' + @desc = nil raise "Can not create a macro without a block!" unless block_given? - Definitions.send :define_method, "macro_#{name}".downcase, &block - end - # Sets description for the next macro to be defined - def desc(txt) - @@desc = txt + tag = Class.new(::Liquid::Tag) do + def initialize(tag_name, markup, tokens) + if markup =~ self.class::Syntax + @args = $1[1..-2].split(',').collect(&:strip) + else + raise ::Liquid::SyntaxError.new("Syntax error in tag '#{name}'") + end + end + end + tag.send :define_method, :render do |context| + context.registers[:view].instance_exec context.registers[:object], @args, &block + end + tag.const_set 'Syntax', /(#{::Liquid::QuotedFragment})/ + + Dispatcher.to_prepare do + ChiliProject::Liquid::Tags.register_tag(name, tag, :html => true) + ChiliProject::Liquid::Legacy.add(name, :tag) + end end end end From fe6a79ac17bb4d7c773e0f23c29b142f18a426f6 Mon Sep 17 00:00:00 2001 From: Holger Just Date: Mon, 17 Oct 2011 19:01:34 +0200 Subject: [PATCH 16/22] [#604] Add some handy filters --- lib/chili_project/liquid.rb | 1 + lib/chili_project/liquid/filters.rb | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 lib/chili_project/liquid/filters.rb diff --git a/lib/chili_project/liquid.rb b/lib/chili_project/liquid.rb index d9da7d5b..f2783d6a 100644 --- a/lib/chili_project/liquid.rb +++ b/lib/chili_project/liquid.rb @@ -1,4 +1,5 @@ require 'chili_project/liquid/liquid_ext' +require 'chili_project/liquid/filters' require 'chili_project/liquid/tags' module ChiliProject diff --git a/lib/chili_project/liquid/filters.rb b/lib/chili_project/liquid/filters.rb new file mode 100644 index 00000000..baa2ed5d --- /dev/null +++ b/lib/chili_project/liquid/filters.rb @@ -0,0 +1,15 @@ +module ChiliProject + module Liquid + module Filters + def default(input, default) + input.to_s.strip.present? ? input : default + end + + def strip(input) + input.to_s.strip + end + end + + Template.register_filter(Filters) + end +end From 994132a51ad04c9d2fae3c58a4f2217b3d53a4fb Mon Sep 17 00:00:00 2001 From: Holger Just Date: Mon, 17 Oct 2011 18:47:13 +0200 Subject: [PATCH 17/22] [#604] Add nicer error formatting, similar to the old style --- lib/chili_project/liquid/liquid_ext/context.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/chili_project/liquid/liquid_ext/context.rb b/lib/chili_project/liquid/liquid_ext/context.rb index 777f820f..1dc38739 100644 --- a/lib/chili_project/liquid/liquid_ext/context.rb +++ b/lib/chili_project/liquid/liquid_ext/context.rb @@ -4,9 +4,20 @@ module ChiliProject module Context def self.included(base) base.send(:include, InstanceMethods) + base.class_eval do + alias_method_chain :handle_error, :formatting + end end module InstanceMethods + def handle_error_with_formatting(e) + error = handle_error_without_formatting(e) + escaped_error = registers[:view].send(:h, error) rescue CGI::escapeHTML(error) + + html = '
' + escaped_error + '
' + html_result(html) + end + def html_result(html) key = nil while key.nil? || html_results.has_key?(key) From f6805303fb265f2e9ecab1add30f99e823ad9e0f Mon Sep 17 00:00:00 2001 From: Holger Just Date: Fri, 9 Sep 2011 23:51:02 +0200 Subject: [PATCH 18/22] [#604] Remove the leading newline from Liquid blocks for easier formatting --- lib/chili_project/liquid/liquid_ext.rb | 1 + lib/chili_project/liquid/liquid_ext/block.rb | 22 ++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 lib/chili_project/liquid/liquid_ext/block.rb diff --git a/lib/chili_project/liquid/liquid_ext.rb b/lib/chili_project/liquid/liquid_ext.rb index b35798a9..d001afe4 100644 --- a/lib/chili_project/liquid/liquid_ext.rb +++ b/lib/chili_project/liquid/liquid_ext.rb @@ -1,6 +1,7 @@ module ChiliProject module Liquid module LiquidExt + ::Liquid::Block.send(:include, Block) ::Liquid::Context.send(:include, Context) end end diff --git a/lib/chili_project/liquid/liquid_ext/block.rb b/lib/chili_project/liquid/liquid_ext/block.rb new file mode 100644 index 00000000..f37dffc4 --- /dev/null +++ b/lib/chili_project/liquid/liquid_ext/block.rb @@ -0,0 +1,22 @@ +module ChiliProject + module Liquid + module LiquidExt + module Block + def self.included(base) + base.send(:include, InstanceMethods) + base.class_eval do + alias_method_chain :render_all, :cleaned_whitespace + end + end + + module InstanceMethods + def render_all_with_cleaned_whitespace(list, context) + # Remove the leading newline in a block's content + list[0].sub!(/\A\r?\n/, "") if list[0].is_a?(String) + render_all_without_cleaned_whitespace(list, context) + end + end + end + end + end +end \ No newline at end of file From 464dafc1e706ccd6bbbebf61eeb7701d9a5e3b1a Mon Sep 17 00:00:00 2001 From: Holger Just Date: Sun, 20 Nov 2011 01:21:59 +0100 Subject: [PATCH 19/22] [#604] We don't support the old escape style anymore --- test/unit/lib/redmine/wiki_formatting/macros_test.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/unit/lib/redmine/wiki_formatting/macros_test.rb b/test/unit/lib/redmine/wiki_formatting/macros_test.rb index 40a6968d..731e97a6 100644 --- a/test/unit/lib/redmine/wiki_formatting/macros_test.rb +++ b/test/unit/lib/redmine/wiki_formatting/macros_test.rb @@ -39,9 +39,6 @@ class Redmine::WikiFormatting::MacrosTest < HelperTestCase def test_macro_hello_world text = "{{hello_world}}" assert textilizable(text).match(/Hello world!/) - # escaping - text = "!{{hello_world}}" - assert_equal '

{{hello_world}}

', textilizable(text) end def test_macro_include @@ -59,7 +56,7 @@ class Redmine::WikiFormatting::MacrosTest < HelperTestCase assert textilizable(text).match(/CookBook documentation/) text = "{{include(unknowidentifier:somepage)}}" - assert textilizable(text).match(/Page not found/) + assert textilizable(text).match(/No such page/) end def test_macro_child_pages From dedf696666ee70bc4729ba66e3a955428580b82b Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 3 May 2011 16:37:07 -0700 Subject: [PATCH 20/22] [#604] Add missing test for Liquid --- test/unit/lib/chili_project/liquid_test.rb | 211 +++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 test/unit/lib/chili_project/liquid_test.rb diff --git a/test/unit/lib/chili_project/liquid_test.rb b/test/unit/lib/chili_project/liquid_test.rb new file mode 100644 index 00000000..2fb25020 --- /dev/null +++ b/test/unit/lib/chili_project/liquid_test.rb @@ -0,0 +1,211 @@ +#-- encoding: UTF-8 +#-- copyright +# ChiliProject is a project management system. +# +# Copyright (C) 2010-2011 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ +require File.expand_path('../../../../test_helper', __FILE__) + +class ChiliProject::LiquidTest < ActionView::TestCase + include ApplicationHelper + + context "hello_world tag" do + should "render 'Hello world!'" do + text = "{% hello_world %}" + assert_match /Hello world!/, textilizable(text) + end + end + + context "variable_list tag" do + should "render a list of the current variables" do + text = "{% variable_list %}" + formatted = textilizable(text) + + assert formatted.include?('
    '), "Not in a list format" + assert formatted.include?('current_user') + end + end + + context "child_pages tag" do + context "with no arg" do + context "and @project set" do + should "should list all wiki pages for the current project" do + @project = Project.generate!.reload + wiki = @project.wiki + top = WikiPage.generate!(:wiki => wiki, :title => 'Top', :content => WikiContent.new(:text => 'top page')) + child1 = WikiPage.generate!(:wiki => wiki, :title => 'Child1', :content => WikiContent.new(:text => 'child'), :parent => top) + + text = "{% child_pages %}" + formatted = textilizable(text) + + assert formatted.include?('pages-hierarchy') + assert formatted.include?('Child1') + assert formatted.include?('Top') + end + end + + context "and no @project set" do + should "render a warning" do + text = "{% child_pages %}" + formatted = textilizable(text) + + assert_match /flash error/, formatted + assert formatted.include?('With no argument, this tag can be called from projects only') + end + end + + end + + context "with a valid WikiPage arg" do + should "list all child pages for the wiki page" do + @project = Project.generate!.reload + wiki = @project.wiki + top = WikiPage.generate!(:wiki => wiki, :title => 'Top', :content => WikiContent.new(:text => 'top page')) + child1 = WikiPage.generate!(:wiki => wiki, :title => 'Child1', :content => WikiContent.new(:text => 'child'), :parent => top) + + text = "{% child_pages 'Top' %}" + formatted = textilizable(text) + + assert formatted.include?('pages-hierarchy') + assert formatted.include?('Child1') + assert !formatted.include?('Top') + end + + should "allow cross project listings even when outside of a project" do + project = Project.generate!.reload # project not an ivar + wiki = project.wiki + top = WikiPage.generate!(:wiki => wiki, :title => 'Top', :content => WikiContent.new(:text => 'top page')) + child1 = WikiPage.generate!(:wiki => wiki, :title => 'Child1', :content => WikiContent.new(:text => 'child'), :parent => top) + + text = "{% child_pages #{project.identifier}:'Top' %}" + formatted = textilizable(text) + + assert formatted.include?('pages-hierarchy') + assert formatted.include?('Child1') + assert !formatted.include?('Top') + end + + should "show the WikiPage when parent=1 is set" do + @project = Project.generate!.reload + wiki = @project.wiki + top = WikiPage.generate!(:wiki => wiki, :title => 'Top', :content => WikiContent.new(:text => 'top page')) + child1 = WikiPage.generate!(:wiki => wiki, :title => 'Child1', :content => WikiContent.new(:text => 'child'), :parent => top) + + text = "{% child_pages 'Top', 'parent=1' %}" + formatted = textilizable(text) + + assert formatted.include?('pages-hierarchy') + assert formatted.include?('Child1') + assert formatted.include?('Top') + + end + end + + context "with an invalid arg" do + should "render a warning" do + @project = Project.generate!.reload + wiki = @project.wiki + top = WikiPage.generate!(:wiki => wiki, :title => 'Top', :content => WikiContent.new(:text => 'top page')) + child1 = WikiPage.generate!(:wiki => wiki, :title => 'Child1', :content => WikiContent.new(:text => 'child'), :parent => top) + + text = "{% child_pages 1 %}" + formatted = textilizable(text) + + assert_match /flash error/, formatted + assert formatted.include?('No such page') + + end + end + end + + context "include tag" do + setup do + @project = Project.generate!.reload + @wiki = @project.wiki + @included_page = WikiPage.generate!(:wiki => @wiki, :title => 'Included_Page', :content => WikiContent.new(:text => 'included page [[Second_Page]]')) + + @project2 = Project.generate!.reload + @cross_project_page = WikiPage.generate!(:wiki => @project2.wiki, :title => 'Second_Page', :content => WikiContent.new(:text => 'second page')) + + end + + context "with a direct page" do + should "show the included page's content" do + text = "{% include 'Included Page' %}" + formatted = textilizable(text) + + assert formatted.include?('included page') + end + end + + context "with a cross-project page" do + should "show the included page's content" do + text = "{% include '#{@project2.identifier}:Second Page' %}" + formatted = textilizable(text) + + assert formatted.include?('second page') + end + end + + context "with recursive includes" do + should "render all child pages" do + parent = WikiPage.generate!(:wiki => @wiki, :title => 'Recursive_Parent', :content => WikiContent.new(:text => "h1. Parent\r\n{% include 'Recursive_Child1' %}")) + child1 = WikiPage.generate!(:wiki => @wiki, :title => 'Recursive_Child1', :content => WikiContent.new(:text => "h1. Child1\r\n{% include 'Recursive_Child2' %}")) + child2 = WikiPage.generate!(:wiki => @wiki, :title => 'Recursive_Child2', :content => WikiContent.new(:text => 'h1. Child2')) + + formatted = textilizable(parent.reload.text) + + assert_match /\s*Parent.*?<\/h1>/, formatted + assert_match /\s*Child1.*?<\/h1>/, formatted + assert_match /\s*Child2.*?<\/h1>/, formatted + + # make sure there are no dangling html result variables + assert_no_match /!!html_results.*?!!/, formatted + end + end + + context "with a circular inclusion" do + should "render a warning" do + circle_page = WikiPage.generate!(:wiki => @wiki, :title => 'Circle', :content => WikiContent.new(:text => '{% include "Circle2" %}')) + circle_page2 = WikiPage.generate!(:wiki => @wiki, :title => 'Circle2', :content => WikiContent.new(:text => '{% include "Circle" %}')) + formatted = textilizable(circle_page.reload.text) + + assert_match /flash error/, formatted + assert_match 'Circular inclusion detected', formatted + end + end + + context "with an invalid arg" do + should "render a warning" do + text = "{% include '404' %}" + formatted = textilizable(text) + + assert_match /flash error/, formatted + assert formatted.include?('No such page') + end + + should "HTML escape the error" do + text = "{% include '' %}" + formatted = textilizable(text) + + assert formatted.include?("No such page '<script>alert("foo"):</script>'") + end + end + + context "legacy" do + should "map to native include" do + text = "{{include(#{@project2.identifier}:Second_Page)}}" + formatted = textilizable(text) + + assert formatted.include?('second page') + end + end + end +end From a31a4a8852db5c25c4acb427bc5ae0b2e2952b99 Mon Sep 17 00:00:00 2001 From: Holger Just Date: Sun, 20 Nov 2011 01:49:35 +0100 Subject: [PATCH 21/22] [#604] Adapt fixtures for new liquid syntax --- test/fixtures/wiki_contents.yml | 4 ++-- test/unit/helpers/application_helper_test.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/fixtures/wiki_contents.yml b/test/fixtures/wiki_contents.yml index bf2797b8..060ec167 100644 --- a/test/fixtures/wiki_contents.yml +++ b/test/fixtures/wiki_contents.yml @@ -3,7 +3,7 @@ wiki_contents_001: text: |- h1. CookBook documentation - {{child_pages}} + {% child_pages %} Some updated [[documentation]] here with gzipped history updated_on: 2007-03-07 00:10:51 +01:00 @@ -17,7 +17,7 @@ wiki_contents_002: This is a link to a ticket: #2 And this is an included page: - {{include(Page with an inline image)}} + {% include 'Page with an inline image' %} updated_on: 2007-03-08 00:18:07 +01:00 page_id: 2 id: 2 diff --git a/test/unit/helpers/application_helper_test.rb b/test/unit/helpers/application_helper_test.rb index d1a6e255..9f85b101 100644 --- a/test/unit/helpers/application_helper_test.rb +++ b/test/unit/helpers/application_helper_test.rb @@ -593,7 +593,7 @@ RAW h1. Included -{{include(Child_1)}} +{% include 'Child_1' %} RAW expected = '
      ' + From b1d9667335a0b3b94a6f9ab184726b42af07d6c2 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Tue, 3 May 2011 14:47:43 -0700 Subject: [PATCH 22/22] Fix test so it runs in isolation --- test/functional/wiki_controller_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/wiki_controller_test.rb b/test/functional/wiki_controller_test.rb index d8b442df..b583b728 100644 --- a/test/functional/wiki_controller_test.rb +++ b/test/functional/wiki_controller_test.rb @@ -18,8 +18,8 @@ require 'wiki_controller' class WikiController; def rescue_action(e) raise e end; end class WikiControllerTest < ActionController::TestCase - fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis, :wiki_pages, :wiki_contents, :journals, :attachments - + fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis, :wiki_pages, :wiki_contents, :journals, :attachments, :enumerations + def setup @controller = WikiController.new @request = ActionController::TestRequest.new