## ---------------------------------------------------------------------------- # ExtUtils::MY_Metafile # ----------------------------------------------------------------------------- # Mastering programmed by YAMASHINA Hio # # Copyright 2006 YAMASHINA Hio # ----------------------------------------------------------------------------- # $Id: /perl/ExtUtils-MY_Metafile/lib/ExtUtils/MY_Metafile.pm 209 2006-11-07T07:42:56.011738Z hio $ # ----------------------------------------------------------------------------- package ExtUtils::MY_Metafile; use strict; use warnings; use ExtUtils::MakeMaker; our $VERSION = '0.07'; our @EXPORT = qw(my_metafile); our %META_PARAMS; # DISTNAME(pkgname)=>HASHREF. our $DIAG_VERSION and &_diag_version; 1; # ----------------------------------------------------------------------------- # for: use inc::ExtUtils::MY_Metafile; # sub inc::ExtUtils::MY_Metafile::import { push(@inc::ExtUtils::MY_Metafile::ISA, __PACKAGE__); goto &import; } # ----------------------------------------------------------------------------- # import. # sub import { my $pkg = shift; my @syms = (!@_ || grep{/^:all$/}@_) ? @EXPORT : @_; my $callerpkg = caller; foreach my $name (@syms) { my $sub = $pkg->can($name); $sub or next; no strict 'refs'; *{$callerpkg.'::'.$name} = $sub; } if( !grep{ /^:no_setup$/ } @_ ) { # override. *MM::metafile_target = \&_mm_metafile; } } # ----------------------------------------------------------------------------- # _diag_version(); # sub _diag_version { my $mmver = $ExtUtils::MakeMaker::VERSION; if( $mmver >= 6.30 ) { print STDERR "# ExtUtils::MY_Metafile for MM 6.30 or later ($mmver).\n"; }else { print STDERR "# ExtUtils::MY_Metafile for MM 6.25 or earlier ($mmver).\n"; } } # ----------------------------------------------------------------------------- # my_metafile($distname => $param); # my_metafile($param); # sub my_metafile { my $distname = @_>=2 && shift; my $param = shift; UNIVERSAL::isa($distname,'HASH') and $distname = $distname->{DISTNAME}; $distname ||= ''; $distname =~ s/::/-/g; $META_PARAMS{$distname} and warn "# overwrite previous meta config $distname.\n"; $META_PARAMS{$distname} = $param; } # ----------------------------------------------------------------------------- # _mm_metafile($MM) # altanative of MM::metafile_target. # takes $MM object and returns makefile text. # sub _mm_metafile { my $this = shift; if( $this->{NO_META} ) { return "metafile:\n" . "\t\$(NOECHO) \$(NOOP)\n"; } # generate META.yml text. # my $meta = _gen_meta_yml($this); my @write_meta = ( '$(NOECHO) $(ECHO) Generating META.yml', $this->echo($meta, 'META_new.yml'), ); # format as makefile text. # my ($make_target, $metaout_file); if( $ExtUtils::MakeMaker::VERSION >= 6.30 ) { $make_target = "# for MM 6.30 or later.\n"; $make_target .= "metafile : create_distdir\n"; $metaout_file = '$(DISTVNAME)/META.yml'; }else { $make_target = "# for MM 6.25 or earlier.\n"; $make_target .= "metafile :\n"; $metaout_file = 'META.yml', } my $rename_meta = "-\$(NOECHO) \$(MV) META_new.yml $metaout_file"; my $make_body = join('', map{"\t$_\n"} @write_meta, $rename_meta); "$make_target$make_body"; } # ----------------------------------------------------------------------------- # _gen_meta_yml($MM); # generate META.yml text. # sub _gen_meta_yml { # from MakeMaker-6.30. my $this = shift; my $param = shift; my $check_mete_spec = 1; if( !$param ) { $param = $META_PARAMS{$this->{DISTNAME}} || $META_PARAMS{''}; if( !$param ) { $param = {}; $check_mete_spec = 0; } } if( $META_PARAMS{':all'} ) { # special key. $param = { %{$META_PARAMS{':all'}}, %$param }; } # requires:, build_requires: my $requires_to_yaml = sub{ my $key = shift; my $hash = shift; my $yaml = ''; my ($maxkeylen) = sort{$b<=>$a} map{length($_)} keys %$hash; my ($maxvallen) = sort{$b<=>$a} map{length($_)} values %$hash; foreach my $name ( sort { lc $a cmp lc $b } keys %$hash ) { my $ver = $hash->{$name}; $yaml .= sprintf " %-*s %*s\n", $maxkeylen+1, "$name:", $maxvallen, $ver; } chomp $yaml; $yaml ? "$key:\n$yaml" : ''; }; my $requires = $requires_to_yaml->(requires => $param->{requires} || $this->{PREREQ_PM}); my $build_requires = $requires_to_yaml->(build_requires => $param->{build_requires}); # no_index: my $no_index = $param->{no_index}; if( !$no_index || !$no_index->{directory} ) { my @dirs = grep{-d $_} (qw( inc t ex eg example examples sample samples demo demos )); $no_index = @dirs && +{ directory => \@dirs }; } $no_index = $no_index ? _yaml_out({no_index=>$no_index}) : ''; chomp $no_index; if( $param->{no_index} && !$ENV{NO_NO_INDEX_CHECK} ) { foreach my $key (keys %{$param->{no_index}}) { # dir is in spec-v1.2, directory is from spec-v1.3? (blead). $key =~ /^(file|dir|directory|package|namespace)$/ and next; warn "$key is invalid field for no_index.\n"; } } # abstract is from file. my $abstract = ''; if( $this->{ABSTRACT} ) { $abstract = _yaml_out({abstract => $this->{ABSTRACT}}); }elsif( $this->{ABSTRACT_FROM} && open(my$fh, "< $this->{ABSTRACT_FROM}") ) { while(<$fh>) { /^=head1 NAME$/ or next; (my $pkg = $this->{DISTNAME}) =~ s/-/::/g; while(<$fh>) { /^=/ and last; /^(\Q$pkg\E\s+-+\s+)(.*)/ or next; $abstract = $2; last; } last; } $abstract = $abstract ? _yaml_out({abstract=>$abstract}) : ''; } chomp $abstract; # build yaml object as hash. my $yaml = {}; $yaml->{name} = $this->{DISTNAME}; $yaml->{version} = $this->{VERSION}; $yaml->{version_from} = $this->{VERSION_FROM}; $yaml->{installdirs} = $this->{INSTALLDIRS}; $yaml->{author} = $this->{AUTHOR}; $yaml->{license} = $this->{LICENSE}; foreach my $key (keys %$yaml) { if( $yaml->{$key} ) { my $pad = ' 'x(12-length($key)); $yaml->{$key} = sprintf('%s:%s %s', $key, $pad, $yaml->{$key}); } } $yaml->{abstract} = $abstract; $yaml->{no_index} = $no_index; $yaml->{requires} = $requires; $yaml->{build_requires} = $build_requires; $yaml->{distribution_type} = 'distribution_type: module'; $yaml->{generated_by} = "generated_by: ExtUtils::MY_Metafile version $VERSION, EUMM-$ExtUtils::MakeMaker::VERSION."; $yaml->{'meta-spec'} = "meta-spec:\n"; $yaml->{'meta-spec'} .= " version: 1.2\n"; $yaml->{'meta-spec'} .= " url: http://module-build.sourceforge.net/META-spec-v1.2.html\n"; # customize yaml. my $extras = {}; foreach my $key (sort keys %$param) { grep{$key eq $_} qw(no_index requires build_requires) and next; my $line = _yaml_out->({$key=>$param->{$key}}); if( exists($yaml->{$key}) ) { chomp $line; $yaml->{$key} = $line; }else { $extras->{$key} = $line; } } $yaml->{extras} = join('', map{$extras->{$_}} sort keys %$extras); my @required_keys = qw(meta-spec name version abstract author license generated_by); foreach my $key (@required_keys) { $check_mete_spec or next; my $ok = $yaml->{$key} && $yaml->{$key}=~/\w/; $ok ||= $extras->{$key} and next; warn "$key is required for meta-spec v1.2 ($this->{DISTNAME}).\n"; } $yaml->{license} ||= 'license: unknown'; foreach my $key (keys %$yaml) { $key eq 'extras' and next; $yaml->{$key} ||= "#$key:"; } $yaml->{extras} &&= "\n# extras.\n$yaml->{extras}"; # packing into singple text. my $meta = <{name} $yaml->{version} $yaml->{version_from} $yaml->{installdirs} $yaml->{author} $yaml->{abstract} $yaml->{license} $yaml->{requires} $yaml->{build_requires} $yaml->{no_index} $yaml->{extras} $yaml->{distribution_type} $yaml->{generated_by} $yaml->{'meta-spec'} YAML #print "$meta"; $meta; } # ----------------------------------------------------------------------------- # generate simple yaml. # sub _yaml_out { my $obj = shift; my $depth = shift || 0; my $out = ''; if( !defined($obj) ) { $out = " "x$depth."~\n"; }elsif( !ref($obj) ) { $out = " "x$depth.$obj."\n"; }elsif( ref($obj)eq'ARRAY' ) { my @e = map{_yaml_out->($_, $depth+1)} @$obj; @e = map{ " "x$depth."- ".substr($_, ($depth+1)*2)} @e; $out = join('', @e); $out ||= " "x$depth."[]"; }elsif( ref($obj)eq'HASH' ) { foreach my $k (sort keys %$obj) { $out .= " "x$depth."$k:"; $out .= ref($obj->{$k}) ? "\n"._yaml_out($obj->{$k}, $depth+1) : " $obj->{$k}\n"; } $out ||= " "x$depth."{}"; }else { die "not supported: $obj"; } $out; } # ----------------------------------------------------------------------------- # End of Code. # ----------------------------------------------------------------------------- __END__ =encoding utf8 =for stopwords YAMASHINA Hio ACKNOWLEDGEMENTS AnnoCPAN CPAN EUMM META.yml RT =head1 NAME ExtUtils::MY_Metafile - META.yml customize with ExtUtil::MakeMaker =head1 VERSION Version 0.07 =head1 SYNOPSIS put ExtUtils/MY_Metafile.pm into inc/ExtUtils/MY_Metafile.pm: $ mkdir -p inc/ExtUtils $ cp `perldoc -l ExtUtils::MY_Metafile` inc/ExtUtils/ and write in your Makefile.PL: use ExtUtils::MakeMaker; use inc::ExtUtils::MY_Metafile; my_metafile { no_index => { directory => [ qw(inc example t), ], }, license => 'perl', }; WriteMakefile( DISTNAME => 'Your::Module', ... ); =head1 EXPORT This module exports one function. =head1 FUNCTIONS =head2 my_metafile $modname => \%meta_param; Takes two arguments. First one is package name to be generated, and you can omit this argument. Second is hashref which contains META.yml contents. my_metafile { no_index => { directory => [ qw(inc example t), ], }, license => 'perl', }; Some parameters are checked automatically. =over =item no_index If you not specify C parameter for C and there is directory C, they are set as it. =item requires C directive is set from C parameter of EUMM. If you want to use C, you can write it. =back =head1 AUTHOR YAMASHINA Hio, C<< >> =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 SUPPORT You can find documentation for this module with the perldoc command. perldoc ExtUtils::MY_Metafile You can also look for information at: =over 4 =item * AnnoCPAN: Annotated CPAN documentation L =item * CPAN Ratings L =item * RT: CPAN's request tracker L =item * Search CPAN L =back =head1 ACKNOWLEDGEMENTS =head1 COPYRIGHT & LICENSE Copyright 2006 YAMASHINA Hio, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut # ----------------------------------------------------------------------------- # End of File. # -----------------------------------------------------------------------------