diff --git a/Rakefile b/Rakefile index 7b0672d..c662a0f 100644 --- a/Rakefile +++ b/Rakefile @@ -9,7 +9,7 @@ begin rescue LoadError require 'rdoc/rdoc' require 'rake/rdoctask' - require 'rdoc/task' + require 'rdoc/task' RDoc::Task = Rake::RDocTask end diff --git a/lib/ruby-bbcode-to-md.rb b/lib/ruby-bbcode-to-md.rb index 376021a..ea5590e 100644 --- a/lib/ruby-bbcode-to-md.rb +++ b/lib/ruby-bbcode-to-md.rb @@ -27,7 +27,7 @@ def self.validation_enabled # This method converts the given text (with BBCode tags) into a HTML representation # The escape_html parameter (default: true) escapes HTML tags that were present in the given text and therefore blocking (mallicious) HTML in the original text # The additional_tags parameter is used to add additional BBCode tags that should be accepted - # The method paramter determines whether the tags parameter needs to be used to blacklist (when set to :disable) or whitelist (when not set to :disable) the list of BBCode tags + # The method parameter determines whether the tags parameter needs to be used to blacklist (when set to :disable) or whitelist (when not set to :disable) the list of BBCode tags def self.to_html(text, escape_html = true, additional_tags = {}, method = :disable, *tags) text = text.clone diff --git a/lib/ruby-bbcode-to-md/bbtree.rb b/lib/ruby-bbcode-to-md/bbtree.rb index 93c8921..eef52e3 100644 --- a/lib/ruby-bbcode-to-md/bbtree.rb +++ b/lib/ruby-bbcode-to-md/bbtree.rb @@ -17,6 +17,7 @@ def initialize(hash = { :nodes => TagCollection.new }, dictionary) @bbtree = hash @current_node = TagNode.new(@bbtree) @tags_list = [] + @nodes_list = [] @dictionary = dictionary end @@ -55,6 +56,7 @@ def parent_has_constraints_on_children? def escalate_bbtree(element) element[:parent_tag] = parent_tag @tags_list.push element[:tag] + @nodes_list.push @current_node @current_node = TagNode.new(element) end @@ -63,12 +65,7 @@ def retrogress_bbtree @tags_list.pop # remove latest tag in tags_list since it's closed now... # The parsed data manifests in @bbtree.current_node.children << TagNode.new(element) which I think is more confusing than needed - if within_open_tag? - # Set the current node to be the node we've just parsed over which is infact within another node??... - @current_node = TagNode.new(self.nodes.last) - else # If we're still at the root of the BBTree or have returned back to the root via encountring closing tags... - @current_node = TagNode.new({:nodes => self.nodes}) - end + @current_node = @nodes_list.pop # OKOKOK! # Since @bbtree = @current_node, if we ever set @current_node to something, we're actually changing @bbtree... @@ -91,4 +88,4 @@ def to_html(tags = {}) end end -end \ No newline at end of file +end diff --git a/lib/ruby-bbcode-to-md/debugging.rb b/lib/ruby-bbcode-to-md/debugging.rb index f09639c..33bad57 100644 --- a/lib/ruby-bbcode-to-md/debugging.rb +++ b/lib/ruby-bbcode-to-md/debugging.rb @@ -1,12 +1,12 @@ module RubyBBCode def self.log(string, clear_file = true) clear_log_file_at_beginning_of_execution clear_file - + File.open('/tmp/ruby-bbcode.log', 'a') do |f| f.puts string end end - + def self.clear_log_file_at_beginning_of_execution(clear_file) return if !clear_file if defined?(@@cleared_file).nil? @@ -16,16 +16,16 @@ def self.clear_log_file_at_beginning_of_execution(clear_file) end end end - - + + # This module can be included in the BBTree and TagNode to give them debugging features module DebugBBTree # For Debugging/ visualization purposes. - # This can be used to render the #nodes array in a pretty manor, showing the hirarchy. + # This can be used to render the #nodes array in a pretty manor, showing the hierarchy. def to_v tree = self visual_string = '' - + walk_tree(tree) do |node, depth| indentation = ' ' * depth case node[:is_tag] @@ -35,11 +35,11 @@ def to_v visual_string += "#{indentation}\"#{node[:text]}\"\n" end end - + visual_string end - - + + # this blocky method counts how many children are # in the TagNode.children, recursively walking the tree def count_child_nodes(hash = self) @@ -50,13 +50,13 @@ def count_child_nodes(hash = self) count end - # For BBTree, teh to_s method shows the count of the children plus a graphical - # depiction of the tree, and the relation of the nodes. - # For TagNodes, the root-most tag is displayed, and the children are counted. + # For BBTree, the to_s method shows the count of the children plus a graphical + # depiction of the tree, and the relation of the nodes. + # For TagNodes, the root-most tag is displayed, and the children are counted. def to_s object_identifier = "#<#{self.class.to_s}:0x#{'%x' % (self.object_id << 1)}\n" close_object = ">\n" - + case self when RubyBBCode::BBTree object_identifier + "Children: #{count_child_nodes}\n" + self.to_v + close_object @@ -68,26 +68,26 @@ def to_s end end end - + private - - # This function is used by to_v and anything else that needs to iterate through the + + # This function is used by to_v and anything else that needs to iterate through the # @bbtree def walk_tree(tree, depth = -1, &blk) return enum_for(:walk_tree) unless blk # ignore me for now, I'm a convention for being versatile - + # Perform the block action specified at top level!!! yield tree, depth unless depth == -1 - + # next if we're a text node return if tree.type == :text - + # Enter into recursion (including block action) for each child node in this node tree.children.each do |node| walk_tree(node, depth + 1, &blk) end end - + end - -end \ No newline at end of file + +end diff --git a/lib/ruby-bbcode-to-md/tag_collection.rb b/lib/ruby-bbcode-to-md/tag_collection.rb index 9e92e72..4fa7a44 100644 --- a/lib/ruby-bbcode-to-md/tag_collection.rb +++ b/lib/ruby-bbcode-to-md/tag_collection.rb @@ -9,6 +9,14 @@ def to_html(tags) # let child node render: children_html = node.has_children? ? node.children.to_html(tags) : nil + if children_html + if node.definition[:newlines] == :to_br + children_html.gsub!(/\n/, "
") + elsif node.definition[:paragraphs].nil? || node.definition[:paragraphs] == :to_br + children_html.gsub!(/\n\s*\n/, "\n
") + end + end + t = HtmlTemplate.new node t.inlay_between_text!(children_html) @@ -118,4 +126,4 @@ def between_text_goes_into_html_output_as_param? end end -end \ No newline at end of file +end diff --git a/lib/ruby-bbcode-to-md/tag_node.rb b/lib/ruby-bbcode-to-md/tag_node.rb index 40ed60f..67614c9 100644 --- a/lib/ruby-bbcode-to-md/tag_node.rb +++ b/lib/ruby-bbcode-to-md/tag_node.rb @@ -64,4 +64,4 @@ def tag_param=(param) end end -end \ No newline at end of file +end diff --git a/lib/ruby-bbcode-to-md/tag_sifter.rb b/lib/ruby-bbcode-to-md/tag_sifter.rb index 8c32b42..9b9a8b7 100644 --- a/lib/ruby-bbcode-to-md/tag_sifter.rb +++ b/lib/ruby-bbcode-to-md/tag_sifter.rb @@ -25,6 +25,7 @@ def process_text @ti.handle_unregistered_tags_as_text # if the tag isn't in the @dictionary list, then treat it as text handle_closing_tags_that_are_multi_as_text_if_it_doesnt_match_the_latest_opener_tag_on_the_stack + handle_tags_that_are_plain_as_text_if_it_doesnt_match_the_latest_opener_tag_on_the_stack return if !valid_element? @@ -99,6 +100,18 @@ def handle_closing_tags_that_are_multi_as_text_if_it_doesnt_match_the_latest_ope end + def handle_tags_that_are_plain_as_text_if_it_doesnt_match_the_latest_opener_tag_on_the_stack + if @ti.element_is_tag? + return if @bbtree.current_node[:definition].nil? + if parent_tag != @ti[:tag].to_sym and @bbtree.current_node[:definition][:plain_tag] + @ti[:is_tag] = false + @ti[:closing_tag] = false + @ti[:text] = @ti.tag_data[:complete_match] + end + end + + end + private diff --git a/lib/tags/tags.rb b/lib/tags/tags.rb index a3551c4..a32620a 100644 --- a/lib/tags/tags.rb +++ b/lib/tags/tags.rb @@ -1,7 +1,7 @@ module RubyBBCode module Tags # tagname => tag, HTML open tag, HTML close tag, description, example - # All of these entrys are represented as @dictionary in the classes (or as the variable tags) + # All of these entries are represented as @dictionary in the classes (or as the variable tags) # A single item from this file (eg the :b entry) is refered to as a @definition @@tags = { :b => { @@ -16,6 +16,15 @@ module Tags :html_open => '', :html_close => '', :description => 'Underline text', :example => 'This is [u]underlined[/u].'}, + :s => { + :html_open => '~~', :html_close => '~~', + :description => 'Strike-through text', + :example => 'This is strike-through text.'}, + :code => { + :html_open => "\n```\n", :html_close => "\n```\n", + :description => 'Code block', + :example => '[code]code[/code].', + :plain_tag => true}, :center => { :html_open => '', :html_close => '', :description => 'Center a text', @@ -24,12 +33,14 @@ module Tags :html_open => "\n", :html_close => "\n", :description => 'Unordered list', :example => '[ul][li]List item[/li][li]Another list item[/li][/ul].', - :only_allow => [ :li ]}, + :only_allow => [ :li ], + :paragraphs => :allow}, :ol => { :html_open => "\n", :html_close => "\n", :description => 'Ordered list', :example => '[ol][li]List item[/li][li]Another list item[/li][/ol].', - :only_allow => [ :li ]}, + :only_allow => [ :li ], + :paragraphs => :allow}, :li => { :html_open => { :ul => ' - ', @@ -61,20 +72,21 @@ module Tags :tag_param => /(.*)/, :tag_param_tokens => [{:token => :href}]}, :quote => { - :first_html_open => "\n", :last_html_close => "\n", - :html_open => "[quote%author%]", :html_close => "[/quote]\n", + :html_open => "\n[quote%author%]\n", :html_close => "\n[/quote]\n", :description => 'Quote another person', :example => '[quote]BBCode is great[/quote]', :allow_tag_param => true, :allow_tag_param_between => false, :tag_param => /(.*)/, - :tag_param_tokens => [{:token => :author, :prefix => '=', :postfix => ""}]}, + :tag_param_tokens => [{:token => :author, :prefix => '=', :postfix => ""}], + :paragraphs => :allow}, :size => { :html_open => '[size=%size%]', :html_close => '[/size]', :description => 'Change the size of the text', :example => '[size=32]This is 32px[/size]', :allow_tag_param => true, :allow_tag_param_between => false, :tag_param => /(\d*)/, - :tag_param_tokens => [{:token => :size}]}, + :tag_param_tokens => [{:token => :size}], + :paragraphs => :allow}, :color => { :html_open => '', :html_close => '', :description => 'Change the color of the text', diff --git a/test/fluxbb_test.rb b/test/fluxbb_test.rb new file mode 100644 index 0000000..59db167 --- /dev/null +++ b/test/fluxbb_test.rb @@ -0,0 +1,44 @@ +require_relative 'test_helper' + +class FluxbbTest < MiniTest::Unit::TestCase + def fluxbb_tags + return { + img: RubyBBCode::Tags.tag_list[:img].merge( + :html_open => '', + :html_close => '', + :example => '[img=my alt text]http://www.google.com/intl/en_ALL/images/logo.gif[/img]', + :tag_param => /(.*)/, + :tag_param_tokens => [{:token => :alt_text, :prefix => ' alt="', :postfix => '"'}], + :tag_param_description => 'The img bbcode takes alt text as a parameter' + ), + :h => { + :html_open => "\n### ", :html_close => "\n", + :newlines => :to_br, + :description => 'Make a heading', + :example => '[h]My Heading[/h].'} + } + end + + def test_heading + assert_equal "\n### My Heading\n", "[h]My Heading[/h]".bbcode_to_md(false, fluxbb_tags) + end + + def test_heading_on_two_lines + assert_equal "\n### My Heading
on two lines\n", "[h]My Heading\non two lines[/h]".bbcode_to_md(false, fluxbb_tags) + end + + def test_image_with_alt_text + assert_equal 'FluxBB allows alt text', + '[img=FluxBB allows alt text]http://www.ruby-lang.org/images/header-ruby-logo.png[/img]'.bbcode_to_md(false, fluxbb_tags) + end + + def test_image_without_alt_text + assert_equal '', + '[img]http://www.ruby-lang.org/images/header-ruby-logo.png[/img]'.bbcode_to_md(false, fluxbb_tags) + end + + def test_ignored_attempt_to_pass_width_height + assert_equal '100x200', + '[img=100x200]http://www.ruby-lang.org/images/header-ruby-logo.png[/img]'.bbcode_to_md(false, fluxbb_tags) + end +end diff --git a/test/ruby_bbcode_test.rb b/test/ruby_bbcode_test.rb index 24f05d0..d8dc916 100644 --- a/test/ruby_bbcode_test.rb +++ b/test/ruby_bbcode_test.rb @@ -9,7 +9,7 @@ def test_multiline def test_strong assert_equal '**simple**', '[b]simple[/b]'.bbcode_to_md - assert_equal "**line 1\nline 2**", "**line 1\nline 2**".bbcode_to_md + assert_equal "**line 1\nline 2**", "[b]line 1\nline 2[/b]".bbcode_to_md end def test_em @@ -17,11 +17,20 @@ def test_em assert_equal "*line 1\nline 2*", "[i]line 1\nline 2[/i]".bbcode_to_md end + def test_paragraph_breaking_up_markdown + assert_equal "**paragraph 1\n
paragraph 2**", "[b]paragraph 1\n\nparagraph 2[/b]".bbcode_to_md + assert_equal "*paragraph 1\n
paragraph 2*", "[i]paragraph 1\n\nparagraph 2[/i]".bbcode_to_md + end + def test_u assert_equal 'simple', '[u]simple[/u]'.bbcode_to_md assert_equal "line 1\nline 2", "[u]line 1\nline 2[/u]".bbcode_to_md end + def test_s + assert_equal '~~simple~~', '[s]simple[/s]'.bbcode_to_md + end + def test_size assert_equal '[size=32]32px Text[/size]', '[size=32]32px Text[/size]'.bbcode_to_md end @@ -34,6 +43,14 @@ def test_color def test_center assert_equal 'centered', '[center]centered[/center]'.bbcode_to_md end + + def test_code + assert_equal "\n```\ncode\n```\n", '[code]code[/code]'.bbcode_to_md + assert_equal "\n```\ncode\n```\n", '[code=javascript]code[/code]'.bbcode_to_md + assert_equal "\n```\nSome [b]bbcode[/b] :-)\n```\n", '[code]Some [b]bbcode[/b] :-)[/code]'.bbcode_to_md + assert_equal "\n```\nSome <b>html</b>\n```\n", '[code]Some html[/code]'.bbcode_to_md + assert_equal "\n```\nSome html\n```\n", '[code]Some html[/code]'.bbcode_to_md(false) + end def test_ordered_list assert_equal "\n 1. item 1\n 1. item 2\n\n", '[ol][li]item 1[/li][li]item 2[/li][/ol]'.bbcode_to_md @@ -55,13 +72,15 @@ def test_whitespace_in_only_allowed_tags end def test_quote - assert_equal "\n[quote]quoting[/quote]\n\n", '[quote]quoting[/quote]'.bbcode_to_md - assert_equal "\n[quote=someone]quoting[/quote]\n\n", '[quote=someone]quoting[/quote]'.bbcode_to_md + assert_equal "\n[quote]\nquoting\n[/quote]\n", '[quote]quoting[/quote]'.bbcode_to_md + assert_equal "\n[quote=someone]\nquoting\n[/quote]\n", '[quote=someone]quoting[/quote]'.bbcode_to_md end def test_nested_quotes - assert_equal "\n[quote=Kitten]\n[quote=creatiu]f1[/quote]\n\nf2[/quote]\n\n", + assert_equal "\n[quote=Kitten]\n\n[quote=creatiu]\nf1\n[/quote]\nf2\n[/quote]\n", '[quote=Kitten][quote=creatiu]f1[/quote]f2[/quote]'.bbcode_to_md + assert_equal "A\n[quote]\nB\n[quote]\nC\n[quote]\nD\n[/quote]\nE\n[/quote]\nF\n[/quote]\nG", + 'A[quote]B[quote]C[quote]D[/quote]E[/quote]F[/quote]G'.bbcode_to_md end def test_link @@ -138,7 +157,7 @@ def test_addition_of_tags end def test_multiple_tag_test - assert_equal "**bold***italic*underline\n[quote]quote[/quote]\n\n[link](https://test.com)", + assert_equal "**bold***italic*underline\n[quote]\nquote\n[/quote]\n[link](https://test.com)", "[b]bold[/b][i]italic[/i][u]underline[/u][quote]quote[/quote][url=https://test.com]link[/url]".bbcode_to_md end @@ -157,15 +176,15 @@ def test_different_start_and_ending_tags # TODO: This stack level problem should be validated during the validations def test_stack_level_too_deep num = 2300 # increase this number if the test starts failing. It's very near the tipping point - openers = "[s]hi i'm" * num - closers = "[/s]" * num + openers = "[x]hi i'm" * num + closers = "[/x]" * num assert_raises( RuntimeError ) do (openers+closers).bbcode_to_md end end - def test_mulit_tag + def test_multi_tag input1 = "[media]https://www.youtube.com/watch?v=cSohjlYQI2A[/media]" input2 = "[media]http://vimeo.com/46141955[/media]" diff --git a/test/test_helper.rb b/test/test_helper.rb index 1773bd6..1ca1f19 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,7 +1,7 @@ require 'ruby-bbcode-to-md' require 'minitest/autorun' -# This hack allows us to make all the private methods of a class public. +# This hack allows us to make all the private methods of a class public. class Class def publicize_methods saved_private_instance_methods = self.private_instance_methods diff --git a/test/unit/debugging_test.rb b/test/unit/debugging_test.rb index ba38a1f..f9a8eb8 100644 --- a/test/unit/debugging_test.rb +++ b/test/unit/debugging_test.rb @@ -2,7 +2,7 @@ class RubyBbcodeTest < MiniTest::Unit::TestCase include ::RubyBBCode::Tags - + def test_bbtree_to_v text = "[i][b]a[/b][b]a[/b][b]a[/b][b]a[/b]item 1[/i][i]item 2[/i]" visual = <