diff --git a/lib/chunks/include.rb b/lib/chunks/include.rb index 7ec8aba9..a60c81d7 100644 --- a/lib/chunks/include.rb +++ b/lib/chunks/include.rb @@ -10,27 +10,22 @@ require 'chunks/wiki' class Include < WikiChunk::WikiReference INCLUDE_PATTERN = /\[\[!include\s+([^\]\s][^\]]+?)\s*\]\]/i - Thread.current[:included_by] = [] def self.pattern() INCLUDE_PATTERN end def initialize(match_data, content) super @page_name = match_data[1].strip rendering_mode = content.options[:mode] || :show - Thread.current[:included_by].push(@content.page_name) + add_to_include_list @unmask_text = get_unmask_text_avoiding_recursion_loops(rendering_mode) end private def get_unmask_text_avoiding_recursion_loops(rendering_mode) - if refpage - if Thread.current[:included_by].include?(refpage.page.name) - @content.delete_chunk(self) - Thread.current[:included_by] = [] - return "Recursive include detected: #{@content.page_name} → #{@content.page_name}\n" - end - # TODO This way of instantiating a renderer is ugly. + if refpage + return "Recursive include detected: #{@content.page_name} " + + "→ #{@content.page_name}\n" if self_inclusion(refpage) renderer = PageRenderer.new(refpage.current_revision) included_content = case rendering_mode @@ -41,12 +36,37 @@ class Include < WikiChunk::WikiReference raise "Unsupported rendering mode #{@mode.inspect}" end @content.merge_chunks(included_content) - Thread.current[:included_by] = [] + clear_include_list return included_content.pre_rendered else - Thread.current[:included_by] = [] + clear_include_list return "Could not include #{@page_name}\n" end end + + # We track included pages in a thread-local variable. + # This allows a multi-threaded Rails to handle one request/thread, + # without getting confused. + + def clear_include_list + Thread.current[:included_by] = [] + end + + def add_to_include_list + if Thread.current[:included_by] + Thread.current[:included_by].push(@content.page_name) + else + Thread.current[:included_by] = [@content.page_name] + end + end + + def self_inclusion(refpage) + if Thread.current[:included_by].include?(refpage.page.name) + @content.delete_chunk(self) + clear_include_list + else + return false + end + end end