--Boundary_(ID_9gkU1IyKGTVurzshKHmIBg)
Content-type: text/plain; charset=ISO-8859-1
Content-transfer-encoding: 7BIT

Ruby Quiz wrote:
> The three rules of Ruby Quiz:
> 
> 1.  Please do not post any solutions or spoiler discussion for this quiz until
> 48 hours have passed from the time on this message.
> 
> 2.  Support Ruby Quiz by submitting ideas as often as you can:
> 
> http://www.rubyquiz.com/
> 
> 3.  Enjoy!
> 
> Suggestion:  A [QUIZ] in the subject of emails about the problem helps everyone
> on Ruby Talk follow the discussion.  Please reply to the original quiz message,
> if you can.
> 
> --------------------
> 
> by Justin Bailey
> 
> "Literate Programming"[1] is an idea popularized by Donald Knuth, where the
> traditional order of code and comments in a source file is switched. Instead of
> using special delimiters to mark comments, special delimiters are used to mark
> *code*.

  Here is my solution. It features basically both methods to mark that
were proposed (with > end \begin{code}  \end{code}). It should be able
to run as is irb output (practical to test directly from an email) and
it features a small hack to require literate ruby files.

 There are five attached files:

  * rweb.rb, the actual interpreter;
  * small_test.lrb and required.lrb, a test file and the file included
from it (to demonstrate the require feature);
  * rweb2tex.lrb, a literate program converting a literate program into
"appropriately" formatted LaTeX file (that definitely could be improved)
  * rweb2tex.tex,the result of rweb2tex.lrb ran on itself. (I personally
don't like its look so much, but, well, I don't like literate
programming so much anyway ;-)...)

  Hope you appreciate it !

	Vince

-- 
Vincent Fourmond, PhD student
http://vincent.fourmond.neuf.fr/


--Boundary_(ID_9gkU1IyKGTVurzshKHmIBg)
Content-type: text/plain; name=rweb.rb
Content-transfer-encoding: 7BIT
Content-disposition: inline; filename=rweb.rb

#!/usr/bin/ruby 

module RWeb

  # Escapes a whole line if it starts with this regular expression: the
  # rest of the line is fed as is to the current output (text or code)
  # without interpretation.
  ESCAPE  ^\s*@@/

  # Inline code
  INLINE  ^\s*>+/

  # Beginning of a code block
  B_o_CODE  ^\s*\\begin\{code\}\s*$/

  # End of a code block
  E_o_CODE  ^\s*\\end\{code\}\s*$/
  
  # Takes an array of lines, and returns code lines and text lines
  # separately, optionnally including code in text
  def self.unliterate_lines(lines, include_code  alse)
    text  ]
    code  ]
    current  ext
    for line in lines
      case line
      when ESCAPE               # Escaping
        current << $'
      when INLINE
        code << $'
        text << $' if include_code
      when B_o_CODE
        if current code
          current << line
        else
          current  ode
        end
        text << line if include_code
      when E_o_CODE
        if current text
          current << line
        else
          text << line if include_code
          current  ext
        end
      else
        current << line
      end
    end
    return [code, text]
  end

  # Unliterates a file
  def self.unliterate_file(file, include_code  alse)
    return unliterate_lines(File.open(file).readlines, include_code)
  end

  # Runs the unliterated code
  def self.run_code(code, bnd  OPLEVEL_BINDING)
    eval(code.join, bnd)
  end

  # Runs a file.
  def self.run_file(file)
    run_code(unliterate_file(file).first)
  end

end

# Here, we hack our way through require so that we can include
# .lrb files and understand them as literate ruby.
module Kernel

  alias :old_kernel_require :require
  undef :require
  def require(file)
    # if file doesn't have an extension, we look for it
    # as a .lrb file.
    if file /\.[^\/]*$/
      old_kernel_require(file)
    else
      found  alse
      for path in ($:).map {|x| File.join(x, file + ".lrb") }
        if File.readable?(path)
          found  rue
          RWeb::run_code(RWeb::unliterate_file(path).first, 
                         self.send(:binding))
          break
        end
      end
      old_kernel_require(file) unless found
    end
  end
end

# We remove the first element of ARGV so that the script believes
# it is called on its own
file  RGV.shift
$0  ile
RWeb::run_file(file)


--Boundary_(ID_9gkU1IyKGTVurzshKHmIBg)
Content-type: text/plain; name=small_test.lrb
Content-transfer-encoding: 7BIT
Content-disposition: inline; filename=small_test.lrb

This file contains a small test for the literate ruby
quiz. 

