<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">use strict;
use warnings;
use Carp;

package Software::LicenseUtils;
# ABSTRACT: little useful bits of code for licensey things
$Software::LicenseUtils::VERSION = '0.103010';
use File::Spec;
use IO::Dir;
use Module::Load;

#pod =method guess_license_from_pod
#pod
#pod   my @guesses = Software::LicenseUtils-&gt;guess_license_from_pod($pm_text);
#pod
#pod Given text containing POD, like a .pm file, this method will attempt to guess
#pod at the license under which the code is available.  This method will either
#pod a list of Software::License classes (or instances) or false.
#pod
#pod Calling this method in scalar context is a fatal error.
#pod
#pod =cut

my $_v = qr/(?:v(?:er(?:sion|\.))(?: |\.)?)/i;
my @phrases = (
  "under the same (?:terms|license) as perl $_v?6" =&gt; [],
  'under the same (?:terms|license) as (?:the )?perl'    =&gt; 'Perl_5',
  'affero g'                                    =&gt; 'AGPL_3',
  "GNU (?:general )?public license,? $_v?([123])" =&gt; sub { "GPL_$_[0]" },
  'GNU (?:general )?public license'             =&gt; [ map {"GPL_$_"} (1..3) ],
  "GNU (?:lesser|library) (?:general )?public license,? $_v?([23])\\D"  =&gt; sub {
    $_[0] == 2 ? 'LGPL_2_1' : $_[0] == 3 ? 'LGPL_3_0' : ()
  },
  'GNU (?:lesser|library) (?:general )?public license'  =&gt; [ qw(LGPL_2_1 LGPL_3_0) ],
  'BSD license'                =&gt; 'BSD',
  "Artistic license $_v?(\\d)" =&gt; sub { "Artistic_$_[0]_0" },
  'Artistic license'           =&gt; [ map { "Artistic_$_\_0" } (1..2) ],
  "LGPL,? $_v?(\\d)"             =&gt; sub {
    $_[0] == 2 ? 'LGPL_2_1' : $_[0] == 3 ? 'LGPL_3_0' : ()
  },
  'LGPL'                       =&gt; [ qw(LGPL_2_1 LGPL_3_0) ],
  "GPL,? $_v?(\\d)"              =&gt; sub { "GPL_$_[0]" },
  'GPL'                        =&gt; [ map { "GPL_$_" } (1..3) ],
  'BSD'                        =&gt; 'BSD',
  'Artistic'                   =&gt; [ map { "Artistic_$_\_0" } (1..2) ],
  'MIT'                        =&gt; 'MIT',
);

my %meta_keys  = ();
my %meta1_keys = ();
my %meta2_keys = ();

# find all known Software::License::* modules and get identification data
#
# XXX: Grepping over @INC is dangerous, as it means that someone can change the
# behavior of your code by installing a new library that you don't load.  rjbs
# is not a fan.  On the other hand, it will solve a real problem.  One better
# solution is to check "core" licenses first, then fall back, and to skip (but
# warn about) bogus libraries.  Another is, at least when testing S-L itself,
# to only scan lib/ blib. -- rjbs, 2013-10-20
for my $lib (map { "$_/Software/License" } @INC) {
  next unless -d $lib;
  for my $file (IO::Dir-&gt;new($lib)-&gt;read) {
    next unless $file =~ m{\.pm$};

    # if it fails, ignore it
    eval {
      (my $mod = $file) =~ s{\.pm$}{};
      my $class = "Software::License::$mod";
      load $class;
      $meta_keys{  $class-&gt;meta_name  }{$mod} = undef;
      $meta1_keys{ $class-&gt;meta_name  }{$mod} = undef;
      $meta_keys{  $class-&gt;meta2_name }{$mod} = undef;
      $meta2_keys{ $class-&gt;meta2_name }{$mod} = undef;
      my $name = $class-&gt;name;
      unshift @phrases, qr/\Q$name\E/, [$mod];
    };
  }
}

