sábado, 13 de junio de 2009

Writing Latex Documents with Ruby

I worked in my thesis about Evolutionary Algorithms, and in the job I worked in Ruby Language, then I want to share with the community the mix of the technologies.

The source code is above:

#!/bin/ruby -w
#Carlos Augusto Monterrosa Lopez -------- cmonterrosa@gmail.com ----
#------------- Compilador para codigo de latex -----------------

#------ Funcion que identifica al caracter ------------------
def identifica(caracter)
case caracter
when /[0-9]/
#print "#{caracter} = Numero\n"
return "numero"
when /[a-z]|[A-Z]/
#print "#{caracter} = alfanumerico\n"
return "letra"
when /$/
#print "#{caracter} = delimitador\n"
return "delimitador"
when /\s/
return "espacio"
end
end

#----------- Etapa de lexico ----------------------
def lexico
archivo='C:\texto.txt'
@palabra=Hash.new
@palabras=[]; @numeros=[]
File.open(archivo,"r").each{|line|
line= line.strip.split(//)
@palabra_string=""
@numeros_string=""
break if line.empty?
for caracter in line
if caracter[0] == 32
@palabra[:palabra]=@palabra_string if @palabra_string!= ""
@palabra[:tipo]="palabra" if @palabra_string != ""
#------- numeros -----------
@palabra[:palabra]=@numeros_string unless @numeros_string==""
@palabra[:tipo]="numero" unless @numeros_string == ""
@palabras << @palabra unless @palabra.empty?
@palabra_string=""
@numeros_string=""
@palabra={}
else
case identifica(caracter)
when "letra"
@palabra_string = (@palabra_string + caracter).to_s
when "numero"
@numeros_string = (@numeros_string + caracter).to_s
end
end

end #cierra el for

if @palabra_string!=""
@palabra[:palabra]=@palabra_string
@palabra[:tipo] = "palabra"
@palabra_string = ""
end

if @numeros_string!=""
@palabra[:palabra]=@numeros_string
@palabra[:tipo] = "numero"
@numeros_string=""
end
@palabras << @palabra if @palabra.size == 2
@palabra={}
} #cierra ciclo principal de lineas

return @palabras
#---- Retorna un arreglo de palabras ----------
end

#---- El programa valida la siguiente sintaxis -----
#---- The ruby program validate the next sintax ----
# MARGEN SUPERIOR 30
# MARGEN INFERIOR 40


def sintaxis
@palabras_reservadas= %w{margen izquierdo derecho superior inferior titulo}
@palabras=lexico() #------ Mandamos a llamar a la etapa de lexico -------
#----------- Recorremos el archivo---------------
if @palabras[0].has_value?("margen") || @palabras[0].has_value?("MARGEN")
@palabras.delete_at(0)

if @palabras[0].has_value?("superior")
@palabras.delete_at(0)

if @palabras[0][:tipo]== 'numero'
@superior=@palabras[0][:palabra].to_i
@palabras.delete_at(0)
# ------------- empieza el segundo margen --------------
if @palabras[0].has_value?("margen")
@palabras.delete_at(0)

if @palabras[0].has_value?("inferior")
@palabras.delete_at(0)

if @palabras[0][:tipo]== 'numero'
@inferior=@palabras[0][:palabra]
@palabras.delete_at(0)
else
exit(1)
end

else
#puts "se esperaba la palabra inferior"
end


else #------------else del segundo margen
#puts "se esperaba el margen inferior"
end

else
#puts "sintaxis incorrecta debiste de poner un numero"
exit(1)
end




else
puts "sintaxis incorrecta"
exit(1)
end

@margen_string = '\marginsize{' + @superior.to_s + 'cm}{' + @inferior.to_s + 'cm}{3cm}{3cm}'
@palabras.each {|hash|
if @palabras_reservadas.include?(hash[:palabra].to_s)
#print "reservada "
else
#print "#{hash[:palabra]} "
end
}
else
#print "debe de empezar con la palabra margen"
end


end


#--------------- Definicion de clase y metodos para latex -----------
class LaTeX
def initialize()
@nesting = 0
@indent = " "
end

# Allows the user to change the default indenting (default is two spaces
# per nesting)
attr_accessor :indent

# Return the string for a newline
def newline()
return "\\\n"
end

# Return the string for a newline that won't break a page
def newline!()
return "\\*\n"
end

# Return a string for the LaTeX symbol
def latex()
return "\\LaTeX"
end

# Return a string for a comment, ended with a carriage-return
def comment(comment)
return "% #{comment}\n"
end

# Let % be an alternative way to specify a comment
alias_method :%, :comment #,

# Return an indented string, terminated by a newline if it isn't a comment
# that is already newline-terminated
def indent(str)
s = indent?(str)
if not s =~ /^\s*%.*\n/ then
s << "\n"
end
return s
end

# Return an indented string that is never newline-terminated
def indent?(str)
s = ""
@nesting.times do
s << @indent
end
s << str
return s
end

# Create a new LaTeX command
def newcommand(cmd, func)
method_missing("newcommand", "\\#{cmd}", func)
end

# Print a LaTeX command using the rules specified above
def method_missing(symbol, *args)
symbol = symbol.to_s.gsub('!', '*')
symbol = symbol.to_s.gsub('_star', '*')
nl = !(symbol =~ /(\?|_suppress)\*$/)
symbol = symbol.gsub('\?', '')
symbol = symbol.gsub('_suppress', '')
s = ""
if block_given? then
s << __begin__(symbol, *args) << __gen_newline__(nl)
nesting_tmp = @nesting
@nesting = @nesting.succ
s << proc.call()
@nesting = nesting_tmp
s << __end__(symbol) << __gen_newline__(nl)
else
s << indent?("\\#{symbol}#{__arg_list__(args)}#{__gen_newline__(nl)}")
end
return s
end

alias_method :__cmd__, :method_missing
alias_method :__env__, :method_missing

# Return the arguments of a LaTeX function; Use an array to specify
# optional arguments
def __arg_list__(args)
s = ""
args.each do |arg|
case arg
when Array
s << "["
arg.each do |a|
s << "#{a},"
end
s.chop!
s << "]"
else
s << "{#{arg}}"
end
end
return s
end

# Return a newline if nl is true, otherwise return an empty string
def __gen_newline__(nl)
return nl ? "\n" : ""
end

def __begin__(symbol, *args)
return indent?("\\begin{#{symbol}}#{__arg_list__(args)}")
end

def __end__(symbol)
return indent?("\\end{#{symbol}}")
end

end


def lee_archivo
archivo='C:\texto.txt'
@cadena= String.new
File.open(archivo,"r").each{|line| @cadena = @cadena + line.strip.to_s }
return @cadena
end


#----------- Ciclo principal -------------
sintaxis()

@conjunto_palabras = ""
@palabras.each{|palabra|@conjunto_palabras = @conjunto_palabras + " " + palabra[:palabra].to_s}


l = LaTeX.new

s =
l.documentclass("article") +
l.newcommand("foo", l.latex) +
'\usepackage{anysize}' + "\n" +
@margen_string + "\n" +
l.newenvironment("myitemize", l.__begin__("itemize"), l.__end__("itemize")) +
l.document {
l.title("#{l.LARGE?} Esta es una prueba") +
l.author("Me") +
l.date() +
l.maketitle() +

l.section("Escribiendo #{l.foo_suppress} documentos en Ruby") {
l.indent(l % "COMENTARIOS") +
l.indent("Aqui ponemos un texto.....") +
l.indent(@conjunto_palabras)


} +

l.section("Mas acerca #{l.foo_suppress} Ruby") {
l.myitemize {
l.item?(["a)"]) + "articulo a.\n" +
l.item?(["b)"]) + "articulo b.\n"
}
}
}
puts s