Tokenizer de rapidito
Después de mirar un rato el estado de las bibliotecas para hacer wikis en Ruby, y descubrir que ninguna me servía, Decidí que tenía que poner cartas en el asunto y hacer la mía. Mi idea es implementar el markup de Trac, haciéndolo extensible, y agregarle un par de cositas que por ahora son un secreto :-p.
Lo importante del asunto es que puse manos en el asunto. Al final, después de un intento fallido de hackear mi camino al andar, decidí que lo mejor es armar un tokenizer y un parser que use esos tokens para generar el árbol del que extraeré el HTML.
Así que me puse a programar. Como no encontré ningún tokenizer en ruby, programé uno. El tokenizer se contruye con un montón de expresiones regulares que definen cada delimitador. Después se le setea una fuente de caracteres (un string) y separa el string en los delimitadores de arriba (que se devuelven como símbolos) y cadenas que no matchean con ninguno de los delimitadores (que devuelve como strings).
Bueno, basta de cháchara, acá tá el código:
module Rapidito
class Tokenizer
def initialize( *delimiters )
@regexp = Regexp.union( *delimiters + [/$/] )
end
attr_accessor :source
def has_next?
! @source.empty?
end
def next_token
p = (@source =~ @regexp)
if p == 0 #delimiter
token = nil
@source.sub!( @regexp ) { |match| token=match.to_sym; "" }
token
else #text
token = @source[0,p]
@source = @source[p,@source.length]
token
end
end
def all_tokens
tokens = []
while has_next?
tokens << next_token
end
tokens
end
end
end
Y, acá abajo la única documentación que hice hasta ahora, o sea los tests de unidad:
require 'test/unit'
require 'rapidito/tokenizer'
include Rapidito
class TokenizerTest < Test::Unit::TestCase
def test_no_token
tok = Tokenizer.new
tok.source = "aaaa"
assert_equal true, tok.has_next?
assert_equal "aaaa", tok.next_token
assert_equal false, tok.has_next?
end
def test_two_delimiters
tok = Tokenizer.new( /\|/, /;;/ )
tok.source = "aa|bbb;;;;cccc"
assert_equal [ "aa", :"|", "bbb", :";;", :";;", "cccc" ], tok.all_tokens
tok.source = "aa;;bbb||cccc"
assert_equal [ "aa", :";;", "bbb", :"|", :"|", "cccc" ], tok.all_tokens
end
def test_choose_first_match
tok = Tokenizer.new( /aa/, /aaa/ )
tok.source = "aaa"
assert_equal [ :aa, "a" ], tok.all_tokens
end
end
Happy hacking,
Aureliano.
PD: ¿Prefieren que ponga el código con syntax highlighting?
2 comentarios:
code to colored html!
http://tohtml.com/
Sí sí, queda mucho mejor con syntax highlighting!
Publicar un comentario