sub guess_license_from_pod {
  my ($class, $pm_text) = @_;
  die "can't call guess_license_* in scalar context" unless wantarray;
  return unless $pm_text =~ /
    (
      =head \d \s+
      (?:licen[cs]e|licensing|copyright|legal)\b
    )
  /ixmsg;

  my $header = $1;

	if (
		$pm_text =~ m/
      \G
      (
        .*?
      )
      (=head\\d.*|=cut.*|)
      \z
    /ixms
  ) {
		my $license_text = "$header$1";

    for (my $i = 0; $i &lt; @phrases; $i += 2) {
      my ($pattern, $license) = @phrases[ $i .. $i+1 ];
			$pattern =~ s{\s+}{\\s+}g
				unless ref $pattern eq 'Regexp';
			if ( $license_text =~ /$pattern/i ) {
        my $match = $1;
				# if ( $osi and $license_text =~ /All rights reserved/i ) {
				# 	warn "LEGAL WARNING: 'All rights reserved' may invalidate Open Source licenses. Consider removing it.";
				# }
        my @result = (ref $license||'') eq 'CODE'  ? $license-&gt;($match)
                   : (ref $license||'') eq 'ARRAY' ? @$license
                   :                                 $license;

        return unless @result;
				return map { "Software::License::$_" } sort @result;
			}
		}
	}

	return;
}

#pod =method guess_license_from_meta
#pod
#pod   my @guesses = Software::LicenseUtils-&gt;guess_license_from_meta($meta_str);
#pod
#pod Given the content of the META.(yml|json) file found in a CPAN distribution, this
#pod method makes a guess as to which licenses may apply to the distribution.  It
#pod will return a list of zero or more Software::License instances or classes.
#pod
#pod =cut

