mcbean 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
@@ -1,2 +1,3 @@
1
- "5��RiOs+�?�'�/�Z�~�5'%���ٗ]��ce62����P�~��פ�Dґ<Xᚯ}c��-���·�An&HTX}������ޝ�k/ж�!uD}�Sm�p� ?������ �P���>��Pi��{k����7�d���N=���6�])�Z�"Q�qH�&�֤q� ��A��7v''��]�\Qu�M��>
2
- �љ���]ֺ�y,a�Ѿ) G,=�aJ\��Z����ki��@�+
1
+ WBB�����90���\֫5�#�$Kߵ�2f�Fko��%�s��c���
2
+ n���%�I0?-���aI�j@�hk jo ��k��ҷA�j��±�I�?b6Ïw�{�VK9P�:��u�-��~�C��n�g�yeΪ��Z�Lr�.��� ���>E��ښ�Ҝ��k�CZ�F�!/���=N���k܁��+� t�� x�먊<e�w)
3
+ �j���%
@@ -2,10 +2,33 @@
2
2
 
3
3
  == HEAD
4
4
 
5
+ Features:
6
+
7
+ * Support for Textile.
8
+ * McBean#to_html now does the right thing when the instance is created via McBean.markdown or McBean.textile.
9
+ * McBean#to_html now entity-escapes unsafe and invalid HTML tags (thanks to Loofah).
10
+
11
+ Deprecations:
12
+
13
+ * McBean.new and .allocate are now private. You shouldn't have been using them, anyway.
14
+ * McBean#html and #markdown accessors have been dropped.
15
+
16
+ == 0.2.0 (2010-03-24)
17
+
18
+ * Converts Markdown to HTML (thanks to RDiscount). GH #2.
5
19
  * <br> elements are converted into newlines (markdown). GH #5
6
20
  * <a> elements without an 'href' attribute are not rendered as hyperlinks (markdown). GH #4
7
21
 
22
+ == 0.1.2 (2010-03-10)
23
+
24
+ * Command line utility "mcbean"
25
+ * Demo site on Heroku
26
+
27
+ == 0.1.1 (2010-03-09)
28
+
29
+ * Better hyperlink handling
30
+
8
31
  == 0.1.0 (2010-03-09)
9
32
 
10
33
  * Happy Birthday!
11
- * Converts HTML documents into Markdown.
34
+ * Converts HTML documents to Markdown.
@@ -1,12 +1,13 @@
1
1
  .autotest
2
2
  CHANGELOG.rdoc
3
- History.txt
4
3
  Manifest.txt
5
4
  README.rdoc
6
5
  Rakefile
7
6
  bin/mcbean
8
7
  lib/mcbean.rb
9
8
  lib/mcbean/markdown.rb
9
+ lib/mcbean/textile.rb
10
10
  test/helper.rb
11
11
  test/test_markdown.rb
12
12
  test/test_mcbean.rb
13
+ test/test_textile.rb
@@ -1,46 +1,51 @@
1
1
  = McBean
2
2
 
3
3
  * http://github.com/flavorjones/mcbean
4
- * http://mcbean.heroku.com/
4
+ * http://mcbean.heroku.com (live demo)
5
5
 
6
6
  == Description
7
7
 
8
- McBean converts HTML into Markdown, and Markdown into HTML (with the
9
- help of Loofah, Nokogiri and RDiscount).
8
+ McBean can convert documents from one format to another. McBean currently supports:
10
9
 
11
- Its goal is to eventually be able to transform documents from HTML to
12
- Markdown to Textile, and anything in between. It will be the Sylvester
13
- McMonkey McBean of markup, placing stars onto the bellies of all kinds
14
- of Sneetchy document formats.
10
+ * HTML
11
+ * Markdown (a subset)
12
+ * Textile (a subset)
15
13
 
16
- "You can't teach a Sneetch."
14
+ with the help of Loofah, Nokogiri, RDiscount and RedCloth.
17
15
 
18
- == Features / Problems
16
+ "You can't teach a Sneetch." -- Sylvester McMonkey McBean
19
17
 
20
- * Transforms HTML into Markdown, and Markdown into HTML.
21
- * Doesn't do anything else yet.
18
+ == Features
22
19
 
23
- == Synopsis
20
+ * Transforms HTML into Markdown, and Markdown into HTML (thanks to RDiscount).
21
+ * Transforms HTML into Textile, and Textile into HTML (thanks to RedCloth).
22
+ * Transforms Textile into Markdown, and Markdown into Textile.
23
+ * Emitted HTML is sanitized (thanks to Loofah).
24
+ * Fancy-pants command line utility, "mcbean".
24
25
 
25
- If you have an HTML fragment, you can convert it into Markdown:
26
+ == Problems
26
27
 
27
- McBean.fragment(your_html).to_markdown
28
+ * Only supports a limited subset of Markdown and Textile. Patches welcome.
28
29
 
29
- Or if you have an HTML document, you can convert it into Markdown:
30
+ == Synopsis
30
31
 
31
- McBean.document(your_html).to_markdown
32
+ Wrap your document (which can be either a String or an IO object):
32
33
 
33
- You can also convert Markdown into HTML (via RDiscount):
34
+ mcbean = McBean.fragment(your_html_fragment)
35
+ mcbean = McBean.document(your_html_document)
36
+ mcbean = McBean.markdown(your_markdown)
37
+ mcbean = McBean.textile(your_textile)
34
38
 
35
- McBean.markdown(your_markdown).to_html
39
+ And then generate the desired markup format:
36
40
 
37
- Note that the parameter passed to +fragment+, +document+ and
38
- +markdown+ can be either a String or an IO.
41
+ mcbean.to_html
42
+ mcbean.to_markdown
43
+ mcbean.to_textile
39
44
 
40
45
  Also, +mcbean+ provides a command-line utility installed into your gem path:
41
46
 
42
- $ mcbean /usr/lib/openoffice/licenses/LICENSE_en-GB.html
43
- $ mcbean http://daringfireball.net/projects/markdown/syntax
47
+ $ mcbean --html="http://en.wikipedia.org/wiki/The_Sneetches_and_Other_Stories" --to-markdown
48
+ $ mcbean --markdown="treetop-1.4.2/doc/grammar_composition.markdown" --to-textile
44
49
 
45
50
  You can try out McBean at the live demo site: http://mcbean.heroku.com
