Slow Dance RSSフィード

2008-03-29

Timeオブジェクトの等価でちょいはまった

Railsのテストでこんなメッセージが出た

<Sat Mar 29 20:05:49 +0900 2008> expected but

was

<Sat Mar 29 20:05:49 +0900 2008>.


あれ?なんでテスト落ちるんだろう。


irbで確認

irb(main):002:0> a = b = Time.now

=> Sat Mar 29 20:07:31 +0900 2008

irb(main):003:0> a == b

=> true

これは当たり前だ。同じオブジェクト指してるわけだし。


irb(main):004:0> a = Time.now

=> Sat Mar 29 20:08:18 +0900 2008

irb(main):005:0> b = Time.parse(a.to_s)

=> Sat Mar 29 20:08:18 +0900 2008

irb(main):006:0> a == b

=> false

げ。なんでfalse。


原因

簡単なことだった。

irb(main):004:0> a = Time.now

=> Sat Mar 29 20:08:18 +0900 2008

irb(main):005:0> b = Time.parse(a.to_s)

=> Sat Mar 29 20:08:18 +0900 2008

irb(main):006:0> a == b

=> false

irb(main):007:0> a - b

=> 0.859

irb(main):008:0> a.usec

=> 859000

irb(main):009:0> b.usec

=> 0


Time.nowには浮動小数点が含まれている。Time.parseとかlocalでやると、浮動小数点は0なんだ。


あ、今のは嘘だ。ごめんなさい(ノд`)Time.localはusecは指定できる。parseは無理のようです。

Time.local(year[, mon[, day[, hour[, min[, sec[, usec)


まぁ、Timeの値は浮動小数点が考慮されていることを忘れないようしよう。

ファイルテキストコンバーター

ファイル中のある文字列を別の文字列に変えたい

例えばこんなの。

  • source.txt

■ファイル中のある文字列

・source.txt

これを下に変えたい。


  • converted.txt
**ファイル中のある文字列
-source.txt

それ、ワンライナーでできるお(・∀・)!

はぁ?置換すりゃいいじゃんか。

って言われるのは承知で書きました。


ファイルテキストコンバーター

#!usr/local/bin/ruby -Ku

class StringUtil
  require 'nkf'
  
  def self.encode(str,code = "u")
    NKF::nkf("-W -#{code} -m0",str)
  end
end

class TextConverter
  def self.encode_table(source,code = "u")
    keys = source.keys
    keys.inject({}){|h,k| h.merge(StringUtil.encode(k,code) => StringUtil.encode(source[k],code))}
  end
  
  def initialize(conversion_table)
    @conversion_table = conversion_table
    @target_regexp = Regexp.union(*(conversion_table.keys))
  end
  
  def convert(str)
    str.gsub(@target_regexp) do |match|
      @conversion_table[match]
    end
  end
end

class FileTextConverter < TextConverter
  def convert(source)
    File.open(ARGV[0],"r") do |file|
      ext      = File.extname(file.path)
      filename = File.basename(file.path,".*")
      
      File.open("#{filename}_converted#{ext}","w") do |new_file|
        file.each_line do |line|
          line = super(line)
          new_file.write(line)
        end
      end
    end
  end
end

使うときはこんな感じ。

CONVERSION_TABLE = {
  "" => "**",
  "" => "-"
}.freeze

conversion_table = FileTextConverter.encode_table(CONVERSION_TABLE,ARGV[1])
ftc = FileTextConverter.new(conversion_table)
ftc.convert(ARGV[0])

うーん。なんか、StringUtilを2回使っているところと、そもそもFileTextConverterの中にencode_tableメソッドがあるのが変な気がする。でも、下みたいにやるのはもっと変だしな。

class TextConverter
  def initialize(conversion_table,code = "u")
    @conversion_table = self.encode_table(conversion_table,code)
    @target_regexp = Regexp.union(*(conversion_table.keys))
  end
end

Converter#initializeは、conversion_tableをセットするものだから、conversion_table自体をいじるのはおかしいよなー。依存度があがる。渡されたものをただセットするだけのほうがいいと思う。


すると、そもそもTextConverterにencode_tableメソッドがあるのが変なのかな。

その変の感覚がまだ分かりきってないよね(ノд`)


というか、この使い捨てツール系に継承とか使うのどうなんだ・・・(汗)


追記:ワンライナーでやってみた

最近ワンライナー系の記事が2つもあったのでワンライナーでやってみました。


C:\>ruby -ne 'print $_.gsub("■","**").gsub("・","-")' "a.txt" > a_converted.txt


できた。ファイル読み込むのが簡単でいいなー。ワンライナー楽しい。

がー。すごい簡単にできた。