About Dancer2 (ja)

この記事は、Perl5 Advent Calendar 2015 の20日目の記事です。

Web Application Framework の Dancer2 について紹介したいと思います。

まずは、YAPC::Asia 2014 の LT から。 こちらは、Dancer2 のリリースマネージャーの SawyerX による、Dancer2の超速紹介です。 Dancer2 の要点が凝縮されたLTです。

目を凝らすとこんなスライドが見えます。DSLで、ルーティングを記述します。

package MyApp;
use Dancer2;

get '/' => sub {
   template index => {
      name => 'Sawyer X',
      event => 'YAPC::Asia'
   }
};

JSON を返却するようなAPIも簡単に用意できます。

package MyApp::API;
use Dancer2;

set serializer => 'JSON';

get '/' => sub {
    return {
        hello => 'world',
    }
};

Dancer2 は Plack化されているので、plackupできます。

# app.psgi
use MyApp;
my $app = MyApp->psgi_app;
plackup app.psgi

ここまでが、LTの抜粋です。

Dancer2 は、元々、RubySinatraPerl に port した Dancer の次バージョンです。 Dancer の DSL はほぼそのままに、設計面での調整が大幅に入っています*1

例えば、以下のような対応が行われています。

この対応に関して、2011 年の Dancer Advent Calendar にて、(超訳ですが)「全部書き換えるぞい」という記事があります。

Dancer 2, or Why I Rewrote Everything | PerlDancer Advent Calendar

利用者が多数のプロダクトにおいて、こういった完全な書き換えは、個人的な興味をそそりました。 今現在も活発に開発され、Dancer という名前を冠するPerl カンファレンスも開かれています。

Dancer を作った sukria のポスト。

Perl Dancer 2015 Report
blog.sukria.net

最近の開発状況の話。

(Dancer2::XS ってあって、すごいってなった)

