YAPC::Asia に来たメモ

聞いたセッションの感想などつらつらと

お待たせしました。Perl で BDD を簡単に実践する最高にクールなフレームワークができました - YAPC::Asia Tokyo 2014

特に BDD のスタイルに拘りがないのであれば、Test::More 風にも書けるので良い。
テストの結果が見やすくなっている以下の点が最大の利点だと感じた。

  • power-assert ぽくエラーとなった時の変数の値が出力される
  • 色が付いている

テスト数のカウントを 1..1 と出力していて、いつくテストを実行したのかまったく気にしていないのがストイック。

Perl::Lint - Yet Another Perl Source Code Linter - YAPC::Asia Tokyo 2014

より良いコードを書く/あるいは人に書いてもらうために、泥臭いコードで頑張っている[twitter:@moznion]氏の献身が印象的。

ライブコーディング 2014 - YAPC::Asia Tokyo 2014

フレームワークに乗っかる形だと、なかなか「より良いコードのためにどのような工夫をしているのか」がわかり難いかも。

既にあるアプリケーションに対して、何か機能を追加します。といった小さなイテレーションの方が見ている側はおもしろいかもしれない。

Ruby東海32回に参加した

Ruby東海 第32回 勉強会 - Ruby東海 | Doorkeeperに参加した。

@antimon2さんからメモ化の発表があって、ひとりで「わからん」って騒いでたのが私です。

コードを超絶簡略化すると

class MemoSample
  def hello(name)
    @greet ||= Hash.new { |hash, name| hash[name] = "hello #{name}" }
    @greet[name]
  end
end

memo = MemoSample.new
puts memo.hello("Tom")
puts memo.hello("Ken")
puts memo.hello("Tom")

ですが、ハッシュにメモを記録する所が全然わからんかった。Ruby力なさすぎて辛い。

つまった所1

memo.hello("Tom") で1回だけ @greet が作成されるので、memo.hello("Ken") では @greet["Ken"] で nil が返ってくるのでは?

こたえ1

Hash.new に渡したブロックが遅延評価されるので、"Ken" に応答できる。
イメージとしては

@greet = { "Tom" => "hello Tom", "Ken" => {後で計算する}, "Marry" => {後で計算する} }

というハッシュが最初に作られて、後で計算する所は @greet["Ken"] が呼ばれてからブロックを実行する。
いったん計算すれば、

@greet = { "Tom" => "hello Tom", "Ken" => "hello Ken", "Marry" => {後で計算する} }

になるから、メモ化 ( ゚Д゚)ウマー てこと。

つまった所2

後で計算するとして、ブロック { |hash, name| hash[name] = "hello #{name}" } は memo.hello("Tom") の呼び出し時に定義している。
結局 @greet[key] にはいつも "hello Tom" が格納されてしまうのでは?

こたえ2

ブロック引数に渡した name と hello の引数は別物 { |hash, key| hash[key] = "hello #{key}" } と同じ。
{後で計算する}箇所は指定されたキー "Ken" によって計算されるだけ。

Comparator を指定した set

initializer_list を使って初期化できるようになったので

std::set<int, std::greater<int>> mySet{10, 4, 20, 50};

などとよく書くようになった。

比較の所を自前で用意するために、

struct MyLessThan {
  bool operator()(int a, int b) { return a > b; }
};

std::set<int, MyLessThan> mySet{10, 4, 20, 50};

などとも書ける。MyLessThan が使い捨てでよければ

auto myLessThan = [](int a, int b) { return a > b; };
std::set<int, decltype(myLessThan)> mySet({10, 4, 20, 50}, myLessThan);

この時だけ、コンストラクタで initializer_list の次に、比較用の myLessThan が必要
delctype(myLessThan) のデフォルトコンストラクタで myLessThan が得られたりはしないみたい。

Perl の文字列中で式を展開する

Perl は文字列中に変数を書くと展開してくれる

my $name = "koko_u";
print "Hello,$name\n";

出力

Hello,koko_u

しかし、式を計算することはできない

my $name = "koko_u";
my $times = 3;
print "Hello,${name}'!'x$times\n";

こんな感じで "" 中で '!'x$times の結果 !!! を出力したいが無理。
無理矢理すると

my $name = "koko_u";
my $times = 3;
print "Hello,${name}@{['!'x$times]}";

トリッキーすぎる。。。

Perl の while 文で continue

Perl の while 文の中で、next とか last とかできるのは知ってたけど

my $counter = 0;
while ($counter < 5) {
    print "$counter\n";
} continue {
    $counter++;
}

とか書けるんか。知らんかった。
while の本体で next ですっとばされても $counter を間違いなくカウントアップできる。便利?

my $counter = 0;
while ($counter < 5) {
    next if $counter < 2;
    print "$counter\n";
} continue {
    $counter++;
}

出力

2
3
4

rubyで簡単なツールを作る時の備忘

個人的に使用するだけのコマンドラインツールをrubyで作成する時の手順を備忘録として残しておく

1. テンプレートの作成

$ bundle gem awesome_tool -b -t

-b が実行ファイルを bin の下に作成。-t がテスト含む

2. gemspec 編集

development_depencency に適当に guard-rspec とか fuubar とか足す

3. bundle install

$ bundle install --path=vendor/bundle --binstubs .bundle/bin

foobar とかグローバルにインストールしても意味ないので、手元のプロジェクト内だけにインストールする
vendor/bundle と .bundle は .gitignore に追加しておく
rspec や rake といったコマンドを .bundle/bin に放り込んでおくと、rbenv-binstubs プラグインがよしなにやってくれて bundle exec rspec とか打たなくて済む。

4. Guard ファイル作成

$ guard init rspec

できた Guardfile から、Rails のための設定を削除しておく。
notification :emacs しておくと growl っぽいのが飛んでこなくてよい。

5. コードを書く

6. 手元で試す

$ rake build
$ rake install
$ bundle exec awesome_tool

で完成。github とかに野良gemとして置いておく

ruby で変数が nil の時にアサインするあれ

ruby でよく変数 name に値が設定されていない時だけデフォルトの "山田権兵衛" とか設定したい時に

  name ||= "山田権兵衛"

という記述が紹介されるけど、これって name が false の時も権兵衛さんになっちゃうけど、設定されていない(=nil)の時だけに値を入れるとすると

  name = "山田権兵衛" if name.nil?

になってしまうよな。でもこれだと name "田中"の時に式の評価値が nil になって残念な感じ。

  name = "山田権兵衛" if name.nil? ; name

かますますダサいし。

そもそも、RailsActiveRecord も find_by でユーザーが見つからない時に nil ではなくて false を返してくるし、きっと皆あんまり気にしてないのかもね。