| Pod-PerldocJp documentation | Contained in the Pod-PerldocJp distribution. |
Pod::PerldocJp - perldoc that also checks perldoc.jp
perldocjp -J perlfunc # show translation (if any) perldocjp perlfunc # show original version perldocjp perldocjp # 日本語で使い方を見る
This is a drop-in-replacement for perldoc for Japanese people. Usage is the same, except it can look for a translation at http://perldoc.jp with -J option.
to support -J option.
looks for a 5.10.0 translation at perldoc.jp if -J option is set.
looks also under Pod::PerldocJp namespace.
always try to use "text" formatter.
adds encoding info while writing a temp file to show.
decode while searching.
are translated.
And for Japanized Perl Resources Project:
Kudos to all the contributors thereof.
Kenichi Ishigaki, <ishigaki@cpan.org>
Copyright (C) 2009 by Kenichi Ishigaki.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| Pod-PerldocJp documentation | Contained in the Pod-PerldocJp distribution. |
package Pod::PerldocJp; use strict; use warnings; use base 'Pod::Perldoc'; use Encode; use Encode::Guess; use Term::Encoding; use LWP::UserAgent; use Path::Extended; use URI::Escape; use utf8; my $term_encoding = Term::Encoding::get_encoding() || 'utf-8'; our $VERSION = '0.14'; sub opt_J { shift->_elem('opt_J', @_) } sub _perldocjp_dir { my $self = shift; my @subs = ( sub { require File::HomeDir; dir(File::HomeDir->my_home, '.perldocjp'); }, sub { dir(File::Spec->tmpdir, '.perldocjp') }, sub { dir('.') }, ); foreach my $sub (@subs) { my $dir = eval { $sub->() } or next; $dir->logger(0); $dir->mkdir; return $dir if -d $dir && -w $dir; }; } sub grand_search_init { my ($self, $pages, @found) = @_; my $dir = $self->_perldocjp_dir() or return $self->SUPER::grand_search_init($pages, @found); my @encodings = split ' ', $ENV{PERLDOCJP_ENCODINGS} || 'euc-jp shiftjis utf8'; if ($self->opt_J or ($pages->[0] && $pages->[0] =~ /^https?:/)) { my $ua = LWP::UserAgent->new(agent => "Pod-PerldocJp/$VERSION"); $ua->env_proxy; my $api_url = $ENV{PERLDOCJP_SERVER} || 'http://perldoc.tcool.org/api/pod'; $api_url =~ s|/+$||; foreach my $page (@$pages) { $self->aside("Searching for $page\n"); my $url = ($page =~ /^https?:/) ? $page : "$api_url/$page"; my $file = $dir->file(uri_escape($page, '^A-Za-z0-9_') . '.pod'); unless ($file->size && $file->mtime > time - 60 * 60 * 24) { my $res = $ua->mirror($url => $file->absolute); if ($res->is_success && (my $pod = $file->slurp) !~ /^=encoding\s/m) { # You can't trust perldoc.jp's Content-Type too much. # (there're several utf-8 translations, though perldoc.jp # is (or was) supposed to use euc-jp) my $encoding; my $enc = guess_encoding($pod, @encodings); if (ref $enc) { $encoding = $enc->name; } elsif (my $ctype = $res->header('Content-Type')) { ($encoding) = $ctype =~ /charset\s*=\s*([\w-]+)/; } if ($encoding) { $pod = "=encoding $encoding\n\n$pod"; $file->save($pod); } } } push @found, $file->absolute if $file->size; } return @found if @found; } @found = $self->SUPER::grand_search_init($pages, @found); if ($self->opt_J) { foreach my $path (@found) { my $pod = file($path)->slurp; unless ($pod =~ /^=encoding\s/m) { my $encoding; my $enc = guess_encoding($pod, @encodings); if (ref $enc) { $encoding = $enc->name; next if $encoding eq 'ascii'; $pod = "=encoding $encoding\n\n$pod"; my $file = $dir->file(uri_escape($path, '^A-Za-z0-9_')); $file->save($pod); $path = $file->absolute if $file->size; } } } } @found; } { # shamelessly ripped from Pod::Perldoc 3.15 and tweaked sub opt_o_with { # "o" for output format my($self, $rest) = @_; return unless defined $rest and length $rest; if($rest =~ m/^(\w+)$/s) { $rest = $1; #untaint } else { warn "\"$rest\" isn't a valid output format. Skipping.\n"; return; } $self->aside("Noting \"$rest\" as desired output format...\n"); # Figure out what class(es) that could actually mean... my @classes; # TWEAKED: to include "Pod::PerldocJp::To" foreach my $prefix ("Pod::PerldocJp::To", "Pod::Perldoc::To", "Pod::Simple::", "Pod::") { # Messy but smart: foreach my $stem ( $rest, # Yes, try it first with the given capitalization "\L$rest", "\L\u$rest", "\U$rest" # And then try variations ) { push @classes, $prefix . $stem; #print "Considering $prefix$stem\n"; } # Tidier, but misses too much: #push @classes, $prefix . ucfirst(lc($rest)); } $self->opt_M_with( join ";", @classes ); return; } sub init_formatter_class_list { my $self = shift; $self->{'formatter_classes'} ||= []; # Remember, no switches have been read yet, when # we've started this routine. $self->opt_M_with('Pod::Perldoc::ToPod'); # the always-there fallthru $self->opt_o_with('text'); # TWEAKED: man requires external pod2man, thus hard to tweak # $self->opt_o_with('man') unless IS_MSWin32 || IS_Dos # || !($ENV{TERM} && ( # ($ENV{TERM} || '') !~ /dumb|emacs|none|unknown/i # )); return; } sub maybe_generate_dynamic_pod { my ($self, $found_things) = @_; my @dynamic_pod; $self->search_perlfunc($found_things, \@dynamic_pod) if $self->opt_f; $self->search_perlvar($found_things, \@dynamic_pod) if $self->opt_v; $self->search_perlfaqs($found_things, \@dynamic_pod) if $self->opt_q; if( ! $self->opt_f and ! $self->opt_q and ! $self->opt_v ) { Pod::Perldoc::DEBUG > 4 and print "That's a non-dynamic pod search.\n"; } elsif ( @dynamic_pod ) { $self->aside("Hm, I found some Pod from that search!\n"); my ($buffd, $buffer) = $self->new_tempfile('pod', 'dyn'); push @{ $self->{'temp_file_list'} }, $buffer; # I.e., it MIGHT be deleted at the end. my $in_list = $self->opt_f || $self->opt_v; # TWEAKED: to add =encoding utf-8 and encode_utf8 print $buffd "=encoding utf-8\n\n"; print $buffd "=over 8\n\n" if $in_list; print $buffd map {encode_utf8($_)} @dynamic_pod or die "Can't print $buffer: $!"; print $buffd "=back\n" if $in_list; close $buffd or die "Can't close $buffer: $!"; @$found_things = $buffer; # Yes, so found_things never has more than one thing in # it, by time we leave here $self->add_formatter_option('__filter_nroff' => 1); } else { @$found_things = (); $self->aside("I found no Pod from that search!\n"); } return; } sub search_perlfunc { my($self, $found_things, $pod) = @_; Pod::Perldoc::DEBUG > 2 and print "Search: @$found_things\n"; my $perlfunc = shift @$found_things; open(PFUNC, "<", $perlfunc) # "Funk is its own reward" or die("Can't open $perlfunc: $!"); # Functions like -r, -e, etc. are listed under `-X'. my $search_re = ($self->opt_f =~ /^-[rwxoRWXOeszfdlpSbctugkTBMAC]$/) ? '(?:I<)?-X' : quotemeta($self->opt_f) ; Pod::Perldoc::DEBUG > 2 and print "Going to perlfunc-scan for $search_re in $perlfunc\n"; my $re = 'Alphabetical Listing of Perl Functions'; if ( $self->opt_L ) { my $tr = $self->{'translators'}->[0]; $re = $tr->search_perlfunc_re if $tr->can('search_perlfunc_re'); } # Skip introduction local $_; # TWEAKED: to find encoding my $encoding = 'utf-8'; while (<PFUNC>) { if (/^=encoding\s+(\S+)/) { $encoding = $1; } last if /^=head2 $re/; } # Look for our function my $found = 0; my $inlist = 0; while (<PFUNC>) { # "The Mothership Connection is here!" if ( m/^=item\s+$search_re\b/ ) { $found = 1; } elsif (/^=item/) { last if $found > 1 and not $inlist; } next unless $found; if (/^=over/) { ++$inlist; } elsif (/^=back/) { --$inlist; } # TWEAKED: to decode push @$pod, decode($encoding, $_); ++$found if /^\w/; # found descriptive text } if (!@$pod) { die sprintf "No documentation for perl function `%s' found\n", $self->opt_f ; } close PFUNC or die "Can't open $perlfunc: $!"; return; } sub search_perlvar { my ($self, $found_things, $pod) = @_; my $opt = $self->opt_v; if ( $opt !~ /^ (?: [\@\%\$]\S+ | [A-Z]\w* ) $/x ) { die "'$opt' does not look like a Perl variable\n"; } Pod::Perldoc::DEBUG > 2 and print "Search: @$found_things\n"; my $perlvar = shift @$found_things; open(PVAR, "<", $perlvar) # "Funk is its own reward" or die("Can't open $perlvar: $!"); if ( $opt =~ /^\$\d+$/ ) { # handle $1, $2, ..., $9 $opt = '$<I<digits>>'; } my $search_re = quotemeta($opt); Pod::Perldoc::DEBUG > 2 and print "Going to perlvar-scan for $search_re in $perlvar\n"; # Skip introduction local $_; # TWEAKED: to find encoding my $encoding = 'utf-8'; while (<PVAR>) { if (/^=encoding\s+(\S+)/) { $encoding = $1; } last if /^=over 8/; } # Look for our variable my $found = 0; my $inheader = 1; my $inlist = 0; while (<PVAR>) { # "The Mothership Connection is here!" last if /^=head2 Error Indicators/; # \b at the end of $` and friends borks things! if ( m/^=item\s+$search_re\s/ ) { $found = 1; } elsif (/^=item/) { last if $found && !$inheader && !$inlist; } elsif (!/^\s+$/) { # not a blank line if ( $found ) { $inheader = 0; # don't accept more =item (unless inlist) } else { @$pod = (); # reset $inheader = 1; # start over next; } } if (/^=over/) { ++$inlist; } elsif (/^=back/) { --$inlist; } # TWEAKED: to decode push @$pod, decode($encoding, $_); # ++$found if /^\w/; # found descriptive text } @$pod = () unless $found; if (!@$pod) { die "No documentation for perl variable '$opt' found\n"; } close PVAR or die "Can't open $perlvar: $!"; return; } sub search_perlfaqs { my ($self, $found_things, $pod) = @_; my $found = 0; my %found_in; my $search_key = $self->opt_q; my $rx = eval { qr/$search_key/ } or die <<EOD; Invalid regular expression '$search_key' given as -q pattern: $@ Did you mean \\Q$search_key ? EOD local $_; foreach my $file (@$found_things) { die "invalid file spec: $!" if $file =~ /[<>|]/; open(INFAQ, "<", $file) # XXX 5.6ism or die "Can't read-open $file: $!\nAborting"; # TWEAKED: to find encoding my $encoding = 'utf-8'; while (<INFAQ>) { if (/^=encoding\s+(\S+)/) { $encoding = $1; } if ( m/^=head2\s+.*(?:$search_key)/i ) { $found = 1; push @$pod, "=head1 Found in $file\n\n" unless $found_in{$file}++; } elsif (/^=head[12]/) { $found = 0; } next unless $found; # TWEAKED: to decode push @$pod, decode($encoding, $_); } close(INFAQ); } die("No documentation for perl FAQ keyword `$search_key' found\n") unless @$pod; return; } # TWEAKED: translation and encoding sub usage { my $self = shift; warn "@_\n" if @_; # Erase evidence of previous errors (if any), so exit status is simple. $! = 0; my $usage = <<"EOF"; perldoc [options] PageName|ModuleName|ProgramName|URL... perldoc [options] -f BuiltinFunction perldoc [options] -q FAQRegex perldoc [options] -v PerlVariable ãªãã·ã§ã³: -h ãã®ãã«ãã表示ãã -V ãã¼ã¸ã§ã³ã表示ãã -r å帰æ¤ç´¢ (æéããããã¾ã) -i 大æåå°æåãç¡è¦ãã -t pod2manã¨nroffã§ã¯ãªãpod2textã使ã£ã¦è¡¨ç¤º(ããã©ã«ã) -u æ´å½¢åã®PODã表示ãã -m æå®ããã¢ã¸ã¥ã¼ã«ã®ã³ã¼ããå«ãã¦è¡¨ç¤ºãã -n nroffã®ããããæå®ãã -l ã¢ã¸ã¥ã¼ã«ã®ãã¡ã¤ã«åã表示ãã -F 弿°ã¯ã¢ã¸ã¥ã¼ã«åã§ã¯ãªããã¡ã¤ã«åã§ãã -D ãããã°ã¡ãã»ã¼ã¸ã表示ãã -T ãã¼ã¸ã£ãéããã«ç»é¢ã«åºåãã -d ä¿åãããã¡ã¤ã«å -o åºåãã©ã¼ãããå -M ãã©ã¼ãããç¨ã®ã¢ã¸ã¥ã¼ã«å(FormatterModuleNameToUse) -w ãã©ã¼ãããç¨ã®ãªãã·ã§ã³:å¤(formatter_option:option_value) -L å½å¥ã³ã¼ããï¼ããã°ï¼ç¿»è¨³ã表示ãã¾ã -X ããã°ç´¢å¼ãå©ç¨ãã (pod.idxãæ¢ãã¾ã) -J perldoc.jpã®æ¥æ¬èªè¨³ãæ¤ç´¢ -q perlfaq[1-9]ã®è³ªåãæ¤ç´¢ -f Perlã®çµã¿è¾¼ã¿é¢æ°ãæ¤ç´¢ -v Perlã®å®ç¾©æ¸ã¿å¤æ°ãæ¤ç´¢ PageName|ModuleName... 表示ãããããã¥ã¡ã³ãåã§ãããperlfuncãã®ãããªãã¼ã¸åã ã¢ã¸ã¥ã¼ã«å(ãTerm::Infoãã¾ãã¯ãTerm/Infoã)ããperldocã ã®ãããªããã°ã©ã åãæå®ã§ãã¾ãã0.09ããã¯PODã®URLãæå® ãããã¨ãã§ããããã«ãªãã¾ããã BuiltinFunction Perlã®é¢æ°åã§ãããperlfuncãããããã¥ã¡ã³ããæ½åºãã¾ãã FAQRegex perlfaq[1-9]ãæ¤ç´¢ãã¦æ£è¦è¡¨ç¾ã«ããããã質åãæ½åºãã¾ãã PERLDOCç°å¢å¤æ°ã§æå®ããã¹ã¤ããã¯ã³ãã³ãã©ã¤ã³å¼æ°ã®åã«é©ç¨ããã¾ãã PODã®ç´¢å¼ã«ã¯(ããã°)ãã¡ã¤ã«åã®ä¸è¦§ã(1è¡ã«1ã¤)å«ã¾ãã¦ãã¾ãã [PerldocJp v$Pod::PerldocJp::VERSION based on Perldoc v$Pod::Perldoc::VERSION] EOF die encode($term_encoding => $usage); } sub usage_brief { my $me = $0; # Editing $0 is unportable $me =~ s,.*[/\\],,; # get basename my $usage =<<"EOUSAGE"; ä½¿ãæ¹: $me [-h] [-V] [-r] [-i] [-D] [-t] [-u] [-m] [-n nroffer_program] [-l] [-J] [-T] [-d output_filename] [-o output_format] [-M FormatterModuleNameToUse] [-w formatter_option:option_value] [-L translation_code] [-F] [-X] PageName|ModuleName|ProgramName|URL $me -f PerlFunc $me -q FAQKeywords $me -A PerlVar -hãªãã·ã§ã³ãã¤ããã¨ããå°ã詳ãããã«ãã表示ããã¾ãã 詳細ã¯"perldocjp perldocjp"ãã覧ãã ããã [PerldocJp v$Pod::PerldocJp::VERSION based on Perldoc v$Pod::Perldoc::VERSION] EOUSAGE die encode($term_encoding => $usage); } } 1; __END__