Tociyuki::Diary RSSフィード

tociyuki によるPerl・Rubyのコード説明を中心に、日常雑記も混在 : B  F  twitter  GitHub  CPAN  本館
 

2012年02月09日

[]YukiWiki 2.1.3 のグローバル変数参照箇所リスト

hyuki さんの YukiWiki 2.1.3 CGI スクリプト解読のために、グローバル変数とグローバル定数をどの手続きが参照しているのかリストアップしてみました。

http://www.hyuki.com/yukiwiki/

グローバル変数

$plugin_context
    init_plugin             print_plugin_log

$plugin_manager
    init_plugin             make_link               print_editform
    print_plugin_log        text_to_html

%database
    close_db                do_adminedit            do_comment
    do_edit                 do_index                do_read
    do_search               do_write                get_subjectline
    init_InterWikiName      init_form               is_exist_page
    make_link               open_db                 send_mail_to_admin
    update_recent_changes   update_rssfile

%diffbase
    close_diff              do_diff                 do_write
    open_diff

%fixedpage
    do_FrontPage            is_editable

%form
    conflict                do_FrontPage            do_adminchangepassword
    do_adminedit            do_comment              do_diff
    do_edit                 do_read                 do_search
    do_write                embedded_to_html        frozen_reject
    init_form               keyword_reject          length_reject
    main                    print_editform          print_header
    update_recent_changes

%infobase
    close_db                do_write                get_info
    open_db                 set_info

%interwiki
    init_InterWikiName      make_link

%page_command
    init_form               make_link

%resource
    do_adminchangepassword  do_adminedit            do_create
    do_diff                 do_edit                 do_search
    do_write                embedded_to_html        frozen_reject
    init_resource           length_reject           make_link
    print_editform          print_header            print_passwordform
    print_searchform        text_to_html

グローバル定数

%command_do
    main

$AdminChangePassword
    do_adminchangepasswordform

$AdminSpecialPage
    do_adminchangepassword  valid_password

$CompletedSuccessfully
    do_adminchangepassword  do_write

$CreatePage
    do_create               print_header

$ErrorPage
    print_error

$FrontPage
    do_FrontPage            init_form               print_header

$IndexPage
    do_index                print_header

$InterWikiName
    init_InterWikiName

$RecentChanges
    do_search               print_header            update_recent_changes
    update_rssfile

$RssPage

$SearchPage
    do_search               do_searchform           print_header

$bracket_name
    inline                  is_bracket_name         unarmor_name

$charset
    print_header            update_rssfile

$cols
    print_editform

$dataname
    open_db

$diffname
    open_diff

$editchar
    make_link

$embed_comment
    do_comment              embedded_to_html

$embed_rcomment
    do_comment              embedded_to_html

$embedded_name
    make_link

$file_FrontPage
    do_FrontPage

$file_conflict
    conflict

$file_format
    print_editform

$file_resource
    init_resource

$file_rss
    do_rss                  update_recent_changes   update_rssfile

$file_touch
    update_recent_changes

$icontag
    print_footer

$info_AdminPassword
    do_adminchangepassword  valid_password

$info_ConflictChecker
    conflict                do_adminedit            do_edit
    do_write                embedded_to_html

$info_IsFrozen
    do_write                frozen_reject           is_frozen

$info_LastModified
    do_write

$infoname
    open_db

$inline_plugin
    inline                  make_link

$interwiki_definition
    inline                  make_link

$interwiki_name
    is_editable             make_link

$kanjicode
    code_convert            conflict                do_FrontPage
    init_form               init_resource           print_editform

$lang
    print_header

$max_message_length
    length_reject

$maxrecent
    update_recent_changes

$modifier_dbtype
    close_db                close_diff              open_db
    open_diff

$modifier_dir_data

$modifier_dir_plugin
    init_plugin

$modifier_mail
    print_header            send_mail_to_admin

$modifier_name
    print_footer

$modifier_rss_about
    do_rss                  print_header            update_rssfile

$modifier_rss_description
    update_rssfile

$modifier_rss_link
    update_rssfile

$modifier_rss_timezone
    update_rssfile

$modifier_rss_title
    update_rssfile

$modifier_sendmail
    send_mail_to_admin

$modifier_url
    print_footer

$modifier_url_data

$rows
    print_editform

$subject_delimiter
    get_subjectline

$url_cgi
    do_create               do_index                do_search
    embedded_to_html        make_link               print_editform
    print_header            print_passwordform      print_searchform

$url_stylesheet
    print_header

$use_FixedFrontPage

$use_autoimg
    make_link

$use_exists
    is_exist_page

$version
    print_footer

$wiki_name
    armor_name              init_form               inline
    interwiki_convert

2012年02月06日

[]WalWikiCSV テーブル行のフォーマット部を書き直し

YukiWiki 2.1.3 のソースの中に WalWiki からバックポートした CSV データをテーブルに組み立てる部分が組み込まれています。カラムの前後にスペースを置いておくと、左右詰め・中央詰めになり、イコールを2つ置いたカラムは直左のカラムを colspan するようにマークアップします。この部分、パズルのようで、私にはぱっと読んで動作を理解することができませんでした。