It is meant to be run from the command line with some arguments.
Here, we simply begin with displaying the command-line arguments

> p ARGV

Who are we ??

> puts "Here is #{$0}"

Then, just to show, we require the file required.lrb
> require 'required'

We complain if there is not arguments on the command-line
> puts "It will be more interesting if "+
> "you actually provide #$0 with command-line arguments" if ARGV.empty? 

Then, I thought it would be interesting to make a small report about
letters used in the command-line arguments:
\begin{code}
letters  }
for letter in ARGV.join('').split('')
  if letters.has_key?(letter)
    letters[letter] + 
  else
    letters[letter]  
  end
end

for letter in letters.keys.sort
  puts "Letter #{letter} used #{letters[letter]} times"
end
\end{code}

And just for fun, we will show that we can use \end{code}
right in the middle of some code:
\begin{code}
puts <<'EOT'
You see that we can use
@@\end{code}
even alone on its line !!
EOT
\end{code}

I believe this should suffice as a demonstration.

--Boundary_(ID_9gkU1IyKGTVurzshKHmIBg)
Content-type: text/plain; name=required.lrb
Content-transfer-encoding: 7BIT
Content-disposition: inline; filename=required.lrb

Just a test file to show that code can be required fine
with rweb:
\begin{code}
puts "This is required literate code !"
\end{code}


--Boundary_(ID_9gkU1IyKGTVurzshKHmIBg)
Content-type: text/plain; name=rweb2tex.lrb
Content-transfer-encoding: 7BIT
Content-disposition: inline; filename=rweb2tex.lrb

Now that we have a \verb|rweb.rb| file that does the correct job
of executing the literate Ruby code given, the next step in literate
programming is to actually provide a nice display of the program.

\verb|rweb2text.rb| converts the text and the code of a literate Ruby
program into (hopefully) nicely formatted LaTeX.

The \verb|RWebBeautifier| is the main class.

> class RWebBeautifier

Now, we copy the regular expressions to parse the literate programs
straight from \verb|rweb|

\begin{code}
# Escapes a whole line if it starts with this regular expression: the
# rest of the line is fed as is to the current output (text or code)
# without interpretation.
ESCAPE  ^\s*@@/

# Inline code
INLINE  ^\s*>+/

# Beginning of a code block
B_o_CODE  ^\s*\\begin\{code\}\s*$/

# End of a code block
E_o_CODE  ^\s*\\end\{code\}\s*$/
\end{code}

Initialization; as I don't provide many hooks, this is rather simple:
\verb|cls| is the document class, \verb|code_env| is the name of
the environment used to display code and \verb|packages|
a list of packages to be included.
\begin{code}
def initialize(cls  article', 
               code_env  verbatim', 
               packages  'verbatim'])
  @document_class  ls
  @code_env  ode_env
  @packages  ackages
end
\end{code}

The \verb|literate_lines| function is a rewrite of
\verb|unliterate_lines| from \verb|rweb.rb| --- a rewrite is indeed
needed as special formatting is required for included code, and
we don't really care about getting only code.

\begin{code}
def literate_lines(lines)
  text  ]
  code  ]
\end{code}

This time, \verb|code| holds a different meaning: it is the current code
block, not all the code read so far.

\begin{code}
  current  ext
  for line in lines
    case line
    when ESCAPE               # Escaping
      current << $'
    when INLINE
      code << $'
    when B_o_CODE
      if current code
        current << line
      else
        current  ode
      end
    when E_o_CODE
      if current text
        current << line
      else
        current  ext
      end
    else
\end{code}
Now come the real difference: if we are in text mode, we need to flush first
the code which hasn't been written yet.
\begin{code}
      if (current text) and (not code.empty?)
        current << "\\begin{#{@code_env}}\n"
\end{code}
Here, I had first coded using a simple \verb|+ but that miserably
fails to work, because after it, \verb|current| is neither \verb|text|
nor \verb|code|, and the code is lost. The solution is
\begin{code}
        current.concat(code)
        current << "\\end{#{@code_env}}\n"
        code.clear
      end
      current << line
    end
  end
  return text
end
\end{code}

Now, a simple function that wraps the appropriate
\verb|literate_lines| call for a file. I find it self-explanatory.
\begin{code}
def literate_file(file)
  output_file  ile.sub(/(\.lrb)?$/, '.tex')
  out  ile.open(output_file, 'w')
  out.puts "\\documentclass{#{@document_class}}"
  @packages.each do |p|
    out.puts "\\usepackage{#{p}}"
  end
  out.puts "\\begin{document}"
  out.puts(literate_lines(File.open(file).readlines))
  out.puts "\\end{document}"
  out.close
