[perldocjp-cvs 1028] CVS update: utils/web/module_list

Back to archive index

ktats****@users***** ktats****@users*****
2011年 1月 28日 (金) 22:54:36 JST


Index: utils/web/module_list/create_module_list_html.pl
diff -u /dev/null utils/web/module_list/create_module_list_html.pl:1.1
--- /dev/null	Fri Jan 28 22:54:36 2011
+++ utils/web/module_list/create_module_list_html.pl	Fri Jan 28 22:54:36 2011
@@ -0,0 +1,525 @@
+#!/usr/bin/perl
+
+use strict;
+use Time::Piece;
+use HTML::Template;
+use List::MoreUtils qw/uniq/;
+
+use constant HTDOCS_DIR => '/home/ktat/cvs/perldocjp/web/htdocs/';
+use constant CPAN_HOME  => '/home/ktat/.cpan/';
+
+main();
+
+sub main{
+  # my $check = new Perldocjp ('/home/ktat/cvs/perldocjp');
+  my $check = Perldocjp->new;
+  $check->cpan_home(CPAN_HOME);
+#  $check->cpan_reload;
+  $check->check();
+  create_file($check);
+}
+
+sub create_file {
+  my $check = shift;
+  my $update = $check->all_module;
+
+  my $menu = [ map{ { alpha => lc $_, alpha_uc => uc $_ } } sort {$a cmp $b} uniq map { lc substr $_, 0, 1 } keys %$update ];
+  my (%module_per_initial, %tmp);
+  foreach my $module (sort {($tmp{$a} ||= lc $a) cmp ($tmp{$b} ||= lc $b)} keys %$update) {
+    my $initial = lc substr $module, 0, 1;
+    my $module_name_cpan = $module;
+    $module_name_cpan =~ s{::}{-}g;
+    $module_per_initial{$initial} ||= [];
+    push @{$module_per_initial{$initial}},
+      {
+       module         => $module,
+       color          => (@{$module_per_initial{$initial}} % 2 ? '' : 'bgcolor="#eeeeee"'),
+       cpan_link      => 'http://search.cpan.org/dist/' . $module_name_cpan,
+       module2        => $update->{$module}->[0],
+       status         => $update->{$module}->[1],
+       perldocjp_link => 'http://perldoc.jp/docs/modules/' . $module_name_cpan . '-' . $update->{$module}->[0] . '/',
+      };
+  }
+
+  my $text = template();
+  my $rh = { alpha_menu  => $menu, update_time => Time::Piece->new->strftime("%Y/%m/%d %H:%M:%S") };
+  foreach my $initial (keys %module_per_initial) {
+    $rh->{module_list} = $module_per_initial{$initial};
+    my $tmpl = HTML::Template->new(scalarref => \$text);
+    $tmpl->param($rh);
+    open my $fh,">", HTDOCS_DIR . 'module_list_' . $initial . '.htm' or die $!;
+    print $fh $tmpl->output;
+    close $fh;
+  }
+}
+
+sub template {
+  return <<'_TEMPLATE_';
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<HTML>
+<HEAD>
+<link rel="stylesheet" href="style.css">
+<TITLE>最新のバージョンとの対応 - Japanaized Perl Resources Project</TITLE>
+</HEAD>
+<BODY>
+<div class="menu">
+<ul>
+<li><a href="/">Home</a></li>
+<li><a HREF="joinus">参加するには?</a>(<a HREF="joinus#ml">メーリングリスト</a>)</li>
+
+<li><a HREF="translation">翻訳の入手</a></li>
+<li><a HREF="event">イベント</a></li>
+<li><a HREF="perldocjp-faq">FAQ</a></li>
+<li><a HREF="link">リンク</a></li>
+<li class="sourceforge"><a HREF="http://sourceforge.jp/projects/perldocjp/">sourceforge site</a></li>
+</ul>
+</div>
+<H1>最新のバージョンとの対応</H1>
+<div><TMPL_VAR UPDATE_TIME>更新</div>
+<p>
+下記の内容は正確でない可能性があります。また、Perlのコアドキュメントとして登録されているモジュールは、チェックしていません。<br>
+翻訳バージョンのリンクは、perldoc.jp のドキュメントへのリンクです。<br>
+最新バージョンのリンクは、cpan.org のドキュメントへのリンクです。<br>
+</p>
+<DL><DT>
+<TMPL_LOOP NAME="alpha_menu">
+<A HREF="module_list_<TMPL_VAR ALPHA>"><TMPL_VAR ALPHA_UC></A>
+</TMPL_LOOP>
+</DT>
+<DD><P>
+<TABLE border=1 cellspacing=0>
+<TR><TH>モジュール名</TH><TH>翻訳バージョン</TH><TH>最新バージョン</TH><TR>
+<TMPL_LOOP name="module_list">
+<TR>
+<TD <TMPL_VAR color>><tmpl_var module></TD>
+<TD <tmpl_var color> align=right><a href="<TMPL_VAR perldocjp_link>"><tmpl_var module2></a></TD>
+<TD <tmpl_var color> align=right><a href="<TMPL_VAR cpan_link>"><tmpl_var status></a></TD><TR>
+</TMPL_LOOP>
+</TABLE>
+</P>
+</DD>
+</DL>
+
+<div class="footer">
+<address>
+<a href="http://sourceforge.jp/projects/perldocjp/">Japanize Perl Resources Project</a></address>
+
+</div>
+</BODY>
+<HTML>
+_TEMPLATE_
+}
+
+BEGIN {
+package Perldocjp;
+
+use strict;
+use Carp;
+use version;
+use CPAN;
+use CPAN::Config;
+use Storable;
+use LWP::Simple ();
+
+$Perldocjp::VERSION = '0.6';
+
+my $Cpan = new CPAN;
+
+=pod
+
+=head1 Name
+
+ Perldocjp
+
+=head1 Description
+
+翻訳されたドキュメントが最新かどうかチェックするもの
+違う名前のがよさそう。
+
+=head1 Requirement
+
+ version
+ CPAN
+ LWP::Simple
+
+=head1 Example
+
+ #!/usr/binn/perl -w
+
+ use strict;
+ use Perldocjp;
+
+ # ディレクトリを指定しなければ、http://perldoc.jp/docs/modules をパースします。
+ my $check = new Perldocjp ('/home/ktat/cvs/perldocjp');
+
+ # .cpan が、/root 下にあって、読めない場合
+ $check->cpan_home($ENV{HOME}.'my_cpan_dir');
+
+ # Metadata を最新にしたければ
+ $check->cpan_reload;
+
+ # チェックするものをしぼる場合
+ $check->check_list('Date::Simple','Data::FormValidator','Test::Simple','Audio::Beep','VCS::Lite');
+
+ $update = $check->updated_module;
+
+ foreach my $module(sort {$a cmp $b} keys %$update){
+   printf "%-25s %10s   ->%10s\n", $module,@{$update->{$module}};
+ }
+
+=head1 Constructor
+
+=over 4
+
+=item new
+
+ my $obj = new Perldocjp($perldocjp_dir);
+
+$perldoc_dir は、perldocjp の cvs のディレクトリ。
+たとえば、"/home/hoo/cvs/perldocjp" みたいな。
+
+ディレクトリを指定しない場合、
+http://perldoc.jp/docs/modules/ を解析します。
+
+=back
+
+=cut
+
+sub new{
+  my $class = shift;
+  my $cvs_dir = shift;
+  my $cvs_module_dir = $cvs_dir ? $cvs_dir . "/docs/modules" : undef;
+  my $self =
+    {
+     cvs_dir => $cvs_dir,
+     cvs_module_dir => $cvs_module_dir,
+     cvs_module => ($cvs_module_dir ? _read_cvs_dir($cvs_module_dir) : _read_perldocjp()),
+     cpan_module => $Cpan,
+     check_list => {},
+     update => {},
+    };
+  bless $self => $class;
+}
+
+=pod
+
+=head1 Methods
+
+=over 4
+
+=item cvs_dir
+
+ $dir = $obj->cvs_dir;
+
+perldocjp の cvs のディレクトリを返します。
+
+=cut
+
+sub cvs_dir{
+  return $_[0]->{cvs_dir};
+}
+
+sub _cpan_metadata{
+  return retrieve($CPAN::Config->{cpan_home} . '/Metadata');
+}
+
+=pod
+
+=item check_list
+
+ $obj->check_list('Date::Simple','Audio::Beep');
+ @list = $obj->check_list;
+
+チェックするモジュールを配列で渡します。
+返り値は、渡されたモジュールの名前。
+なお、'-' が、名前に含まれる場合は、'::' に変換されます。
+
+指定しない場合は、cvs にある全てのモジュールについて、チェックします。
+
+=cut
+
+sub check_list{
+  my $self = shift;
+  my @list = @_;
+  foreach (@list){
+    s/-/::/g;
+  }
+  @{$self->{check_list}}{@list} = ();
+  return keys %{$self->{check_list}};
+}
+
+=pod
+
+=item remove_check_list
+
+ $obj->remove_check_list('Date::Simple','Audio::Beep');
+
+check_list で指定したものを削除します。
+
+=cut
+
+sub remove_check_list{
+  my $self = shift;
+  delete @{$self->{check_list}}{@_};
+  return keys %{$self->{check_list}};
+}
+
+=pod
+
+=item cpan_reload
+
+ CPAN モジュールが使っている Metadata を最新版にします。
+
+=cut
+
+sub cpan_reload{
+  my $self = shift;
+  CPAN::Index->reload;
+  $self->cpan_module(_cpan_metadata());
+}
+
+sub _read_cvs_dir{
+  my $self = shift if ref $_[0];
+  my $dir = shift;
+  opendir(IN,$dir) or die("Can't read $dir");
+  my @modules = grep !/^\.\.?$/,readdir(IN);
+  closedir IN;
+  my $mod = {};
+  foreach my $dir (@modules){
+    my $regex = __parse_regex();
+    if(my($module, $version) = ($dir =~/^$regex$/)){
+      $module =~s/-/::/g;
+      unless($mod->{$module}){
+        $mod->{$module} = $version;
+      }elsif(new version ($mod->{$module}) lt new version ($version)){
+        $mod->{$module} = $version;
+      }
+    }
+  }
+  return $mod;
+}
+
+sub _read_perldocjp{
+  my $urls = perldocjp_url();
+  my %module;
+  foreach my $url (ref $urls ? @{$urls} : $urls){
+    my $contents = LWP::Simple::get($url);
+    $contents =~s/^.*Parent Directory//s;
+    $contents =~s/^<\/A>.*$//m;
+    $contents =~s|</PRE>.*$||is;
+    my $regex = __parse_regex();
+    my %mod = ($contents =~m|/">$regex/</A>|img);
+    @module{keys %mod} = @mod{keys %mod};
+  }
+  return {map { my $key = $_; s/-/::/g;
+                my $module_name = $_;
+                ($_ => $module{$key});
+              } keys %module};
+}
+
+sub __parse_regex{
+  return '([\w-]+)-(\d[\d.]+)';
+}
+
+=pod
+
+=item perldocjp_url
+
+ $obj->perldocjp_url
+
+perldoc.jp の モジュール置いてるとこのURLを返す。
+
+http://perldoc.jp/docs/modules/
+
+=cut
+
+sub perldocjp_url{
+  return 'http://perldoc.jp/docs/modules/';
+}
+
+=pod
+
+=item check
+
+ $obj->check;
+
+ チェックします。
+
+=cut
+
+sub check{
+  my $self = shift;
+  my $opt  = shift || '';
+  my $cvs_module = $self->cvs_module;
+  $self->cpan_module(_cpan_metadata()) unless %{$self->{cpan_module}};
+  if($self->check_list){
+    %$cvs_module = map{$_ => $self->cvs_version($_) }$self->check_list;
+  }
+  if($opt eq 'all'){
+    %$cvs_module = map{$_ => $self->cvs_version($_) || 'unknown' } keys %{$self->cpan_module};
+  }
+  while(my($module, $cvs_version) = (each %$cvs_module)){
+    my $cpan_version = $self->cpan_version($module);
+    unless($cvs_version){
+      $self->{update}->{$module} = ["none" => $cpan_version];
+      $self->{all}->{$module} = ["none" => $cpan_version];
+    }else{
+      if(new version ($cvs_version) lt new version ($cpan_version)){
+        $self->{update}->{$module} = [$cvs_version => $cpan_version];
+        $self->{all}->{$module} = [$cvs_version => $cpan_version];
+      }elsif(new version ($cvs_version) gt new version ($cpan_version)){
+        $self->{all}->{$module} = [$cvs_version => $cpan_version];
+      }else{
+        $self->{all}->{$module} = [$cvs_version => 'latest'];
+      }
+    }
+  }
+  return $self->{update};
+}
+
+=pod
+
+=item updated_module
+
+ $hash_ref = $obj->updated_module;
+
+ハッシュリファレンスを返します。
+キーはモジュール名で、値は配列リファレンスです。
+配列リファレンスの、最初の要素は翻訳されたモジュールのバージョンで、
+2番目の要素は、Metadata の中のバージョンです。
+
+check を行っていない場合、自動的に check が呼ばれます。
+
+=cut
+
+sub updated_module{
+  my $self = shift;
+  return $self->check unless %{$self->{update}};
+  return $self->{update};
+}
+
+=pod
+
+=item all_module
+
+ハッシュリファレンスを返します。
+update_module と大体同じですが、更新されていないものも返します。
+
+check を行っていない場合、自動的に check が呼ばれます。
+
+=cut
+
+sub all_module{
+  my $self = shift;
+  return $self->check unless %{$self->{update}};
+  return $self->{all};
+}
+
+sub cvs_module{
+  my $self = shift;
+  $self->{cvs_module} = shift  if @_;
+  return $self->{cvs_module};
+}
+
+sub cvs_version{
+  my $self = shift;
+  my $module = shift or Carp::croak("module name is needed.");
+  return $self->cvs_module->{$module};
+}
+
+sub cpan_module{
+  my $self = shift;
+  $self->{cpan_module} = shift  if @_;
+  return $self->{cpan_module}->{'CPAN::Module'};
+}
+
+sub cpan_bundle{
+  my $self = shift;
+  return $self->{cpan_module}->{'CPAN::Bundle'};
+}
+
+sub list_cpan_module{
+  my $self = shift;
+  $self->capn_module(_cpan_metadata()) unless %{$self->cpan_module};
+  return keys %{$self->{cpan_module}->{'CPAN::Module'}};
+}
+
+
+my %FIX_MAP = (
+               'libapreq'        => 'Apache::libapreq',
+               # 'Text::CVS_XS'    => 'Text::CSV_XS',
+               'libwww::perl'    => 'LWP',
+               'Net::TrackBack'  => 'Net::Trackback::Client',
+               'MIDI::Perl'      => 'MIDI',
+               'HTTPD::WatchLog' => undef,
+              );
+
+sub cpan_version{
+  my $self = shift;
+  my $module = shift or Carp::croak("module name is needed.");
+  $module = $FIX_MAP{$module} if $FIX_MAP{$module};
+  unless ($self->cpan_module->{$module}) {
+    # maybe Bundle;
+    my $bundle = $self->cpan_bundle;
+    unless($bundle->{"Bundle::$module"}){
+      warn("I don't know about $module");
+    }else{
+      return __retrieve_version($bundle->{"Bundle::$module"})
+    }
+  }else{
+    return __retrieve_version($self->cpan_module->{$module})
+  }
+  return '';
+}
+
+sub __retrieve_version {
+  my $mod_data = shift;
+  if ($mod_data->{CPAN_VERSION}) {
+    return $mod_data->{CPAN_VERSION};
+  } else {
+    if ($mod_data->{CPAN_FILE} =~ m{-([\d\.]+)\.tar\.(gz|bz2)}) {
+      return $1;
+    }
+  }
+}
+
+=pod
+
+=item $obj->cpan_dir($dir);
+
+$CPAN::Config->{cpan_home}の値を変更します。
+第一引数は、ディレクトリ。省略すると、$ENV{HOME}.'/.cpan' になる。
+明示的に呼ばなければ、$CPAN::Config->{cpan_home}は、変更されません。
+
+$CPAN::Config->{cpan_home}が、root のホームディレクトリだと
+一般ユーザが使えないので、自分用のディレクトリを指定するためにあります。
+
+=cut
+
+sub cpan_home{
+  my $self = shift;
+  my $cpan_dir = shift || $ENV{HOME}.'/.cpan';
+  $CPAN::Config->{cpan_home} = $cpan_dir;
+  $CPAN::Config->{build_dir} = $cpan_dir.'/build';
+  $CPAN::Config->{keep_source_where} = $cpan_dir.'/source';
+}
+
+=pod
+
+=back
+
+=head1 Author
+
+ Kato Atushi <atusi****@pure*****>.
+
+=head1 Copyright
+
+ Copyright 2003 by Kato Atushi <atusi****@pure*****>.
+ This program is free software; you can redistribute it
+ and/or modify it under the same terms as Perl itself.
+
+ See http://www.perl.com/perl/misc/Artistic.html
+
+=cut
+
+}



perldocjp-cvs メーリングリストの案内
Back to archive index