aboutsummaryrefslogtreecommitdiffstats
path: root/guides/rails_guides/markdown/renderer.rb
diff options
context:
space:
mode:
Diffstat (limited to 'guides/rails_guides/markdown/renderer.rb')
-rw-r--r--guides/rails_guides/markdown/renderer.rb123
1 files changed, 123 insertions, 0 deletions
diff --git a/guides/rails_guides/markdown/renderer.rb b/guides/rails_guides/markdown/renderer.rb
new file mode 100644
index 0000000000..78820a7856
--- /dev/null
+++ b/guides/rails_guides/markdown/renderer.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+
+module RailsGuides
+ class Markdown
+ class Renderer < Redcarpet::Render::HTML
+ cattr_accessor :edge, :version
+
+ def block_code(code, language)
+ <<-HTML
+<div class="code_container">
+<pre class="brush: #{brush_for(language)}; gutter: false; toolbar: false">
+#{ERB::Util.h(code)}
+</pre>
+</div>
+HTML
+ end
+
+ def link(url, title, content)
+ if url.start_with?("http://api.rubyonrails.org")
+ %(<a href="#{api_link(url)}">#{content}</a>)
+ elsif title
+ %(<a href="#{url}" title="#{title}">#{content}</a>)
+ else
+ %(<a href="#{url}">#{content}</a>)
+ end
+ end
+
+ def header(text, header_level)
+ # Always increase the heading level by 1, so we can use h1, h2 heading in the document
+ header_level += 1
+
+ %(<h#{header_level}>#{text}</h#{header_level}>)
+ end
+
+ def paragraph(text)
+ if text =~ %r{^NOTE:\s+Defined\s+in\s+<code>(.*?)</code>\.?$}
+ %(<div class="note"><p>Defined in <code><a href="#{github_file_url($1)}">#{$1}</a></code>.</p></div>)
+ elsif text =~ /^(TIP|IMPORTANT|CAUTION|WARNING|NOTE|INFO|TODO)[.:]/
+ convert_notes(text)
+ elsif text.include?("DO NOT READ THIS FILE ON GITHUB")
+ elsif text =~ /^\[<sup>(\d+)\]:<\/sup> (.+)$/
+ linkback = %(<a href="#footnote-#{$1}-ref"><sup>#{$1}</sup></a>)
+ %(<p class="footnote" id="footnote-#{$1}">#{linkback} #{$2}</p>)
+ else
+ text = convert_footnotes(text)
+ "<p>#{text}</p>"
+ end
+ end
+
+ private
+
+ def convert_footnotes(text)
+ text.gsub(/\[<sup>(\d+)\]<\/sup>/i) do
+ %(<sup class="footnote" id="footnote-#{$1}-ref">) +
+ %(<a href="#footnote-#{$1}">#{$1}</a></sup>)
+ end
+ end
+
+ def brush_for(code_type)
+ case code_type
+ when "ruby", "sql", "plain"
+ code_type
+ when "erb", "html+erb"
+ "ruby; html-script: true"
+ when "html"
+ "xml" # HTML is understood, but there are .xml rules in the CSS
+ else
+ "plain"
+ end
+ end
+
+ def convert_notes(body)
+ # The following regexp detects special labels followed by a
+ # paragraph, perhaps at the end of the document.
+ #
+ # It is important that we do not eat more than one newline
+ # because formatting may be wrong otherwise. For example,
+ # if a bulleted list follows, the first item is not rendered
+ # as a list item, but as a paragraph starting with a plain
+ # asterisk.
+ body.gsub(/^(TIP|IMPORTANT|CAUTION|WARNING|NOTE|INFO|TODO)[.:](.*?)(\n(?=\n)|\Z)/m) do
+ css_class = \
+ case $1
+ when "CAUTION", "IMPORTANT"
+ "warning"
+ when "TIP"
+ "info"
+ else
+ $1.downcase
+ end
+ %(<div class="#{css_class}"><p>#{$2.strip}</p></div>)
+ end
+ end
+
+ def github_file_url(file_path)
+ tree = version || edge
+
+ root = file_path[%r{(\w+)/}, 1]
+ path = \
+ case root
+ when "abstract_controller", "action_controller", "action_dispatch"
+ "actionpack/lib/#{file_path}"
+ when /\A(action|active)_/
+ "#{root.sub("_", "")}/lib/#{file_path}"
+ else
+ file_path
+ end
+
+ "https://github.com/rails/rails/tree/#{tree}/#{path}"
+ end
+
+ def api_link(url)
+ if url =~ %r{http://api\.rubyonrails\.org/v\d+\.}
+ url
+ elsif edge
+ url.sub("api", "edgeapi")
+ else
+ url.sub(/(?<=\.org)/, "/#{version}")
+ end
+ end
+ end
+ end
+end