或るプログラマの開発日記

日々の勉強したことの備忘録なんかに使っていきます

DATA変数と__END__トークンがテストに便利

今回は、ちょっとしたRubyプログラムのテストに便利なDATA変数の使い方のメモです。

DATA変数とは

Rubyプログラムファイルに__END__トークンだけの行が含まれている場合、その次の行以降にアクセスする為のストリームとしてDATA変数が定義されます。

この機能を使うと、paizaやCodeIQの課題なんかでよくある複数行の標準入力データを処理するプログラムを作る際に非常に便利だったりします。

__END__トークン以降に、テストしたいデータを貼り付けておけば、いちいち実行してからコンソールにデータを貼り付けるなんて面倒な事せずに済みますから!

使い方

というわけで、複数行の入力データを元にHashを作るという簡単な実装例を作ってみました。

プログラム

$_input = DATA #標準入力に切り替える場合、STDINに変更する
h = {}
while line = $_input.gets do
  (k, n) = line.split(" ")
  h.store(k, n)
end
p h
__END__
1 apple
2 orange
3 lemon
4 banana

実行結果

{"1"=>"apple", "2"=>"orange", "3"=>"lemon", "4"=>"banana"}

雑感

よくよく調べて見ると、RubyだけでなくPerlでも似たような使い方が出来るようですね。Perlは昔業務で少し触ったことがあるが、全然知らんかったわい。。(- -;)
無知というのは恐ろしいもんじゃ。。

RubyのLoggerを使ってみる

どうも、パイソンです。今回はRubyのログ出力に関する簡単なメモです。

Loggerクラスの使い方

Rubyにはどうも標準でLoggerというログ出力用ライブラリが備わっているようです。
使い勝手としてはJavalog4jと似た風な感じかなーという印象。

プログラム

require 'logger'
log = Logger.new('./logsample.log')
log.debug("debug log")
log.info("info log")
log.warn("warn log")
log.error("error log")
log.fatal("fatal log")

#INFO以上のレベルのみ出力
log.level=Logger::INFO

log.debug("debug log")
log.info("info log")
log.warn("warn log")
log.error("error log")
log.fatal("fatal log")

出力結果(logsample.log)