end
\end{code}

The end of the class.

> end

Now, what is left is some wrapper call; we first create an instance of
\verb|RWebBeautifier|

> rweb  WebBeautifier.new

And we use it on all command-line arguments:

> ARGV.each do |file|
> rweb.literate_file(file)
> end

And that's all ! 


--Boundary_(ID_9gkU1IyKGTVurzshKHmIBg)
Content-type: application/x-tex; name=rweb2tex.tex
Content-transfer-encoding: 7bit
Content-disposition: inline; filename=rweb2tex.tex

\documentclass{article}
\usepackage{verbatim}
\begin{document}
Now that we have a \verb|rweb.rb| file that does the correct job
of executing the literate Ruby code given, the next step in literate
programming is to actually provide a nice display of the program.

\verb|rweb2text.rb| converts the text and the code of a literate Ruby
program into (hopefully) nicely formatted LaTeX.

The \verb|RWebBeautifier| is the main class.

\begin{verbatim}
 class RWebBeautifier
\end{verbatim}

Now, we copy the regular expressions to parse the literate programs
straight from \verb|rweb|

\begin{verbatim}
# Escapes a whole line if it starts with this regular expression: the
# rest of the line is fed as is to the current output (text or code)
# without interpretation.
ESCAPE  ^\s*@@/

# Inline code
INLINE  ^\s*>+/

# Beginning of a code block
B_o_CODE  ^\s*\\begin\{code\}\s*$/

# End of a code block
E_o_CODE  ^\s*\\end\{code\}\s*$/
\end{verbatim}

Initialization; as I don't provide many hooks, this is rather simple:
\verb|cls| is the document class, \verb|code_env| is the name of
the environment used to display code and \verb|packages|
a list of packages to be included.
\begin{verbatim}
def initialize(cls  article', 
               code_env  verbatim', 
               packages  'verbatim'])
  @document_class  ls
  @code_env  ode_env
  @packages  ackages
end
\end{verbatim}

The \verb|literate_lines| function is a rewrite of
\verb|unliterate_lines| from \verb|rweb.rb| --- a rewrite is indeed
needed as special formatting is required for included code, and
we don't really care about getting only code.

\begin{verbatim}
def literate_lines(lines)
  text  ]
  code  ]
\end{verbatim}

This time, \verb|code| holds a different meaning: it is the current code
block, not all the code read so far.

\begin{verbatim}
  current  ext
  for line in lines
    case line
    when ESCAPE               # Escaping
      current << $'
    when INLINE
      code << $'
    when B_o_CODE
      if current code
        current << line
      else
        current  ode
      end
    when E_o_CODE
      if current text
        current << line
      else
        current  ext
      end
    else
\end{verbatim}
Now come the real difference: if we are in text mode, we need to flush first
the code which hasn't been written yet.
\begin{verbatim}
      if (current text) and (not code.empty?)
        current << "\\begin{#{@code_env}}\n"
\end{verbatim}
Here, I had first coded using a simple \verb|+ but that miserably
fails to work, because after it, \verb|current| is neither \verb|text|
nor \verb|code|, and the code is lost. The solution is
\begin{verbatim}
        current.concat(code)
        current << "\\end{#{@code_env}}\n"
        code.clear
      end
      current << line
    end
  end
  return text
end
\end{verbatim}

Now, a simple function that wraps the appropriate
\verb|literate_lines| call for a file. I find it self-explanatory.
\begin{verbatim}
def literate_file(file)
  output_file  ile.sub(/(\.lrb)?$/, '.tex')
  out  ile.open(output_file, 'w')
  out.puts "\\documentclass{#{@document_class}}"
  @packages.each do |p|
    out.puts "\\usepackage{#{p}}"
  end
  out.puts "\\begin{document}"
  out.puts(literate_lines(File.open(file).readlines))
  out.puts "\\end{document}"
  out.close
end
\end{verbatim}

The end of the class.

\begin{verbatim}
 end
\end{verbatim}

Now, what is left is some wrapper call; we first create an instance of
\verb|RWebBeautifier|

\begin{verbatim}
 rweb  WebBeautifier.new
\end{verbatim}

And we use it on all command-line arguments:

\begin{verbatim}
 ARGV.each do |file|
 rweb.literate_file(file)
 end
\end{verbatim}

And that's all ! 
\end{document}

--Boundary_(ID_9gkU1IyKGTVurzshKHmIBg)--