ソースが読み辛いのでドキュメントが整備してあるべきなんですが、そんなに使う人いないだろうという理由と、簡易READMEとRSpecファイルが用意してあるので、そういうところを参照してもらえればいいかな、という勝手な立ち位置であります。ちなみにカレントディレクトリで rake するとテストが発動します。
GitHubの「こちら」にてメンテされてますが、Rubyライセンスですよということと、 fork などはご自由に、というお知らせでした。
# -*- coding: utf-8 -*-$KCODE='u'require 'nkf'require 'date'require "enumerator"module Kifuclass Kifuattr_accessor :nameattr_reader :footerValidKifuPattern = "手数----指手---------消費時間--"HeaderPattern = /^#/SplitPattern = ValidKifuPattern # ここから指し手KifuHeaders = {"棋戦" => :kisen, "手合割" => :teai,"先手" => :sente, "後手" => :gote}# 柿木形式棋譜の判定を行う(適当)def self.valid? kifuif NKF.nkf('-w', kifu).match(ValidKifuPattern)trueelsefalseendenddef initialize kifu, name='', headers=[], attributes={}, body=[], footer=nil# merge 判定if (not headers.empty? or not attributes.empty? ornot body.empty? or not footer.nil?)@name = name@headers = headers@attributes = attributes@body = body.dup@footer = footerelsif not Kifu.valid? kifuraise RuntimeError, "正式な柿木形式棋譜ファイルではありません"else@name = nameparse NKF.nkf('-w', kifu) # 新たに解析するendenddef merge_comment! sashiteraise RuntimeError, "指し手オブジェクトではありません" if sashite.class != Sashite@body[sashite.tesuu-1] = @body[sashite.tesuu-1].merge sashiteenddef merge anotherif not another.class == self.classraise RuntimeError, "棋譜オブジェクトではありません"elsif not same? anotherraise RuntimeError, "同じ棋譜ではありません"end# ヘッダは呼び出し元を保持headers = @headers.dupattributes = @attributes.dupbody = @body.enum_with_index.map{|sashite, index|sashite.merge another[index]}footer = @footer.merge another.footerKifu.new nil, self.name, headers, attributes, body, footerenddef & anothermerge anotherenddef started_at@attributes[:started_at]enddef same? anothereach_with_index do |sashite, index|return false if not sashite.te == another[index].teendreturn trueenddef strict_same? anotherif (header != another.header orstarted_at != another.started_at orkisen != another.kisen orteai != another.teai orsente != another.sente orgote != another.gote)return falseendeach_with_index do |sashite, index|if (sashite.te != another[index].te orsashite.comment != another[index].comment)return falseendendenddef header@attributes[:header]enddef teai@attributes[:teai]enddef sente@attributes[:sente]enddef gote@attributes[:gote]enddef kisen@attributes[:kisen]enddef at pos@body[pos]enddef [] posat posenddef each &block@body.each do |sashite|block.call sashiteendenddef each_with_index &block@body.each_with_index do |sashite, index|block.call sashite, indexendenddef to_s_to_s :to_senddef to_s_with_names_to_s :to_s_with_names_and_commentsenddef _to_s method # privatebuffer = []buffer.push @headers.join("\n")buffer.push ValidKifuPatternbuffer += @body.map{|sashite| sashite.__send__ method}buffer.push @footer.__send__ method# to_s するときは改行コードを CRLF に固定buffer.join("\n").gsub(/\r/m, "").gsub(/\n/m, "\r\n") + "\r\n"enddef kifuto_senddef parse kifu@headers = []@attributes = {}@body = []@footer = []queue = ""sashite_mode = falsekifu.each_line do |line|if not sashite_mode and line.match HeaderPattern@headers << line.chomp@attributes[:header] = line.stripelsif not sashite_mode and not line.match SplitPattern # まだヘッダ部分@headers << line.chompkey, value = line.split(/:/)if key == "開始日時"@attributes[:started_at] = DateTime.parse valueelse@attributes[KifuHeaders[key]] = zenkaku_strip(value.to_s)endelse # 指し手突入if not sashite_modesashite_mode = truenext # 最初の行はスキップendif Sashite.comment? linequeue += lineelsif Sashite.sashite? linequeue += line@body << Sashite.new(queue, @name)queue = ""elsif Sashite.footer?(line)queue += line@footer = Sashite.new(queue, @name)endendendenddef zenkaku_strip stringstring.strip.gsub(/ +$/, '')endprivate :parse, :zenkaku_strip, :_to_sendclass Sashiteattr_reader :tesuu, :te, :prev_te, :time_considered, :clockSashitePattern = /^\s+?(\d+?)\s(.+?)(\(\d\d\))?\s+?\(\s(.*?)\)/CommentPattern = /^\*(.*)/ToryoPattern = /^まで.*/def self.sashite? lineline.to_s.match SashitePatternenddef self.comment? lineline.to_s.match CommentPatternenddef self.comment_or_sashite? linecomment?(line) or sashite?(line)enddef self.footer? lineline.to_s.match ToryoPatternenddef initialize text, name="no name", args={}if args.empty?@names = []@comments = []@names.push name@comment = []text.each_line do |line|if match = Sashite.comment?(line)@comment << match[1].to_s.chompelsif match = Sashite.footer?(line)@footer = match[0]elsif match = Sashite.sashite?(line)@tesuu = match[1].to_i@te = match[2].chomp@prev_te = match[3].match(/\d\d/)[0].chomp if match[3]@time_considered, @clock = match[4].chomp.split(/\//)endend@comment = @comment.join("\n")@comments.push @commentelse # args 処理if args[:merge] # マージ用の一時オブジェクトの場合@tesuu = args[:tesuu]@names = [args[:name]]@comments = [args[:comment]]else@names = args[:names]@comments = args[:comments].map{|c| c.gsub(/\r/, "")}@tesuu = args[:tesuu]@te = args[:te]@prev_te = args[:prev_te]@time_considered = args[:time_considered]@clock = args[:clock]@footer = args[:footer]endendenddef footer?true if @footerenddef names@names.dup.freezeenddef name@names.firstenddef merge anotherif not another.class == self.classraise RuntimeError, "指し手オブジェクトではありません"endSashite.new(nil, nil, {:names => @names + another.names,:comments => @comments + another.comments,:tesuu => @tesuu, :te => @te,:prev_te => @prev_te,:time_considered => @time_considered,:clock => @clock, :footer => @footer})enddef & anothermerge anotherenddef comments_with_namescomments_with_names_within(0..-1)enddef comments@comments.map{|c| crlfize c}enddef comment_with_namecomments_with_names_within(0..0).firstenddef comments_with_names_within rangeresult = []queue = ""@comments[range].each_with_index do |comment, index|comment.each_line do |line|queue += "#{@names[index]}: #{line}"endresult.push queuequeue = ""endresult.map{|c| crlfize c}enddef commentcrlfize @comments.firstenddef crlfize stringstring.gsub(/\n/m, "\r\n")end# to_s は最初のコメントを名前無し + 指し手で返すdef to_sreturn crlfize(comments_to_s(0, false)) + @footer if footer?result = comments_to_s 0, falseresult += te_to_scrlfize resultenddef to_s_with_names_and_commentsreturn crlfize(comments_to_s((0..-1), true)) + @footer if footer?result = comments_to_s((0..-1), true)result += te_to_scrlfize resultenddef to_s_without_commentsreturn crlfize(@footer) if footer?te_to_senddef comment_to_s pos, with_name # private@comments[pos].split("\n").map{ |comment|if with_name"*#{@names[pos]}: #{comment}"else"*#{comment}"end}.join("\n")enddef comments_to_s range, with_name # privateresult = ""if range.class == Rangeresult =@comments[range].enum_with_index.map{ |c, pos|comment_to_s pos, with_name}.select{|v| not v.empty?}.join("\n")elseresult = comment_to_s range, with_nameendresult += "\n" if not result.empty?return resultenddef commented?not count_of_comment.zero?enddef count_of_comment@comments.inject(0){|count, comment| comment.empty? ? count+0 : count+1}enddef te_to_sresult = sprintf("%4d", @tesuu) + " "te = @te.to_ste += "(#{@prev_te})" if @prev_tete += " " if not @prev_tesprintf_length = 13sprintf_length += (te.length - NKF.nkf("-s", te).length)result += sprintf("%-*s", sprintf_length, te)time = "( " + @time_considered.to_s + "/" + @clock.to_s + ")"result += timereturn crlfize resultendprivate :te_to_s, :crlfize, :comments_with_names_within,:comment_to_s, :comments_to_sendendif $0 == __FILE__k = Kifu::Kifu.new NKF.nkf("-w", File.read("sandmark.kif"))puts NKF.nkf("-s", k.to_s)end
押してねっ→BlogPeople「趣味の世界」ブログランキング
0 件のコメント:
コメントを投稿