# Logfile created on 2017-04-16 23:45:50 +0900 by logger.rb/47272
D, [2017-04-16T23:45:50.273300 #9628] DEBUG -- : debug log
I, [2017-04-16T23:45:50.273300 #9628]  INFO -- : info log
W, [2017-04-16T23:45:50.273300 #9628]  WARN -- : warn log
E, [2017-04-16T23:45:50.273300 #9628] ERROR -- : error log
F, [2017-04-16T23:45:50.273300 #9628] FATAL -- : fatal log
I, [2017-04-16T23:45:50.273300 #9628]  INFO -- : info log
W, [2017-04-16T23:45:50.273300 #9628]  WARN -- : warn log
E, [2017-04-16T23:45:50.273300 #9628] ERROR -- : error log
F, [2017-04-16T23:45:50.273300 #9628] FATAL -- : fatal log

という感じで出力することができます。


なお、

log = Logger.new('./logsample.log')

のところを

log = Logger.new(STDOUT)

に変えてみると、標準出力に出すことが出来ます。

Loggerクラスの機能等

そういや、ログローテート機能はどうなってんだろ?と思い調べてみたらちゃんと機能として備わっている模様。

参考URL
Rubyist Magazine - 標準添付ライブラリ紹介 【第 2 回】 Logger


今更ながら、標準で大抵必要な機能が備わっているのがRubyの良さだと感心する。

RubyのTimeクラスを使ってみた

どうも、パイソンです。今回はRubyのTimeクラスのメモです。

Timeクラス

Rubyで現在時間を取るにはTimeクラスを使う。
使い方もRubyらしく結構シンプル。

プログラム

puts Time.new 
t = Time.new
puts "今日は" + t.year.to_s + "" + t.month.to_s + "" + t.day.to_s + "日です。"


実行結果

2017-04-15 22:49:35 +0900
今日は2017415日です。

雑感

Rubyとは直接関係無いけど、時間クラスの仕様って結構落とし穴になったりすることがあるので、慎重に仕様確認する必要があると思います。

たとえば私、昔お仕事でperlを使ってたことがありまして、、

my (undef, undef, undef, $mday,$mon,$year) = localtime();

とすると、$yearに+1900しないと西暦にならんかったり、$monに至っては、1月の癖に0を返却したりするんだからね!!


ということで、今回はそんな懐かしい思い出がよみがえったという記事でした。

参考URL

stackoverflow.com

Rubyでベンチマークを取る

Rubyについて調べてると、そこかしこのサイトでRubyプログラムの処理速度を出しているところがあったんですが、どうすれば出せるかを理解してなかったので、ちゃんと調べた結果をメモしておきます。

Rubyベンチマーク測定

なんとRubyでは、標準で処理速度測定用のモジュールが用意されていました。
うーん、今更ながらRuby便利すぎる。

プログラム

require 'benchmark'

Benchmark.bm 10 do |x|
  x.report "concat1" do
    str1 = ""
    100000.times do
      str1 += "str"
    end
  end
  x.report "concat2" do
    str2 = ""
    100000.times do
      str2 << "str"
    end
  end
end

実行結果

                 user     system      total        real
concat1      2.184000   3.510000   5.694000 (  5.697419)
concat2      0.000000   0.015000   0.015000 (  0.018270)

とりあえず、サンプルがてら文字列連結を+演算子で処理するバージョンと、<<演算子で処理するバージョンを比較。
その結果、まあやはりというか、処理速度という点では破壊的バージョンの方が優れているという事になりましたとさ。

参考URL

こちらの記事が非常に参考になりました!

qiita.com

sortとsort!の違い

どうも、パイソンです。

今日は、Rubyでsortのやり方を調査した時の内容をメモしておきます。

sortとsort!

ref.xaio.jp


ruby sort」とググッたら出てきたリファレンスを眺めてると、並び替えをするメソッドにもsortと、sort!という2通りがある模様。

はぁ、、?「!」に何の意味があるんじゃ?ということで確認してみると、、

「!」はメソッド名の一部です。慣用的に、 同名の(! の無い)メソッドに比べてより破壊的な作用をもつメソッド(例: tr と tr!)で使われます。

https://docs.ruby-lang.org/ja/2.1.0/doc/symref.html

ということらしい。

要は「!」付きのメソッドはオブジェクトに作用するから気を付けましょうねー。的なノリなんだろうか。。

そこで、試しに書いて見たのがこんなプログラム。

numbers1 = [2, 6, 5, 4, 9, 8, 10, 3, 7, 1]

p numbers1.sort  #=>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
p numbers1       #=>[2, 6, 5, 4, 9, 8, 10, 3, 7, 1]

numbers2 = [2, 6, 5, 4, 9, 8, 10, 3, 7, 1]

p numbers2.sort! #=>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
p numbers2       #=>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

ま、確かにsort!のほうはオブジェクトそのものを書き換えてるんだなーというのが分かりました。

「!」無しのメソッドは安全?

そんなことなら、「!」無しのメソッドは元のオブジェクトを編集したらあかんのかい!という疑問も浮かんでくるもの。

が、そんな事は無かった。どうも「!」の有無はあくまで目安的な物に過ぎないというのが現状である模様。

参考URL

qiita.com

あくまで、こんな慣習があるんですよー、という程度に覚えておこう。

Rubyの文字列連結メモ

どうも、パイソンです。

今日は、Rubyの文字列連結で少しハマった事をメモしておきます。

Rubyの文字列連結演算子

まずは、基本から。

Rubyで文字列を連結する方法には、+演算子を使う方法と、<<演算子を使う方法があります。

#文字列連結テスト
str1 = "ABC" + "DEF"
puts str1 #"ABCDEF"と出力
str2 = "abc" << "def"
puts str2 #"abcdef"と出力

+演算子と<<演算子の違い

どちらも文字列を連結しているだけのように見えますが、

  • +演算子は連結した新たなオブジェクトを返す。
  • <<演算子は左辺のオブジェクトを直接書き換える。

という点で違いがあります。

いろんなサイトで調べてみたところ、「+演算子は処理速度が遅い。<<演算子は処理速度が速いけどオブジェクトを破壊するので気をつけましょう。」という感じのようです。

何に気をつけるの?

じゃぁ、オブジェクトを書き換える事で実際どんな事が起きるの?ということで少しサンプルを組んでみました。処理内容は、"A","B","C"の文字をn個繋げてできる全ての文字列の組み合わせを出力するというものです。

#+演算子で連結するVer
def func1(str, depth)
  if depth == 0
    puts str
    return
  end
  ["A", "B", "C"].each do |c|
    func1(str + c, depth -1)
  end
end

puts "func1を実行してみた結果"
func1("", 2)

実行結果

func1を実行してみた結果
AA
AB
AC
BA
BB
BC
CA
CB
CC


このプログラムの+演算子を<<に変更してみましょう。

#<<演算子で連結するVer
def func2(str, depth)
  if depth == 0
    puts str
    return
  end
  ["A", "B", "C"].each do |c|
    func2(str << c, depth -1)
  end
end

puts "func2を実行してみた結果"
func2("", 2)

実行結果

func2を実行してみた結果
AA
AAB
AABC
AABCBA
AABCBAB
AABCBABC
AABCBABCCA
AABCBABCCAB
AABCBABCCABC

と、まあ前の結果とは大違いの結果。。

要は再帰処理を使ってオブジェクトをスタックに積んでるつもりが、<<演算子を使ったのでひたすら一点のオブジェクトを書き換えてただけでした、というオチ。

雑感

当初Rubyおぼえたての私は、「<<のほうが早いんじゃん!」と単純に考えてましたが、やはりそれぞれの違いを理解して状況に応じ適切に使い分けるようにしないといけませんね。

Twitterはじめました

どうも、パイソンです。

ブログ連携用にツイッター始めてみることにしました。

基本ブログ連携用ですが、なんか思いついたさいにつぶやくこともありますので、フォローしてくださったら嬉しいです。


んで、当面の活用方法としては、、

twitter.com

コイツを試して見るのが面白いかも。なんて思っております。



あー、でもなんかアイコンが無いとだいぶさみしい感じがするなー。(-_-;)
さっさと、なんかいいアイコン探しておこう。

では、また。