require_dependency 'syntax/convertors/html'
# The base class for all figures. A "figure" in this sense is a visual aid for
# documentation, such as a block of code, or a chart, or graph, or such. Each
# type of figure should subclass this. Currently, Figure::for_options needs
# to be edited for each new type of figure to allow the subclass to be found
# based on the set of options given to it.
class Figure
# the unformatted body of the figure
attr_reader :body
# the hash of options for this figure
attr_reader :opts
# A factory method for returning the appropriate figure subclass for the
# given set of options.
def self.for_options( options )
if options["lang"]
CodeFigure
else
Figure
end
end
# Create a new Figure with the given body and hash of options.
def initialize( body, opts )
@body = body
@opts = opts
end
# A convenience for accessing the options of the figure.
def []( name )
@opts[ name ]
end
# Returns the caption for this figure. If no caption was given, it defaults
# to "Figure".
def caption
@opts["caption"] || "Figure"
end
# Convert this figure to html. If the parameter is non-nil, it will be used
# as the body of the figure. (This allows subclasses to perform partial
# formatting of the body and pass the result back up the inheritance chain.)
def to_html( body=nil )
body ||= @body
style=""
if opts["align"]
style << "align: #{opts["align"]};"
elsif opts["float"]
style << "float: #{opts["float"]};"
end
"
\n" +
"#{caption}\n" +
"
#{body}
\n" +
"
"
end
end
# Any textual figure should inherit from this, including code blocks and
# (heaven forbid) ascii art.
class TextualFigure < Figure
# Returns the result of the "number" options, and should be treated as
# a boolean indicating whether or not line numbers should be displayed for
# this figure. (Note that subclasses must add the pre tag themselves if they
# wish the text to be preformatted.)
def number?
@opts["number"]
end
# Check to see if line numbers should be applied, and apply them if so. Then
# call the ancestor's #to_html method.
def to_html( body=nil )
body ||= @body
# If "number" is set, then each line of the figure should be numbered.
if number?
line = 1
numbers = ""
body.each_line { numbers << "#{line} "; line += 1 }
body = "
" +
"
#{numbers}
" +
"
#{body}
"
end
super body
end
end
# Represents a figure that contains a block of code in some syntax. It will be
# syntax highlighted if the underlying highlighter understands the syntax
# requested.
class CodeFigure < TextualFigure
# Returns the name of the syntax that the code uses. This should never
# return +nil+.
def lang
@opts["lang"]
end
# Appends the name of the requested syntax to the caption given by the
# superclass.
def caption
super + " [#{lang}]"
end
# Applies syntax highlighting to the body of the figure and passes the
# result up the inheritance chain.
def to_html( body=nil )
body ||= @body
convertor = for_syntax( lang )
body = "" +
"
" +
convertor.convert( body ) +
"
"
super body
end
private
# For returning the syntax translator for the named language. (This
# is for unit testing purposes, so that the convertor may be replaced
# with a mock object.)
def for_syntax( lang )
Syntax::Convertors::HTML.for_syntax( lang )
end
end