Perl入学式in東京 #5に参加しました
イベント情報
イベント
Perl入学式in東京 #5
日時
2013/12/08(日)13:00~17:00(17:40までかかりましたけど)
URL
場所
東京都品川区西五反田1-21-8 KSS五反田ビル 株式会社ガイアックス 6Fセミナールーム
参加人数
11人くらい
今回は少しづつ寒くなったせいか欠席する人も増えてしまいました
講師陣
いつもの方々に加えて、とある1流エンジニアの方が参加してくれました。
1流エンジニアというべきかプログラマというべきかなんか呼び名に困りそうなんでまあ、すごい人と思ってください。〇〇○代表とかはさすがに言えないんで…
サブルーチンの復習
calc.pl(2つの引数を比較して、add、sub、mul、div、mod)の結果を返す
#!/usr/bin/env perl use strict; use warnings; # 2つの数値を引数として、+、-、*、/、%の結果を返すモジュール sub calc{ my ($left, $right) = @_; return { add => $left + $right, sub => $left - $right, mul => $left * $right, div => $left / $right, mod => $left % $right }; } # チェック use Data::Dumper; print Dumper(calc(66, 5)); print Dumper(calc(999, 100));
結果
m-shige1979@mshige1979-virtual-machine:/tmp/perl/sample0$ perl calc.pl $VAR1 = { 'div' => '13.2', 'mul' => 330, 'mod' => 1, 'add' => 71, 'sub' => 61 }; $VAR1 = { 'mul' => 99900, 'div' => '9.99', 'sub' => 899, 'mod' => 99, 'add' => 1099 };
calc.pl(2つの引数を正規表現を使用してチェック)
#!/usr/bin/env perl use strict; use warnings; # 2つの数値を引数として、+、-、*、/、%の結果を返すモジュール sub calc{ my ($left, $right) = @_; # 数値チェック if(!check($left) || !check($right)){ return undef; } # 数値チェックが正常な場合は計算 return { add => $left + $right, sub => $left - $right, mul => $left * $right, div => $left / $right, mod => $left % $right }; } sub check{ my ($str) = @_; if($str =~ /\d+/){ return 1; } return 0; } # チェック use Data::Dumper; print Dumper(calc(66, 5)); print Dumper(calc(999, 100)); print Dumper(calc("a", 5)); print Dumper(calc(66, "b")); print Dumper(calc("a", "b"));
結果
m-shige1979@mshige1979-virtual-machine:/tmp/perl/sample0$ perl calc2.pl $VAR1 = { 'mod' => 1, 'div' => '13.2', 'sub' => 61, 'add' => 71, 'mul' => 330 }; $VAR1 = { 'div' => '9.99', 'mod' => 99, 'sub' => 899, 'add' => 1099, 'mul' => 99900 }; $VAR1 = undef; $VAR1 = undef; $VAR1 = undef;
food.pl(食べ物の数をカウント?)
#!/usr/bin/env perl use strict; use warnings; use Data::Dumper; my $data = q{ papix : sushi moznion : soba boolfool : sushi macopy : sushi }; sub food{ my ($string) = @_; my $res = {}; # まず改行で分割 my @list = split(/\n/, $string); # ループしたものを正規表現で抽出してない場合は設定、ある場合は追加? for my $val(@list){ if($val =~ /^(.+) : (.+)$/){ if($res->{$2}){ $res->{$2} += 1; }else{ $res->{$2} = 1; } } } return $res; } print Dumper($data); print Dumper(food($data));
結果
m-shige1979@mshige1979-virtual-machine:/tmp/perl/sample0$ perl food.pl $VAR1 = ' papix : sushi moznion : soba boolfool : sushi macopy : sushi '; $VAR1 = { 'sushi' => 3, 'soba' => 1 };
Mojolicious
まあ、したんですけど今回はインストールだけだったんで省略します。
cpanm Mojolicious mojo generate lite_app Sample.pl
こんな感じ?おそらく第6回に参加できれば書くかも…
mapとgrep
本音いうとパフォーマンスで速度向上が見込めない場合は使わないと思います。
実装サンプル
!/usr/bin/env perl use strict; use warnings; use Data::Dumper; my @files = qw/papix.pl moznion.pm macopy.py boolfool.vim/; # Dumper; print Dumper(@files); sub map_pl{ my ($list) = @_; my @res = (); # for my $val (@$list) { # if($val =~ /^(\w+)\.(.+$)/){ # push @res, $1 . ".pl"; # } # } @res = map { my ($name) = ($_ =~ /^(\w+)\.(.+$)/); "$name.pl"; } @$list; return \@res; } sub grep_pl_and_pm{ my ($list) = @_; my @res = (); # for my $val (@$list) { # if($val =~ /(\.pl$)|(\.pm$)/){ # push @res, $val; # } # } @res = grep { $_ =~ /(\.pl$)|(\.pm$)/ } @$list; return \@res; } print Dumper(map_pl(\@files)); print Dumper(grep_pl_and_pm(\@files));
結果
m-shige1979@mshige1979-virtual-machine:/tmp/perl/sample1$ perl sample1.pl $VAR1 = 'papix.pl'; $VAR2 = 'moznion.pm'; $VAR3 = 'macopy.py'; $VAR4 = 'boolfool.vim'; $VAR1 = [ 'papix.pl', 'moznion.pl', 'macopy.pl', 'boolfool.pl' ]; $VAR1 = [ 'papix.pl', 'moznion.pm' ];
使用した所感としては1行で組める程度なら使うかもしれないが、複数行になりそうなら使わないかも…
while、next、last
whileは他の言語と実行回数が不明の場合に処理する場合に使用する感じ
#!/usr/bin/env perl use strict; use warnings; while(my $input = <STDIN>){ chomp $input; # 繰り返し if($input eq ""){ # 以下の処理を行わないでループ先頭へ移動して繰り返す next; } # ループを抜ける if($input eq "end"){ # これはループを脱出する last; } print "input->$input\n"; }
後置if、後置for
処理のあとにif文やfor文をかける機能
ちょっと分かりにくいので省略
サンプル
#!/usr/bin/env perl use strict; use warnings; use Data::Dumper; sub calc_string{ my ($string) = @_; my $res = undef; # 設定漏れ return undef if($string eq ''); if($string =~ /^(-?\d+) ([\+\-\*\/\%]) (-?\d+)$/){ # if($2 eq "+"){ # $res = $1 + $3; # }elsif($2 eq "-"){ # $res = $1 - $3; # }elsif($2 eq "*"){ # $res = $1 * $3; # }elsif($2 eq "/"){ # $res = $1 / $3; # }elsif($2 eq "%"){ # $res = $1 % $3; # } # 後置ifの書き方 $res = $1 + $3 if($2 eq "+"); $res = $1 - $3 if($2 eq "-"); $res = $1 * $3 if($2 eq "*"); $res = $1 / $3 if($2 eq "/"); $res = $1 % $3 if($2 eq "%"); return $res; } return $res; } while(my $input = <STDIN>){ my $val = calc_string($input); # なんかこうした方がいいらしい if(defined($val)){ print Dumper($val); }else{ print "Error\n"; } #print Dumper($val); }
結果
m-shige1979@mshige1979-virtual-machine:/tmp/perl/sample1$ perl sample3_calc_string.pl 1 + 21 $VAR1 = 22; 20 * 20 $VAR1 = 400; 1000 - 59 $VAR1 = 941; 100 / 2 $VAR1 = '50'; 666 % 4 $VAR1 = 2;
package(モジュール)
サブルーチンなどを1つのパッケージとして管理する
5.14あたりから中括弧でくくることが可能になった
#!/usr/bin/env perl use strict; use warnings; use Data::Dumper; # なんか過去にみたソースの場合は{}ではなかったはず package PerlEntrance{ sub tokyo{ return 'papix!!!'; } sub osaka{ return 'boolfool!!!'; } } # 実行 print Dumper(PerlEntrance::tokyo()); print Dumper(PerlEntrance::osaka());
結果
m-shige1979@mshige1979-virtual-machine:/tmp/perl/sample1$ perl sample4_package.pl $VAR1 = 'papix!!!'; $VAR1 = 'boolfool!!!';
モジュール
パッケージをモジュールとして任意のディレクトリに配置して読み込む方式
ファイルの拡張子
pmになります
呼び出し元
#!/usr/bin/env perl use strict; use warnings; use lib 'lib'; use Data::Dumper; use PerlEntrance; # 実行 print Dumper(PerlEntrance::tokyo()); print Dumper(PerlEntrance::osaka());
もジュール(lib/PerlEntrance.pm)
package PerlEntrance{ use strict; use warnings; sub tokyo{ #return 'papix!!!'; return 'moznion!!!'; } sub osaka{ return 'boolfool!!!'; } } 1; # おまじない?
実行
m-shige1979@mshige1979-virtual-machine:/tmp/perl/sample1$ perl -Ilib plactice.pl $VAR1 = 'moznion!!!'; $VAR1 = 'boolfool!!!';
※use lib 'lib';を指定しておくことでディレクトリを参照してもらえる。それができない場合は-llibなどを実行時に付与する
テスト
個人で作成する場合にモジュールを使用するけどパッケージのパターンがちょっと複雑な場合にパターンを考える上でテストケースをコードとして記述することで仕様を明確にすることが可能
テストコードを書く場合はxxxx.tファイルを作成する
テストコードは拡張子が".t"となるよう
また、他の人が作成したコードをテストする際に仕様をいちいち理解しなくてもテストコードが正しいかなどで判定出来る場合がある
テストコード
#!/usr/bin/env perl use strict; use warnings; use lib 'lib'; use Test::More; use PerlEntrance; is PerlEntrance::tokyo(), 'moznion!!!'; # ここが基本的なテストコード done_testing();
テスト対象にしたモジュール
package PerlEntrance{ use strict; use warnings; sub tokyo{ #return 'papix!!!'; return 'moznion!!!'; } sub osaka{ return 'boolfool!!!'; } } 1; # おまじない?
結果
m-shige1979@mshige1979-virtual-machine:/tmp/perl/sample1$ prove -Ilib plactice.t plactice.t .. ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.01 cusr 0.02 csys = 0.07 CPU) Result: PASS
※正常な場合は緑色で表示、エラーが有る場合は赤色となる
まとめ
とりあえず、正規表現がわからないせいでサンプルソースを作成するのに手間取りました。
パラメータを取得したり、判定するのにパターンを考えるけど正規表現に苦手意識があったため、ちょっとうまく行きませんでした。
ペアプログラミングを行う機会が出てお互いに検証しながら実行するのは勉強には良いと思いました。
実際の作業の場合は時間がかかりすぎるけど、お互いにフォローし合いながら学習(復習)できるのは良いかも。
時間というより、うまくできるかという問題はありそうですが…
一応今までの資料より正規表現のサンプルで勉強し直すことが必要になった。
もう少し頑張らねば…
おまけ
ペアプログラミングした際の途中までのコード
仕様:2014年度のYAPCの日付取得及び範囲チェックを行うモジュールの作成
ペアプログラミングのテストコード
#!/usr/bin/env perl use strict; use warnings; use lib 'lib'; use Test::More; use YAPC; is YAPC::year(), 2014; is YAPC::month(), 8; is YAPC::day(), 28; done_testing();
ペアプログラミングのモジュール
package YAPC; sub year { return 2014; } sub month { return 8; } sub day { return 28; } 1;
結果
m-shige1979@mshige1979-virtual-machine:/tmp/perl/yapc_test$ prove test.t -v test.t .. ok 1 ok 2 ok 3 1..3 ok All tests successful. Files=1, Tests=3, 0 wallclock secs ( 0.04 usr 0.00 sys + 0.03 cusr 0.01 csys = 0.08 CPU) Result: PASS
※テストコードを実行する際、-vを付与するとちょっと詳細なテストを表示する
日付の判定を行うのがちょっと大変そうなので別途調査して記載することにする