あなたの天然記念物
ホーム更新雑談Perl鉄ゲタランドナーコースガイド自転車Linuxリンク経歴連絡先

モジュール分割 (2016.04.28)

背景

以前からNiconico(ニコニコ動画)を操作するパッケージモジュールNiconico.pmを作っていました(CPANと無関係、非公開)。 このパッケージにはログインが必要な機能と不要な機能が同居しています。 ログイン不要な機能だけを使うプログラムでもパッケージの使い方として、わざわざログインして使っています。 プログラムによるログインが行われると、先にログインしていた自分がはじき出されてログアウトされてしまう。 そこでログイン不要な機能を別モジュールにして使うようにすれば自分がログアウトされないことに気付きました(正直に言うと以前から気付いてたが面倒で後回しにしてた)。
【重要】ログインが必要な機能を使う既存のプログラムに対しては互換(ソース変更なし)で継続使用したい。

概要

変更前 変更後 ラッパーが両者のオブジェクトを作成します。 同一LWPオブジェクトを使用する都合があるのでUser→Outsideへリファレンスをコピーして共用させます。 ラッパーのオブジェクトが呼ばれた際にメソッド名を取得してUserにあればUserのメソッドを呼びます。 なければOutsideのメソッドを呼びます。 これで既存プログラムの互換を確保できます。 メソッドが両者になければ、ない場合の診断メッセージをdieして終了します。 今後、ログイン不要な機能だけを使うプログラムは「use Niconico;」を「use Niconico::Outside;」に修正、ログイン/ログアウト処理も削除していきます。

ソース

と言ってもラッパーだけ。
package Niconico;

use utf8;
use strict;
use warnings;

use Niconico::User;
use Niconico::Outside;

our $AUTOLOAD;

sub new {
	my $class = shift;
	my $self = {};

	my %spec = @_;
	$self->{user} = Niconico::User->new(@_);
	$self->{outside} = Niconico::Outside->new(ua => $self->{user}->ua());

	bless($self, $class);

	return $self;
}

sub AUTOLOAD {
	my $self = shift;

	my ($class_name, $func_name) = $AUTOLOAD =~ /^(.+)::(.+)$/;
	my $user_ref = $self->{user}->can($func_name);
	my $outside_ref = $self->{outside}->can($func_name);
	if (defined $user_ref) {
		return &$user_ref($self->{user}, @_);
	} elsif (defined $outside_ref) {
		return &$outside_ref($self->{outside}, @_);
	}

	die "Can't call method $func_name in empty package $class_name";
}

1;