46
51
 
@@ -52,8 +57,9 @@ have a single root node, you have a *fragment*.
52
57
 
53
58
  == Requirements
54
59
 
55
- * Loofah 0.4.7 (and thusly Nokogiri)
56
- * RDiscount 1.3.4
60
+ * Loofah >= 0.4.7 (and thusly Nokogiri)
61
+ * RDiscount >= 1.3.4
62
+ * RedCloth >= 4.0.0
57
63
 
58
64
  == Install
59
65
 
@@ -63,6 +69,8 @@ have a single root node, you have a *fragment*.
63
69
 
64
70
  Thanks to David Loren Parsons and Ryan Tomayko for RDiscount.
65
71
 
72
+ Thanks to Jason Garber for RedCloth.
73
+
66
74
  == License
67
75
 
68
76
  (The MIT License)
data/Rakefile CHANGED
@@ -13,10 +13,12 @@ Hoe.spec 'mcbean' do
13
13
  self.history_file = "CHANGELOG.rdoc"
14
14
  self.readme_file = "README.rdoc"
15
15
 
16
- extra_deps << ["loofah", ">= 0.4.7"]
17
- extra_deps << ["rdiscount", ">= 1.3.4"]
18
- extra_dev_deps << ["shoulda", ">= 2.10"]
19
- extra_dev_deps << ["rr", ">= 0.10.4"]
16
+ self.extra_deps << ["loofah", ">= 0.4.7"]
17
+ self.extra_deps << ["rdiscount", ">= 1.3.4"]
18
+ self.extra_deps << ["RedCloth", ">= 4.0.0"]
19
+ self.extra_dev_deps << ["minitest", ">= 1.6.0"]
20
+
21
+ self.testlib = :minitest
20
22
  end
21
23
 
22
24
  task :redocs => :fix_css
@@ -35,11 +37,6 @@ task :fix_css do
35
37
  margin-top : .5em ;
36
38
  }
37
39
 
38
- #main ul, div#documentation ul {
39
- list-style-type : disc ! IMPORTANT ;
40
- list-style-position : inside ! IMPORTANT ;
41
- }
42
-
43
40
  h2 + ul {
44
41
  margin-top : 1em;
45
42
  }
data/bin/mcbean CHANGED
@@ -3,12 +3,65 @@
3
3
  require 'open-uri'
4
4
  require 'rubygems'
5
5
  require 'mcbean'
6
+ require 'getoptlong'
6
7
 
7
- unless ARGV[0]
8
- puts "USAGE: #{File.basename(__FILE__)} <file-or-url>"
8
+ SCRIPT = File.basename(__FILE__)
9
+ @input_format = "html"
10
+ @output_format = "markdown"
11
+ @input_file = nil
12
+
13
+ OPTS = []
14
+ McBean.formats.each do |format|
15
+ OPTS << [ "--#{format}", "-#{format[0,1]}", GetoptLong::REQUIRED_ARGUMENT ]
16
+ OPTS << [ "--to-#{format}", "-#{format[0,1].upcase}", GetoptLong::NO_ARGUMENT ]
17
+ end
18
+
19
+ def _usage
20
+ puts "USAGE: #{SCRIPT} [--<FROM_FORMAT>=]<FILE-OR-URL> [--to-<TO_FORMAT>]"
21
+ puts
22
+ puts " McBean transforms a file from one format to another, for your reading pleasure."
23
+ puts
24
+ puts " e.g.:"
25
+ puts " #{SCRIPT} --html=\"http://en.wikipedia.org/wiki/The_Sneetches_and_Other_Stories\" --to-markdown"
26
+ puts " #{SCRIPT} --markdown=\"sneetches.md\" --to-textile"
27
+ puts
28
+ puts " If FROM_FORMAT option is not specified, --#{@input_format} is assumed"
29
+ puts " If TO_FORMAT option is not specified, --to-#{@output_format} is assumed"
9
30
  puts
10
- puts "McBean transforms HTML into Markdown for your reading pleasure."
31
+ puts " Shortcuts / Supported Formats:"
32
+ OPTS.each do |long, short, _|
33
+ puts " #{short} for #{long}"
34
+ end
11
35
  exit 1
12
36
  end
13
37
 
14
- puts McBean.document(open(ARGV[0])).to_markdown
38
+ begin
39
+ GetoptLong.new(*OPTS).each do |opt, arg|
40
+ McBean.formats.each do |format|
41
+ if opt == "--#{format}"
42
+ @input_format = format
43
+ @input_file = arg
44
+ elsif opt == "--to-#{format}"
45
+ @output_format = format
46
+ end
47
+ end
48
+ end
49
+ rescue
50
+ _usage
51
+ end
52
+
53
+ if @input_file.nil?
54
+ _usage if ARGV.length != 1
55
+ @input_file = ARGV[0]
56
+ end
57
+
58
+ mcbean = case @input_format
59
+ when "html"
60
+ McBean.document(open(@input_file))
61
+ else
62
+ McBean.send(@input_format, open(@input_file))
63
+ end
64
+
65
+ puts mcbean.send("to_#{@output_format}")
66
+
67
+ exit 0
@@ -1,36 +1,82 @@
1
1
  require "loofah"
2
2
 
3
+ #
4
+ # McBean can convert documents from one format to another.
5
+ #
6
+ # See the README.rdoc for more details and examples.
7
+ #
3
8
  class McBean
4
- VERSION = "0.2.0"
9
+ # Current version of McBean
10
+ VERSION = "0.3.0"
11
+
12
+ # Minimum required version of Loofah
5
13
  REQUIRED_LOOFAH_VERSION = "0.4.7"
6
14
 
7
- attr_accessor :html
15
+ attr_writer :__html__ # :nodoc:
16
+
17
+ private_class_method :new, :allocate
8
18
 
19
+ @@__formats__ = ["html"]
20
+
21
+ ##
22
+ # Create a McBean from an HTML fragment string (or IO object)
23
+ #
24
+ # Please see README.rdoc for more information on HTML fragments and documents.
25
+ #
9
26
  def McBean.fragment(string_or_io)
10
- mcbean = allocate
11
- mcbean.html = Loofah.fragment(string_or_io)
27
+ mcbean = new
28
+ mcbean.__html__ = Loofah.fragment(string_or_io)
12
29
  mcbean
