丁稚な日々

Rubyで遊んだ日々の記録。あくまで著者視点の私的な記録なので、正確さを求めないように。
Rubyと関係ない話題にはその旨注記しているはず。なので、一見関係無いように見える話題もどこかで関係あるのかもしれません。または、注記の書き忘れかもしれません...

[直前] [最新] [直後] [Top]

Sep.14,2004 (Tue)

Revision: 1.11 (Sep.15,2004 09:26)

ここ

_ 先日、ここに引用するRubyスクリプトにちろっと色をつけたりしてましたが、ripperが入ったので真面目にやってみることにしました。

require 'cgi'
require 'ripper.so'

class ColorParser < ::Ripper
  def self.define_event(ev, action)
    eval <<-EOM
      def on__#{ev}(token)
        add(token, '#{action}')
      end
    EOM
  end

  def parse
    @klass = nil
    @nl = ''
    @script = ''
    super
    @script << '</span>' if @klass
    @script << @nl
  end

  private
  def add(str, klass = nil)
    if @klass && (!klass || (klass && @klass != klass))
      @script << '</span>'
      @klass = nil
    end
    @script << @nl
    @nl = ''
    if klass && !@klass
      @script << %Q!<span class="#{klass}">!
      @klass = klass
    end

    nstr = str.sub(/((\r?\n)+)$/) do
      @nl = $1
      ''
    end
    @script << CGI.escapeHTML(nstr)
    str
  end

  def method_missing(mid, *args)
    raise NoMethodError, mid.to_s unless /^on__/ =~ mid.to_s
     add(args[0]) if args[0].is_a?(String)
    args[0]
  end

  define_event('comment', 'comment')
  define_event('embdoc_beg', 'comment')
  define_event('embdoc', 'comment')
  define_event('embdoc_end', 'comment')
  define_event('kw', 'reserved')
  define_event('tstring_beg', 'string')
  define_event('tstring_content', 'string')
  define_event('tstring_end', 'string')
  define_event('words_beg', 'string')
  define_event('qwords_beg', 'string')
  define_event('qwords_sep', 'string')
  define_event('regexp_beg', 'string')
  define_event('regexp_end', 'string')
  define_event('heredoc_content', 'string')

  def on__heredoc_beg(token)
    add(' ')
    add(token)
    add("\n")
  end

  def on__heredoc_end(token)
    add(token.chomp)
  end

  def on__ident(token)
    if @script[-1, 1] != '.' &&
       (::Kernel.methods.include?(token) ||
        ::Module.private_methods.include?(token))
      add(token, 'keyword')
    else
      add(token)
    end
  end
end

ってぜんぜん真面目にやってないじゃん!
(実際に使ってるコードとはたぶん微妙に違います)

_ えーと、on__heredoc_begで変なことしてますが、つまりtoken前後の空白文字類が失踪してる気がします。なんでだろ。
そしてon__heredoc_endには謎の改行文字が出現します。なんでだろ。
というわけなので、ちょっとprint(<<EOP)とか書いたとたんに破綻しますが気にしちゃ駄目だ。サンプルなんだから!

Sep.15,2004 (Wed)

Revision: 1.9 (Sep.15,2004 18:05)

ここ

_ この日記の話題というより、Ripperを試行錯誤(ある意味思考錯誤)しながら使ってみよう話題だなこりゃ。

_ さて、青木さんからon__scanのがよさそうというお言葉をいただいたのだけど、method_missingを使ってる最大の理由はon__spがないからだよママン!
ま、それはHEADではもう直ったはずなので、method_missingは追放。

_ あ、method_missing使うのをやめてon__scanで「その他全てのtoken」を扱うようにすれば、素直にripper.soじゃなくてripper.rbをrequireしてもよくなるな。

_ 問題は、on__scanでは「その他全てのtoken」じゃなくて、ほんとに「全てのtoken」を拾ってしまうことか。
うーん、on__scanは他のon__*よりはおおよそ先に呼ばれるわけで、それがその後別のon__*で処理されるかどうかはon__scan時にはわからんじゃん。
そういえば、連続する同一の<span>を統合するために変なことしてるのも含めて、まとめて整理すると...

require 'cgi'
require 'ripper'

class ColorParser < ::Ripper
  def self.define_event(ev, action)
    eval <<-EOM
      def on__#{ev}(token)
        @tokens.pop
        @tokens.push([token, '#{action}'])
      end
    EOM
  end

  def parse
    @tokens = []
    super

    script = ''
    preklass = nil
    @tokens.to_a.each do |token, klass|
      if preklass && klass != preklass
        script << '</span>'
        preklass = nil
      end
      if klass && !preklass
        script << %Q!<span class="#{klass}">!
      end
      script << CGI.escapeHTML(token)
      preklass = klass
    end
    script
  end

  private
  def on__scan(mid, token)
    @tokens.push(token)
  end

  define_event('comment', 'comment')
  define_event('embdoc_beg', 'comment')
  define_event('embdoc', 'comment')
  define_event('embdoc_end', 'comment')
  define_event('kw', 'reserved')
  define_event('tstring_beg', 'string')
  define_event('tstring_content', 'string')
  define_event('tstring_end', 'string')
  define_event('words_beg', 'string')
  define_event('qwords_beg', 'string')
  define_event('qwords_sep', 'string')
  define_event('regexp_beg', 'string')
  define_event('regexp_end', 'string')
  define_event('heredoc_content', 'string')

  def on__heredoc_beg(token)
    @tokens.pop
    @tokens.push(' ')
    @tokens.push(token)
    @tokens.push("\n")
  end

  def on__heredoc_end(token)
    @tokens.pop
    @tokens.push(token.chomp)
  end

  def on__ident(token)
    @tokens.pop
    if @tokens.empty? ||
       (@tokens[-1].to_a[0][-1,1] != '.' &&
        (::Kernel.methods.include?(token) ||
         ::Module.private_methods.include?(token)))
      @tokens.push([token, 'keyword'])
    else
      @tokens.push(token)
    end
  end
end

_ そういや、evalキライなのはかねてから公言してるけど、method_missingもけっこうキライだなあ。
ってどっちも使ってたのかよ前回は!(今回もevalは残ってます)

_ ところで、MoonWolfさんもおっしゃってますが、ヒアドキュメントもちゃんと扱えるのがRipperの強みだと思います。
だから、そこでトークンをロストしてる場合じゃないですよ青木さん!(とかいう

[Web] ruby-talk

_ 名指しされていたので該当スレッドを斜め読みしてみましたが、別にWindowsと関係なくて、しかも単にバグってただけでもう解決した、のかなあ。そういうことにしておこう。

_ というわけで、ruby-talkは普段読んでませんのであしからず。
あれを読んでたら生活が成り立たないです、私の英語力では。


被捕捉アンテナ類
[\ay antenna (testing)] [Ant] [Antenna-Julia] [LayserあんてなV2] [nAntenna] [nuance de Antenna] [Rabbit's Antenna] [Read List] [Ruby hotlinks 五月雨版 (るるりん。)] [してたま (私的アンテナ with たまてばこ)] [ただのあんてな] [ちゃらんぽらん] [でこぽんリンク] [なよろアンテナ] [にっきトレーサー] [偽善者あんてな - 2nd season -] [湘南日記放送局(SDB)] [はてなの各アンテナ]