もう少し、Dancer2 の特徴を触れて、記事を終わりにしたいと思います。
(と言っても、ほぼ、2014 年の dancer advent calendar *2 からの抜粋です。

fatpack、つまり一枚スクリプトにするのをサポートしています。 (なので、XSモジュールは、recommend 扱いです)

ポータビリティを考えると良い選択になるかもしれません。

コマンドラインで利用も考慮されています。

use Dancer2;

warn config->{environment}; # => development
warn dancer_version;        # => 0.165000

複数のアプリケーションの同居が考慮されています。 Dancer2 に appname を渡すことで、config やdbh などが、appname ごとに管理されます。

以下の例だと、 MyApp::Foo1, Foo2 で、一つの Dancer2::Core::App obj が作られ、 Bar にもう一つの Dancer2::Core::App obj が作られます。

package MyApp::Foo1 {
  use Dancer2 appname => 'foo';
  get '/' => sub { ... }
}

package MyApp::Foo2 {
  use Dancer2 appname => 'foo';
  get '/' => sub { ... }
}

package MyApp::Bar {
  use Dancer2;
  get '/' => sub { ... }
}

まとめ

  • なんだか Dancer2 楽しそうだぞ

明日は、akihiro_0228 さんです。

設定とFixtureのテスト

この記事は、モバイルファクトリー Advent Calendar 2015 2日目の記事です

昨日は、nekobato さんの superagentとaxiosの使い分け でした  

Perl Advent Calender 2014 の最高の記事の ソースコード以外もとにかくテストする。もしくはカバレッジだけではダメだという話 から、 アプリケーション設定ファイルのテストFixtureのテスト の例を書いてみたいと思います

アプリケーション設定ファイルのテスト

本番環境、開発環境、テスト環境で設定が過不足がないかチェックするため、 Test::Deep, Test::Deep::Matcher を利用しています

テストの流れとしては

  1. 本番環境の設定値を、Test::Deep::Matcher のmatcher に変換
  2. 開発環境、テスト環境の設定値が、matcher にあうか比較

です

例えば、以下のような本番設定があったとして..

# production.pl
{
  servers => [
    'XX.XX.XXX.XXX:11211',
    'XX.XX.XXX.YYY:11211',
  ],
  options => {
    utf8 => 1,
  },
}

再帰的にmatcherに変換してあげます

use Test::Deep::Matcher;
use Test::Deep qw//;

sub convert_matcher {
    my $v = shift;

    if (!ref $v) {
        return Data::Util::is_integer($v) ? is_integer
             : Data::Util::is_number($v)  ? is_number
             : Data::Util::is_string($v)  ? is_string
             : Data::Util::is_value($v)   ? is_value
             : undef;
    }
    elsif(ref $v eq 'ARRAY') {
        return Test::Deep::array_each(convert_matcher($v->[0])) # XXX: 仮定
    }
    elsif(rev $v eq 'HASH') {
        return +{ map { $_ => convert_matcher($v->{$_}) } keys %$v }
    }
}

あとは比較するだけです

my $expect = convert_matcher($production_conf)
cmp_deeply $development_conf, $expect;

(余談)

  • 上の例では、本番環境の設定から(雑な)型推定をしました
  • 設定の型定義を用意しておけるなら、その方が良いかもしれません
    • 異常値などの定義をしやすいですし

以下、crystal の例です

require "json"

class Config
  JSON.mapping({
    servers: String,
    options: { type: ServerOptions },
  })
end

class ServerOptions
  JSON.mapping({
    utf8: Int32
  })
end

Fixture のテスト

リレーションチェックのため、 DBIx::Schema::DSL, SQL::Translator::Schema を利用しています

チェックには、外部キー制約を利用します
実際のアプリケーションでの利用は、諸事情 でしていないですが、 テストでの利用では最高に便利です
(この辺の外部キーありなしのスイッチを、no_fk_output/output だけで簡単にできるのが、DBIx::Schema::DSL めっちゃ便利だーってなって便利です)

流れは、

  • 外部キー制約つきのスキーマを用意して、INSERT する

だけです。 ただ、エラーメッセージを、人間が読みやすい形にするため、地味にループを回すようなコードにしています:p

# Schema
use 5.014002;
package MyProj::DB::Schema {
    use DBIx::Schema::DSL;

    create_table 'module' => columns {
        integer 'id', primary_key, auto_increment;
        varchar 'name';
        integer 'author_id';

        add_index 'author_id_idx' => ['author_id'];

        belongs_to 'author';
    };

    create_table 'author' => columns {
        integer 'id', primary_key, auto_increment;
        varchar 'name', unique;
    };
}
# belongs_to.t

$db->execute(MyProj::DB::Schema->output);

my $schema         = MyProj::DB::Schema->context->schema;
my $module_schema  = $schema->get_table('module');
my $constraints    = $module_schema->fkey_constraints;

for my $fkey (@$constraints) {
    my $ref_table = $fkey->reference_table;

    my @errors = try_load($ref_table);
    ok !@errors
       or note explain @errors;
}

sub try_load {
    my ($table) = @_;

    my @errors;
    for my $row (@{$FIXTURE_DATA{$table}}) {
        try {
            $db->insert($table => $row);
        }
        catch {
            push @errors => shift;
        };
    }
    return @errors;
}

まとめ

  • アプリケーション設定ファイルのテストFixtureのテスト の実装例を紹介しました

明日は、 nekobato さんです!

Hello, Crystal

この記事は Crystal Advent Calendar 2015 の 2 日目の記事です

昨日は、pine613 さんの これから Crystal を始める方へ: Crystal 日本語情報まとめ でした。 公式ドキュメントの日本語訳が整っているの素敵ですね!! http://ja.crystal-lang.org/

今日は、crystal の setup から、heroku に deploy するまで、です。
完全、後発です。厳しいです。詳しいことは、↓を見ると良いのではないでしょうか!?

subvisual.co

zephiransas.github.io

setup

  • *env 最高
% anyenv install crenv
% crenv install 0.9.1
% crenv rehash
% crystal -v
Crystal 0.9.1 [b3b1223] (Fri Oct 30 03:26:53 UTC 2015)

initialize app

% crystal init app app # `app` という名前のapplication の雛形用意
% cd app
% git commit -m 'initial commit'

create app

  • crystal-lang.org の冒頭のHello返すだけのHTTP server に OptionParserでport食わせられるようにしただけ
% cat src/app.cr

require "http/server"
require "option_parser"

port = 8080
OptionParser.parse! do |parser|
  parser.on("-p PORT", "--port=PORT", "Set server port") { |p| port = p.to_i }
end

server = HTTP::Server.new("0.0.0.0", port) do |req|
  HTTP::Response.ok "text/plain", "Hello"
end

puts "Listening on http://0.0.0.0:#{port}"
server.listen
  • 試しに実行してみる
# 即時実行
% crystal run src/app.cr
Listening on http://0.0.0.0:8080

# ビルドしてあげる
% crystal build src/app.cr
% ./app -p 5000
Listening on http://0.0.0.0:5000

deploy to heroku

  • Procfile とりあえず用意して、手元の環境で、ps 動かしてみる
% cat Procfile
web: ./app -p $PORT
% heroku local
forego | starting web.1 on port 5000
web.1  | Listening on http://0.0.0.0:5000
% git add .
% git commit -m 'update'

heroku create

  • ↓のカスタムビルドは、適宜・・好きなのを用意してください
    • 今回は手抜きで、crystal version が、手元では、0.9.1 だけど、0.9.0 でビルドされるカスタムビルドパックを利用しました:p
    • 今回のカスタムビルドの要件は、0.9.0 でのビルド。shard.yml があること。./src/app.cr がソースファイルで、 ./app にリリースビルドされて、Procfile./app を呼び出している感じですね。
% heroku create --buildpack https://github.com/scaint/heroku-buildpack-crystal.git
% git push heroku master

Counting objects: 16, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (10/10), done.
Writing objects: 100% (16/16), 306.50 KiB | 0 bytes/s, done.
Total 16 (delta 0), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Fetching set buildpack https://github.com/scaint/heroku-buildpack-crystal.git... done
remote: -----> Crystal app detected
remote: -----> Installing Crystal 0.9.0
remote: -----> Installing Shards 0.5.3
remote: -----> Installing Dependencies
remote: -----> Compiling src/app.cr
remote:
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote:
remote: -----> Compressing... done, 409K
remote: -----> Launching... done, v3
remote:        https://arcane-harbor-8307.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/arcane-harbor-8307.git
 * [new branch]      master -> master
% heroku open

反省

アドベントカレンダー事前に準備する

明日は、 5t111111 さんです!

DBIx::Schema::DSL::Dumper というのを書きました

kfly8/DBIx-Schema-DSL-Dumper · GitHub

songmuさんの書いたDBIx::Schema::DSL を使いたい状況が出て来て、
すでに結構もりもり書かれてたDDLを移行する為に書いてみました。

使い方は、Teng::Schema::Dumper と同じように、$dbh を渡すだけで、DSLが吐き出せます。

雰囲気は次のような感じです!

use DBI;
use DBIx::Schema::DSL::Dumper;

my $dbh = DBI->connect('dbi:mysql:dbname=test', 'root', '');
print DBIx::Schema::DSL::Dumper->dump(
    dbh => $dbh,
    pkg => 'Foo::DSL',
);

よかったら使ってほしいです!

間接オブジェクト記法のアンチパターン

この記事は Perl Advent Calendar 2014 の 17日目 の記事です。

16日目の記事は magnolia_k_ さんの perlの関数を第一級オブジェクトとして扱う話 でした

目次

はじめに

15日目の記事の id:akihiro0228 さんの記事を読んで、

自分がよくハマってしまう間接オブジェクト記法について紹介したいと思います。
便乗です!

間接オブジェクト記法ってそもそも何?

メソッドを呼び出しの別表現です

$obj->method($a, $b); # 普段の呼び出し

method $obj $a, $b;   # 間接オブジェクト記法

一番なじみやすい例はnewだと思います

my $dog = new Dog;

普段は、誤読につながりやすいのであまり使うことをおすすめしないです
ですが、意図せず間接オブジェクト記法な呼び出しにしてしまったり、 この表現の方が簡潔に書ける例もあったりするので紹介してみたいと思います

間接オブジェクト記法が活きる例

定数を扱う時に便利なconstantプラグマを使ってみます
普段使う時は、以下のような感じで使うと思います

use constant FOO => 'foo';

これを動的に定数定義してみたいとします

動的に定義したい場合は use XXX は、BEGIN { require XXX; do { XXX->import } } のsugarなので、
このsugarをほどいて1つ1つ自分で順に追ってやれば変数だったりが使えます

package XXX;

BEGIN {
    require constant;
    constant->import(FOO => 'foo' x 4);
}

say FOO; # => foofoofoofoo

間接オブジェクト記法を使ってみると以下のようになります

package YYY;

BEGIN {
    require constant;
    import constant FOO => 'foo' x 4;
}

say FOO; # => foofoofoofoo

どうですかね?
普段のconstantプラグマの使い方に近く、簡潔に書けているように思います


逆に今度は、よくあるハマる例を書いてみます

ハマる例1 Try::Tiny のuse 漏れ

ずばり、 id:karupanerura 先生の話を例を取ってみます。

use strict;
use warnings;
use utf8;
use feature 'say';
 
# XXX わざとuseしないで、errorを起こす
#use Try::Tiny;
 
try {
    say 'foo';
    say 'bar';
}
# =>
# foo
# bar
# Can't locate object method "try" via package "1" (perhaps you forgot to load "1"?) at try2.pl line 6.

このエラーだとよくわからないので、 7日目の id:papix さんと11日目の id:hisaichi5518 さんが紹介しているB::Deparseを使います

# perl -MO=Deparse %

use utf8;
use warnings;
use strict;
use feature 'say';
do {
    say 'foo';
    say 'bar'
}->try;

do の最後に評価された 1 を package として、1->try みたいなことをしています

# Can't locate object method "try" via package "1" (perhaps you forgot to load "1"?) at try2.pl line 6.

packageが1だとちょっと分かりにくいと思うので、
次の例を見てみてください

use strict;
use warnings;
use utf8;
use feature 'say';
 
#use Try::Tiny;
 
try {
    say 'foo';
    bless {}, 'foo'; # XXX obj を最後においてやる
}
# =>
# foo
# Can't locate object method "try" via package "foo" at try2.pl line 6.

Deparse すると以下のようになります

use utf8;
use warnings;
use strict;
use feature 'say';
do {
    say 'foo';
    bless {}, 'foo'
}->try;

今度のエラーと、Deparse した例を見ると、foo->try と呼び出しされたことが分かってもらえると思います

# Can't locate object method "try" via package "foo" at try2.pl line 6.

最後にちゃんと use Try::Tiny した例です

use strict;
use warnings;
use utf8;
use feature 'say';

use Try::Tiny;

try {
    say 'foo';
    bless {}, 'foo';
}
# => foo
# perl -MO=Deparse %

use utf8;
use Try::Tiny;
use warnings;
use strict;
use feature 'say';
try sub {
    say 'foo';
    bless {}, 'foo';
}
;

Deparse したコードを見ると、try に coderef が渡されていることが分かると思います

余談 code block

Try::Tiny の try のコード を見ると、次のようにサブルーチン名に(&;@)といった指定がされています

sub try (&;@) {

これはプロトタイプと呼ばれるものです

http://perldoc.jp/docs/perl/5.6.1/perlsub.pod#Prototypes

これにより、blockで、coderef を表現できるので、より簡潔な記法ができます
try 以外にも、grep, mapなどが身近な例だと思います

coderef を実行しながら、sumを取る関数を実装してみます

まずは、prototypeを使わない例

use strict;
use warnings;
use utf8;
use Test::More;
use Test::Exception;
use Test::Perl::Critic;
use List::Util qw/sum/;

sub sum_map {
    my $cb = shift;
    sum map { $cb->($_); } @_;
}

subtest 'basic' => sub {

    is sum_map(sub { $_[0] * 10 }, 1..10), 550;
};

subtest 'dies' => sub {

    dies_ok { sum_map { $_ * 10 }, 1..10; }

    # =>
    # Use of uninitialized value $_ in multiplication (*) at proto.pl line 23.
    # Odd number of elements in anonymous hash at proto.pl line 23.
    # Not a CODE reference at proto.pl line 10.
};

subtest 'critic' => sub {
    critic_ok($0);
};

done_testing;

次にprototypeを指定してみます

use warnings;
use utf8;
use Test::More;
use Test::Exception;
use Test::Perl::Critic;
use List::Util qw/sum/;

sub sum_map (&@) {
    my $cb = shift;
    sum map { $cb->($_) } @_;
}

subtest 'basic' => sub {

    my $ret = sum_map { $_ * 10 } 1..10;
    is $ret, 550;
};

subtest 'other use case' => sub {

    my $ret = sum_map(sub { $_[0] * 10 }, 1..10);
    is $ret, 550;
};

subtest 'critic' => sub {
    critic_ok($0); ## failed!!

    # not ok 1 - Test::Perl::Critic for "proto2.pl"
    # Failed test 'Test::Perl::Critic for "proto2.pl"'
    #   at proto2.pl line 27.
    #
    # Perl::Critic found these violations in "proto2.pl":
    # Subroutine prototypes used at line 9, column 1.  See page 194 of PBP.  (Severity: 5)
};

done_testing;

critic のテストが通りませんでした
blockが coderef になっているのは、確かに副作用が強いです
その為、多用はしたくないです

以下のように ## no critic と注釈をつけてあげて、
副作用を許容してあげることができます

http://search.cpan.org/~thaljef/Perl-Critic-1.123/lib/Perl/Critic.pm#BENDING_THE_RULES

use strict;
use warnings;
use utf8;
use Test::More;
use Test::Exception;
use Test::Perl::Critic;
use List::Util qw/sum/;

sub sum_map (&@) { ## no critic
    my $cb = shift;
    sum map { $cb->($_) } @_;
}

subtest 'critic' => sub {
    critic_ok($0), '注釈をつけることで回避';
};

done_testing;

ハマる例2? UNIVERSAL

間接オブジェクトわざとらしく使ってみたいと思います canを使っているのがわざとらしいです!

use strict;
use warnings;
use utf8;
use feature qw/say/;

my $dog = bless {}, 'Dog';

if (can $dog 'bow') {
    say 'can bow';
}
else {
    say 'cannot bow';
} # => cannot bow
#perl -MO=Deparse %

use utf8;
use warnings;
use strict;
use feature 'say';
my $dog = bless({}, 'Dog');
if ($dog->can('bow')) {
    say 'can bow';
}
else {
    say 'cannot bow';
}
# original
if (can $dog 'bow')

# Deparse
if ($dog->can('bow')) {

$dogにcan methodは生やしていないですが、
Perlの場合、全てのクラスは暗黙的にUNIVERSAL を元にするようになっているので、
$dog->can で UNIVERSAL->can が呼び出しされます

試しに、UNIVERSALのcanが呼び出しされないように、
このパッケージに can というサブルーチンを生やしてみます

use strict;
use warnings;
use utf8;
use feature qw/say/;

my $dog = bless {}, 'Dog';

sub can { 1 }

if (can $dog 'bow') { # XXX => syntax error
    say 'can bow';
}
else {
    say 'cannot bow';
}

=pod

syntax error at can2.pl line 10, near "$dog 'bow'"
can2.pl had compilation errors.
use utf8;
use warnings;
use strict;
use feature 'say';
my $dog = bless({}, 'Dog');
sub can {
    use warnings;
    use strict;
    use feature 'say';
    1;
}

$dog と 'bow' の間にカンマがなくて、エラーになりました
もちろんカンマを入れれば、次のように、'can bow'と表示されます

このカンマのあるなしの意思表示で、間接記法であるかどうか示します
それは意思表示としては、わかりずらいので、誤読の元になりやすいです

use strict;
use warnings;
use utf8;
use feature qw/say/;

my $dog = bless {}, 'Dog';

sub can { 1 }

if (can $dog, 'bow') { # リストにするため、カンマを入れた
    say 'can bow';
}
else {
    say 'cannot bow';
} # => can bow

このように暗黙に定義されたメソッドで、間接オブジェクト記法が出てくるなんて、
あまりないと思いますが、良い機会なので、
UNIVERSALに生えているメソッドを洗ってみます

Class::Inspector を使うと、can, isa, VERSION, DOES ということが分かります
http://perldoc.perl.org/UNIVERSAL.html の通りです
これで、もう多分、if (isa $foo 'FOO') とやってハマること?もないでしょう?

use strict;
use warnings;
use utf8;

package Dog;

sub new { bless {}, shift };

package main;

use Test::More;

my $dog = Dog->new;

subtest 'isa' => sub {
    isa_ok $dog, 'Dog';
    isa_ok $dog, 'UNIVERSAL';
};

subtest 'methods' => sub {

    ok $dog->can('can');
    ok $dog->can('isa');
    ok $dog->can('VERSION');
    ok $dog->can('DOES');
};

subtest 'methods count' => sub {

    require Class::Inspector;
    is scalar @{Class::Inspector->methods('UNIVERSAL')}, 4;

    is_deeply(Class::Inspector->methods('Dog'), [qw/new/]);
};

done_testing;

ハマる例3 テストにて

生々しいですが、例2のClass::Inspector を使っていて、今、ミスった例です。

use strict;
use warnings;
use utf8;

package Dog;

sub new { bless {}, shift };

package main;
use Test::More;
use Class::Inspector;

is_deeply Class::Inspector->methods('Dog'), [qw/new/];
# XXX failed!!
# => Can't locate object method "is_deeply" via package "Class::Inspector" at can5.pl line 12

=pod
use utf8;
package Dog;
sub new {
    use warnings;
    use strict;
    bless {}, shift();
}
package main;
sub BEGIN {
    use warnings;
    use strict;
    require Test::More;
    do {
        'Test::More'->import
    };
}
use Class::Inspector;
use warnings;
use strict;
'Class::Inspector'->is_deeply->methods('Dog'), ['new'];

これは、要点だけを絞り出すと次のようになっています

package Foo;
sub new { bless {}, shift() }

use strict;
use warnings;
use utf8;

use Test::More;

isa_ok Foo->new, 'Foo';

done_testing;
# Deparse

package Foo;
sub new {
    bless {}, shift();
}
use utf8;
use Test::More;
use warnings;
use strict;
'Foo'->isa_ok->new, '???';
done_testing();
/Users/kfly8/aa.pl syntax OK

実際にはまった例では、

is_deeply Class::Inspector->methods('Dog'), [qw/new/];

が、次のように評価されてしまい、残念なことになりました

'Class::Inspector'->is_deeply->methods('Dog'), ['new'];

括弧付きで呼び出してあげてください

is_deeply(Class::Inspector->methods('Dog'), ['new']);

まとめ

  • Perl には、method を呼び出す方法に、method $obj LIST のような呼び出し方もあり、それを間接オブジェクト記法という
  • 使いどころを(すごい)選べば、import constant FOO => 'foo' のような簡潔な表現になる
  • よくあるハマり方
    • 関数のexport漏れ
      • 余談 prototype
    • 暗黙なmethod定義
    • func Class->foo の Class->func->foo という誤読しやすい評価順

補足 この記事のコードは、gistでも見れますー。

Perl Advent Calender 2014 . 17th

明日

18日目は、wanji さんです!

#Perl入学式 のお手伝いさせてもらってきた

Perl入学式 に参加するのは初めてだったのですが、 サポーターとして参加させてもらいました。 お疲れ様でした!特に講師のid:xtetsuji さんお疲れ様でした!!

「サブルーチンと正規表現」がお題でした。 資料はコチラ

寿司はコチラ。

美味かった。

面白かった(?)罠がコチラ

use strict;
use warnings;
use utf8;

sub dump_hash {
    my $hash = @_;
    $hash->{foo};
}

dump_hash({foo => 1, bar => 2});
# => Can't use string ("1") as a HASH ref while "strict refs" in use at foo.pl line 7.

生徒:「1って何?!?!」
おれ:「配列をスカラーで評価して、配列長..ですね...」
生徒:「??????」
おれ:「ですよね!!!!!!!!」

幸い?他のプログラミング言語を触っている人だったからか、 「Perlだと、どう値を使いたいか意思表示できて、 例えば、配列が欲しいのか、スカラが欲しいのかなど。 逆に言うと意思表示に慣れるまで、ハマります!!」 でコンテキストのことを濁し、次のような引数の取り方の例を見てもらったら納得してもらえたよう。

sub dump_hash2 {
    my $h   = @_; # bad...
    my ($h) = @_; # ok (補足: 括弧が、優先順位の括弧に見えてしまったよう。 my ($a,$b) = @_ の例も併わせて紹介して、リストの括弧と分かってもらえた。
    my ($h,)= @_; # ok (さらに補足: 人によっては配列をより意識する為にこう書く人もいる
    my $h   = shift; # ok
    my $h   = $_[0]; # ok
}

蛇足にこんな例も話したら、楽しんでもらえたよう(多分)

my @a  = ('a', 'b', 'c', 'd');
#my @a = qw/ a b c d /; # これで上と同じ意味

my %hash  = ( a => 1, b => 2 );
#my %hash = ( 'a', 1, 'b', 2 );  # これで上と同じ意味
#my %hash = qw/ a 1 b 2 /;  # これも同じ意味
my @b     = ( 'a', 1, 'b', 2 );  # さらに配列として受け止めることもできる

慣れるのは苦労するかもしれないけど、、、
例えば、「対になっているデータが欲しいから、ハッシュにしよう!」
とか思った時に、特にこねくり回したことしなくて良いのが、個人的に楽だと思っている。

完全なる蛇足

楽しみついでに、サブルーチンの定義に関して、 「!」「数字」や「日本語」をサブルーチン名に使ったりする応用例?を書いた。

この辺、YAPC::Asia 2014 のid:karupanerurameta programmingの話 が詳しい。(demoが多いので、動画がおすすめ)

そんなこんなで、Perl入学式楽しませてもらいました!! ありがとうございました! またの機会もよろしくお願いします!

#chibapm 5で好き放題ランダウ記号の話をしてきた

数学の話を息抜きにしてきた。 グラフが、写真なあたりまさに息抜き←手抜き

インデックス構造によって計算オーダーが変わったりするので、 云々かんぬんで久しぶりに数学に触れられて、楽しかった。

chibapmの懐の深さに感謝!