人気ブログランキング | 話題のタグを見る

edb.rb で簡単プログラム開発 その1

easydb.rb の名前が被っていたのと長い単語をタイプするのが嫌だったので名前を edb.rb に変更した。合わせて、データ例の表も掲載した。テキストデータからのデータの取り込みを簡単にやりたい、対話的なRubyの環境でプログラム開発を簡単に行いたいという二つの目的は達成できたと思う。使用例は次のエントリに掲載する。

コピペで使うときは、open,eval がそれぞれ5ヶ所全角英数になっているのでエディタで半角英数に変換しなくてはならない。また、edit メソッドではシェルコマンドをRubyの system コマンドで使っているので、Windows では vi を notepad に、rm を del に変更しないといけない。

またブログの表示の関係で、データファイルのフォーマットを記載した1行めが折り返しになっているが、一行になるように編集しないとプログラムから読み込めない。

著作権は Ruby の著作権に準じる。

ファイル名: edb.rb

require 'readline'
include Readline

class Edb
  def initialize(path = nil)
    if path == nil
      @table = []
      @label = ''
    else
      data = IO.read(path).split(/\n/)
      format = data.shift
      @label = data.shift
      raise 'format error' if format =~ /system|open/
      @table = data.collect{|x| x.split(/,/)}.collect{|x| eval format}
    end
  end

  attr_accessor :table, :label

  def methods
    puts 'read dump write select gt ge lt le cond sort reverse ' +
      'dup push delete_at to_array to_hash'
  end

  def read(path)
    data = IO.read(path).split(/\n/)
    format = data.shift
    @label = data.shift
    raise 'format error' if format =~ /system|open/
    @table = data.collect{|x| x.split(/,/)}.collect{|x| eval format}
  end

  def dump(label = @label)
    format = 'print ' +
      label.split(/ /).collect{|x| 'x[:'+x+']'}.join('," ",') + ', "\n"'
    puts label
    @table.each{|x| eval format}
  end

  def write(path = 'temp.txt')
    key = @table[0].keys
    val = @table[0].values
    suff = {'String' => ']', 'Float' => '].to_f', 'Fixnum' => '].to_i'}
    i = -1
    format = key.map{|x|
      i += 1
      ':' + x.to_s + '=> x[' + i.to_s + suff[val.shift.class.to_s]
    }.join(",")
    format = '{' + format + '}'
    f = open(path, 'w')
      f.puts format
      f.puts @label
      @table.each{|x| f.puts x.values.map{|y| y.to_s}.join(',')} 
    f.close
  end

  def select(col, pattern)
    tbl = Edb.new
    tbl.label = @label
    tbl.table = @table.select{|x| x[col] =~ pattern}
    return tbl
  end

  def gt(col, val)
    tbl = Edb.new
    tbl.label = @label
    tbl.table = @table.select{|x| x[col] > val}
    return tbl
  end

  def ge(col, val)
    tbl = Edb.new
    tbl.label = @label
    tbl.table = @table.select{|x| x[col] >= val}
    return tbl
  end

  def lt(col, val)
    tbl = Edb.new
    tbl.label = @label
    tbl.table = @table.select{|x| x[col] < val}
    return tbl
  end

  def le(col, val)
    tbl = Edb.new
    tbl.label = @label
    tbl.table = @table.select{|x| x[col] <= val}
    return tbl
  end

  def cond(condition)
    raise 'condition error' if condition =~ /system|open/
    tbl = Edb.new
    tbl.label = @label
    tbl.table = @table.select{|x| eval condition}
    return tbl
  end

  def sort(col)
    tbl = Edb.new
    tbl.label = @label
    tbl.table = @table.sort{|x,y| x[col] <=> y[col]}
    return tbl
  end

  def reverse
    tbl = Edb.new
    tbl.label = @label
    tbl.table = @table.reverse
    return tbl
  end

  def dup
    tbl = Edb.new
    tbl.label = @label
    tbl.table = @table.collect{|x| x.dup}
    return tbl
  end

  def push(row)
    @table.push(row)
    return self
  end

  def delete_at(row_num)
    @table.delete_at(row_num)
    return self
  end

  def to_array(lbl = @label)
    cols = lbl.split(/ /).map{|x| x.intern}
    tbl = @table.map do |x|
      row = []
      cols.each{|y| row.push(x[y])}
      row
    end
    return tbl
  end

  def to_hash(lbl = @label)
    cols = lbl.split(/ /).map{|x| x.intern}
    tbl = @table.map do |x|
      row = {}
      cols.each{|y| row[y] = x[y]}
      row
    end
    return tbl
  end

end

def edit(prog = nil)
  if prog != nil
    File.open('temp.txt','w') {|f| f.write(prog) }
  end
  system "vi temp.txt"
  prog = IO.read('temp.txt')
  system "rm temp.txt"
  prog
end

def save(path, var)
  File.open(path, 'w'){|f| f.write(var) }
end

def ml
  prog = ""
  while true
    line = readline('lines*> ', true)
    break if line == ";"
    prog << line + "\n"
  end
  return prog
end

loop do
  begin
    line = readline('easydb> ', true)
    if line == ";"
      then line = ml
    end
    eval(line, TOPLEVEL_BINDING)
  rescue SyntaxError, LoadError, StandardError
    STDERR.puts "Warning: #$!"
  end
end

サンプルデータファイル1: seiseki.txt

{:name=>x[0], :sugaku=>x[1].to_i, :kokugo=>x[2].to_i,
 :eigo=>x[3].to_i}
name sugaku kokugo eigo
A,90,65,55
B,46,50,50
C,63,63,58
D,50,40,48
E,55,32,40

サンプルデータファイル2: aminoacid.txt

{:name=>x[0],:let3=>x[1],:let1=>x[2],:polarity=>x[3],:acidity=>x[4],
:hydropathy=>x[5]}
name let3 let1 polarity acidity hydropathy
Alanine      ,Ala,A,nonpolar,neutral         , 1.8
Arginine     ,Arg,R,polar   ,basic (strongly),-4.5
Asparagine   ,Asn,N,polar   ,neutral         ,-3.5
Aspartic acid,Asp,D,polar   ,acidic          ,-3.5
Cysteine     ,Cys,C,nonpolar,neutral         , 2.5
Glutamic acid,Glu,E,polar   ,acidic          ,-3.5
Glutamine    ,Gln,Q,polar   ,neutral         ,-3.5
Glycine      ,Gly,G,nonpolar,neutral         ,-0.4
Histidine    ,His,H,polar   ,basic (weakly)  ,-3.2
Isoleucine   ,Ile,I,nonpolar,neutral         , 4.5
Leucine      ,Leu,L,nonpolar,neutral         , 3.8
Lysine       ,Lys,K,polar   ,basic           ,-3.9
Methionine   ,Met,M,nonpolar,neutral         , 1.9
Phenylalanine,Phe,F,nonpolar,neutral         , 2.8
Proline      ,Pro,P,nonpolar,neutral         ,-1.6
Serine       ,Ser,S,polar   ,neutral         ,-0.8
Threonine    ,Thr,T,polar   ,neutral         ,-0.7
Tryptophan   ,Trp,W,nonpolar,neutral         ,-0.9
Tyrosine     ,Tyr,Y,polar   ,neutral         ,-1.3
Valine       ,Val,V,nonpolar,neutral         , 4.2
by tnomura9 | 2008-09-20 06:36 | Ruby | Comments(0)
<< edb.rb で簡単プログラム... プログラムを変数に入れる ed... >>