Class: RDoc::Generator::Papyrus

Inherits:
Object
  • Object
show all
Defined in:
lib/rdoc/generator/papyrus.rb,
lib/rdoc/generator/papyrus/options.rb

Overview

This is the main class for the Papyrus PDF generator for RDoc. It takes RDoc’s raw parsed data and transforms it into a single PDF file backed by pdfLaTeX. If you’re interested in how this process works, feel free to dig into this class’ code, but ensure you also have a look on the Markup::ToLaTeX class which does the heavy work of translating the markup tokens into LaTeX code. The below section also has a brief overview of how the generation process works.

The generation process

  1. During startup, RDoc calls the ::setup_options method that adds

some commandline options to RDoc (these are described in the
RDoc::Generator::Papyrus::Options module).
  1. RDoc parses the source files.

  2. RDoc calls the #generate method and passes it all encountered

files as an array of RDoc::TopLevel objects.
  1. The #generate method examines all encountered classes, modules

and methods and then starts to transform the raw data handed by
RDoc into LaTeX markup by means of the formatter class
RDoc::Markup::ToLaTeX_Crossref. The generated markup is written
into a temporary directory "tmp" below the output directory
RDoc has chosen or has been instructed to choose (via commandline),
generating one LaTeX file for each class and module plus one main
file "main.tex" that includes the other files as needed.
  1. pdfLaTeX is invoked on that final main file, generating “main.pdf”

in the temporary directory.
  1. The generated PDF file is copied over to the real output directory

and renamed to "Documentation.pdf".
  1. The temporary directory is recursively deleted.

  2. A file index.html is created inside the output directory

that contains a link to the PDF file. This allows navigating to the
documentation via RubyGems’ server (if somebody really set his
default generator to +pdf_latex+...).

Defined Under Namespace

Modules: Options Classes: PapyrusError

Constant Summary collapse

DESCRIPTION =

Description displayed in RDoc’s help.

"PDF generator based on LaTeX"
ROOT_DIR =

Root directory of this project.

Pathname.new(__FILE__).dirname.parent.parent.parent
VERSION =

The version number.

ROOT_DIR.join("VERSION.txt").read.chomp.freeze
DATA_DIR =

Directory where the LaTeX template files are stored.

ROOT_DIR + "data"
FONT_DIR =

Directory where the internal fonts are stored.

DATA_DIR + "fonts"
MAIN_TEMPLATE =

The main file’s ERB template.

ERB.new(File.open(DATA_DIR.join("main.tex.erb"), "r:UTF-8"){|f| f.read})
RDOC_FILE_TEMPLATE =

The ERB template for a single file.

ERB.new(File.open(DATA_DIR.join("rdoc_file.tex.erb"), "r:UTF-8"){|f| f.read})
MODULE_TEMPLATE =

The ERB template for a single class or module.

ERB.new(File.open(DATA_DIR.join("module.tex.erb"), "r:UTF-8"){|f| f.read})
MAIN_FILE_BASENAME =

Basename of the main resulting LaTeX file. The path is prepended later as it’s a temporary directory.

"main.tex"
MAIN_FILE_RESULT_BASENAME =

Basename of the resulting documentation file inside the temporary directory.

"main.pdf"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Papyrus

Creates a new instance of this class. Automatically called by RDoc. There shouldn’t be any need for you to call this.

Parameter

options

RDoc passes the current RDoc::Options instance here.

Return value

The newly created instance.


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/rdoc/generator/papyrus.rb', line 161

def initialize(options)
  #The requiring of the rest of the library *must* be placed here,
  #because otherwise it’s loaded during RDoc’s discovering process,
  #effectively eliminating the possibility to generate anything
  #other than LaTeX output due to the overwrites the
  #RDoc::Generator::LaTeX_Markup module does.
  require_relative "../markup/to_latex_crossref"
  require_relative "latex_markup"
  
  @options = options
  @output_dir = Pathname.pwd.expand_path + @options.op_dir
  #The following variable is used to generate unique filenames.
  #During processing the ERB templates, many files are created and
  #accidentally creating two files with the same name, effectively
  #overwriting the previous one, should be avoided. Hence, this
  #little number is prepended to generated filenames (except the
  #main file).
  @counter = 0
end

Class Method Details

.setup_options(options) ⇒ Object

Called by RDoc during option processing. Adds commandline switches specific to this generator.

Parameter

options

The yet unparsed RDoc::Options.


105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/rdoc/generator/papyrus.rb', line 105

