Skip to content

Instantly share code, notes, and snippets.

@kfly8
Last active October 3, 2025 23:55
Show Gist options
  • Select an option

  • Save kfly8/4bdb11d0cdf3f8785f350ef3ca297827 to your computer and use it in GitHub Desktop.

Select an option

Save kfly8/4bdb11d0cdf3f8785f350ef3ca297827 to your computer and use it in GitHub Desktop.
Perl Today
use v5.42;
use Test2::V0;
use experimental qw(builtin);
use builtin qw(is_bool);
subtest 'スカラーの場合' => sub {
subtest '比較演算などの結果は boolean' => sub {
my @case = (
1==1, true, '1==1 is true',
1<2, true, '1<2 is true',
2<1, false, '2<1 is false',
!1, false, '!1 is false',
);
for my ($v, $expected, $message) (@case) {
is $v, $expected, $message;
ok is_bool($v), 'and is boolean';
}
};
subtest 'falsyなスカラー' => sub {
my @case = (
# 1. 未定義値
undef, 'undef is falsy',
# 2. 数値の0および0と評価される数値表現
0, '0 is falsy',
0.0, '0.0 is falsy',
0e0, '0e0 is falsy',
# 3. 文字列の空文字列""および"0"
"", '""(空文字) is falsy',
"0", '"0" is falsy',
);
for my ($v, $message) (@case) {
my $got = $v ? 'true' : 'false';
my $expected = 'false';
is $got, $expected, $message;
ok !is_bool($v), 'but not boolean';
}
};
subtest 'falsyなスカラー以外は truthy' => sub {
my @case = (
1, '1 is truthy',
123, '123 is truthy',
'foo', 'foo is truthy',
# falsy に見えるけれど、 truthy なもの
" ", '" "(空白文字) is truthy',
"00", '"00"(文字列) is truthy',
"0.0", '"0.0"(文字列) is truthy',
"0e0", '"0e0"(文字列) is truthy',
\0, '\0 is truthy',
{}, '{} is truthy',
[], '[] is truthy',
);
for my ($v, $message) (@case) {
my $got = $v ? 'true' : 'false';
my $expected = 'true';
is $got, $expected, $message;
ok !is_bool($v), 'but not boolean';
}
};
};
subtest 'リストの場合' => sub {
subtest '要素のある配列は、truthy' => sub {
my @array = (1, 2, 3);
my $got = @array ? true : false;
is $got, true, 'non-empty array is truthy';
# この配列の配列長が3なので、 truthy になる。
is scalar @array, 3;
};
subtest '空配列は、falsy' => sub {
my @array = ();
my $got = @array ? true : false;
is $got, false, 'empty array is falsy';
# EXPR ? true : false の EXPR は、スカラーコンテキストの真偽評価される。
# 配列を、スカラーコンテキストで評価すると、配列長が得られる。
# 空配列の配列長は0なので、falsy になる。
is scalar @array, 0;
};
subtest 'falsyな要素を含む配列は、truthy' => sub {
my @array = (undef);
my $got = @array ? true : false;
is $got, true, 'array with falsy elements is truthy';
# この配列の配列長が1なので、 truthy になる。
is scalar @array, 1;
};
subtest '要素のあるハッシュは、truthy' => sub {
my %hash = (a => 1, b => 2);
my $got = %hash ? true : false;
is $got, true, 'non-empty hash is truthy';
# このハッシュのキーの数が2なので、 truthy になる。
is scalar %hash, 2;
};
subtest '空ハッシュは、falsy' => sub {
my %hash = ();
my $got = %hash ? true : false;
is $got, false, 'empty hash is falsy';
# ハッシュをスカラーコンテキストで評価すると、ハッシュのキーの数が得られる。
# (この挙動は、Perl5.25 以降 Ref: https://perldoc.perl.org/perldata#Scalar-values )
# 空のハッシュのキーの数は0なので、falsy になる。
is scalar %hash, 0;
};
subtest 'リストに要素がある場合' => sub {
my $got1 = (1, 2) ? true : false;
is $got1, true, 'last element is truthy, so the list is truthy';
my $got2 = (1, undef) ? true : false;
is $got2, false, 'last element is falsy, so the list is falsy';
# リストをスカラーコンテキストで評価する時、カンマはカンマ演算子。
# カンマ演算子は、`EXPR1, EXPR2` の時、EXPR1 を評価し、その結果を捨てて、次に EXPR2 を評価し、その結果を返す。これは、C言語のカンマ演算子と同じ
# 結果的に、リストの最後の要素が得られる。
my $i = 0;
my $got = ($i++, $i++, $i++, $i);
is $got, 3, 'the last element is returned';
# 補足: リストをリストコンテキストで評価する時、カンマはただの区切り文字
# 例: `@array = (1,2)`、`@hash = (a=>1, b=>2)`、`for my $i (1,2,3) { ... }` など
};
subtest '空リストは、falsy' => sub {
my $got = () ? true : false;
is $got, false, 'empty list is falsy';
# リストに最後の要素がないので、undefが得られる
my $x = ();
is $x, undef;
};
};
done_testing;
use v5.42;
use Test2::V0;
package Sample {
our $foo = "Hello";
our @foo = (1,2,3);
our %foo = ( a => 1, b => 2 );
sub foo { return "bar" };
}
subtest 'シンボルテーブルへのアクセス' => sub {
# グロブリファレンスの利用例の一つが、シンボルテーブルへのアクセスです。
# Sampleパッケージのfooシンボルをすべて取得
# すべて取得するので、* ワイルドカードが記号として使われている
my $glob = *Sample::foo;
# グロブのリファレンスを取得
my $globref = \$glob;
is reftype $globref, 'GLOB';
# Sample パッケージのfooシンボルの各スロットを確認
is *$globref{SCALAR}, \"Hello", 'SCALAR slot for globref';
is *$globref{ARRAY}, [1,2,3], 'ARRAY slot for globref';
is *$globref{HASH}, { a => 1, b => 2 }, 'HASH slot for globref';
is *$globref{CODE}->(), "bar", 'CODE slot for globref';
# シンボルテーブルにアクセスする典型的なコードは、一時的にシンボルの挙動を変更し、元に戻すようなコードです。
# 例えば、このコードは、Sampleのfoo関数を一時的に書き換えをしています。
# テストなどの場面で、よく使われるテクニックです。
{
local *Sample::foo = sub { "modified" };
is Sample::foo(), "modified", 'CODE slot modified';
is *$globref{CODE}->(), "modified", 'CODE slot from globref';
}
is Sample::foo(), "bar", 'CODE slot restored';
is *$globref{CODE}->(), "bar", 'CODE slot from globref restored';
};
subtest 'ファイルハンドル' => sub {
# グロブリファレンスが自然と現れるもう一つの場面は、ファイルハンドルです
# このファイル自身を開きます
my $filepath = __FILE__;
open my $fh, '<', $filepath or die $!;
# openで指定したファイルハンドル$fhは、グロブリファレンスです。
is reftype $fh, 'GLOB', 'filehandle is also a globref';
# 内部的にはこのグロブリファレンスのIOスロットにIO::Fileオブジェクトとして格納されます。
is *$fh{IO}, check_isa('IO::File'), 'IO slot for filehandle';
# ダイヤモンド演算子<>で行を読み込むことができます。
my $first_line = <$fh>;
is $first_line, "use v5.42;\n", 'first line of this file';
# IO::Handleのメソッドも利用できます
my $second_line = $fh->getline();
is $second_line, "use Test2::V0;\n", 'second line of this file';
};
done_testing;
use v5.42;
use Test2::V0;
package Sample {
our $foo = "Hello";
our @foo = (1,2,3);
our %foo = ( a => 1, b => 2 );
sub foo { return "bar" };
}
subtest 'シンボルテーブルへのアクセス' => sub {
# グロブリファレンスの利用例の一つが、シンボルテーブルへのアクセスです。
# Sampleパッケージのfooシンボルをすべて取得
# すべて取得するので、* ワイルドカードが記号として使われている
my $glob = *Sample::foo;
# グロブのリファレンスを取得
my $globref = \$glob;
is reftype $globref, 'GLOB';
# Sample パッケージのfooシンボルの各スロットを確認
is *$globref{SCALAR}, \"Hello", 'SCALAR slot for globref';
is *$globref{ARRAY}, [1,2,3], 'ARRAY slot for globref';
is *$globref{HASH}, { a => 1, b => 2 }, 'HASH slot for globref';
is *$globref{CODE}->(), "bar", 'CODE slot for globref';
# シンボルテーブルにアクセスする典型的なコードは、一時的にシンボルの挙動を変更し、元に戻すようなコードです。
# 例えば、このコードは、Sampleのfoo関数を一時的に書き換えをしています。
# テストなどの場面で、よく使われるテクニックです。
{
local *Sample::foo = sub { "modified" };
is Sample::foo(), "modified", 'CODE slot modified';
is *$globref{CODE}->(), "modified", 'CODE slot from globref';
}
is Sample::foo(), "bar", 'CODE slot restored';
is *$globref{CODE}->(), "bar", 'CODE slot from globref restored';
};
subtest 'ファイルハンドル' => sub {
# グロブリファレンスが自然と現れるもう一つの場面は、ファイルハンドルです
# このファイル自身を開きます
my $filepath = __FILE__;
open my $fh, '<', $filepath or die $!;
# openで指定したファイルハンドル$fhは、グロブリファレンスです。
is reftype $fh, 'GLOB', 'filehandle is also a globref';
# 内部的にはこのグロブリファレンスのIOスロットにIO::Fileオブジェクトとして格納されます。
is *$fh{IO}, check_isa('IO::File'), 'IO slot for filehandle';
# ダイヤモンド演算子<>で行を読み込むことができます。
my $first_line = <$fh>;
is $first_line, "use v5.42;\n", 'first line of this file';
# IO::Handleのメソッドも利用できます
my $second_line = $fh->getline();
is $second_line, "use Test2::V0;\n", 'second line of this file';
};
done_testing;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment