- 
      
- 
        Save mojombo/118964 to your computer and use it in GitHub Desktop. 
| require 'digest/md5' | |
| def gfm(text) | |
| # Extract pre blocks | |
| extractions = {} | |
| text.gsub!(%r{<pre>.*?</pre>}m) do |match| | |
| md5 = Digest::MD5.hexdigest(match) | |
| extractions[md5] = match | |
| "{gfm-extraction-#{md5}}" | |
| end | |
| # prevent foo_bar_baz from ending up with an italic word in the middle | |
| text.gsub!(/(^(?! {4}|\t)\w+_\w+_\w[\w_]*)/) do |x| | |
| x.gsub('_', '\_') if x.split('').sort.to_s[0..1] == '__' | |
| end | |
| # in very clear cases, let newlines become <br /> tags | |
| text.gsub!(/^[\w\<][^\n]*\n+/) do |x| | |
| x =~ /\n{2}/ ? x : (x.strip!; x << " \n") | |
| end | |
| # Insert pre block extractions | |
| text.gsub!(/\{gfm-extraction-([0-9a-f]{32})\}/) do | |
| "\n\n" + extractions[$1] | |
| end | |
| text | |
| end | |
| if $0 == __FILE__ | |
| require 'test/unit' | |
| require 'shoulda' | |
| class GFMTest < Test::Unit::TestCase | |
| context "GFM" do | |
| should "not touch single underscores inside words" do | |
| assert_equal "foo_bar", gfm("foo_bar") | |
| end | |
| should "not touch underscores in code blocks" do | |
| assert_equal " foo_bar_baz", gfm(" foo_bar_baz") | |
| end | |
| should "not touch underscores in pre blocks" do | |
| assert_equal "\n\n<pre>\nfoo_bar_baz\n</pre>", gfm("<pre>\nfoo_bar_baz\n</pre>") | |
| end | |
| should "not treat pre blocks with pre-text differently" do | |
| a = "\n\n<pre>\nthis is `a\\_test` and this\\_too\n</pre>" | |
| b = "hmm<pre>\nthis is `a\\_test` and this\\_too\n</pre>" | |
| assert_equal gfm(a)[2..-1], gfm(b)[3..-1] | |
| end | |
| should "escape two or more underscores inside words" do | |
| assert_equal "foo\\_bar\\_baz", gfm("foo_bar_baz") | |
| end | |
| should "turn newlines into br tags in simple cases" do | |
| assert_equal "foo \nbar", gfm("foo\nbar") | |
| end | |
| should "convert newlines in all groups" do | |
| assert_equal "apple \npear \norange\n\nruby \npython \nerlang", | |
| gfm("apple\npear\norange\n\nruby\npython\nerlang") | |
| end | |
| should "convert newlines in even long groups" do | |
| assert_equal "apple \npear \norange \nbanana\n\nruby \npython \nerlang", | |
| gfm("apple\npear\norange\nbanana\n\nruby\npython\nerlang") | |
| end | |
| should "not convert newlines in lists" do | |
| assert_equal "# foo\n# bar", gfm("# foo\n# bar") | |
| assert_equal "* foo\n* bar", gfm("* foo\n* bar") | |
| end | |
| end | |
| end | |
| end | 
Thanks for sharing!  I found one Ruby 1.9 compatibility issue that's worth mentioning.  Array#to_s is equivalent to Array#inspect now.
http://eigenclass.org/hiki/Changes+in+Ruby+1.9#l83
The fix is simple -- just change the to_s on line 14 to join and this fine code snippet will run for both Ruby 1.8 and 1.9.
The code [\#1](http://github.com) without the backslash breaks GH's markdown parser. This generates [#1](http://github.com).
Edit: it looks ok now it's posted here. Maybe it's just in the issue tracker / JS previews; try it in the preview box below.
If you have a pre-formatted code block that contains the string '#1', it gets expanded to a link.
I agree with @viking.  Here is an example of the problem:
https://github.com/tenderlove/nokogiri/issues/#issue/405/comment/725920
Why is there a '?' in here.....< pre >.*?< / pre > Does the ruby regex have some weird bug I don't know about.
Normally .+? == .★
The ? prevents .* from matching </pre>.  And .+? is not the same as .*.  See reluctant matching.
Thanks.
is there a port of this to PHP?
Coffeescript port is here: https://gist.github.com/2349475
PHP port here: https://gist.github.com/3194002
There's an error in the line break handling code. Take for example this input:
**foo**
bar
baz
On GitHub, this is rendered as expected, because GitHub actually uses redcarpet for rendering GFM on the site:
foo
bar
baz
But using the code here in gfm.rb, it renders as:
foo bar
baz
This is happening because the regex used in gfm.rb is incorrect; it does not add a line break when the line begins with a * (emphasized / strong text) or a > (blockquote). It can rectified as follows:
--- gfm.rb
+++ gfm.2.rb
@@ -15,6 +15,6 @@
   end
   # in very clear cases, let newlines become <br /> tags
-  text.gsub!(/^[\w\<][^\n]*\n+/) do |x|
+  text.gsub!(/^[\w\<\>\*][^\n]*\n+/) do |x|
     x =~ /\n{2}/ ? x : (x.strip!; x << "  \n")
   endVery good Work
Thanks for making this code available - I was pulling my hair out trying to figure out how to accomplish something like this on my site.