sub guess_license_from_meta {
  my ($class, $meta_text) = @_;
  die "can't call guess_license_* in scalar context" unless wantarray;

  my ($license_text) = $meta_text =~ m{\b["']?license["']?\s*:\s*["']?([a-z_0-9]+)["']?}gm;

  return unless $license_text and my $license = $meta_keys{ $license_text };

  return map { "Software::License::$_" } sort keys %$license;
}

{
  no warnings 'once';
  *guess_license_from_meta_yml = \&amp;guess_license_from_meta;
}

#pod =method guess_license_from_meta_key
#pod
#pod   my @guesses = Software::LicenseUtils-&gt;guess_license_from_meta_key($key, $v);
#pod
#pod This method returns zero or more Software::License classes known to use C&lt;$key&gt;
#pod as their META key.  If C&lt;$v&gt; is supplied, it specifies whether to treat C&lt;$key&gt;
#pod as a v1 or v2 meta entry.  Any value other than 1 or 2 will raise an exception.
#pod
#pod =cut

sub guess_license_from_meta_key {
  my ($self, $key, $v) = @_;

  my $src = (! defined $v) ? \%meta_keys
          : $v eq '1'      ? \%meta1_keys
          : $v eq '2'      ? \%meta2_keys
          : Carp::croak("illegal META version: $v");

  return unless $src-&gt;{$key};
  return map { "Software::License::$_" } sort keys %{ $src-&gt;{$key} };
}

my %short_name = (
  'Expat'      =&gt;  'Software::License::MIT',
  'GPL-1'      =&gt;  'Software::License::GPL_1',
  'GPL-2'      =&gt;  'Software::License::GPL_2',
  'GPL-3'      =&gt;  'Software::License::GPL_3',
  'LGPL-2'     =&gt;  'Software::License::LGPL_2',
  'LGPL-2.1'   =&gt;  'Software::License::LGPL_2_1',
  'LGPL-3'     =&gt;  'Software::License::LGPL_3_0',
  'LGPL-3.0'   =&gt;  'Software::License::LGPL_3_0',
  'Artistic'   =&gt;  'Software::License::Artistic_1_0',
  'Artistic-1' =&gt;  'Software::License::Artistic_1_0',
  'Artistic-2' =&gt;  'Software::License::Artistic_2_0',
  'GPL-1+'     =&gt;  [ 'Software::License::GPL_1',    or_later =&gt; 1 ],
  'GPL-2+'     =&gt;  [ 'Software::License::GPL_2',    or_later =&gt; 1 ],
  'GPL-3+'     =&gt;  [ 'Software::License::GPL_3',    or_later =&gt; 1 ],
  'LGPL-2+'    =&gt;  [ 'Software::License::LGPL_2',   or_later =&gt; 1 ],
  'LGPL-2.1+'  =&gt;  [ 'Software::License::LGPL_2_1', or_later =&gt; 1 ],
  'LGPL-3+'    =&gt;  [ 'Software::License::LGPL_3_0', or_later =&gt; 1 ],
  'LGPL-3.0+'  =&gt;  [ 'Software::License::LGPL_3_0', or_later =&gt; 1 ],
);

#pod =method new_from_short_name
#pod
#pod   my $license_object = Software::LicenseUtils-&gt;new_from_short_name( {
#pod      short_name =&gt; 'GPL-1',
#pod      holder =&gt; 'X. Ample'
#pod   }) ;
#pod
#pod Create a new L&lt;Software::License&gt; object from the license specified
#pod with C&lt;short_name&gt;. Known short license names are C&lt;GPL-*&gt;, C&lt;LGPL-*&gt; ,
#pod C&lt;Artistic&gt; and C&lt;Artistic-*&gt;
#pod
#pod =cut

sub new_from_short_name {
  my ( $class, $arg ) = @_;

  Carp::croak "no license short name specified"
    unless defined $arg-&gt;{short_name};
  my $subclass = my $short = delete $arg-&gt;{short_name};
  $subclass =~ s/[\-.]/_/g;

  my $info = $short_name{$short} || "Software::License::$subclass";
  my @infos = ref $info ? @$info : ($info);
  my $lic_file = my $lic_class = shift @infos;
  $lic_file =~ s!::!/!g;
  eval { require "$lic_file.pm"; } ;
  Carp::croak "Unknow license with short name $short ($@)" if $@;
  return $lic_class-&gt;new( { %$arg, @infos } );
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Software::LicenseUtils - little useful bits of code for licensey things

=head1 VERSION

version 0.103010

=head1 METHODS

=head2 guess_license_from_pod

  my @guesses = Software::LicenseUtils-&gt;guess_license_from_pod($pm_text);

Given text containing POD, like a .pm file, this method will attempt to guess
at the license under which the code is available.  This method will either
a list of Software::License classes (or instances) or false.

Calling this method in scalar context is a fatal error.

=head2 guess_license_from_meta

  my @guesses = Software::LicenseUtils-&gt;guess_license_from_meta($meta_str);

Given the content of the META.(yml|json) file found in a CPAN distribution, this
method makes a guess as to which licenses may apply to the distribution.  It
will return a list of zero or more Software::License instances or classes.

=head2 guess_license_from_meta_key

  my @guesses = Software::LicenseUtils-&gt;guess_license_from_meta_key($key, $v);

This method returns zero or more Software::License classes known to use C&lt;$key&gt;
as their META key.  If C&lt;$v&gt; is supplied, it specifies whether to treat C&lt;$key&gt;
as a v1 or v2 meta entry.  Any value other than 1 or 2 will raise an exception.

=head2 new_from_short_name

  my $license_object = Software::LicenseUtils-&gt;new_from_short_name( {
     short_name =&gt; 'GPL-1',
     holder =&gt; 'X. Ample'
  }) ;

Create a new L&lt;Software::License&gt; object from the license specified
with C&lt;short_name&gt;. Known short license names are C&lt;GPL-*&gt;, C&lt;LGPL-*&gt; ,
C&lt;Artistic&gt; and C&lt;Artistic-*&gt;. If the short name is not know, this
method will try to create a license object with C&lt;Software::License::&gt; and
the specified short name (e.g. C&lt;Software::License::MIT&gt; with
C&lt;&lt; short_name =&gt; 'MIT' &gt;&gt;.

=head1 AUTHOR

Ricardo Signes &lt;rjbs@cpan.org&gt;

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Ricardo Signes.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
</pre></body></html>