13
30
  end
14
31
 
32
+ ##
33
+ # Create a McBean from an HTML document string (or IO object)
34
+ #
35
+ # Please see README.rdoc for more information on HTML fragments and documents.
36
+ #
15
37
  def McBean.document(string_or_io)
16
- mcbean = allocate
17
- mcbean.html = Loofah.document(string_or_io)
38
+ mcbean = new
39
+ mcbean.__html__ = Loofah.document(string_or_io)
18
40
  mcbean
19
41
  end
20
42
 
21
- def McBean.markdown(string_or_io)
22
- if string_or_io.respond_to?(:read)
23
- McBean::Markdownify::Antidote.new(string_or_io.read)
24
- else
25
- McBean::Markdownify::Antidote.new(string_or_io)
43
+ ##
44
+ # Returns an array of formats that McBean supports.
45
+ #
46
+ def McBean.formats
47
+ @@__formats__
48
+ end
49
+
50
+ ##
51
+ # Generate an HTML string representation of the McBeaned document.
52
+ #
53
+ # So you can convert documents in other formats to HTML as follows:
54
+ #
55
+ # McBean.markdown(File.read(path_to_markdown_file)).to_html
56
+ #
57
+ def to_html
58
+ __html__.dup.scrub!(:escape).to_html
59
+ end
60
+
61
+ def __html__ # :nodoc:
62
+ @__html__ ||= nil
63
+ unless @__html__
64
+ (McBean.formats - ["html"]).each do |format|
65
+ obj = send("__#{format}__", false)
66
+ if obj
67
+ @__html__ = Loofah.document(obj.to_html)
68
+ break
69
+ end
70
+ end
26
71
  end
72
+ @__html__
27
73
  end
28
74
  end
29
75
  Mcbean = McBean
30
76
 
31
77
  require "mcbean/markdown"
78
+ require "mcbean/textile"
32
79
 
33
80
  if Loofah::VERSION < McBean::REQUIRED_LOOFAH_VERSION
34
81
  raise RuntimeError, "McBean requires Loofah #{McBean::REQUIRED_LOOFAH_VERSION} or later (currently #{Loofah::VERSION})"
35
82
  end
36
-
@@ -1,6 +1,42 @@
1
1
  require 'rdiscount'
2
2
 
3
3
  class McBean
4
+ attr_writer :__markdown__ # :nodoc:
5
+
6
+ @@__formats__ << "markdown"
7
+
8
+ ##
9
+ # Create a McBean from a Markdown document string (or IO object)
10
+ #
11
+ def McBean.markdown(string_or_io)
12
+ mcbean = new
13
+ mcbean.__markdown__ = McBean::Markdownify::Antidote.new(string_or_io.respond_to?(:read) ? string_or_io.read : string_or_io)
14
+ mcbean
15
+ end
16
+
17
+ ##
18
+ # Generate a Markdown string representation of the McBeaned document.
19
+ #
20
+ # So you can convert documents in other formats to Markdown as follows:
21
+ #
22
+ # McBean.fragment(File.read(path_to_html_file)).to_markdown
23
+ #
24
+ def to_markdown
25
+ __markdown__.text
26
+ end
27
+
28
+ def __markdown__ generate_from_html_if_necessary=true # :nodoc:
29
+ @__markdown__ ||= nil
30
+ if @__markdown__.nil? && generate_from_html_if_necessary
31
+ @__markdown__ = McBean::Markdownify::Antidote.new(
32
+ Loofah::Helpers.remove_extraneous_whitespace(
33
+ __html__.dup.scrub!(:escape).scrub!(Markdownify.new).text(:encode_special_chars => false)
34
+ ))
35
+ end
36
+ @__markdown__
37
+ end
38
+
39
+ # :stopdoc:
4
40
  class Markdownify < Loofah::Scrubber
5
41
  Antidote = ::RDiscount # could conceivably be BlueCloth
6
42
 
@@ -88,10 +124,5 @@ class McBean
88
124
  (node.document.serialize_root || node.ancestors.last).children.last
89
125
  end
90
126
  end
91
-
92
- def to_markdown
93
- Loofah::Helpers.remove_extraneous_whitespace \
94
- html.dup.scrub!(:prune).scrub!(Markdownify.new).text(:encode_special_chars => false)
95
- end
127
+ # :startdoc:
96
128
  end
