1package ExtUtils::Typemaps::Cmd;
2use 5.006001;
3use strict;
4use warnings;
5our $VERSION = '3.51';
6
7use ExtUtils::Typemaps;
8
9require Exporter;
10
11our @ISA = qw(Exporter);
12our @EXPORT = qw(embeddable_typemap);
13our %EXPORT_TAGS = (all => \@EXPORT);
14
15sub embeddable_typemap {
16  my @tms = @_;
17
18  # Get typemap objects
19  my @tm_objs = map [$_, _intuit_typemap_source($_)], @tms;
20
21  # merge or short-circuit
22  my $final_tm;
23  if (@tm_objs == 1) {
24    # just one, merge would be pointless
25    $final_tm = shift(@tm_objs)->[1];
26  }
27  else {
28    # multiple, need merge
29    $final_tm = ExtUtils::Typemaps->new;
30    foreach my $other_tm (@tm_objs) {
31      my ($tm_ident, $tm_obj) = @$other_tm;
32      eval {
33        $final_tm->merge(typemap => $tm_obj);
34        1
35      } or do {
36        my $err = $@ || 'Zombie error';
37        die "Failed to merge typ";
38      }
39    }
40  }
41
42  # stringify for embedding
43  return $final_tm->as_embedded_typemap();
44}
45
46sub _load_module {
47  my $name = shift;
48  return eval "require $name; 1";
49}
50
51SCOPE: {
52  my %sources = (
53    module => sub {
54      my $ident = shift;
55      my $tm;
56      if (/::/) { # looks like FQ module name, try that first
57        foreach my $module ($ident, "ExtUtils::Typemaps::$ident") {
58          if (_load_module($module)) {
59            eval { $tm = $module->new }
60              and return $tm;
61          }
62        }
63      }
64      else {
65        foreach my $module ("ExtUtils::Typemaps::$ident", "$ident") {
66          if (_load_module($module)) {
67            eval { $tm = $module->new }
68              and return $tm;
69          }
70        }
71      }
72      return();
73    },
74    file => sub {
75      my $ident = shift;
76      return unless -e $ident and -r _;
77      return ExtUtils::Typemaps->new(file => $ident);
78    },
79  );
80  # Try to find typemap either from module or file
81  sub _intuit_typemap_source {
82    my $identifier = shift;
83
84    my @locate_attempts;
85    if ($identifier =~ /::/ || $identifier !~ /[^\w_]/) {
86      @locate_attempts = qw(module file);
87    }
88    else {
89      @locate_attempts = qw(file module);
90    }
91
92    foreach my $source (@locate_attempts) {
93      my $tm = $sources{$source}->($identifier);
94      return $tm if defined $tm;
95    }
96
97    die "Unable to find typemap for '$identifier': "
98        . "Tried to load both as file or module and failed.\n";
99  }
100} # end SCOPE
101
102=head1 NAME
103
104ExtUtils::Typemaps::Cmd - Quick commands for handling typemaps
105
106=head1 SYNOPSIS
107
108From XS:
109
110  INCLUDE_COMMAND: $^X -MExtUtils::Typemaps::Cmd \
111                   -e "print embeddable_typemap(q{Excommunicated})"
112
113Loads C<ExtUtils::Typemaps::Excommunicated>, instantiates an object,
114and dumps it as an embeddable typemap for use directly in your XS file.
115
116=head1 DESCRIPTION
117
118This is a helper module for L<ExtUtils::Typemaps> for quick
119one-liners, specifically for inclusion of shared typemaps
120that live on CPAN into an XS file (see SYNOPSIS).
121
122For this reason, the following functions are exported by default:
123
124=head1 EXPORTED FUNCTIONS
125
126=head2 embeddable_typemap
127
128Given a list of identifiers, C<embeddable_typemap>
129tries to load typemaps from a file of the given name(s),
130or from a module that is an C<ExtUtils::Typemaps> subclass.
131
132Returns a string representation of the merged typemaps that can
133be included verbatim into XS. Example:
134
135  print embeddable_typemap(
136    "Excommunicated", "ExtUtils::Typemaps::Basic", "./typemap"
137  );
138
139This will try to load a module C<ExtUtils::Typemaps::Excommunicated>
140and use it as an C<ExtUtils::Typemaps> subclass. If that fails, it'll
141try loading C<Excommunicated> as a module, if that fails, it'll try to
142read a file called F<Excommunicated>. It'll work similarly for the
143second argument, but the third will be loaded as a file first.
144
145After loading all typemap files or modules, it will merge them in the
146specified order and dump the result as an embeddable typemap.
147
148=head1 SEE ALSO
149
150L<ExtUtils::Typemaps>
151
152L<perlxs>
153
154=head1 AUTHOR
155
156Steffen Mueller C<<smueller@cpan.org>>
157
158=head1 COPYRIGHT & LICENSE
159
160Copyright 2012 Steffen Mueller
161
162This program is free software; you can redistribute it and/or
163modify it under the same terms as Perl itself.
164
165=cut
166
1671;
168
169