@nqounetです。
前回は、ハードコードされた設定値をConfigクラスで管理する方法を学びました。
今回は、設定値を外部ファイルから読み込む機能を追加します。
今回のゴール
外部の設定ファイル(INI形式)を読み込んで、設定値を取得できるようにすることです。
ミキさんからの追加要望
ミキさんからこんな相談がありました。
「設定値を変えるたびにスクリプトを書き換えるのは面倒だな。設定ファイルを用意して、そこから読み込めるようにできない?」
確かに、設定ファイルを分離すれば、コードを変更せずに設定を変えられます。やってみましょう。
設定ファイルの形式
シンプルなINI風の形式を使います。=の左側がキー、右側が値です。
1
2
3
| app_name = MyApp
version = 1.0.0
debug = 1
|
この形式なら、Perlの標準機能だけで簡単に読み込めます。
設定ファイルを読み込む処理
まずは、ファイルを読み込む処理を見てみましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| sub load_config ($self, $file) {
open my $fh, '<', $file or die "Cannot open $file: $!";
while (my $line = <$fh>) {
chomp $line;
next if $line =~ /^\s*$/; # 空行をスキップ
next if $line =~ /^\s*#/; # コメント行をスキップ
if ($line =~ /^\s*(\w+)\s*=\s*(.+?)\s*$/) {
my ($key, $value) = ($1, $2);
$self->set($key, $value);
}
}
close $fh;
}
|
ポイントを確認しましょう。
openでファイルを開く- 1行ずつ読み込んで、空行とコメント行(
#で始まる行)をスキップ - 正規表現で
key = valueの形式を解析 setメソッドで値を保存
設定値を動的に保存する
設定ファイルから読み込んだ値を保存するには、ハッシュを使います。
1
2
3
4
5
6
7
8
9
| has _settings => (is => 'ro', default => sub { {} });
sub set ($self, $key, $value) {
$self->_settings->{$key} = $value;
}
sub get ($self, $key) {
return $self->_settings->{$key};
}
|
_settingsというプライベートなハッシュに、キーと値のペアを保存します。
Configクラスの実装
それでは、ファイル読み込みに対応したConfigクラスを実装しましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| use v5.36;
use Moo;
package Config {
use Moo;
has _settings => (is => 'ro', default => sub { {} });
sub load_config ($self, $file) {
open my $fh, '<', $file or die "Cannot open $file: $!";
while (my $line = <$fh>) {
chomp $line;
next if $line =~ /^\s*$/; # 空行をスキップ
next if $line =~ /^\s*#/; # コメント行をスキップ
if ($line =~ /^\s*(\w+)\s*=\s*(.+?)\s*$/) {
my ($key, $value) = ($1, $2);
$self->set($key, $value);
}
}
close $fh;
}
sub set ($self, $key, $value) {
$self->_settings->{$key} = $value;
}
sub get ($self, $key) {
return $self->_settings->{$key};
}
};
package main;
my $config = Config->new();
$config->load_config('config.ini');
say "アプリ名: " . $config->get('app_name');
say "バージョン: " . $config->get('version');
say "デバッグモード: " . ($config->get('debug') ? 'ON' : 'OFF');
|
設定ファイルの用意
設定ファイルconfig.iniを用意します。
1
2
3
4
| # アプリケーション設定
app_name = MyApp
version = 1.0.0
debug = 1
|
実行してみよう
スクリプトを実行すると、設定ファイルから値が読み込まれます。
1
2
3
| アプリ名: MyApp
バージョン: 1.0.0
デバッグモード: ON
|
設定ファイルの値を変更してみましょう。
1
2
3
4
| # アプリケーション設定
app_name = AwesomeApp
version = 2.0.0
debug = 0
|
再度実行すると、変更が反映されます。
1
2
3
| アプリ名: AwesomeApp
バージョン: 2.0.0
デバッグモード: OFF
|
スクリプトを変更せずに、設定を切り替えられるようになりました!
第2回 完成コード
今回の完成コードは以下の通りです。
ファイル構成
1
2
3
| .
├── app.pl
└── config.ini
|
app.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| use v5.36;
use Moo;
package Config {
use Moo;
has _settings => (is => 'ro', default => sub { {} });
sub load_config ($self, $file) {
open my $fh, '<', $file or die "Cannot open $file: $!";
while (my $line = <$fh>) {
chomp $line;
next if $line =~ /^\s*$/; # 空行をスキップ
next if $line =~ /^\s*#/; # コメント行をスキップ
if ($line =~ /^\s*(\w+)\s*=\s*(.+?)\s*$/) {
my ($key, $value) = ($1, $2);
$self->set($key, $value);
}
}
close $fh;
}
sub set ($self, $key, $value) {
$self->_settings->{$key} = $value;
}
sub get ($self, $key) {
return $self->_settings->{$key};
}
};
package main;
my $config = Config->new();
$config->load_config('config.ini');
say "アプリ名: " . $config->get('app_name');
say "バージョン: " . $config->get('version');
say "デバッグモード: " . ($config->get('debug') ? 'ON' : 'OFF');
|
config.ini
1
2
3
4
| # アプリケーション設定
app_name = MyApp
version = 1.0.0
debug = 1
|
まとめ
- INI形式の設定ファイルを読み込む
load_configメソッドを実装した - 設定値を動的に保存・取得する
set/getメソッドを追加した - 設定ファイルを変更すれば、コードを変更せずに設定を切り替えられるようになった
次回予告
ミキさんのアプリが大きくなってきました。
「メインのスクリプト以外にも、別のモジュールから設定を使いたいんだけど…」
次回は、複数の場所から設定を使う方法を考えます。でも、ちょっとした問題が発生するかも…?