97
-
@@ -0,0 +1,110 @@
1
+ require 'redcloth'
2
+
3
+ class McBean
4
+ attr_writer :__textile__ # :nodoc:
5
+
6
+ @@__formats__ << "textile"
7
+
8
+ ##
9
+ # Create a McBean from a Textile document string (or IO object)
10
+ #
11
+ def McBean.textile string_or_io
12
+ mcbean = new
13
+ mcbean.__textile__ = McBean::Textilify::Antidote.new(string_or_io.respond_to?(:read) ? string_or_io.read : string_or_io)
14
+ mcbean
15
+ end
16
+
17
+ ##
18
+ # Generate a Textile string representation of the McBeaned document.
19
+ #
20
+ # So you can convert documents in other formats to Textile as follows:
21
+ #
22
+ # McBean.fragment(File.read(path_to_html_file)).to_textile
23
+ #
24
+ def to_textile
25
+ __textile__.to_s
26
+ end
27
+
28
+ def __textile__ generate_from_html_if_necessary=true # :nodoc:
29
+ @__textile__ ||= nil
30
+ if @__textile__.nil? && generate_from_html_if_necessary
31
+ @__textile__ = McBean::Textilify::Antidote.new(
32
+ Loofah::Helpers.remove_extraneous_whitespace(
33
+ __html__.dup.scrub!(:escape).scrub!(Textilify.new).text(:encode_special_chars => false)
34
+ ))
35
+ end
36
+ @__textile__
37
+ end
38
+
39
+ # :stopdoc:
40
+ class Textilify < Loofah::Scrubber
41
+ Antidote = ::RedCloth::TextileDoc
42
+
43
+ def initialize
44
+ @direction = :bottom_up
45
+ @link_references = nil
46
+ @link_reference_count = 0
47
+ end
48
+
49
+ def scrub(node)
50
+ return CONTINUE if node.text?
51
+ replacement_killer = \
52
+ case node.name
53
+ when "h1"
54
+ new_text node, "\nh1. #{node.content}\n"
55
+ when "h2"
56
+ new_text node, "\nh2. #{node.content}\n"
57
+ when "h3"
58
+ new_text node, "\nh3. #{node.content}\n"
59
+ when "h4"
60
+ new_text node, "\nh4. #{node.content}\n"
61
+ when "blockquote"
62
+ new_text node, "\nbq. #{node.content.gsub(/\n\n/, "\n").sub(/^\n/,'')}"
63
+ when "li"
64
+ nil # handled by parent list tag
65
+ when "ul"
66
+ fragment = []
67
+ node.xpath("./li").each do |li|
68
+ fragment << "* #{li.text}" if li.text =~ /\S/
69
+ end
70
+ new_text node, "\n#{fragment.join("\n")}\n"
71
+ when "ol"
72
+ fragment = []
73
+ node.xpath("./li").each do |li|
74
+ fragment << "# #{li.text}" if li.text =~ /\S/
75
+ end
76
+ new_text node, "\n#{fragment.join("\n")}\n"
77
+ when "code"
78
+ if node.parent.name == "pre"
79
+ new_text node, node.content.sub(/^/,"bc. ")
80
+ else
81
+ nil
82
+ end
83
+ when "br"
84
+ new_text node, "\n"
85
+ when "a"
86
+ if node['href'].nil?
87
+ new_text node, node.content
88
+ elsif node['title']
89
+ new_text node, %Q{["#{node.text} (#{node['title']})":#{node['href']}]}
90
+ else
91
+ new_text node, %Q{["#{node.text}":#{node['href']}]}
92
+ end
93
+ else
94
+ if Loofah::HashedElements::BLOCK_LEVEL[node.name]
95
+ new_text node, "\n#{node.content}\n"
96
+ else
97
+ nil
98
+ end
99
+ end
100
+ node.replace(replacement_killer) if replacement_killer
101
+ end
102
+
103
+ private
104
+
105
+ def new_text(node, text)
106
+ Nokogiri::XML::Text.new(text, node.document)
107
+ end
108
+ end
109
+ # :startdoc:
110
+ end
@@ -1,8 +1,2 @@
1
- require "test/unit"
1
+ require "minitest/autorun"
2
2
  require "mcbean"
3
- require "shoulda"
4
- require "rr"
5
-
6
- class Test::Unit::TestCase
7
- include RR::Adapters::TestUnit
8
- end
@@ -1,132 +1,149 @@
1
1
  require File.dirname(__FILE__) + "/helper"
2
2
 
3
- class TestMcBeanMarkdown < Test::Unit::TestCase
4
- context McBean::Markdownify do
5
- context "#to_markdown" do
6
- should "add whitespace around block elements" do
7
- assert_markdown "before<div>inner</div>after", "before\ninner\nafter", false
3
+ describe McBean::Markdownify do
4
+ describe ".markdown" do
5
+ describe "passed a string" do
6
+ it "sets #__markdown__ to be a Markdownify::Antidote" do
7
+ McBean.markdown("hello\n=====\n").__markdown__.must_be_instance_of McBean::Markdownify::Antidote
8
8
  end
9
+ end
9
10
 
10
- should "convert h1 tag" do
11
- assert_markdown "<h1>Foo</h1>", "\nFoo\n==========\n"
11
+ describe "passed an IO" do
12
+ it "sets #__markdown__ to be a Markdownify::Antidote" do
13
+ io = StringIO.new "hello\n=====\n"
14
+ McBean.markdown(io).__markdown__.must_be_instance_of McBean::Markdownify::Antidote
12
15
  end
16
+ end
17
+ end
13
18
 
14
- should "convert h2 tag" do
15
- assert_markdown "<h2>Foo</h2>", "\nFoo\n----------\n"
16
- end
19
+ describe "#to_html" do
20
+ attr_accessor :mcbean
17
21
 
18
- should "convert h3 tag" do
19
- assert_markdown "<h3>Foo</h3>", "\n### Foo ###\n"
22
+ describe "on an instance created by .markdown" do
23
+ before do
24
+ @mcbean = McBean.markdown "ohai!\n=====\n"
20
25
  end
21
26
 
22
- should "convert h4 tag" do
23
- assert_markdown "<h4>Foo</h4>", "\n#### Foo ####\n"
27
+ it "returns an html string" do
28
+ html = mcbean.to_html
29
+ html.must_be_instance_of String
30
+ html.must_match %r{<h1>ohai!</h1>}
24
31
  end
32
+ end
33
+ end
25
34
 
26
- should "convert blockquote tag" do
27
- assert_markdown "<blockquote><p>Hello\nGoodbye</p></blockquote>",
28
- "> Hello\n> Goodbye\n"
29
- end
35
+ describe "#to_markdown" do
36
+ it "add whitespace around block elements" do
37
+ assert_markdown "before<div>inner</div>after", "before\ninner\nafter", false
38
+ end
30
39
 
31
- # should "convert nested blockquote tag" do
32
- # assert_markdown(
33
- # "<blockquote><p>Hello</p>\n\n<blockquote><p>Nested</p></blockquote>\n\n<p>Goodbye</p></blockquote>",
34
- # <<-EOM
35
- # > Hello
36
- # >
37
- # > > Nested
38
- # >
39
- # > Goodbye
40
- # EOM
41
- # )
42
- # end
43
-
44
- should "convert unordered list" do
45
- assert_markdown "<ul>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ul>\n",
46
- "\n* one\n* two\n* three\n"
47
- end
40
+ it "convert h1 tag" do
41
+ assert_markdown "<h1>Foo</h1>", "\nFoo\n==========\n"
42
+ end
48
43
 
49
- should "convert ordered list" do
50
- assert_markdown "<ol>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ol>\n",
51
- "\n1. one\n2. two\n3. three\n"
52
- end
44
+ it "convert h2 tag" do
45
+ assert_markdown "<h2>Foo</h2>", "\nFoo\n----------\n"
46
+ end
53
47
 
54
- should "ignore empty unordered list items" do
55
- assert_markdown "<ul>\n<li>one</li>\n<li></li>\n<li>three</li>\n</ul>\n",
56
- "\n* one\n* three\n",
57
- false
58
- end
48
+ it "convert h3 tag" do
49
+ assert_markdown "<h3>Foo</h3>", "\n### Foo ###\n"
50
+ end
59
51
 
60
- should "ignore empty ordered list items" do
61
- assert_markdown "<ol>\n<li>one</li>\n<li></li>\n<li>three</li>\n</ol>\n",
62
- "\n1. one\n3. three\n",
63
- false
64
- end
52
+ it "convert h4 tag" do
53
+ assert_markdown "<h4>Foo</h4>", "\n#### Foo ####\n"
54
+ end
65
55
 
66
- should "convert code blocks" do
67
- assert_markdown "<pre><code>This is a code block\ncontinued\n</code></pre>",
68
- "\n This is a code block\n continued\n\n"
69
- end
56
+ it "convert blockquote tag" do
57
+ assert_markdown "<blockquote><p>Hello\nGoodbye</p></blockquote>",
58
+ "> Hello\n> Goodbye\n"
59
+ end
60
+
61
+ # it "convert nested blockquote tag" do
62
+ # assert_markdown(
63
+ # "<blockquote><p>Hello</p>\n\n<blockquote><p>Nested</p></blockquote>\n\n<p>Goodbye</p></blockquote>",
64
+ # <<-EOM
65
+ # > Hello
66
+ # >
67
+ # > > Nested
68
+ # >
69
+ # > Goodbye
70
+ # EOM
71
+ # )
72
+ # end
73
+
74
+ it "convert unordered list" do
75
+ assert_markdown "<ul>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ul>\n",
76
+ "\n* one\n* two\n* three\n"
77
+ end
78
+
79
+ it "convert ordered list" do
80
+ assert_markdown "<ol>\n<li>one</li>\n<li>two</li>\n<li>three</li>\n</ol>\n",
81
+ "\n1. one\n2. two\n3. three\n"
82
+ end
83
+
84
+ it "ignore empty unordered list items" do
85
+ assert_markdown "<ul>\n<li>one</li>\n<li></li>\n<li>three</li>\n</ul>\n",
86
+ "\n* one\n* three\n",
87
+ false
88
+ end
70
89
 
71
- should "convert <br> tags to newlines" do
72
- assert_markdown "<div>hello<br>there</div>",
73
- "\nhello\nthere\n",
74
- false
75
- assert_markdown "<div>hello<br />there</div>",
76
- "\nhello\nthere\n",
77
- false
90
+ it "ignore empty ordered list items" do
91
+ assert_markdown "<ol>\n<li>one</li>\n<li></li>\n<li>three</li>\n</ol>\n",
92
+ "\n1. one\n3. three\n",
93
+ false
94
+ end
95
+
96
+ it "convert code blocks" do
97
+ assert_markdown "<pre><code>This is a code block\ncontinued\n</code></pre>",
98
+ "\n This is a code block\n continued\n\n"
99
+ end
100
+
101
+ it "convert <br> tags to newlines" do
102
+ assert_markdown "<div>hello<br>there</div>",
103
+ "\nhello\nthere\n",
104
+ false
105
+ assert_markdown "<div>hello<br />there</div>",
106
+ "\nhello\nthere\n",
107
+ false
108
+ end
109
+
110
+ describe "anchors" do
111
+ it "convert <a> tags" do
112
+ assert_markdown "<p>Yes, magic helmet. And <a href=\"http://sample.com/\">I'll give you a sample</a>.</p>",
113
+ "\nYes, magic helmet. And [I'll give you a sample](http://sample.com/).\n"
78
114
  end
79
115
 
80
- context "anchors" do
81
- should "convert <a> tags" do
82
- assert_markdown "<p>Yes, magic helmet. And <a href=\"http://sample.com/\">I'll give you a sample</a>.</p>",
83
- "\nYes, magic helmet. And [I'll give you a sample](http://sample.com/).\n"
84
- end
116
+ describe "<a> tags without hrefs" do
117
+ it "be ignored" do
118
+ assert_markdown "<div><a name='link-target'>target title</a></div>",
119
+ "\ntarget title\n",
120
+ false
85
121
 
86
- context "<a> tags without hrefs" do
87
- should "be ignored" do
88
- assert_markdown "<div><a name='link-target'>target title</a></div>",
89
- "\ntarget title\n",
90
- false
122
+ assert_markdown "<div><a id='link-target'>target title</a></div>",
123
+ "\ntarget title\n",
124
+ false
125
+ end
126
+ end
91
127
 
92
- assert_markdown "<div><a id='link-target'>target title</a></div>",
93
- "\ntarget title\n",
94
- false
95
- end
128
+ describe "<a> tags with titles" do
129
+ it "convert fq urls to reference-style" do
130
+ assert_markdown2 "<p>Yes, magic helmet. And <a href=\"http://sample.com/\" title=\"Fudd\">I'll give you a sample</a>.</p>",
131
+ "\nYes, magic helmet. And [I'll give you a sample][1].\n\n[1]: http://sample.com/ \"Fudd\"\n"
96
132
  end
97
133
 
98
- context "<a> tags with titles" do
99
- should "convert fq urls to reference-style" do
100
- assert_markdown2 "<p>Yes, magic helmet. And <a href=\"http://sample.com/\" title=\"Fudd\">I'll give you a sample</a>.</p>",
101
- "\nYes, magic helmet. And [I'll give you a sample][1].\n\n[1]: http://sample.com/ \"Fudd\"\n"
102
- end
103
-
104
- should "convert relative urls to reference-style" do
105
- assert_markdown2 "<p>Yes, magic helmet. And <a href=\"/home\" title=\"Fudd\">I'll give you a sample</a>.</p>",
106
- "\nYes, magic helmet. And [I'll give you a sample][1].\n\n[1]: /home \"Fudd\"\n"
107
- end
108
-
109
- should "convert multiple to appear in order at the end of the document" do
110
- assert_markdown2 "<p>See <a href=\"/prefs\" title=\"Prefs\">Prefs</a> and <a href=\"/home\" title=\"Home\">Home</a>.</p>",
111
- "\nSee [Prefs][1] and [Home][2].\n\n[1]: /prefs \"Prefs\"\n[2]: /home \"Home\"\n"
112
- end
134
+ it "convert relative urls to reference-style" do
135
+ assert_markdown2 "<p>Yes, magic helmet. And <a href=\"/home\" title=\"Fudd\">I'll give you a sample</a>.</p>",
136
+ "\nYes, magic helmet. And [I'll give you a sample][1].\n\n[1]: /home \"Fudd\"\n"
113
137
  end
114
- end
115
- end
116
- end
117
138
 
118
- context McBean::Markdownify::Antidote do
119
- context "given that RDiscount is already pretty well tested" do
120
- context "let's limit ourselves to a token test case" do
121
- should "convert markdown into html" do
122
- assert_equal "<h1>hello</h1>\n", McBean.markdown("hello\n=====\n").to_html
139
+ it "convert multiple to appear in order at the end of the document" do
140
+ assert_markdown2 "<p>See <a href=\"/prefs\" title=\"Prefs\">Prefs</a> and <a href=\"/home\" title=\"Home\">Home</a>.</p>",
141
+ "\nSee [Prefs][1] and [Home][2].\n\n[1]: /prefs \"Prefs\"\n[2]: /home \"Home\"\n"
123
142
  end
124
143
  end
125
144
  end
126
145
  end
127
146
 
128
- private
129
-
130
147
  def assert_markdown html, markdown, roundtrip=true
131
148
  assert_equal(html, McBean::Markdownify::Antidote.new(markdown).to_html.chomp, "markdown roundtrip failed") if roundtrip
132
149
  assert_equal(markdown, McBean.fragment(html).to_markdown, "fragment transformation failed")
@@ -142,3 +159,25 @@ class TestMcBeanMarkdown < Test::Unit::TestCase
142
159
  McBean.document("<div>#{html}</div>").to_markdown, "document transformation failed")
143
160
  end
144
161
  end
162
+
163
+ describe McBean::Markdownify::Antidote do
164
+ describe "given that RDiscount is already pretty well tested, let's limit ourselves to a token test case" do
165
+ it "convert markdown into html" do
166
+ McBean.markdown("hello\n=====\n").to_html.must_match %r{<body><h1>hello</h1></body>}
167
+ end
168
+ end
169
+
170
+ describe "given markdown with an unsafe tag" do
171
+ it "escapes the tag" do
172
+ markdown = "hello\n=====\n\n<script>alert('ohai!');</script>\n\nLOL\n"
173
+ McBean.markdown(markdown).to_html.must_include "<body>\n<h1>hello</h1>\n\n&lt;script&gt;alert('ohai!');&lt;/script&gt;<p>LOL</p>\n</body>"
174
+ end
175
+ end
176
+
177
+ describe "given markdown with an invalid tag" do
178
+ it "escapes the tag" do
179
+ markdown = "hello\n=====\n\n<xyzzy>Adventure!</xyzzy>\n\nLOL\n"
180
+ McBean.markdown(markdown).to_html.must_match %r{<body>\n<h1>hello</h1>\n\n<p>&lt;xyzzy&gt;Adventure!&lt;/xyzzy&gt;</p>\n\n<p>LOL</p>\n</body>}
181
+ end
182
+ end
183
+ end
@@ -1,52 +1,66 @@
1
1
  require File.dirname(__FILE__) + "/helper"
2
2
 
3
- class TestMcBean < Test::Unit::TestCase
4
- context "class name" do
5
- should "set McBean and Mcbean to be the same thing" do
3
+ describe McBean do
4
+ describe "class name" do
5
+ it "sets McBean and Mcbean to be the same thing" do
6
6
  assert McBean == Mcbean
7
7
  end
8
8
  end
9
9
 
10
- context "cleanup" do
11
- should "prune unsafe tags" do
12
- result = McBean.fragment("<div>OK</div><script>BAD</script>").to_markdown
13
- assert_match( /OK/, result)
14
- assert_no_match( /BAD/, result)
10
+ describe ".new" do
11
+ it "cannot be called" do
12
+ proc { McBean.new }.must_raise NoMethodError
15
13
  end
16
14
  end
17
15
 
18
- context "parsing" do
19
- context "McBean.fragment" do
20
- should "call Loofah.fragment" do
21
- html = "<h1>hello</h1>\n"
22
- mock.proxy(Loofah).fragment(html).once
23
- McBean.fragment html
24
- end
16
+ describe ".allocate" do
17
+ it "cannot be called" do
18
+ proc { McBean.allocate }.must_raise NoMethodError
19
+ end
20
+ end
21
+
22
+ describe ".fragment" do
23
+ it "sets #__html__ to be a Loofah fragment" do
24
+ McBean.fragment("<h1>hello</h1>\n").__html__.must_be_instance_of Loofah::HTML::DocumentFragment
25
+ end
26
+ end
27
+
28
+ describe ".document" do
29
+ it "sets #__html__ to be a Loofah document" do
30
+ McBean.document("<h1>hello</h1>\n").__html__.must_be_instance_of Loofah::HTML::Document
25
31
  end
32
+ end
33
+
34
+ describe "#to_html" do
35
+ attr_accessor :mcbean
36
+
37
+ it "escapes unsafe tags" do
38
+ result = McBean.fragment("<div>OK</div><script>BAD</script>").to_html
39
+ result.must_include "<div>OK</div>"
40
+ result.must_include "&lt;script&gt;BAD&lt;/script&gt;"
41
+ end
42
+
43
+ describe "on an instance created by .fragment" do
44
+ before do
45
+ @mcbean = McBean.fragment "<div>ohai!</div>"
46
+ end
26
47
 
27
- context "McBean.document" do
28
- should "call Loofah.document" do
29
- html = "<h1>hello</h1>\n"
30
- mock.proxy(Loofah).document(html).once
31
- McBean.document html
48
+ it "returns an html string" do
49
+ html = mcbean.to_html
50
+ html.must_be_instance_of String
51
+ html.must_match %r{<div>ohai!</div>}
32
52
  end
33
53
  end
34
54
 
35
- context "McBean.markdown" do
36
- context "passed a string" do
37
- should "create a Markdownify::Antidote" do
38
- mock.proxy(McBean::Markdownify::Antidote).new(anything).once
39
- assert_equal "<h1>hello</h1>\n", McBean.markdown("hello\n=====\n").to_html
40
- end
55
+ describe "on an instance created by .fragment" do
56
+ before do
57
+ @mcbean = McBean.document "<div>ohai!</div>"
41
58
  end
42
59
 
43
- context "passed an IO" do
44
- should "create a Markdownify::Antidote" do
45
- io = StringIO.new "hello\n=====\n"
46
- mock.proxy(McBean::Markdownify::Antidote).new(anything).once
47
- mock.proxy(io).read.once
48
- assert_equal "<h1>hello</h1>\n", McBean.markdown(io).to_html
49
- end
60
+ it "returns an html string" do
61
+ html = mcbean.to_html
62
+ html.must_be_instance_of String
63
+ html.must_match %r{<div>ohai!</div>}
50
64
  end
51
65
  end
52
66
  end
@@ -0,0 +1,151 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.dirname(__FILE__) + "/helper"
3
+
4
+ describe McBean::Textilify do
5
+ describe ".textile" do
6
+ describe "passed a string" do
7
+ it "sets #__textile__ to be a Textilify::Antidote" do
8
+ McBean.textile("h1. hello").__textile__.must_be_instance_of McBean::Textilify::Antidote
9
+ end
10
+ end
11
+
12
+ describe "passed an IO" do
13
+ it "sets #__textile__ to be a Textilify::Antidote" do
14
+ io = StringIO.new "h1. hello"
15
+ McBean.textile(io).__textile__.must_be_instance_of McBean::Textilify::Antidote
16
+ end
17
+ end
18
+ end
19
+
20
+ describe "#to_html" do
21
+ attr_accessor :mcbean
22
+
23
+ describe "on an instance created by .textile" do
24
+ before do
25
+ @mcbean = McBean.textile "h1. ohai!"
26
+ end
27
+
28
+ it "returns an html string" do
29
+ html = mcbean.to_html
30
+ html.must_be_instance_of String
31
+ html.must_match %r{<h1>ohai!</h1>}
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#to_textile" do
37
+ it "adds whitespace around block elements" do
38
+ assert_textile "before<div>inner</div>after", "before\ninner\nafter", false
39
+ end
40
+
41
+ it "converts h1 tag" do
42
+ assert_textile "<h1>Foo</h1>", "\nh1. Foo\n"
43
+ end
44
+
45
+ it "converts h2 tag" do
46
+ assert_textile "<h2>Foo</h2>", "\nh2. Foo\n"
47
+ end
48
+
49
+ it "converts h3 tag" do
50
+ assert_textile "<h3>Foo</h3>", "\nh3. Foo\n"
51
+ end
52
+
53
+ it "converts h4 tag" do
54
+ assert_textile "<h4>Foo</h4>", "\nh4. Foo\n"
55
+ end
56
+
57
+ it "converts blockquote tag" do
58
+ assert_textile "<blockquote>\n<p>foo fazz<br />\nbizz buzz<br />\nwang wong</p>\n</blockquote>", "\nbq. foo fazz\nbizz buzz\nwang wong\n"
59
+ end
60
+
61
+ it "converts ul lists" do
62
+ html = "<ul>\n\t<li>foo</li>\n\t<li>wuxx</li>\n</ul>"
63
+ textile = "\n* foo\n* wuxx\n"
64
+ assert_textile html, textile
65
+ end
66
+
67
+ it "converts ol lists" do
68
+ html = "<ol>\n\t<li>foo</li>\n\t<li>wuxx</li>\n</ol>"
69
+ textile = "\n# foo\n# wuxx\n"
70
+ assert_textile html, textile
71
+ end
72
+
73
+ it "ignores empty unordered list items" do
74
+ assert_textile "<ul>\n<li>one</li>\n<li></li>\n<li>three</li>\n</ul>\n",
75
+ "\n* one\n* three\n",
76
+ false
77
+ end
78
+
79
+ it "ignores empty ordered list items" do
80
+ assert_textile "<ol>\n<li>one</li>\n<li></li>\n<li>three</li>\n</ol>\n",
81
+ "\n# one\n# three\n",
82
+ false
83
+ end
84
+
85
+ it "converts code blocks" do
86
+ assert_textile "<pre><code>This is a code block\ncontinued</code></pre>",
87
+ "\nbc. This is a code block\ncontinued\n"
88
+ end
89
+
90
+ it "converts <br> tags to newlines" do
91
+ assert_textile "<p>hello<br>there</p>", "\nhello\nthere\n", false
92
+ assert_textile "<p>hello<br />there</p>", "\nhello\nthere\n", false
93
+ end
94
+
95
+ describe "anchors" do
96
+ it "converts <a> tags" do
97
+ assert_textile "<p>Yes, magic helmet. And <a href=\"http://sample.com/\">I will give you a sample</a>.</p>",
98
+ %Q{\nYes, magic helmet. And ["I will give you a sample":http://sample.com/].\n}
99
+ end
100
+
101
+ describe "<a> tags without hrefs" do
102
+ it "ignores them" do
103
+ assert_textile "<div><a name='link-target'>target title</a></div>",
104
+ "\ntarget title\n",
105
+ false
106
+
107
+ assert_textile "<div><a id='link-target'>target title</a></div>",
108
+ "\ntarget title\n",
109
+ false
110
+ end
111
+ end
112
+
113
+ describe "<a> tags with titles" do
114
+ it "include the title" do
115
+ assert_textile %Q{<p>Yes, magic helmet. And <a href="http://sample.com/" title="Fudd">I will give you a sample</a>.</p>},
116
+ %Q{\nYes, magic helmet. And ["I will give you a sample (Fudd)":http://sample.com/].\n}, false
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ def assert_textile html, textile, roundtrip=true
123
+ assert_equal(html, McBean::Textilify::Antidote.new(textile).to_html, "textile roundtrip failed") if roundtrip
124
+ assert_equal(textile, McBean.fragment(html).to_textile, "fragment transformation failed")
125
+ assert_equal(Loofah::Helpers.remove_extraneous_whitespace("\n#{textile}\n"),
126
+ McBean.document("<div>#{html}</div>").to_textile, "document transformation failed")
127
+ end
128
+
129
+ end
130
+
131
+ describe McBean::Textilify::Antidote do
132
+ describe "given that RedCloth is already pretty well tested, let's limit ourselves to a token test case" do
133
+ it "convert textile into html" do
134
+ McBean.textile("h1. hello").to_html.must_match %r{<body><h1>hello</h1></body>}
135
+ end
136
+ end
137
+
138
+ describe "given textile with an unsafe tag" do
139
+ it "escapes the tag" do
140
+ textile = "h1. hello\n\n<script>alert('ohai!');</script>\n\nlol\n"
141
+ McBean.textile(textile).to_html.must_include "<body>\n<h1>hello</h1>\n&lt;script&gt;alert('ohai!');&lt;/script&gt;<p>lol</p>\n</body>"
142
+ end
143
+ end
144
+
145
+ describe "given textile with an invalid tag" do
146
+ it "escapes the tag" do
147
+ textile = "h1. hello\n\n<xyzzy>Adventure!</xyzzy>\n\nlol\n"
148
+ McBean.textile(textile).to_html.must_match %r{<body>\n<h1>hello</h1>\n&lt;xyzzy&gt;Adventure!&lt;/xyzzy&gt;<p>lol</p>\n</body>}
149
+ end
150
+ end
151
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 2
7
+ - 3
8
8
  - 0
9
- version: 0.2.0
9
+ version: 0.3.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mike Dalessio
@@ -35,7 +35,7 @@ cert_chain:
35
35
  FlqnTjy13J3nD30uxy9a1g==
36
36
  -----END CERTIFICATE-----
37
37
 
38
- date: 2010-03-24 00:00:00 -04:00
38
+ date: 2010-04-18 00:00:00 -04:00
39
39
  default_executable:
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
@@ -67,84 +67,71 @@ dependencies:
67
67
  type: :runtime
68
68
  version_requirements: *id002
69
69
  - !ruby/object:Gem::Dependency
70
- name: rubyforge
70
+ name: RedCloth
71
71
  prerelease: false
72
72
  requirement: &id003 !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - ">="
75
75
  - !ruby/object:Gem::Version
76
76
  segments:
77
- - 2
77
+ - 4
78
78
  - 0
79
- - 3
80
- version: 2.0.3
81
- type: :development
79
+ - 0
80
+ version: 4.0.0
81
+ type: :runtime
82
82
  version_requirements: *id003
83
83
  - !ruby/object:Gem::Dependency
84
- name: gemcutter
84
+ name: rubyforge
85
85
  prerelease: false
86
86
  requirement: &id004 !ruby/object:Gem::Requirement
87
87
  requirements:
88
88
  - - ">="
89
89
  - !ruby/object:Gem::Version
90
90
  segments:
91
+ - 2
91
92
  - 0
92
93
  - 3
93
- - 0
94
- version: 0.3.0
94
+ version: 2.0.3
95
95
  type: :development
96
96
  version_requirements: *id004
97
97
  - !ruby/object:Gem::Dependency
98
- name: shoulda
98
+ name: minitest
99
99
  prerelease: false
100
100
  requirement: &id005 !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - ">="
103
103
  - !ruby/object:Gem::Version
104
104
  segments:
105
- - 2
106
- - 10
107
- version: "2.10"
108
- type: :development
109
- version_requirements: *id005
110
- - !ruby/object:Gem::Dependency
111
- name: rr
112
- prerelease: false
113
- requirement: &id006 !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- segments:
105
+ - 1
106
+ - 6
118
107
  - 0
119
- - 10
120
- - 4
121
- version: 0.10.4
108
+ version: 1.6.0
122
109
  type: :development
123
- version_requirements: *id006
110
+ version_requirements: *id005
124
111
  - !ruby/object:Gem::Dependency
125
112
  name: hoe
126
113
  prerelease: false
127
- requirement: &id007 !ruby/object:Gem::Requirement
114
+ requirement: &id006 !ruby/object:Gem::Requirement
128
115
  requirements:
129
116
  - - ">="
130
117
  - !ruby/object:Gem::Version
131
118
  segments:
132
119
  - 2
133
- - 5
120
+ - 6
134
121
  - 0
135
- version: 2.5.0
122
+ version: 2.6.0
136
123
  type: :development
137
- version_requirements: *id007
124
+ version_requirements: *id006
138
125
  description: |-
139
- McBean converts HTML into Markdown, and Markdown into HTML (with the
140
- help of Loofah, Nokogiri and RDiscount).
126
+ McBean can convert documents from one format to another. McBean currently supports:
127
+
128
+ * HTML
129
+ * Markdown (a subset)
130
+ * Textile (a subset)
141
131
 
142
- Its goal is to eventually be able to transform documents from HTML to
143
- Markdown to Textile, and anything in between. It will be the Sylvester
144
- McMonkey McBean of markup, placing stars onto the bellies of all kinds
145
- of Sneetchy document formats.
132
+ with the help of Loofah, Nokogiri, RDiscount and RedCloth.
146
133
 
147
- "You can't teach a Sneetch."
134
+ "You can't teach a Sneetch." -- Sylvester McMonkey McBean
148
135
  email:
149
136
  - mike.dalessio@gmail.com
150
137
  executables:
@@ -152,23 +139,23 @@ executables:
152
139
  extensions: []
153
140
 
154
141
  extra_rdoc_files:
155
- - History.txt
156
142
  - Manifest.txt
157
143
  - CHANGELOG.rdoc
158
144
  - README.rdoc
159
145
  files:
160
146
  - .autotest
161
147
  - CHANGELOG.rdoc
162
- - History.txt
163
148
  - Manifest.txt
164
149
  - README.rdoc
165
150
  - Rakefile
166
151
  - bin/mcbean
167
152
  - lib/mcbean.rb
168
153
  - lib/mcbean/markdown.rb
154
+ - lib/mcbean/textile.rb
169
155
  - test/helper.rb
170
156
  - test/test_markdown.rb
171
157
  - test/test_mcbean.rb
158
+ - test/test_textile.rb
172
159
  has_rdoc: true
173
160
  homepage: http://github.com/flavorjones/mcbean
174
161
  licenses: []
@@ -199,7 +186,8 @@ rubyforge_project: mcbean
199
186
  rubygems_version: 1.3.6
200
187
  signing_key:
201
188
  specification_version: 3
202
- summary: McBean converts HTML into Markdown, and Markdown into HTML (with the help of Loofah, Nokogiri and RDiscount)
189
+ summary: McBean can convert documents from one format to another
203
190
  test_files:
204
191
  - test/test_mcbean.rb
205
192
  - test/test_markdown.rb
193
+ - test/test_textile.rb
metadata.gz.sig CHANGED
Binary file
@@ -1,6 +0,0 @@
1
- === 1.0.0 / 2010-03-08
2
-
3
- * 1 major enhancement
4
-
5
- * Birthday!
6
-