Tokenizer de rapidito
Posted: June 7th, 2009 | Author: FreedomCoder | Filed under: Open Source, Programming | Tags: Open Source, Programming, Tokens | No Comments »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?
(Via aurelianito.) Original Link: Tokenizer de rapidito