Skip to content

Instantly share code, notes, and snippets.

@Krugloff
Last active November 4, 2019 10:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Krugloff/5491182 to your computer and use it in GitHub Desktop.
Save Krugloff/5491182 to your computer and use it in GitHub Desktop.
Script for create RusRubyBook
#!/usr/bin/env ruby
#encoding: utf-8
# Внимание! Скрипт работает только на версии ruby 2.0
# create_rus_ruby_book filename -> возвращается результат обработки файла;
# create_rus_ruby_book dirname -> все *.md файлы будут обработаны. Результат сохраняется в *.tex файл с тем же именем (файл будет перезаписан).
require 'redcarpet'
module Redcarpet; module Render;
class RusRubyBook < Base
# Блочные элементы.
def normal_text(text)
text = escape(text)
end
def paragraph(text)
"#{text}\n\n"
end
# Вложенный нумерованный список от маркированного пустой строкой не отделяется.
def list( content, list_type )
case list_type
when :ordered
"\\begin{enumerate}\n" +
"#{content}" +
"\\end{enumerate}\n\n"
when :unordered
"\\begin{itemize}\n" +
"#{content}" +
"\\end{itemize}\n\n"
end
end
def list_item( content, list_type )
"\\item #{content}"
end
def block_code( code, language )
case language
when 'ruby'
"\\begin{verbatim}\n" +
code.gsub(/^ /, '') +
"\\end{verbatim}\n\n"
when 'longtable'
code = code.lines
code[0] = code[0] + '\hline'
code[1...code.size].map! { |line| line << '\\\\ \hline' }
code = code.join("\n").gsub( '~', '\textasciitilde\-, ' )
"\\begin{longtable}" +
"#{code}\n" +
"\\end{longtable}\n\n"
# when "table"
# "\\begin{tabular}" +
# "#{code}" +
# "\\end{tabular}\n\n"
when "note"
"\\begin{note}" +
"#{code}" +
"\\end{note}\n\n"
else
"\\begin{verbatim}\n" +
"#{code}" +
"\\end{verbatim}\n\n"
end
end
# > Это сказал Дональд.
# >: Дональд
def block_quote(quote)
author = quote.match( /^:\s+(.+)$/ )
( quote = author.pre_match ) if author
"\\epigraph{\n#{quote.rstrip}\n}" + "{#{author && author[1]}}" + "\n\n"
end
# Конец списка ключей.
def hrule
"\\end{keylist}\n\n"
end
# Строчные элементы.
def link( link, title, content )
case content
# [](link) - создание метки.
when nil
"\\hypertarget{#{link}}{}"
else # обработка внутренних ссылок.
"\\hyperlink{#{link}}{\\textcolor{grey}{#{content}}}"
end
end
# <link>
def autolink(link, link_type)
"\\href{#{link}}{#{link}}"
end
def header( title, level )
case level
# # Заголовок главы.
when 1
"\\chapter{#{title}}\n\n"
# ## Заголовок подглавы.
when 2
"\\section{#{title}}\n\n"
# ### Заголовок подподглавы
when 3
"\\subsection{#{title}}\n\n"
# #### Заголовок пункта
when 4
"\\subsubsection*{#{title}}\n\n"
# ##### Начало списка ключей:
when 5
"\\begin{keylist}{#{title}}\n\n"
# ###### Небольшой резервный заголовок
when 6
"\\paragraph{#{title}}\\-,\\\\\n\n"
end
end
def codespan(code)
# Declare method hack.
# `.method(params) {block} # -> return`
def_method = /^
(?<name> [\.:]{1,2} [\w\%\/\~\^\[\]\`\s\&\|,+=\-\*<>]* [=!\?]?)
(?<params> \(.+\))?
(?<block> \s \{.+?\})?
(?<ret> \s \#\s->\s .+)?
$/x
return code.gsub(def_method) do |match|
name = escape Regexp.last_match(:name)
params = escape_method( Regexp.last_match(:params) )
block = escape_method( Regexp.last_match(:block) )
ret = escape_method( Regexp.last_match(:ret) )
return "\\verb`#{name}`" unless params || block || ret
"\\declare{#{name}#{params}#{block}}{#{ret}}"
end if code =~ def_method
# Declare math hack.
# `$123 * 10^{-10}$`
return code if code =~ /\A\$.+?\$\z/
# verbatim: `text`
if code.include? '`'
"\\verb\'#{code}\'"
else
"\\verb\`#{code}\`"
end
end
# _text_ or *text*
def emphasis(text)
"\\italy{#{text}}"
end
# __text__ or **text**
def double_emphasis(text)
"\\textbf{#{text}}"
end
# Если вы хотите закончить строку, а не параграф,
# то в конце строки ставится два пробела.
def linebreak
"\n\\\\*"
end
# Предварительная и завершающая обработка.
# `key` в начале параграфа считается элементом списка ключей.
def preprocess(full_document)
keylist = / ^\#{5,5}\s.+?$
.+?
\*{5,5}
/mx
full_document.gsub(keylist) do |list|
list.gsub(/\n\n(`{1,2})([^`].*?)\1/) do |key|
match = $2.gsub( /\\(\S)/, '\textbackslash \1' )
.gsub( /--/, '\twominus ' )
.gsub( '{', '\\\\\\{')
.gsub( '}', '\\\\\\}')
"\n\n" + "\\key{#{match}}"
end
end
end
# def block_html(html)
# html
# end
# def raw_html(html)
# html
# end
private
# Fix: вместо нескольких проходов .gsub, использовать один .map.
def escape(text)
return unless text
text
.gsub( '\n', '\textbackslash n')
.gsub( '\r', '\textbackslash r')
.gsub( '~', '\textasciitilde ' )
.gsub( '$', '\$' )
.gsub( '^', '\textasciicircum ')
.gsub( '#', '\#' )
.gsub( '%', '\%' )
.gsub( '&', '\\\\\\&' )
end
def escape_method(text)
return unless text
escape text .gsub( /\\/, '\textbackslash\-, ' )
.gsub('{','\{')
.gsub('}','\}')
end
end
end; end
markdown = Redcarpet::Markdown.new(Redcarpet::Render::RusRubyBook,
no_intra_emphasis: true,
fenced_code_blocks: true,
lax_spacing: true)
if Dir.exist? ARGF.filename
Dir.chdir ARGF.filename do Dir.glob('*.md') do |path|
latex = markdown.render( File.read path )
new_path = File.basename(path, '.md') + '.tex'
File.write new_path, latex, File::TRUNC & File::CREAT
end end
else
puts markdown.render(ARGF.read)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment