| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Module::Faker::Dist; | 
| 2 |  |  |  |  |  |  | # ABSTRACT: a fake CPAN distribution | 
| 3 |  |  |  |  |  |  | $Module::Faker::Dist::VERSION = '0.022'; | 
| 4 | 8 |  |  | 8 |  | 535676 | use Moose; | 
|  | 8 |  |  |  |  | 3147973 |  | 
|  | 8 |  |  |  |  | 53 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 8 |  |  | 8 |  | 62011 | use Module::Faker::File; | 
|  | 8 |  |  |  |  | 26 |  | 
|  | 8 |  |  |  |  | 318 |  | 
| 7 | 8 |  |  | 8 |  | 3769 | use Module::Faker::Heavy; | 
|  | 8 |  |  |  |  | 23 |  | 
|  | 8 |  |  |  |  | 245 |  | 
| 8 | 8 |  |  | 8 |  | 3348 | use Module::Faker::Package; | 
|  | 8 |  |  |  |  | 30 |  | 
|  | 8 |  |  |  |  | 359 |  | 
| 9 | 8 |  |  | 8 |  | 4194 | use Module::Faker::Module; | 
|  | 8 |  |  |  |  | 26 |  | 
|  | 8 |  |  |  |  | 306 |  | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 8 |  |  | 8 |  | 3996 | use Archive::Any::Create; | 
|  | 8 |  |  |  |  | 89092 |  | 
|  | 8 |  |  |  |  | 79 |  | 
| 12 | 8 |  |  | 8 |  | 3737 | use CPAN::DistnameInfo; | 
|  | 8 |  |  |  |  | 7618 |  | 
|  | 8 |  |  |  |  | 91 |  | 
| 13 | 8 |  |  | 8 |  | 3849 | use CPAN::Meta 2.130880; # github issue #9 | 
|  | 8 |  |  |  |  | 209212 |  | 
|  | 8 |  |  |  |  | 68 |  | 
| 14 | 8 |  |  | 8 |  | 287 | use CPAN::Meta::Converter; | 
|  | 8 |  |  |  |  | 17 |  | 
|  | 8 |  |  |  |  | 32 |  | 
| 15 | 8 |  |  | 8 |  | 4010 | use CPAN::Meta::Merge; | 
|  | 8 |  |  |  |  | 16303 |  | 
|  | 8 |  |  |  |  | 66 |  | 
| 16 | 8 |  |  | 8 |  | 249 | use CPAN::Meta::Requirements; | 
|  | 8 |  |  |  |  | 19 |  | 
|  | 8 |  |  |  |  | 50 |  | 
| 17 | 8 |  |  | 8 |  | 164 | use Data::OptList (); | 
|  | 8 |  |  |  |  | 18 |  | 
|  | 8 |  |  |  |  | 159 |  | 
| 18 | 8 |  |  | 8 |  | 4275 | use Encode qw( encode_utf8 ); | 
|  | 8 |  |  |  |  | 68343 |  | 
|  | 8 |  |  |  |  | 525 |  | 
| 19 | 8 |  |  | 8 |  | 4862 | use File::Temp (); | 
|  | 8 |  |  |  |  | 134395 |  | 
|  | 8 |  |  |  |  | 217 |  | 
| 20 | 8 |  |  | 8 |  | 106 | use File::Path (); | 
|  | 8 |  |  |  |  | 19 |  | 
|  | 8 |  |  |  |  | 196 |  | 
| 21 | 8 |  |  | 8 |  | 46 | use Parse::CPAN::Meta 1.4401; | 
|  | 8 |  |  |  |  | 160 |  | 
|  | 8 |  |  |  |  | 332 |  | 
| 22 | 8 |  |  | 8 |  | 3385 | use Path::Class; | 
|  | 8 |  |  |  |  | 147865 |  | 
|  | 8 |  |  |  |  | 478 |  | 
| 23 | 8 |  |  | 8 |  | 5055 | use Storable qw(dclone); | 
|  | 8 |  |  |  |  | 24935 |  | 
|  | 8 |  |  |  |  | 6815 |  | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | #pod =head1 SYNOPSIS | 
| 26 |  |  |  |  |  |  | #pod | 
| 27 |  |  |  |  |  |  | #pod Building one dist at a time makes plenty of sense, so Module::Faker::Dist makes | 
| 28 |  |  |  |  |  |  | #pod it easy.  Building dists from definitions in files is also useful for doing | 
| 29 |  |  |  |  |  |  | #pod things in bulk (see L<CPAN::Faker>), so there are a bunch of ways to build | 
| 30 |  |  |  |  |  |  | #pod dists from a definition in a file. | 
| 31 |  |  |  |  |  |  | #pod | 
| 32 |  |  |  |  |  |  | #pod     # Build from a META.yml or META.json file, or the delightful | 
| 33 |  |  |  |  |  |  | #pod     # AUTHOR_Foo-Bar-1.234.tar.gz.dist file, which can be zero bytes and gets | 
| 34 |  |  |  |  |  |  | #pod     # all the relevant data from the filename. | 
| 35 |  |  |  |  |  |  | #pod     my $dist = Module::Faker::Dist->from_file($filename); | 
| 36 |  |  |  |  |  |  | #pod | 
| 37 |  |  |  |  |  |  | #pod META files can contain a key called X_Module_Faker that contains attributes to | 
| 38 |  |  |  |  |  |  | #pod use in constructing the dist.  C<dist> files can contain anything you want, but | 
| 39 |  |  |  |  |  |  | #pod the contents won't do a thing. | 
| 40 |  |  |  |  |  |  | #pod | 
| 41 |  |  |  |  |  |  | #pod You can use the C<new> method on Module::Faker::Dist, of course, but it's a bit | 
| 42 |  |  |  |  |  |  | #pod of a pain.  You might, instead, want to use C<from_struct>, which is very close | 
| 43 |  |  |  |  |  |  | #pod to C<new>, but with more sugar. | 
| 44 |  |  |  |  |  |  | #pod | 
| 45 |  |  |  |  |  |  | #pod =cut | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | #pod =attr name | 
| 48 |  |  |  |  |  |  | #pod | 
| 49 |  |  |  |  |  |  | #pod This is the name of the dist.  It will usually look like C<Foo-Bar>. | 
| 50 |  |  |  |  |  |  | #pod | 
| 51 |  |  |  |  |  |  | #pod =attr version | 
| 52 |  |  |  |  |  |  | #pod | 
| 53 |  |  |  |  |  |  | #pod This is the version of the dist, usually some kind of versiony string like | 
| 54 |  |  |  |  |  |  | #pod C<1.234> or maybe C<1.2.3>. | 
| 55 |  |  |  |  |  |  | #pod | 
| 56 |  |  |  |  |  |  | #pod =attr abstract | 
| 57 |  |  |  |  |  |  | #pod | 
| 58 |  |  |  |  |  |  | #pod The abstract!  This is a short, pithy description of the distribution, usually | 
| 59 |  |  |  |  |  |  | #pod less than a sentence. | 
| 60 |  |  |  |  |  |  | #pod | 
| 61 |  |  |  |  |  |  | #pod =attr release_status | 
| 62 |  |  |  |  |  |  | #pod | 
| 63 |  |  |  |  |  |  | #pod This is the dist's release status.  (See L<CPAN::Meta::Spec>.)  It defaults to | 
| 64 |  |  |  |  |  |  | #pod C<stable> but C<unstable> and C<testing> are valid values. | 
| 65 |  |  |  |  |  |  | #pod | 
| 66 |  |  |  |  |  |  | #pod =cut | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | my $DEFAULT_VERSION; | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | # required by CPAN::Meta::Spec | 
| 71 |  |  |  |  |  |  | has name           => (is => 'ro', isa => 'Str', required => $DEFAULT_VERSION); | 
| 72 |  |  |  |  |  |  | has version        => (is => 'ro', isa => 'Maybe[Str]', default => '0.01'); | 
| 73 |  |  |  |  |  |  | has abstract       => (is => 'ro', isa => 'Str', default => 'a great new dist'); | 
| 74 |  |  |  |  |  |  | has release_status => (is => 'ro', isa => 'Str', default => 'stable'); | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | #pod =attr cpan_author | 
| 77 |  |  |  |  |  |  | #pod | 
| 78 |  |  |  |  |  |  | #pod This is the PAUSE id of the author, like C<RJBS>. | 
| 79 |  |  |  |  |  |  | #pod | 
| 80 |  |  |  |  |  |  | #pod =attr archive_ext | 
| 81 |  |  |  |  |  |  | #pod | 
| 82 |  |  |  |  |  |  | #pod This is the extension of the archive to build, when you build an archive.  This | 
| 83 |  |  |  |  |  |  | #pod defaults to C<tar.gz>.  C<zip> should work, but right now it doesn't.  So | 
| 84 |  |  |  |  |  |  | #pod probably stuck to C<tar.gz>.  It would be cool to support more attributes in | 
| 85 |  |  |  |  |  |  | #pod the future. | 
| 86 |  |  |  |  |  |  | #pod | 
| 87 |  |  |  |  |  |  | #pod =attr append | 
| 88 |  |  |  |  |  |  | #pod | 
| 89 |  |  |  |  |  |  | #pod This is an arrayref of hashrefs, each of which looks like: | 
| 90 |  |  |  |  |  |  | #pod | 
| 91 |  |  |  |  |  |  | #pod   { file => $filename, content => $character_string } | 
| 92 |  |  |  |  |  |  | #pod | 
| 93 |  |  |  |  |  |  | #pod The content will be UTF-8 encoded and put into a file with the given name. | 
| 94 |  |  |  |  |  |  | #pod | 
| 95 |  |  |  |  |  |  | #pod This feature is a bit weird.  Maybe it will go away eventually. | 
| 96 |  |  |  |  |  |  | #pod | 
| 97 |  |  |  |  |  |  | #pod =attr mtime | 
| 98 |  |  |  |  |  |  | #pod | 
| 99 |  |  |  |  |  |  | #pod If given, this is the epoch seconds to which to set the mtime of the generated | 
| 100 |  |  |  |  |  |  | #pod file.  This is useful in rare occasions. | 
| 101 |  |  |  |  |  |  | #pod | 
| 102 |  |  |  |  |  |  | #pod =cut | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | # Module::Faker options | 
| 105 |  |  |  |  |  |  | has cpan_author  => (is => 'ro', isa => 'Maybe[Str]', default => 'LOCAL'); | 
| 106 |  |  |  |  |  |  | has archive_ext  => (is => 'ro', isa => 'Str', default => 'tar.gz'); | 
| 107 |  |  |  |  |  |  | has append       => (is => 'ro', isa => 'ArrayRef[HashRef]', default => sub {[]}); | 
| 108 |  |  |  |  |  |  | has mtime        => (is => 'ro', isa => 'Int', predicate => 'has_mtime'); | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | #pod =attr x_authority | 
| 111 |  |  |  |  |  |  | #pod | 
| 112 |  |  |  |  |  |  | #pod This is the C<X_Authority> header that gets put into the META files. | 
| 113 |  |  |  |  |  |  | #pod | 
| 114 |  |  |  |  |  |  | #pod =cut | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | has x_authority => (is => 'ro', isa => 'Str'); | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | #pod =attr license | 
| 119 |  |  |  |  |  |  | #pod | 
| 120 |  |  |  |  |  |  | #pod This is the meta spec license string for the distribution.  It defaults to | 
| 121 |  |  |  |  |  |  | #pod C<perl_5>. | 
| 122 |  |  |  |  |  |  | #pod | 
| 123 |  |  |  |  |  |  | #pod =cut | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | has license => ( | 
| 126 |  |  |  |  |  |  | is      => 'ro', | 
| 127 |  |  |  |  |  |  | isa     => 'ArrayRef[Str]', | 
| 128 |  |  |  |  |  |  | default => sub { [ 'perl_5' ] }, | 
| 129 |  |  |  |  |  |  | ); | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | #pod =attr authors | 
| 132 |  |  |  |  |  |  | #pod | 
| 133 |  |  |  |  |  |  | #pod This is an array of strings who are used as the authors in the dist metadata. | 
| 134 |  |  |  |  |  |  | #pod The default is: | 
| 135 |  |  |  |  |  |  | #pod | 
| 136 |  |  |  |  |  |  | #pod   [ "AUTHOR <AUTHOR@cpan.local>" ] | 
| 137 |  |  |  |  |  |  | #pod | 
| 138 |  |  |  |  |  |  | #pod ...where C<AUTHOR> is the C<cpan_author> of the dist. | 
| 139 |  |  |  |  |  |  | #pod | 
| 140 |  |  |  |  |  |  | #pod =cut | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | has authors => ( | 
| 143 |  |  |  |  |  |  | isa  => 'ArrayRef[Str]', | 
| 144 |  |  |  |  |  |  | lazy => 1, | 
| 145 |  |  |  |  |  |  | traits  => [ 'Array' ], | 
| 146 |  |  |  |  |  |  | handles => { authors => 'elements' }, | 
| 147 |  |  |  |  |  |  | default => sub { | 
| 148 |  |  |  |  |  |  | my ($self) = @_; | 
| 149 |  |  |  |  |  |  | return [ sprintf '%s <%s@cpan.local>', ($self->cpan_author) x 2 ]; | 
| 150 |  |  |  |  |  |  | }, | 
| 151 |  |  |  |  |  |  | ); | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | #pod =attr include_provides_in_meta | 
| 154 |  |  |  |  |  |  | #pod | 
| 155 |  |  |  |  |  |  | #pod This is a bool.  If true, the produced META files will include a C<provides> | 
| 156 |  |  |  |  |  |  | #pod key based on the packages in the dist.  It defaults to false, to match the | 
| 157 |  |  |  |  |  |  | #pod most common behavior of dists in the wild. | 
| 158 |  |  |  |  |  |  | #pod | 
| 159 |  |  |  |  |  |  | #pod =cut | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | has include_provides_in_meta => ( | 
| 162 |  |  |  |  |  |  | is  => 'ro', | 
| 163 |  |  |  |  |  |  | isa => 'Bool', | 
| 164 |  |  |  |  |  |  | default => 0, | 
| 165 |  |  |  |  |  |  | ); | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | #pod =attr provides | 
| 168 |  |  |  |  |  |  | #pod | 
| 169 |  |  |  |  |  |  | #pod This is a hashref that gets used as the C<provides> in the metadata. | 
| 170 |  |  |  |  |  |  | #pod | 
| 171 |  |  |  |  |  |  | #pod If no provided, it is built from the C<packages> provided in construction. | 
| 172 |  |  |  |  |  |  | #pod | 
| 173 |  |  |  |  |  |  | #pod If no packages were provided, for a dist named Foo-Bar, it defaults to: | 
| 174 |  |  |  |  |  |  | #pod | 
| 175 |  |  |  |  |  |  | #pod   { 'Foo::Bar' => { version => $DIST_VERSION, file => "lib/Foo/Bar.pm" } } | 
| 176 |  |  |  |  |  |  | #pod | 
| 177 |  |  |  |  |  |  | #pod =cut | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | has provides => ( | 
| 180 |  |  |  |  |  |  | is => 'ro', | 
| 181 |  |  |  |  |  |  | isa => 'HashRef', | 
| 182 |  |  |  |  |  |  | lazy_build => 1, | 
| 183 |  |  |  |  |  |  | ); | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | sub _build_provides { | 
| 186 | 14 |  |  | 14 |  | 37 | my ($self) = @_; | 
| 187 |  |  |  |  |  |  |  | 
| 188 | 14 | 50 |  |  |  | 467 | if ($self->has_packages) { | 
| 189 |  |  |  |  |  |  | return { | 
| 190 | 0 | 0 |  |  |  | 0 | map {; $_->name => { | 
|  | 0 |  |  |  |  | 0 |  | 
| 191 |  |  |  |  |  |  | file    => $_->in_file, | 
| 192 |  |  |  |  |  |  | (defined $_->version ? (version => $_->version) : ()), | 
| 193 |  |  |  |  |  |  | } } $self->packages | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  |  | 
| 197 | 14 |  |  |  |  | 360 | my $pkg = __dist_to_pkg($self->name); | 
| 198 |  |  |  |  |  |  | return { | 
| 199 | 14 |  |  |  |  | 371 | $pkg => { | 
| 200 |  |  |  |  |  |  | version => $self->version, | 
| 201 |  |  |  |  |  |  | file => __pkg_to_file($pkg), | 
| 202 |  |  |  |  |  |  | } | 
| 203 |  |  |  |  |  |  | }; | 
| 204 |  |  |  |  |  |  | }; | 
| 205 |  |  |  |  |  |  |  | 
| 206 | 20 | 100 |  | 20 |  | 701 | sub __dor { defined $_[0] ? $_[0] : $_[1] } | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | sub append_for { | 
| 209 | 48 |  |  | 48 | 0 | 150 | my ($self, $filename) = @_; | 
| 210 |  |  |  |  |  |  | return [ | 
| 211 |  |  |  |  |  |  | # YAML and JSON should both be in utf8 (if not plain ascii) | 
| 212 | 14 |  |  |  |  | 68 | map  { encode_utf8($_->{content}) } | 
| 213 | 30 |  |  |  |  | 80 | grep { $filename eq $_->{file} } | 
| 214 | 48 |  |  |  |  | 98 | @{ $self->append } | 
|  | 48 |  |  |  |  | 1305 |  | 
| 215 |  |  |  |  |  |  | ]; | 
| 216 |  |  |  |  |  |  | } | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | #pod =attr archive_basename | 
| 219 |  |  |  |  |  |  | #pod | 
| 220 |  |  |  |  |  |  | #pod If written to disk, the archive will be written to... | 
| 221 |  |  |  |  |  |  | #pod | 
| 222 |  |  |  |  |  |  | #pod   $dist->archive_basename . '.' . $dist->archive_ext | 
| 223 |  |  |  |  |  |  | #pod | 
| 224 |  |  |  |  |  |  | #pod The default is: | 
| 225 |  |  |  |  |  |  | #pod | 
| 226 |  |  |  |  |  |  | #pod   $dist->name . '.' . ($dist->version // 'undef') | 
| 227 |  |  |  |  |  |  | #pod | 
| 228 |  |  |  |  |  |  | #pod =cut | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  | has archive_basename => ( | 
| 231 |  |  |  |  |  |  | is   => 'ro', | 
| 232 |  |  |  |  |  |  | isa  => 'Str', | 
| 233 |  |  |  |  |  |  | lazy => 1, | 
| 234 |  |  |  |  |  |  | default => sub { | 
| 235 |  |  |  |  |  |  | my ($self) = @_; | 
| 236 |  |  |  |  |  |  | return sprintf '%s-%s', $self->name, __dor($self->version, 'undef'); | 
| 237 |  |  |  |  |  |  | }, | 
| 238 |  |  |  |  |  |  | ); | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | #pod =attr omitted_files | 
| 241 |  |  |  |  |  |  | #pod | 
| 242 |  |  |  |  |  |  | #pod If given, this is an arrayref of filenames that shouldn't be automatically | 
| 243 |  |  |  |  |  |  | #pod generated and included. | 
| 244 |  |  |  |  |  |  | #pod | 
| 245 |  |  |  |  |  |  | #pod =cut | 
| 246 |  |  |  |  |  |  |  | 
| 247 |  |  |  |  |  |  | has omitted_files => ( | 
| 248 |  |  |  |  |  |  | isa  => 'ArrayRef[Str]', | 
| 249 |  |  |  |  |  |  | traits  => [ 'Array' ], | 
| 250 |  |  |  |  |  |  | handles => { omitted_files => 'elements' }, | 
| 251 |  |  |  |  |  |  | lazy    => 1, | 
| 252 |  |  |  |  |  |  | default => sub { [] }, | 
| 253 |  |  |  |  |  |  | ); | 
| 254 |  |  |  |  |  |  |  | 
| 255 | 14 |  |  | 14 |  | 31 | sub __dist_to_pkg { my $str = shift; $str =~ s/-/::/g; return $str; } | 
|  | 14 |  |  |  |  | 71 |  | 
|  | 14 |  |  |  |  | 40 |  | 
| 256 | 14 |  |  | 14 |  | 30 | sub __pkg_to_file { my $str = shift; $str =~ s{::}{/}g; return "lib/$str.pm"; } | 
|  | 14 |  |  |  |  | 60 |  | 
|  | 14 |  |  |  |  | 409 |  | 
| 257 |  |  |  |  |  |  |  | 
| 258 |  |  |  |  |  |  | # This is stupid, but copes with MakeMaker wanting to have a module name as its | 
| 259 |  |  |  |  |  |  | # NAME parameter.  Ugh! -- rjbs, 2008-03-13 | 
| 260 |  |  |  |  |  |  | sub _pkgy_name { | 
| 261 | 19 |  |  | 19 |  | 2158 | my $name = shift->name; | 
| 262 | 19 |  |  |  |  | 112 | $name =~ s/-/::/g; | 
| 263 |  |  |  |  |  |  |  | 
| 264 | 19 |  |  |  |  | 199 | return $name; | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | #pod =attr packages | 
| 268 |  |  |  |  |  |  | #pod | 
| 269 |  |  |  |  |  |  | #pod This is an array of L<Module::Faker::Package> objects.  It's built by | 
| 270 |  |  |  |  |  |  | #pod C<provides> if needed, but you might want to look at using the | 
| 271 |  |  |  |  |  |  | #pod C<L</from_struct>> method to set it up. | 
| 272 |  |  |  |  |  |  | #pod | 
| 273 |  |  |  |  |  |  | #pod =cut | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | has packages => ( | 
| 276 |  |  |  |  |  |  | isa     => 'Module::Faker::Type::Packages', | 
| 277 |  |  |  |  |  |  | lazy    => 1, | 
| 278 |  |  |  |  |  |  | builder => '_build_packages', | 
| 279 |  |  |  |  |  |  | traits  => [ 'Array' ], | 
| 280 |  |  |  |  |  |  | handles => { packages => 'elements' }, | 
| 281 |  |  |  |  |  |  | predicate => 'has_packages', | 
| 282 |  |  |  |  |  |  | ); | 
| 283 |  |  |  |  |  |  |  | 
| 284 |  |  |  |  |  |  | sub _build_packages { | 
| 285 | 19 |  |  | 19 |  | 51 | my ($self) = @_; | 
| 286 |  |  |  |  |  |  |  | 
| 287 | 19 |  |  |  |  | 505 | my $href = $self->provides; | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | # do this dance so we don't autovivify X_Module_Faker in provides | 
| 290 | 19 |  |  |  |  | 91 | my %package_order = map {; | 
| 291 | 36 | 100 |  |  |  | 205 | $_ => (exists $href->{$_}{X_Module_Faker} ? $href->{$_}{X_Module_Faker}{order} : 0 ) | 
| 292 |  |  |  |  |  |  | } keys %$href; | 
| 293 |  |  |  |  |  |  |  | 
| 294 | 19 |  |  |  |  | 49 | my @pkg_names = do { | 
| 295 | 8 |  |  | 8 |  | 72 | no warnings 'uninitialized'; | 
|  | 8 |  |  |  |  | 27 |  | 
|  | 8 |  |  |  |  | 15049 |  | 
| 296 | 19 |  |  |  |  | 98 | sort { $package_order{$a} <=> $package_order{$b} } keys %package_order; | 
|  | 24 |  |  |  |  | 85 |  | 
| 297 |  |  |  |  |  |  | }; | 
| 298 |  |  |  |  |  |  |  | 
| 299 | 19 |  |  |  |  | 55 | my @packages; | 
| 300 | 19 |  |  |  |  | 56 | for my $name (@pkg_names) { | 
| 301 |  |  |  |  |  |  | push @packages, Module::Faker::Package->new({ | 
| 302 |  |  |  |  |  |  | name    => $name, | 
| 303 |  |  |  |  |  |  | version => $href->{$name}{version}, | 
| 304 |  |  |  |  |  |  | in_file => $href->{$name}{file}, | 
| 305 | 36 |  |  |  |  | 25874 | }); | 
| 306 |  |  |  |  |  |  | } | 
| 307 |  |  |  |  |  |  |  | 
| 308 | 19 |  |  |  |  | 28677 | return \@packages; | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | #pod =method modules | 
| 312 |  |  |  |  |  |  | #pod | 
| 313 |  |  |  |  |  |  | #pod This produces and returns a list of L<Module::Faker::Module> objects, | 
| 314 |  |  |  |  |  |  | #pod representing modules.  Modules, if you're not as steeped in CPAN toolchain | 
| 315 |  |  |  |  |  |  | #pod nonsense, are the C<.pm> files in which packages are defined. | 
| 316 |  |  |  |  |  |  | #pod | 
| 317 |  |  |  |  |  |  | #pod These are produced by combining the packages from C<L</packages>> into files | 
| 318 |  |  |  |  |  |  | #pod based on their C<in_file> attributes. | 
| 319 |  |  |  |  |  |  | #pod | 
| 320 |  |  |  |  |  |  | #pod =cut | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | sub modules { | 
| 323 | 38 |  |  | 38 | 1 | 87 | my ($self) = @_; | 
| 324 |  |  |  |  |  |  |  | 
| 325 | 38 |  |  |  |  | 63 | my %module; | 
| 326 | 38 |  |  |  |  | 1331 | for my $pkg ($self->packages) { | 
| 327 | 72 |  |  |  |  | 2000 | my $filename = $pkg->in_file; | 
| 328 |  |  |  |  |  |  |  | 
| 329 | 72 |  | 100 |  |  | 116 | push @{ $module{ $filename } ||= [] }, $pkg; | 
|  | 72 |  |  |  |  | 370 |  | 
| 330 |  |  |  |  |  |  | } | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | my @modules = map { | 
| 333 | 38 |  |  |  |  | 200 | Module::Faker::Module->new({ | 
| 334 | 44 |  |  |  |  | 7876 | packages => $module{$_}, | 
| 335 |  |  |  |  |  |  | filename => $_, | 
| 336 |  |  |  |  |  |  | append   => $self->append_for($_) | 
| 337 |  |  |  |  |  |  | }); | 
| 338 |  |  |  |  |  |  | } keys %module; | 
| 339 |  |  |  |  |  |  |  | 
| 340 | 38 |  |  |  |  | 47642 | return @modules; | 
| 341 |  |  |  |  |  |  | } | 
| 342 |  |  |  |  |  |  |  | 
| 343 |  |  |  |  |  |  | sub _mk_container_path { | 
| 344 | 61 |  |  | 61 |  | 131 | my ($self, $filename) = @_; | 
| 345 |  |  |  |  |  |  |  | 
| 346 | 61 |  |  |  |  | 449 | my (@parts) = File::Spec->splitdir($filename); | 
| 347 | 61 |  |  |  |  | 136 | my $leaf_filename = pop @parts; | 
| 348 | 61 |  |  |  |  | 5862 | File::Path::mkpath(File::Spec->catdir(@parts)); | 
| 349 |  |  |  |  |  |  | } | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | #pod =method C<make_dist_dir> | 
| 352 |  |  |  |  |  |  | #pod | 
| 353 |  |  |  |  |  |  | #pod   my $directory_name = $dist->make_dist_dir(\%arg); | 
| 354 |  |  |  |  |  |  | #pod | 
| 355 |  |  |  |  |  |  | #pod This returns the name of a directory into which the dist's contents have been | 
| 356 |  |  |  |  |  |  | #pod written.  If a C<dir> argument is provided, the dist will be written to a | 
| 357 |  |  |  |  |  |  | #pod directory beneath that dir.  Otherwise, it will be written below a temporary | 
| 358 |  |  |  |  |  |  | #pod directory. | 
| 359 |  |  |  |  |  |  | #pod | 
| 360 |  |  |  |  |  |  | #pod =cut | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | sub make_dist_dir { | 
| 363 | 8 |  |  | 8 | 1 | 4379 | my ($self, $arg) = @_; | 
| 364 | 8 |  | 100 |  |  | 35 | $arg ||= {}; | 
| 365 |  |  |  |  |  |  |  | 
| 366 | 8 |  | 66 |  |  | 40 | my $dir = $arg->{dir} || File::Temp::tempdir; | 
| 367 | 8 |  |  |  |  | 1348 | my $dist_dir = File::Spec->catdir($dir, $self->archive_basename); | 
| 368 |  |  |  |  |  |  |  | 
| 369 | 8 |  |  |  |  | 42 | for my $file ($self->files) { | 
| 370 | 50 |  |  |  |  | 1769 | my $fqfn = File::Spec->catfile($dist_dir, $file->filename); | 
| 371 | 50 |  |  |  |  | 266 | $self->_mk_container_path($fqfn); | 
| 372 |  |  |  |  |  |  |  | 
| 373 | 50 | 50 |  |  |  | 2983 | open my $fh, '>', $fqfn or die "couldn't open $fqfn for writing: $!"; | 
| 374 | 50 |  |  |  |  | 337 | print $fh $file->as_string; | 
| 375 | 50 | 50 |  |  |  | 2041 | close $fh or die "error when closing $fqfn: $!"; | 
| 376 |  |  |  |  |  |  | } | 
| 377 |  |  |  |  |  |  |  | 
| 378 | 8 |  |  |  |  | 61 | return $dist_dir; | 
| 379 |  |  |  |  |  |  | } | 
| 380 |  |  |  |  |  |  |  | 
| 381 |  |  |  |  |  |  | sub _author_dir_infix { | 
| 382 | 0 |  |  | 0 |  | 0 | my ($self) = @_; | 
| 383 |  |  |  |  |  |  |  | 
| 384 | 0 | 0 |  |  |  | 0 | Carp::croak "can't put archive in author dir with no author defined" | 
| 385 |  |  |  |  |  |  | unless my $pauseid = $self->cpan_author; | 
| 386 |  |  |  |  |  |  |  | 
| 387 |  |  |  |  |  |  | # Sorta like pow- pow- power-wheels! -- rjbs, 2008-03-14 | 
| 388 | 0 |  |  |  |  | 0 | my ($pa, $p) = $pauseid =~ /^((.).)/; | 
| 389 | 0 |  |  |  |  | 0 | return ($p, $pa, $pauseid); | 
| 390 |  |  |  |  |  |  | } | 
| 391 |  |  |  |  |  |  |  | 
| 392 |  |  |  |  |  |  | sub archive_filename { | 
| 393 | 11 |  |  | 11 | 0 | 1455 | my ($self, $arg) = @_; | 
| 394 |  |  |  |  |  |  |  | 
| 395 | 11 |  |  |  |  | 314 | my $base = $self->archive_basename; | 
| 396 | 11 |  |  |  |  | 304 | my $ext  = $self->archive_ext; | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | return File::Spec->catfile( | 
| 399 | 11 | 50 |  |  |  | 213 | ($arg->{author_prefix} ? $self->_author_dir_infix : ()), | 
| 400 |  |  |  |  |  |  | "$base.$ext", | 
| 401 |  |  |  |  |  |  | ); | 
| 402 |  |  |  |  |  |  | } | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | #pod =method make_archive | 
| 405 |  |  |  |  |  |  | #pod | 
| 406 |  |  |  |  |  |  | #pod   my $archive_filename = $dist->make_archive(\%arg); | 
| 407 |  |  |  |  |  |  | #pod | 
| 408 |  |  |  |  |  |  | #pod This writes the dist archive file, like a tarball or zip file.  If a C<dir> | 
| 409 |  |  |  |  |  |  | #pod argument is given, it will be written in that directory.  Otherwise, it will be | 
| 410 |  |  |  |  |  |  | #pod written to a temporary directory.  If the C<author_prefix> argument is given | 
| 411 |  |  |  |  |  |  | #pod and true, it will be written under a hashed author dir, like: | 
| 412 |  |  |  |  |  |  | #pod | 
| 413 |  |  |  |  |  |  | #pod   U/US/USERID/Foo-Bar-1.23.tar.gz | 
| 414 |  |  |  |  |  |  | #pod | 
| 415 |  |  |  |  |  |  | #pod =cut | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | sub make_archive { | 
| 418 | 11 |  |  | 11 | 1 | 726 | my ($self, $arg) = @_; | 
| 419 | 11 |  | 50 |  |  | 39 | $arg ||= {}; | 
| 420 |  |  |  |  |  |  |  | 
| 421 | 11 |  | 33 |  |  | 34 | my $dir = $arg->{dir} || File::Temp::tempdir; | 
| 422 |  |  |  |  |  |  |  | 
| 423 | 11 |  |  |  |  | 71 | my $archive   = Archive::Any::Create->new; | 
| 424 | 11 |  |  |  |  | 354 | my $container = $self->archive_basename; | 
| 425 |  |  |  |  |  |  |  | 
| 426 | 11 |  |  |  |  | 64 | $archive->container($container); | 
| 427 |  |  |  |  |  |  |  | 
| 428 | 11 |  |  |  |  | 102 | for my $file ($self->files) { | 
| 429 | 69 |  |  |  |  | 2028 | $archive->add_file($file->filename, $file->as_string); | 
| 430 |  |  |  |  |  |  | } | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | my $archive_filename = File::Spec->catfile( | 
| 433 |  |  |  |  |  |  | $dir, | 
| 434 |  |  |  |  |  |  | $self->archive_filename({ author_prefix => $arg->{author_prefix} }) | 
| 435 | 11 |  |  |  |  | 92 | ); | 
| 436 |  |  |  |  |  |  |  | 
| 437 | 11 |  |  |  |  | 58 | $self->_mk_container_path($archive_filename); | 
| 438 | 11 |  |  |  |  | 76 | $archive->write_file($archive_filename); | 
| 439 | 11 | 100 |  |  |  | 182190 | utime time, $self->mtime, $archive_filename if $self->has_mtime; | 
| 440 | 11 |  |  |  |  | 111 | return $archive_filename; | 
| 441 |  |  |  |  |  |  | } | 
| 442 |  |  |  |  |  |  |  | 
| 443 |  |  |  |  |  |  | sub files { | 
| 444 | 19 |  |  | 19 | 0 | 52 | my ($self) = @_; | 
| 445 | 19 |  |  |  |  | 62 | my @files = ($self->modules, $self->_extras, $self->_manifest_file); | 
| 446 | 19 |  |  |  |  | 43 | for my $file (@{$self->append}) { | 
|  | 19 |  |  |  |  | 532 |  | 
| 447 | 10 | 100 |  |  |  | 2287 | next if grep { $_->filename eq $file->{file} } @files; | 
|  | 62 |  |  |  |  | 1512 |  | 
| 448 |  |  |  |  |  |  | push(@files, | 
| 449 |  |  |  |  |  |  | $self->_file_class->new( | 
| 450 |  |  |  |  |  |  | filename => $file->{file}, | 
| 451 |  |  |  |  |  |  | content  => '', | 
| 452 | 4 |  |  |  |  | 16 | append   => $self->append_for($file->{file}), | 
| 453 |  |  |  |  |  |  | ) ); | 
| 454 |  |  |  |  |  |  | } | 
| 455 | 19 |  |  |  |  | 2351 | return @files; | 
| 456 |  |  |  |  |  |  | } | 
| 457 |  |  |  |  |  |  |  | 
| 458 | 97 |  |  | 97 |  | 487 | sub _file_class { 'Module::Faker::File' } | 
| 459 |  |  |  |  |  |  |  | 
| 460 |  |  |  |  |  |  | around BUILDARGS => sub { | 
| 461 |  |  |  |  |  |  | my ($orig, $self, @rest) = @_; | 
| 462 |  |  |  |  |  |  | my $arg = $self->$orig(@rest); | 
| 463 |  |  |  |  |  |  |  | 
| 464 |  |  |  |  |  |  | confess "can't supply both requires and prereqs" | 
| 465 |  |  |  |  |  |  | if $arg->{prereqs} && $arg->{requires}; | 
| 466 |  |  |  |  |  |  |  | 
| 467 |  |  |  |  |  |  | if ($arg->{requires}) { | 
| 468 |  |  |  |  |  |  | $arg->{prereqs} = { | 
| 469 |  |  |  |  |  |  | runtime => { requires => delete $arg->{requires} } | 
| 470 |  |  |  |  |  |  | }; | 
| 471 |  |  |  |  |  |  | } | 
| 472 |  |  |  |  |  |  |  | 
| 473 |  |  |  |  |  |  | return $arg; | 
| 474 |  |  |  |  |  |  | }; | 
| 475 |  |  |  |  |  |  |  | 
| 476 |  |  |  |  |  |  | sub BUILD { | 
| 477 | 22 |  |  | 22 | 0 | 56251 | my ($self) = @_; | 
| 478 | 22 |  |  |  |  | 697 | my $provides = $self->provides; | 
| 479 |  |  |  |  |  |  |  | 
| 480 | 22 |  | 33 |  |  | 202 | $provides->{$_}{file} //= __pkg_to_file($_) for keys %$provides; | 
| 481 |  |  |  |  |  |  | } | 
| 482 |  |  |  |  |  |  |  | 
| 483 |  |  |  |  |  |  | has prereqs => ( | 
| 484 |  |  |  |  |  |  | is   => 'ro', | 
| 485 |  |  |  |  |  |  | isa  => 'HashRef', | 
| 486 |  |  |  |  |  |  | default => sub {  {}  }, | 
| 487 |  |  |  |  |  |  | ); | 
| 488 |  |  |  |  |  |  |  | 
| 489 |  |  |  |  |  |  | has _manifest_file => ( | 
| 490 |  |  |  |  |  |  | is   => 'ro', | 
| 491 |  |  |  |  |  |  | isa  => 'Module::Faker::File', | 
| 492 |  |  |  |  |  |  | lazy => 1, | 
| 493 |  |  |  |  |  |  | default => sub { | 
| 494 |  |  |  |  |  |  | my ($self) = @_; | 
| 495 |  |  |  |  |  |  | my @files = ($self->modules, $self->_extras); | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  | return $self->_file_class->new({ | 
| 498 |  |  |  |  |  |  | filename => 'MANIFEST', | 
| 499 |  |  |  |  |  |  | content  => join("\n", | 
| 500 |  |  |  |  |  |  | 'MANIFEST', | 
| 501 |  |  |  |  |  |  | map { $_->filename } @files | 
| 502 |  |  |  |  |  |  | ), | 
| 503 |  |  |  |  |  |  | }); | 
| 504 |  |  |  |  |  |  | }, | 
| 505 |  |  |  |  |  |  | ); | 
| 506 |  |  |  |  |  |  |  | 
| 507 |  |  |  |  |  |  | #pod =attr more_metadata | 
| 508 |  |  |  |  |  |  | #pod | 
| 509 |  |  |  |  |  |  | #pod This can be given as a hashref of data to merge into the CPAN::Meta files. | 
| 510 |  |  |  |  |  |  | #pod | 
| 511 |  |  |  |  |  |  | #pod =cut | 
| 512 |  |  |  |  |  |  |  | 
| 513 |  |  |  |  |  |  | has more_metadata => ( | 
| 514 |  |  |  |  |  |  | is    => 'ro', | 
| 515 |  |  |  |  |  |  | isa   => 'HashRef', | 
| 516 |  |  |  |  |  |  | predicate => 'has_more_metadata', | 
| 517 |  |  |  |  |  |  | ); | 
| 518 |  |  |  |  |  |  |  | 
| 519 |  |  |  |  |  |  | #pod =attr meta_munger | 
| 520 |  |  |  |  |  |  | #pod | 
| 521 |  |  |  |  |  |  | #pod If given, this is a coderef that's called just before the CPAN::Meta data for | 
| 522 |  |  |  |  |  |  | #pod the dist is written to disk, an can be used to change things, especially into | 
| 523 |  |  |  |  |  |  | #pod invalid data.  It is expected to return the new content to serialize. | 
| 524 |  |  |  |  |  |  | #pod | 
| 525 |  |  |  |  |  |  | #pod It's called like this: | 
| 526 |  |  |  |  |  |  | #pod | 
| 527 |  |  |  |  |  |  | #pod   $coderef->($struct, { format => $format, version => $version }); | 
| 528 |  |  |  |  |  |  | #pod | 
| 529 |  |  |  |  |  |  | #pod ...where C<$struct> is the result of C<< $cpan_meta->as_struct >>. | 
| 530 |  |  |  |  |  |  | #pod C<$version> is the version number of the target metafile.  Normally, both | 
| 531 |  |  |  |  |  |  | #pod version 1.4 and 2 are requested.  C<$format> is either C<yaml> or C<json>. | 
| 532 |  |  |  |  |  |  | #pod | 
| 533 |  |  |  |  |  |  | #pod If the munger returns a string instead of a structure, it will be used as the | 
| 534 |  |  |  |  |  |  | #pod content of the file being written.  This lets you put all kinds of nonsense in | 
| 535 |  |  |  |  |  |  | #pod those meta files.  Have fun, go nuts! | 
| 536 |  |  |  |  |  |  | #pod | 
| 537 |  |  |  |  |  |  | #pod =cut | 
| 538 |  |  |  |  |  |  |  | 
| 539 |  |  |  |  |  |  | has meta_munger => ( | 
| 540 |  |  |  |  |  |  | isa => 'CodeRef', | 
| 541 |  |  |  |  |  |  | predicate => 'has_meta_munger', | 
| 542 |  |  |  |  |  |  | traits    => [ 'Code' ], | 
| 543 |  |  |  |  |  |  | handles   => { munge_meta => 'execute' }, | 
| 544 |  |  |  |  |  |  | ); | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | has _cpan_meta => ( | 
| 547 |  |  |  |  |  |  | is => 'ro', | 
| 548 |  |  |  |  |  |  | isa => 'CPAN::Meta', | 
| 549 |  |  |  |  |  |  | lazy_build => 1, | 
| 550 |  |  |  |  |  |  | ); | 
| 551 |  |  |  |  |  |  |  | 
| 552 |  |  |  |  |  |  | sub _build__cpan_meta { | 
| 553 | 19 |  |  | 19 |  | 109 | my ($self) = @_; | 
| 554 | 19 |  |  |  |  | 719 | my $meta = { | 
| 555 |  |  |  |  |  |  | 'meta-spec' => { version => '2' }, | 
| 556 |  |  |  |  |  |  | dynamic_config => 0, | 
| 557 |  |  |  |  |  |  | author => [ $self->authors ], # plural attribute that derefs | 
| 558 |  |  |  |  |  |  | }; | 
| 559 |  |  |  |  |  |  | # required fields | 
| 560 | 19 |  |  |  |  | 70 | for my $key ( qw/abstract license name release_status version/ ) { | 
| 561 | 95 |  |  |  |  | 2492 | $meta->{$key} = $self->$key; | 
| 562 |  |  |  |  |  |  | } | 
| 563 |  |  |  |  |  |  | # optional fields | 
| 564 | 19 |  |  |  |  | 59 | for my $key ( qw/prereqs x_authority/ ) { | 
| 565 | 38 |  |  |  |  | 1183 | my $value = $self->$key; | 
| 566 | 38 | 100 |  |  |  | 201 | $meta->{$key} = $value if $value; | 
| 567 |  |  |  |  |  |  | } | 
| 568 |  |  |  |  |  |  |  | 
| 569 | 19 | 100 | 66 |  |  | 533 | if ($self->provides && $self->include_provides_in_meta) { | 
| 570 | 1 |  |  |  |  | 28 | $meta->{provides} = $self->provides; | 
| 571 |  |  |  |  |  |  | } | 
| 572 |  |  |  |  |  |  |  | 
| 573 | 19 |  |  |  |  | 212 | my $cpanmeta = CPAN::Meta->new( $meta, {lazy_validation => 1} ); | 
| 574 | 19 | 50 |  |  |  | 24928 | return $cpanmeta unless $self->has_more_metadata; | 
| 575 |  |  |  |  |  |  |  | 
| 576 | 0 |  |  |  |  | 0 | return CPAN::Meta->new( | 
| 577 |  |  |  |  |  |  | CPAN::Meta::Merge->new(default_version => 2)->merge( | 
| 578 |  |  |  |  |  |  | $cpanmeta, | 
| 579 |  |  |  |  |  |  | $self->more_metadata, | 
| 580 |  |  |  |  |  |  | ), | 
| 581 |  |  |  |  |  |  | { lazy_validation => 1 } | 
| 582 |  |  |  |  |  |  | ); | 
| 583 |  |  |  |  |  |  | } | 
| 584 |  |  |  |  |  |  |  | 
| 585 |  |  |  |  |  |  | has _extras => ( | 
| 586 |  |  |  |  |  |  | isa  => 'ArrayRef[Module::Faker::File]', | 
| 587 |  |  |  |  |  |  | lazy => 1, | 
| 588 |  |  |  |  |  |  | traits    => [ 'Array' ], | 
| 589 |  |  |  |  |  |  | handles   => { _extras => 'elements' }, | 
| 590 |  |  |  |  |  |  | default   => sub { | 
| 591 |  |  |  |  |  |  | my ($self) = @_; | 
| 592 |  |  |  |  |  |  | my @files; | 
| 593 |  |  |  |  |  |  |  | 
| 594 |  |  |  |  |  |  | for my $filename (qw(Makefile.PL t/00-nop.t)) { | 
| 595 |  |  |  |  |  |  | next if grep { $_ eq $filename } $self->omitted_files; | 
| 596 |  |  |  |  |  |  | push @files, $self->_file_class->new({ | 
| 597 |  |  |  |  |  |  | filename => $filename, | 
| 598 |  |  |  |  |  |  | content  => Module::Faker::Heavy->_render( | 
| 599 |  |  |  |  |  |  | $filename, | 
| 600 |  |  |  |  |  |  | { dist => $self }, | 
| 601 |  |  |  |  |  |  | ), | 
| 602 |  |  |  |  |  |  | }); | 
| 603 |  |  |  |  |  |  | } | 
| 604 |  |  |  |  |  |  |  | 
| 605 |  |  |  |  |  |  | unless ( grep { $_ eq 'META.json' } $self->omitted_files ) { | 
| 606 |  |  |  |  |  |  | push @files, $self->_file_class->new({ | 
| 607 |  |  |  |  |  |  | filename => 'META.json', | 
| 608 |  |  |  |  |  |  | content  => $self->_meta_file_content(json => 2), | 
| 609 |  |  |  |  |  |  | }); | 
| 610 |  |  |  |  |  |  | } | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  | unless ( grep { $_ eq 'META.yml' } $self->omitted_files ) { | 
| 613 |  |  |  |  |  |  | push @files, $self->_file_class->new({ | 
| 614 |  |  |  |  |  |  | filename => 'META.yml', | 
| 615 |  |  |  |  |  |  | content  => $self->_meta_file_content(yaml => 1.4), | 
| 616 |  |  |  |  |  |  | }); | 
| 617 |  |  |  |  |  |  | } | 
| 618 |  |  |  |  |  |  |  | 
| 619 |  |  |  |  |  |  | return \@files; | 
| 620 |  |  |  |  |  |  | }, | 
| 621 |  |  |  |  |  |  | ); | 
| 622 |  |  |  |  |  |  |  | 
| 623 |  |  |  |  |  |  | # This code is based on the code in CPAN::Meta v2.150010 | 
| 624 |  |  |  |  |  |  | # -- rjbs, 2019-04-28 | 
| 625 |  |  |  |  |  |  | sub _meta_file_content { | 
| 626 | 36 |  |  | 36 |  | 93 | my ($self, $format, $version) = @_; | 
| 627 |  |  |  |  |  |  |  | 
| 628 | 36 |  |  |  |  | 925 | my $meta = $self->_cpan_meta; | 
| 629 |  |  |  |  |  |  |  | 
| 630 | 36 |  |  |  |  | 67 | my $struct; | 
| 631 | 36 | 100 |  |  |  | 138 | if ($meta->meta_spec_version ne $version) { | 
| 632 | 17 |  |  |  |  | 738 | $struct = CPAN::Meta::Converter->new($meta->as_struct) | 
| 633 |  |  |  |  |  |  | ->convert(version => $version); | 
| 634 |  |  |  |  |  |  | } else { | 
| 635 | 19 |  |  |  |  | 769 | $struct = $meta->as_struct; | 
| 636 |  |  |  |  |  |  | } | 
| 637 |  |  |  |  |  |  |  | 
| 638 | 36 | 50 |  |  |  | 25757 | if ($self->has_meta_munger) { | 
| 639 |  |  |  |  |  |  | # Is that dclone() paranoia?  Maybe. -- rjbs, 2019-04-28 | 
| 640 | 0 |  |  |  |  | 0 | $struct = $self->munge_meta( | 
| 641 |  |  |  |  |  |  | dclone($struct), | 
| 642 |  |  |  |  |  |  | { | 
| 643 |  |  |  |  |  |  | format  => $format, | 
| 644 |  |  |  |  |  |  | version => $version | 
| 645 |  |  |  |  |  |  | }, | 
| 646 |  |  |  |  |  |  | ); | 
| 647 |  |  |  |  |  |  |  | 
| 648 | 0 | 0 |  |  |  | 0 | return $struct unless ref $struct; | 
| 649 |  |  |  |  |  |  | } | 
| 650 |  |  |  |  |  |  |  | 
| 651 | 36 |  |  |  |  | 84 | my ($data, $backend); | 
| 652 | 36 | 100 |  |  |  | 139 | if ($format eq 'json') { | 
|  |  | 50 |  |  |  |  |  | 
| 653 | 19 |  |  |  |  | 112 | $backend = Parse::CPAN::Meta->json_backend(); | 
| 654 | 19 |  |  |  |  | 58222 | local $struct->{x_serialization_backend} = sprintf '%s version %s', | 
| 655 |  |  |  |  |  |  | $backend, $backend->VERSION; | 
| 656 | 19 |  |  |  |  | 134 | $data = $backend->new->pretty->canonical->encode($struct); | 
| 657 |  |  |  |  |  |  | } elsif ($format eq 'yaml') { | 
| 658 | 17 |  |  |  |  | 94 | $backend = Parse::CPAN::Meta->yaml_backend(); | 
| 659 | 17 |  |  |  |  | 7020 | local $struct->{x_serialization_backend} = sprintf '%s version %s', | 
| 660 |  |  |  |  |  |  | $backend, $backend->VERSION; | 
| 661 | 8 |  |  | 8 |  | 75 | $data = eval { no strict 'refs'; &{"$backend\::Dump"}($struct) }; | 
|  | 8 |  |  |  |  | 19 |  | 
|  | 8 |  |  |  |  | 6149 |  | 
|  | 17 |  |  |  |  | 57 |  | 
|  | 17 |  |  |  |  | 36 |  | 
|  | 17 |  |  |  |  | 127 |  | 
| 662 | 17 | 50 |  |  |  | 11973 | if ( $@ ) { | 
| 663 | 0 | 0 |  |  |  | 0 | croak($backend->can('errstr') ? $backend->errstr : $@); | 
| 664 |  |  |  |  |  |  | } | 
| 665 |  |  |  |  |  |  | } else { | 
| 666 | 0 |  |  |  |  | 0 | confess "unknown meta format: $format" | 
| 667 |  |  |  |  |  |  | } | 
| 668 |  |  |  |  |  |  |  | 
| 669 | 36 |  |  |  |  | 17130 | return $data; | 
| 670 |  |  |  |  |  |  | } | 
| 671 |  |  |  |  |  |  |  | 
| 672 |  |  |  |  |  |  | #pod =method from_file | 
| 673 |  |  |  |  |  |  | #pod | 
| 674 |  |  |  |  |  |  | #pod   my $dist = Module::Faker::Dist->from_file($filename); | 
| 675 |  |  |  |  |  |  | #pod | 
| 676 |  |  |  |  |  |  | #pod Given a filename with dist configuration, this builds the dist described by the | 
| 677 |  |  |  |  |  |  | #pod file. | 
| 678 |  |  |  |  |  |  | #pod | 
| 679 |  |  |  |  |  |  | #pod Given a file ending in C<yaml> or C<yml> or C<json>, it's treated as a | 
| 680 |  |  |  |  |  |  | #pod CPAN::Meta file and interpreted as such.  The key C<X_Module_Faker> can be | 
| 681 |  |  |  |  |  |  | #pod present to provide attributes that don't match data found in a meta file. | 
| 682 |  |  |  |  |  |  | #pod | 
| 683 |  |  |  |  |  |  | #pod Given a file ending in C<dist>, all the configuration comes from the filename, | 
| 684 |  |  |  |  |  |  | #pod which should look like this: | 
| 685 |  |  |  |  |  |  | #pod | 
| 686 |  |  |  |  |  |  | #pod   AUTHOR_Dist-Name-1.234.tar.gz.dist | 
| 687 |  |  |  |  |  |  | #pod | 
| 688 |  |  |  |  |  |  | #pod =cut | 
| 689 |  |  |  |  |  |  |  | 
| 690 |  |  |  |  |  |  | # TODO: make this a registry -- rjbs, 2008-03-12 | 
| 691 |  |  |  |  |  |  | my %HANDLER_FOR = ( | 
| 692 |  |  |  |  |  |  | yaml => '_from_meta_file', | 
| 693 |  |  |  |  |  |  | yml  => '_from_meta_file', | 
| 694 |  |  |  |  |  |  | json => '_from_meta_file', | 
| 695 |  |  |  |  |  |  | dist => '_from_distnameinfo' | 
| 696 |  |  |  |  |  |  | ); | 
| 697 |  |  |  |  |  |  |  | 
| 698 |  |  |  |  |  |  | sub from_file { | 
| 699 | 21 |  |  | 21 | 1 | 122501 | my ($self, $filename) = @_; | 
| 700 |  |  |  |  |  |  |  | 
| 701 | 21 |  |  |  |  | 147 | my ($ext) = $filename =~ /.*\.(.+?)\z/; | 
| 702 |  |  |  |  |  |  |  | 
| 703 |  |  |  |  |  |  | Carp::croak "don't know how to handle file $filename" | 
| 704 | 21 | 50 | 33 |  |  | 177 | unless $ext and my $method = $HANDLER_FOR{$ext}; | 
| 705 |  |  |  |  |  |  |  | 
| 706 | 21 |  |  |  |  | 101 | $self->$method($filename); | 
| 707 |  |  |  |  |  |  | } | 
| 708 |  |  |  |  |  |  |  | 
| 709 |  |  |  |  |  |  | sub _from_distnameinfo { | 
| 710 | 2 |  |  | 2 |  | 6 | my ($self, $filename) = @_; | 
| 711 | 2 |  |  |  |  | 12 | $filename = file($filename)->basename; | 
| 712 | 2 |  |  |  |  | 360 | $filename =~ s/\.dist$//; | 
| 713 |  |  |  |  |  |  |  | 
| 714 | 2 |  |  |  |  | 9 | my ($author, $path) = split /_/, $filename, 2; | 
| 715 |  |  |  |  |  |  |  | 
| 716 | 2 |  |  |  |  | 16 | my $dni = CPAN::DistnameInfo->new($path); | 
| 717 |  |  |  |  |  |  |  | 
| 718 | 2 |  |  |  |  | 160 | return $self->new({ | 
| 719 |  |  |  |  |  |  | name     => $dni->dist, | 
| 720 |  |  |  |  |  |  | version  => $dni->version, | 
| 721 |  |  |  |  |  |  | abstract => sprintf('the %s dist', $dni->dist), | 
| 722 |  |  |  |  |  |  | archive_ext => $dni->extension, | 
| 723 |  |  |  |  |  |  | cpan_author => $author, | 
| 724 |  |  |  |  |  |  | }); | 
| 725 |  |  |  |  |  |  | } | 
| 726 |  |  |  |  |  |  |  | 
| 727 |  |  |  |  |  |  | sub _from_meta_file { | 
| 728 | 19 |  |  | 19 |  | 56 | my ($self, $filename) = @_; | 
| 729 |  |  |  |  |  |  |  | 
| 730 | 19 |  |  |  |  | 153 | my $data = Parse::CPAN::Meta->load_file($filename); | 
| 731 | 19 |  | 100 |  |  | 103147 | my $extra = (delete $data->{X_Module_Faker}) || {}; | 
| 732 | 19 |  |  |  |  | 306 | my $dist = $self->new({ %$data, %$extra }); | 
| 733 |  |  |  |  |  |  | } | 
| 734 |  |  |  |  |  |  |  | 
| 735 |  |  |  |  |  |  | sub _flat_prereqs { | 
| 736 | 19 |  |  | 19 |  | 3114 | my ($self) = @_; | 
| 737 | 19 |  |  |  |  | 699 | my $prereqs = $self->_cpan_meta->effective_prereqs; | 
| 738 | 19 |  |  |  |  | 3462 | my $req = CPAN::Meta::Requirements->new; | 
| 739 | 19 |  |  |  |  | 330 | for my $phase ( qw/runtime build test/ ) { | 
| 740 | 57 |  |  |  |  | 2939 | $req->add_requirements( $prereqs->requirements_for( $phase, 'requires' ) ); | 
| 741 |  |  |  |  |  |  | } | 
| 742 | 19 |  |  |  |  | 1201 | return %{ $req->as_string_hash }; | 
|  | 19 |  |  |  |  | 76 |  | 
| 743 |  |  |  |  |  |  | } | 
| 744 |  |  |  |  |  |  |  | 
| 745 |  |  |  |  |  |  | #pod =method from_struct | 
| 746 |  |  |  |  |  |  | #pod | 
| 747 |  |  |  |  |  |  | #pod   my $dist = Module::Faker::Dist->from_struct(\%arg); | 
| 748 |  |  |  |  |  |  | #pod | 
| 749 |  |  |  |  |  |  | #pod This is sugar over C<new>, working like this: | 
| 750 |  |  |  |  |  |  | #pod | 
| 751 |  |  |  |  |  |  | #pod =for :list | 
| 752 |  |  |  |  |  |  | #pod * packages version defaults to the dist version unless specified | 
| 753 |  |  |  |  |  |  | #pod * packages for dist Foo-Bar defaults to Foo::Bar unless specified | 
| 754 |  |  |  |  |  |  | #pod * if specified, packages is an L<optlist|Data::OptList> | 
| 755 |  |  |  |  |  |  | #pod | 
| 756 |  |  |  |  |  |  | #pod =cut | 
| 757 |  |  |  |  |  |  |  | 
| 758 |  |  |  |  |  |  | sub from_struct { | 
| 759 | 0 |  |  | 0 | 1 |  | my ($self, $arg) = @_; | 
| 760 |  |  |  |  |  |  |  | 
| 761 | 0 | 0 |  |  |  |  | my $version = exists $arg->{version} ? $arg->{version} : $DEFAULT_VERSION; | 
| 762 |  |  |  |  |  |  |  | 
| 763 |  |  |  |  |  |  | my $specs = Data::OptList::mkopt( | 
| 764 |  |  |  |  |  |  | ! exists $arg->{packages} ? [ __dist_to_pkg($arg->{name}) ] | 
| 765 |  |  |  |  |  |  | : ref $arg->{packages}      ? $arg->{packages} | 
| 766 | 0 | 0 |  |  |  |  | : defined $arg->{packages}  ? [ $arg->{packages} ] | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 767 |  |  |  |  |  |  | :                             () | 
| 768 |  |  |  |  |  |  | ); | 
| 769 |  |  |  |  |  |  |  | 
| 770 | 0 |  |  |  |  |  | my @packages; | 
| 771 | 0 |  |  |  |  |  | for my $spec (@$specs) { | 
| 772 | 0 | 0 |  |  |  |  | my %spec = $spec->[1] ? %{ $spec->[1] } : (); | 
|  | 0 |  |  |  |  |  |  | 
| 773 |  |  |  |  |  |  |  | 
| 774 |  |  |  |  |  |  | push @packages, Module::Faker::Package->new({ | 
| 775 |  |  |  |  |  |  | name => $spec->[0], | 
| 776 |  |  |  |  |  |  | in_file => __pkg_to_file($spec->[0]), # to be overridden below if needed | 
| 777 |  |  |  |  |  |  | %spec, | 
| 778 | 0 | 0 |  |  |  |  | version => (exists $spec{version} ? $spec{version} : $version), | 
| 779 |  |  |  |  |  |  | }); | 
| 780 |  |  |  |  |  |  | } | 
| 781 |  |  |  |  |  |  |  | 
| 782 | 0 |  |  |  |  |  | return $self->new({ | 
| 783 |  |  |  |  |  |  | %$arg, | 
| 784 |  |  |  |  |  |  | version   => $version, | 
| 785 |  |  |  |  |  |  | packages  => \@packages, | 
| 786 |  |  |  |  |  |  | }); | 
| 787 |  |  |  |  |  |  | } | 
| 788 |  |  |  |  |  |  |  | 
| 789 |  |  |  |  |  |  | 1; | 
| 790 |  |  |  |  |  |  |  | 
| 791 |  |  |  |  |  |  | # vim: ts=2 sts=2 sw=2 et: | 
| 792 |  |  |  |  |  |  |  | 
| 793 |  |  |  |  |  |  | __END__ | 
| 794 |  |  |  |  |  |  |  | 
| 795 |  |  |  |  |  |  | =pod | 
| 796 |  |  |  |  |  |  |  | 
| 797 |  |  |  |  |  |  | =encoding UTF-8 | 
| 798 |  |  |  |  |  |  |  | 
| 799 |  |  |  |  |  |  | =head1 NAME | 
| 800 |  |  |  |  |  |  |  | 
| 801 |  |  |  |  |  |  | Module::Faker::Dist - a fake CPAN distribution | 
| 802 |  |  |  |  |  |  |  | 
| 803 |  |  |  |  |  |  | =head1 VERSION | 
| 804 |  |  |  |  |  |  |  | 
| 805 |  |  |  |  |  |  | version 0.022 | 
| 806 |  |  |  |  |  |  |  | 
| 807 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 808 |  |  |  |  |  |  |  | 
| 809 |  |  |  |  |  |  | Building one dist at a time makes plenty of sense, so Module::Faker::Dist makes | 
| 810 |  |  |  |  |  |  | it easy.  Building dists from definitions in files is also useful for doing | 
| 811 |  |  |  |  |  |  | things in bulk (see L<CPAN::Faker>), so there are a bunch of ways to build | 
| 812 |  |  |  |  |  |  | dists from a definition in a file. | 
| 813 |  |  |  |  |  |  |  | 
| 814 |  |  |  |  |  |  | # Build from a META.yml or META.json file, or the delightful | 
| 815 |  |  |  |  |  |  | # AUTHOR_Foo-Bar-1.234.tar.gz.dist file, which can be zero bytes and gets | 
| 816 |  |  |  |  |  |  | # all the relevant data from the filename. | 
| 817 |  |  |  |  |  |  | my $dist = Module::Faker::Dist->from_file($filename); | 
| 818 |  |  |  |  |  |  |  | 
| 819 |  |  |  |  |  |  | META files can contain a key called X_Module_Faker that contains attributes to | 
| 820 |  |  |  |  |  |  | use in constructing the dist.  C<dist> files can contain anything you want, but | 
| 821 |  |  |  |  |  |  | the contents won't do a thing. | 
| 822 |  |  |  |  |  |  |  | 
| 823 |  |  |  |  |  |  | You can use the C<new> method on Module::Faker::Dist, of course, but it's a bit | 
| 824 |  |  |  |  |  |  | of a pain.  You might, instead, want to use C<from_struct>, which is very close | 
| 825 |  |  |  |  |  |  | to C<new>, but with more sugar. | 
| 826 |  |  |  |  |  |  |  | 
| 827 |  |  |  |  |  |  | =head1 ATTRIBUTES | 
| 828 |  |  |  |  |  |  |  | 
| 829 |  |  |  |  |  |  | =head2 name | 
| 830 |  |  |  |  |  |  |  | 
| 831 |  |  |  |  |  |  | This is the name of the dist.  It will usually look like C<Foo-Bar>. | 
| 832 |  |  |  |  |  |  |  | 
| 833 |  |  |  |  |  |  | =head2 version | 
| 834 |  |  |  |  |  |  |  | 
| 835 |  |  |  |  |  |  | This is the version of the dist, usually some kind of versiony string like | 
| 836 |  |  |  |  |  |  | C<1.234> or maybe C<1.2.3>. | 
| 837 |  |  |  |  |  |  |  | 
| 838 |  |  |  |  |  |  | =head2 abstract | 
| 839 |  |  |  |  |  |  |  | 
| 840 |  |  |  |  |  |  | The abstract!  This is a short, pithy description of the distribution, usually | 
| 841 |  |  |  |  |  |  | less than a sentence. | 
| 842 |  |  |  |  |  |  |  | 
| 843 |  |  |  |  |  |  | =head2 release_status | 
| 844 |  |  |  |  |  |  |  | 
| 845 |  |  |  |  |  |  | This is the dist's release status.  (See L<CPAN::Meta::Spec>.)  It defaults to | 
| 846 |  |  |  |  |  |  | C<stable> but C<unstable> and C<testing> are valid values. | 
| 847 |  |  |  |  |  |  |  | 
| 848 |  |  |  |  |  |  | =head2 cpan_author | 
| 849 |  |  |  |  |  |  |  | 
| 850 |  |  |  |  |  |  | This is the PAUSE id of the author, like C<RJBS>. | 
| 851 |  |  |  |  |  |  |  | 
| 852 |  |  |  |  |  |  | =head2 archive_ext | 
| 853 |  |  |  |  |  |  |  | 
| 854 |  |  |  |  |  |  | This is the extension of the archive to build, when you build an archive.  This | 
| 855 |  |  |  |  |  |  | defaults to C<tar.gz>.  C<zip> should work, but right now it doesn't.  So | 
| 856 |  |  |  |  |  |  | probably stuck to C<tar.gz>.  It would be cool to support more attributes in | 
| 857 |  |  |  |  |  |  | the future. | 
| 858 |  |  |  |  |  |  |  | 
| 859 |  |  |  |  |  |  | =head2 append | 
| 860 |  |  |  |  |  |  |  | 
| 861 |  |  |  |  |  |  | This is an arrayref of hashrefs, each of which looks like: | 
| 862 |  |  |  |  |  |  |  | 
| 863 |  |  |  |  |  |  | { file => $filename, content => $character_string } | 
| 864 |  |  |  |  |  |  |  | 
| 865 |  |  |  |  |  |  | The content will be UTF-8 encoded and put into a file with the given name. | 
| 866 |  |  |  |  |  |  |  | 
| 867 |  |  |  |  |  |  | This feature is a bit weird.  Maybe it will go away eventually. | 
| 868 |  |  |  |  |  |  |  | 
| 869 |  |  |  |  |  |  | =head2 mtime | 
| 870 |  |  |  |  |  |  |  | 
| 871 |  |  |  |  |  |  | If given, this is the epoch seconds to which to set the mtime of the generated | 
| 872 |  |  |  |  |  |  | file.  This is useful in rare occasions. | 
| 873 |  |  |  |  |  |  |  | 
| 874 |  |  |  |  |  |  | =head2 x_authority | 
| 875 |  |  |  |  |  |  |  | 
| 876 |  |  |  |  |  |  | This is the C<X_Authority> header that gets put into the META files. | 
| 877 |  |  |  |  |  |  |  | 
| 878 |  |  |  |  |  |  | =head2 license | 
| 879 |  |  |  |  |  |  |  | 
| 880 |  |  |  |  |  |  | This is the meta spec license string for the distribution.  It defaults to | 
| 881 |  |  |  |  |  |  | C<perl_5>. | 
| 882 |  |  |  |  |  |  |  | 
| 883 |  |  |  |  |  |  | =head2 authors | 
| 884 |  |  |  |  |  |  |  | 
| 885 |  |  |  |  |  |  | This is an array of strings who are used as the authors in the dist metadata. | 
| 886 |  |  |  |  |  |  | The default is: | 
| 887 |  |  |  |  |  |  |  | 
| 888 |  |  |  |  |  |  | [ "AUTHOR <AUTHOR@cpan.local>" ] | 
| 889 |  |  |  |  |  |  |  | 
| 890 |  |  |  |  |  |  | ...where C<AUTHOR> is the C<cpan_author> of the dist. | 
| 891 |  |  |  |  |  |  |  | 
| 892 |  |  |  |  |  |  | =head2 include_provides_in_meta | 
| 893 |  |  |  |  |  |  |  | 
| 894 |  |  |  |  |  |  | This is a bool.  If true, the produced META files will include a C<provides> | 
| 895 |  |  |  |  |  |  | key based on the packages in the dist.  It defaults to false, to match the | 
| 896 |  |  |  |  |  |  | most common behavior of dists in the wild. | 
| 897 |  |  |  |  |  |  |  | 
| 898 |  |  |  |  |  |  | =head2 provides | 
| 899 |  |  |  |  |  |  |  | 
| 900 |  |  |  |  |  |  | This is a hashref that gets used as the C<provides> in the metadata. | 
| 901 |  |  |  |  |  |  |  | 
| 902 |  |  |  |  |  |  | If no provided, it is built from the C<packages> provided in construction. | 
| 903 |  |  |  |  |  |  |  | 
| 904 |  |  |  |  |  |  | If no packages were provided, for a dist named Foo-Bar, it defaults to: | 
| 905 |  |  |  |  |  |  |  | 
| 906 |  |  |  |  |  |  | { 'Foo::Bar' => { version => $DIST_VERSION, file => "lib/Foo/Bar.pm" } } | 
| 907 |  |  |  |  |  |  |  | 
| 908 |  |  |  |  |  |  | =head2 archive_basename | 
| 909 |  |  |  |  |  |  |  | 
| 910 |  |  |  |  |  |  | If written to disk, the archive will be written to... | 
| 911 |  |  |  |  |  |  |  | 
| 912 |  |  |  |  |  |  | $dist->archive_basename . '.' . $dist->archive_ext | 
| 913 |  |  |  |  |  |  |  | 
| 914 |  |  |  |  |  |  | The default is: | 
| 915 |  |  |  |  |  |  |  | 
| 916 |  |  |  |  |  |  | $dist->name . '.' . ($dist->version // 'undef') | 
| 917 |  |  |  |  |  |  |  | 
| 918 |  |  |  |  |  |  | =head2 omitted_files | 
| 919 |  |  |  |  |  |  |  | 
| 920 |  |  |  |  |  |  | If given, this is an arrayref of filenames that shouldn't be automatically | 
| 921 |  |  |  |  |  |  | generated and included. | 
| 922 |  |  |  |  |  |  |  | 
| 923 |  |  |  |  |  |  | =head2 packages | 
| 924 |  |  |  |  |  |  |  | 
| 925 |  |  |  |  |  |  | This is an array of L<Module::Faker::Package> objects.  It's built by | 
| 926 |  |  |  |  |  |  | C<provides> if needed, but you might want to look at using the | 
| 927 |  |  |  |  |  |  | C<L</from_struct>> method to set it up. | 
| 928 |  |  |  |  |  |  |  | 
| 929 |  |  |  |  |  |  | =head2 more_metadata | 
| 930 |  |  |  |  |  |  |  | 
| 931 |  |  |  |  |  |  | This can be given as a hashref of data to merge into the CPAN::Meta files. | 
| 932 |  |  |  |  |  |  |  | 
| 933 |  |  |  |  |  |  | =head2 meta_munger | 
| 934 |  |  |  |  |  |  |  | 
| 935 |  |  |  |  |  |  | If given, this is a coderef that's called just before the CPAN::Meta data for | 
| 936 |  |  |  |  |  |  | the dist is written to disk, an can be used to change things, especially into | 
| 937 |  |  |  |  |  |  | invalid data.  It is expected to return the new content to serialize. | 
| 938 |  |  |  |  |  |  |  | 
| 939 |  |  |  |  |  |  | It's called like this: | 
| 940 |  |  |  |  |  |  |  | 
| 941 |  |  |  |  |  |  | $coderef->($struct, { format => $format, version => $version }); | 
| 942 |  |  |  |  |  |  |  | 
| 943 |  |  |  |  |  |  | ...where C<$struct> is the result of C<< $cpan_meta->as_struct >>. | 
| 944 |  |  |  |  |  |  | C<$version> is the version number of the target metafile.  Normally, both | 
| 945 |  |  |  |  |  |  | version 1.4 and 2 are requested.  C<$format> is either C<yaml> or C<json>. | 
| 946 |  |  |  |  |  |  |  | 
| 947 |  |  |  |  |  |  | If the munger returns a string instead of a structure, it will be used as the | 
| 948 |  |  |  |  |  |  | content of the file being written.  This lets you put all kinds of nonsense in | 
| 949 |  |  |  |  |  |  | those meta files.  Have fun, go nuts! | 
| 950 |  |  |  |  |  |  |  | 
| 951 |  |  |  |  |  |  | =head1 METHODS | 
| 952 |  |  |  |  |  |  |  | 
| 953 |  |  |  |  |  |  | =head2 modules | 
| 954 |  |  |  |  |  |  |  | 
| 955 |  |  |  |  |  |  | This produces and returns a list of L<Module::Faker::Module> objects, | 
| 956 |  |  |  |  |  |  | representing modules.  Modules, if you're not as steeped in CPAN toolchain | 
| 957 |  |  |  |  |  |  | nonsense, are the C<.pm> files in which packages are defined. | 
| 958 |  |  |  |  |  |  |  | 
| 959 |  |  |  |  |  |  | These are produced by combining the packages from C<L</packages>> into files | 
| 960 |  |  |  |  |  |  | based on their C<in_file> attributes. | 
| 961 |  |  |  |  |  |  |  | 
| 962 |  |  |  |  |  |  | =head2 C<make_dist_dir> | 
| 963 |  |  |  |  |  |  |  | 
| 964 |  |  |  |  |  |  | my $directory_name = $dist->make_dist_dir(\%arg); | 
| 965 |  |  |  |  |  |  |  | 
| 966 |  |  |  |  |  |  | This returns the name of a directory into which the dist's contents have been | 
| 967 |  |  |  |  |  |  | written.  If a C<dir> argument is provided, the dist will be written to a | 
| 968 |  |  |  |  |  |  | directory beneath that dir.  Otherwise, it will be written below a temporary | 
| 969 |  |  |  |  |  |  | directory. | 
| 970 |  |  |  |  |  |  |  | 
| 971 |  |  |  |  |  |  | =head2 make_archive | 
| 972 |  |  |  |  |  |  |  | 
| 973 |  |  |  |  |  |  | my $archive_filename = $dist->make_archive(\%arg); | 
| 974 |  |  |  |  |  |  |  | 
| 975 |  |  |  |  |  |  | This writes the dist archive file, like a tarball or zip file.  If a C<dir> | 
| 976 |  |  |  |  |  |  | argument is given, it will be written in that directory.  Otherwise, it will be | 
| 977 |  |  |  |  |  |  | written to a temporary directory.  If the C<author_prefix> argument is given | 
| 978 |  |  |  |  |  |  | and true, it will be written under a hashed author dir, like: | 
| 979 |  |  |  |  |  |  |  | 
| 980 |  |  |  |  |  |  | U/US/USERID/Foo-Bar-1.23.tar.gz | 
| 981 |  |  |  |  |  |  |  | 
| 982 |  |  |  |  |  |  | =head2 from_file | 
| 983 |  |  |  |  |  |  |  | 
| 984 |  |  |  |  |  |  | my $dist = Module::Faker::Dist->from_file($filename); | 
| 985 |  |  |  |  |  |  |  | 
| 986 |  |  |  |  |  |  | Given a filename with dist configuration, this builds the dist described by the | 
| 987 |  |  |  |  |  |  | file. | 
| 988 |  |  |  |  |  |  |  | 
| 989 |  |  |  |  |  |  | Given a file ending in C<yaml> or C<yml> or C<json>, it's treated as a | 
| 990 |  |  |  |  |  |  | CPAN::Meta file and interpreted as such.  The key C<X_Module_Faker> can be | 
| 991 |  |  |  |  |  |  | present to provide attributes that don't match data found in a meta file. | 
| 992 |  |  |  |  |  |  |  | 
| 993 |  |  |  |  |  |  | Given a file ending in C<dist>, all the configuration comes from the filename, | 
| 994 |  |  |  |  |  |  | which should look like this: | 
| 995 |  |  |  |  |  |  |  | 
| 996 |  |  |  |  |  |  | AUTHOR_Dist-Name-1.234.tar.gz.dist | 
| 997 |  |  |  |  |  |  |  | 
| 998 |  |  |  |  |  |  | =head2 from_struct | 
| 999 |  |  |  |  |  |  |  | 
| 1000 |  |  |  |  |  |  | my $dist = Module::Faker::Dist->from_struct(\%arg); | 
| 1001 |  |  |  |  |  |  |  | 
| 1002 |  |  |  |  |  |  | This is sugar over C<new>, working like this: | 
| 1003 |  |  |  |  |  |  |  | 
| 1004 |  |  |  |  |  |  | =over 4 | 
| 1005 |  |  |  |  |  |  |  | 
| 1006 |  |  |  |  |  |  | =item * | 
| 1007 |  |  |  |  |  |  |  | 
| 1008 |  |  |  |  |  |  | packages version defaults to the dist version unless specified | 
| 1009 |  |  |  |  |  |  |  | 
| 1010 |  |  |  |  |  |  | =item * | 
| 1011 |  |  |  |  |  |  |  | 
| 1012 |  |  |  |  |  |  | packages for dist Foo-Bar defaults to Foo::Bar unless specified | 
| 1013 |  |  |  |  |  |  |  | 
| 1014 |  |  |  |  |  |  | =item * | 
| 1015 |  |  |  |  |  |  |  | 
| 1016 |  |  |  |  |  |  | if specified, packages is an L<optlist|Data::OptList> | 
| 1017 |  |  |  |  |  |  |  | 
| 1018 |  |  |  |  |  |  | =back | 
| 1019 |  |  |  |  |  |  |  | 
| 1020 |  |  |  |  |  |  | =head1 AUTHOR | 
| 1021 |  |  |  |  |  |  |  | 
| 1022 |  |  |  |  |  |  | Ricardo Signes <rjbs@cpan.org> | 
| 1023 |  |  |  |  |  |  |  | 
| 1024 |  |  |  |  |  |  | =head1 COPYRIGHT AND LICENSE | 
| 1025 |  |  |  |  |  |  |  | 
| 1026 |  |  |  |  |  |  | This software is copyright (c) 2008 by Ricardo Signes. | 
| 1027 |  |  |  |  |  |  |  | 
| 1028 |  |  |  |  |  |  | This is free software; you can redistribute it and/or modify it under | 
| 1029 |  |  |  |  |  |  | the same terms as the Perl 5 programming language system itself. | 
| 1030 |  |  |  |  |  |  |  | 
| 1031 |  |  |  |  |  |  | =cut |