def setup_options(options)
  debug("Teaching new options to RDoc")
  #Define the methods to get and set the options
  options.extend(RDoc::Generator::Papyrus::Options)

  options.option_parser.separator ""
  options.option_parser.separator "Papyrus generator options:"
  options.option_parser.separator ""

  #Define the options themselves
  options.option_parser.on("--[no-]show-pages", "Enables or disables page", "numbers following hyperlinks (default true).") do |val|
    debug("Found --show-pages: #{val}")
    options.show_pages = val
  end
  options.option_parser.on("--latex-command=VALUE", " Sets the command to run", "LaTeX (defaults to '#{RDoc::Generator::Papyrus::Options::DEFAULT_LATEX_COMMAND}')") do |val|
    debug("Found --latex-command: #{val}")
    options.latex_command = val
  end
  options.option_parser.on("--babel-lang=VALUE", "Sets the language option", "for babel (defaults to '#{RDoc::Generator::Papyrus::Options::DEFAULT_BABEL_LANG}')") do |val|
    debug("Found --babel-lang: #{val}")
    options.babel_lang = val
  end

  options.option_parser.on("--inputencoding", "Sets the encoding used for the input files.", "Defaults to '#{RDoc::Generator::Papyrus::Options::DEFAULT_INPUT_ENCODING}'.") do |val|
    debug("Found --inputencoding: #{val}")
    options.inputencoding = val
  end

  options.option_parser.on("--[no-]append-source",
                           "If set, the sourcecode of all methods is included", 
                           "as an appendix (warning: HUGE PDF", 
                           "files can be the result! Default: false."){|val| options.append_source = val}

end

Instance Method Details

#generate(top_levels) ⇒ Object

Called by RDoc after parsing has happened in order to generate the output. This method takes the input of RDoc::TopLevel objects and tranforms them by means of the RDoc::Markup::ToLaTeX_Crossref class into LaTeX markup.


185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/rdoc/generator/papyrus.rb', line 185

def generate(top_levels)
  #Prepare all the data needed by all the templates
  doc_title = @options.title
  babel_lang = @options.babel_lang

  #Get the rdoc file list and move the "main page file" to the beginning.
  debug("Examining toplevel files")
  @rdoc_files = top_levels.select{|t| t.name =~ /\.rdoc$/i}
  debug("Found #{@rdoc_files.count} toplevels ending in .rdoc that will be processed")
  if @options.main_page #nil if not set, no main page
    main_index = @rdoc_files.index{|t| t.full_name == @options.main_page}
    if main_index #nil if invalid main_page given
      @rdoc_files.unshift(@rdoc_files.slice!(main_index))
      debug("Main page is #{@rdoc_files.first.name}")
    end
  end

  #Get the class, module and methods lists, sorted alphabetically by their full names
  debug("Sorting classes, modules and methods")
  @classes = RDoc::TopLevel.all_classes.sort_by{|klass| klass.full_name}
  @modules = RDoc::TopLevel.all_modules.sort_by{|mod| mod.full_name}
  @classes_and_modules = @classes.concat(@modules).sort_by{|mod| mod.full_name}
  @methods = @classes_and_modules.map{|mod| mod.method_list}.flatten.sort

  #Start the template filling process
  if @options.dry_run
    temp_dir = Pathname.pwd #No output directory in dryrun mode!
  else
    temp_dir = @output_dir + "tmp"
    temp_dir.mkpath
  end
  debug("Temporary directory is at '#{temp_dir.expand_path}'")
  Dir.chdir(temp_dir) do #We want LaTeX to output it’s files into our temporary directory
    #Evaluate the main page which includes all
    #subpages as necessary.
    debug("Evaluating main ERB temlpate")
    main_file = temp_dir + MAIN_FILE_BASENAME
    main_file.open("w"){|f| f.write(MAIN_TEMPLATE.result(binding))} unless @options.dry_run
    
    #Let LaTeX process the whole thing -- 3 times, to ensure
    #any kinds of references are correct.
    debug("Invoking LaTeX")
    3.times{latex(main_file)}
    
    #Oh, and don’t forget to copy the result file into our documentation
    #directory :-)
    debug("Copying resulting Documentation.pdf file")
    unless @options.dry_run
      FileUtils.rm(@output_dir + "Documentation.pdf") if File.file?(@output_dir + "Documentation.pdf")
      FileUtils.cp(temp_dir + MAIN_FILE_RESULT_BASENAME, @output_dir + "Documentation.pdf")
    end
    
    #To allow browsing the documentation with the RubyGems server, put an index.html
    #file there that points to the PDF file.
    debug("Creating index.html")
    unless @options.dry_run
      File.open(@output_dir + "index.html", "w") do |f|
        f.puts("<html>")
        f.puts("<!-- This file exists to allow browsing docs with the Gem server -->")
        f.puts("<head><title>#{doc_title}</title></head>")
        f.puts('<body><p>Documentation available as a <a href="Documentation.pdf">PDF file</a>.</p></body>')
        f.puts("</html>")
      end
    end
  end
  
  #Remove the temporary directory (this is *not* done if invoking LaTeX
  #failed, as the #latex method throws an exception. This is useful for
  #debugging the generated LaTeX files)
  unless $DEBUG_RDOC
    debug("Removing temporary directory")
    temp_dir.rmtree unless @options.dry_run
  end
end