⇒ yukiwiki213.zip の $BASE/wiki.cgi より

        } elsif (/^\,(.*?)[\x0D\x0A]*$/) {
            &back_push('table', 1, \@saved, \@result, ' border="1"');
            #######
            # This part is taken from Mr. Ohzaki's Perl Memo and Makio Tsukamoto's WalWiki.
            # XXXXX
            my $tmp = "$1,";
            my @value = map {
                /^"(.*)"$/ ? scalar($_ = $1, s/""/"/g, $_) : $_
            } ($tmp =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g);
            my @align = map {
                (s/^\s+//) ? ((s/\s+$//) ? ' align="center"' : ' align="right"')
                : ''
            } @value;
            my @colspan = map {($_ eq '==') ? 0 : 1} @value;
            for (my $i = 0; $i < @value; $i++) {
                if ($colspan[$i]) {
                    while ($i + $colspan[$i] < @value and $value[$i + $colspan[$i]] eq '==') {
                        $colspan[$i]++;
                    }
                    $colspan[$i] = ($colspan[$i] > 1) ? sprintf(' colspan="%d"', $colspan[$i]) : '';
                    $value[$i] = sprintf('<td%s%s>%s</td>', $align[$i], $colspan[$i], &inline($value[$i]));
                } else {
                    $value[$i] = '';
                }
            }
            push(@result, join('', '<tr>', @value, '</tr>'));
            # XXXXX
            #######

そこで、数行長くなるのですけど、わかりやすさ優先で書き直してみました。

https://gist.github.com/1751969 (ユニット・テスト)

        } elsif (/^\,(.*?)[\x0D\x0A]*$/) {
            back_push('table', 1, \@saved, \@result, q{ border="1"});
            my $csv = "$1,";
            my @td;
            while ($csv =~ m{
                \G(?:"([^"]*(?:""[^"]*)*)"|([^,]*)), ((?:(?:"=="|==),)*)
            }gmosx) {
                my($data, $span_mark) = (defined $1 ? $1 : $2, $3);
                if ($1) {
                    $data =~ s/""/"/gmosx;
                }
                my $align = q{};
                if ($data =~ m/\A([ ]+)?(.*?)([ ]+)?\z/mosx) {
                    if ($1) {
                        $align = $3 ? q{ align="center"} : q{ align="right"};
                    }
                    $data = $2;
                }
                my $colspan = q{};
                if ($span_mark) {
                    my $n = 1 + ($span_mark =~ tr/,/,/);
                    $colspan = qq{ colspan="$n"};
                }
                push @td, sprintf '<td%s%s>', $align, $colspan;
                push @td, inline($data);
                push @td, '</td>';
            }
            push @result, (join q{}, '<tr>', @td, '</tr>');

1つだけ、オリジナルから仕様を変更しています。CSV の先頭カラムに colspan マークを置いても、colspan マークとはみなさずに、カラムのデータ扱いするようにしました。この辺の挙動は、ユニット・テストに記述してあります。

2012年02月04日

[]ユリウス日

和田先生のユリウス暦とグレゴリオ暦両方対応の「パラメトロン計算機: ユリウス日」計算コードを perl に意訳してみました。通常、ユリウス日は天文計算に使う目的が多く、倍精度浮動小数点演算で求めるものですが、和田先生のコードは整数演算で求めているのがポイントでしょう。オリジナルから変更した箇所は、うるう年かどうかの判定式をユリウス暦とグレゴリオ暦の両方一発で求めるようにしたぐらいです。グレゴリオ暦への切替日より後かどうかの判定には、Perl はリストの比較ができないので、日付をパックしてから文字列比較してみました。

my @YDAY = (
    [-31, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365],
    [-31, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366],
);

sub julian_date {
    my($y, $m, $d) = @_;
    use integer;
    my $leap = $y > 1600 && $y % 100 == 0 ? $y % 400 == 0
              : $y % 4 == 0;
    my $a = ($y + 4712) * 365;
    my $b = ($y + 4712 + 3) / 4;
    my $c = 0;
    if ($y > 1601) {
        my $j = $y - 1601;
        $c = $j / 400 - $j / 100;
    }
    my $e = (pack 'nnn', $y, $m, $d) ge (pack 'nnn', 1582, 10, 15) ? -10 : 0;
    my $f = $YDAY[$leap ? 1 : 0][$m];
    my $g = $d - 1;
    return $a + $b + $c + $e + $f + $g;
}

ついでに、自分が普段使っている天文計算用の倍精度浮動小数点演算を使う C 言語のコードは、グレゴリオ暦の時代だけを計算する方法です。ユリウス暦のずれを補正しないで良いので、短くなります。こっちも Perl に訳してみました。

sub julian_date {
    my($yyyy, $mm, $dd, $hh) = @_;
    my($y, $m) = $mm > 2 ? ($yyyy, $mm) : ($yyyy - 1, $mm + 12);
    my $c = (int $y / 400) - (int $y / 100);
    return (int 365.25 * $y) + (int 30.6001 * ($m + 1)) + $dd + $hh / 24 + 1720996.5 + $c;
}

これをどこで拾ったのか30年以上も前のことなので、はっきり覚えてないのですけど、確か古の FORTRAN数値計算ライブラリにあったもののような記憶があります。