AI-Ollama-Client

 view release on metacpan or  search on metacpan

MANIFEST  view on Meta::CPAN

ollama/ollama-curated.json
ollama/ollama-curated.yaml
openapi/petstore-expanded.yaml
README
README.mkdn
scripts/code-completion.pl
scripts/describe-image.pl
scripts/music-genre-json.pl
t/00-load.t
t/generate.request
t/testdata/objectdetection.jpg
testrules.yml
xt/99-changes.t
xt/99-compile.t
xt/99-manifest.t
xt/99-minimumversion.t
xt/99-pod.t
xt/99-synopsis.t
xt/99-test-prerequisites.t
xt/99-todo.t
xt/99-unix-text.t
xt/99-versions.t
xt/copyright.t
xt/meta-lint.t

META.json  view on Meta::CPAN

            "OpenAPI::Modern" : "0",
            "PerlX::Maybe" : "0",
            "Role::EventEmitter" : "0",
            "URI::Template" : "0",
            "YAML::PP" : "0",
            "experimental" : "0.031",
            "perl" : "5.020",
            "stable" : "0.031"
         }
      },
      "test" : {
         "requires" : {
            "Test2::V0" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/Corion/AI-Ollama-Client/issues"
      },

Makefile.PL  view on Meta::CPAN

# Normalize version strings like 6.30_02 to 6.3002,
# so that we can do numerical comparisons on it.
my $eumm_version = $ExtUtils::MakeMaker::VERSION;
$eumm_version =~ s/_//;

my $module = 'AI::Ollama::Client';
(my $main_file = "lib/$module.pm" ) =~ s!::!/!g;
(my $distbase = $module) =~ s!::!-!g;
my $distlink = $distbase;

my @tests = map { glob $_ } 't/*.t', 't/*/*.t';

my %module = (
    NAME                => $module,
    AUTHOR              => q{Max Maischein <corion@cpan.org>},
    VERSION_FROM        => $main_file,
    ABSTRACT_FROM       => $main_file,
    META_MERGE => {
        "meta-spec" => { version => 2 },
        resources => {
            repository => {

Makefile.PL  view on Meta::CPAN

        'URI::Template'       => 0,
        'YAML::PP'            => 0,
    },
    TEST_REQUIRES => {
        'Test2::V0'    => 0,
    },

    dist                => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
    clean               => { FILES => "$distbase-*" },

    test            => { TESTS => join( ' ', @tests ) },
);

# This is so that we can do
#     require 'Makefile.PL'
# and then call get_module_info

sub get_module_info { %module }

if( ! caller ) {
    require File::ShareDir::Install;

Makefile.PL  view on Meta::CPAN


  cpanm .
  cpan  .
  cpanp -i .

Consult https://www.cpan.org/modules/INSTALL.html for further instruction.
Should you wish to install this module manually, the procedure is

  perl Makefile.PL
  make
  make test
  make install

INSTALL
            pod_section($file, 'REPOSITORY'),
            pod_section($file, 'SUPPORT'),
            pod_section($file, 'TALKS'),
            pod_section($file, 'KNOWN ISSUES'),
            pod_section($file, 'BUG TRACKER'),
            pod_section($file, 'CONTRIBUTING'),
            pod_section($file, 'SEE ALSO'),

README  view on Meta::CPAN


  cpanm .
  cpan  .
  cpanp -i .

Consult https://www.cpan.org/modules/INSTALL.html for further instruction.
Should you wish to install this module manually, the procedure is

  perl Makefile.PL
  make
  make test
  make install









README.mkdn  view on Meta::CPAN

    say $info->modelfile;

Show details about a model including modelfile, template, parameters, license, and system prompt.

Returns a [AI::Ollama::ModelInfo](https://metacpan.org/pod/AI%3A%3AOllama%3A%3AModelInfo).

## `listModels`

    my $info = $client->listModels()->get;
    for my $model ($info->models->@*) {
        say $model->model; # llama2:latest
    }

List models that are available locally.

Returns a [AI::Ollama::ModelsResponse](https://metacpan.org/pod/AI%3A%3AOllama%3A%3AModelsResponse).

lib/AI/Ollama/Client.pm  view on Meta::CPAN

Show details about a model including modelfile, template, parameters, license, and system prompt.

Returns a L<< AI::Ollama::ModelInfo >>.

=cut

=head2 C<< listModels >>

  my $info = $client->listModels()->get;
  for my $model ($info->models->@*) {
      say $model->model; # llama2:latest
  }

List models that are available locally.

Returns a L<< AI::Ollama::ModelsResponse >>.

=cut

1;

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

=back

=item C<< messages >>

The messages of the chat, this can be used to keep a chat memory

=item C<< model >>

The model name.

Model names follow a C<model:tag> format. Some examples are C<orca-mini:3b-q4_1> and C<llama2:70b>. The tag is optional and, if not provided, will default to C<latest>. The tag is used to identify a specific version.

=item C<< options >>

Additional model parameters listed in the documentation for the Modelfile such as C<temperature>.

=item C<< stream >>

If C<false> the response will be returned as a single response object, otherwise the response will be streamed as a series of objects.

=back

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

=over 4

=item C<< modelfile >>

The contents of the Modelfile.

=item C<< name >>

The model name.

Model names follow a C<model:tag> format. Some examples are C<orca-mini:3b-q4_1> and C<llama2:70b>. The tag is optional and, if not provided, will default to C<latest>. The tag is used to identify a specific version.

=item C<< stream >>

If C<false> the response will be returned as a single response object, otherwise the response will be streamed as a series of objects.

=back

Returns a L<< AI::Ollama::CreateModelResponse >> on success.

=cut

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN



=head3 Options

=over 4

=item C<< name >>

The model name.

Model names follow a C<model:tag> format. Some examples are C<orca-mini:3b-q4_1> and C<llama2:70b>. The tag is optional and, if not provided, will default to C<latest>. The tag is used to identify a specific version.

=back


=cut

sub build_deleteModel_request( $self, %options ) {
    my $method = 'DELETE';
    my $path = '/delete';
    my $url = Mojo::URL->new( $self->server . $path );

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN



=head3 Options

=over 4

=item C<< model >>

The model name.

Model names follow a C<model:tag> format. Some examples are C<orca-mini:3b-q4_1> and C<llama2:70b>. The tag is optional and, if not provided, will default to C<latest>. The tag is used to identify a specific version.

=item C<< options >>

Additional model parameters listed in the documentation for the Modelfile such as C<temperature>.

=item C<< prompt >>

Text to generate embeddings for.

=back

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN


If not set, the model will stay loaded for 5 minutes by default


=back

=item C<< model >>

The model name.

Model names follow a C<model:tag> format. Some examples are C<orca-mini:3b-q4_1> and C<llama2:70b>. The tag is optional and, if not provided, will default to C<latest>. The tag is used to identify a specific version.

=item C<< options >>

Additional model parameters listed in the documentation for the Modelfile such as C<temperature>.

=item C<< prompt >>

The prompt to generate a response.

=item C<< raw >>

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

=item C<< insecure >>

Allow insecure connections to the library.

Only use this if you are pulling from your own library during development.

=item C<< name >>

The model name.

Model names follow a C<model:tag> format. Some examples are C<orca-mini:3b-q4_1> and C<llama2:70b>. The tag is optional and, if not provided, will default to C<latest>. The tag is used to identify a specific version.

=item C<< stream >>

If C<false> the response will be returned as a single response object, otherwise the response will be streamed as a series of objects.

=back

Returns a L<< AI::Ollama::PullModelResponse >> on success.

=cut

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN



=head3 Options

=over 4

=item C<< name >>

The model name.

Model names follow a C<model:tag> format. Some examples are C<orca-mini:3b-q4_1> and C<llama2:70b>. The tag is optional and, if not provided, will default to C<latest>. The tag is used to identify a specific version.

=back

Returns a L<< AI::Ollama::ModelInfo >> on success.

=cut

sub build_showModelInfo_request( $self, %options ) {
    my $method = 'POST';
    my $path = '/show';

lib/AI/Ollama/CreateModelRequest.pm  view on Meta::CPAN

has 'modelfile' => (
    is       => 'ro',
    isa      => Str,
    required => 1,
);

=head2 C<< name >>

The model name.

Model names follow a `model:tag` format. Some examples are `orca-mini:3b-q4_1` and `llama2:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.

=cut

has 'name' => (
    is       => 'ro',
    isa      => Str,
    required => 1,
);

=head2 C<< stream >>

lib/AI/Ollama/DeleteModelRequest.pm  view on Meta::CPAN

sub as_hash( $self ) {
    return { $self->%* }
}

=head1 PROPERTIES

=head2 C<< name >>

The model name.

Model names follow a `model:tag` format. Some examples are `orca-mini:3b-q4_1` and `llama2:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.

=cut

has 'name' => (
    is       => 'ro',
    isa      => Str,
    required => 1,
);


lib/AI/Ollama/GenerateChatCompletionRequest.pm  view on Meta::CPAN

has 'messages' => (
    is       => 'ro',
    isa      => ArrayRef[HashRef],
    required => 1,
);

=head2 C<< model >>

The model name.

Model names follow a `model:tag` format. Some examples are `orca-mini:3b-q4_1` and `llama2:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.

=cut

has 'model' => (
    is       => 'ro',
    isa      => Str,
    required => 1,
);

=head2 C<< options >>

lib/AI/Ollama/GenerateChatCompletionResponse.pm  view on Meta::CPAN


has 'message' => (
    is       => 'ro',
    isa      => HashRef,
);

=head2 C<< model >>

The model name.

Model names follow a `model:tag` format. Some examples are `orca-mini:3b-q4_1` and `llama2:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.

=cut

has 'model' => (
    is       => 'ro',
    isa      => Str,
);

=head2 C<< prompt_eval_count >>

lib/AI/Ollama/GenerateCompletionRequest.pm  view on Meta::CPAN


has 'keep_alive' => (
    is       => 'ro',
    isa      => Int,
);

=head2 C<< model >>

The model name.

Model names follow a `model:tag` format. Some examples are `orca-mini:3b-q4_1` and `llama2:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.

=cut

has 'model' => (
    is       => 'ro',
    isa      => Str,
    required => 1,
);

=head2 C<< options >>

lib/AI/Ollama/GenerateCompletionResponse.pm  view on Meta::CPAN


has 'load_duration' => (
    is       => 'ro',
    isa      => Int,
);

=head2 C<< model >>

The model name.

Model names follow a `model:tag` format. Some examples are `orca-mini:3b-q4_1` and `llama2:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.

=cut

has 'model' => (
    is       => 'ro',
    isa      => Str,
);

=head2 C<< prompt_eval_count >>

lib/AI/Ollama/GenerateEmbeddingRequest.pm  view on Meta::CPAN

sub as_hash( $self ) {
    return { $self->%* }
}

=head1 PROPERTIES

=head2 C<< model >>

The model name.

Model names follow a `model:tag` format. Some examples are `orca-mini:3b-q4_1` and `llama2:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.

=cut

has 'model' => (
    is       => 'ro',
    isa      => Str,
    required => 1,
);

=head2 C<< options >>

lib/AI/Ollama/Model.pm  view on Meta::CPAN


has 'modified_at' => (
    is       => 'ro',
    isa      => Str,
);

=head2 C<< name >>

The model name.

Model names follow a `model:tag` format. Some examples are `orca-mini:3b-q4_1` and `llama2:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.

=cut

has 'name' => (
    is       => 'ro',
    isa      => Str,
);

=head2 C<< size >>

lib/AI/Ollama/ModelInfoRequest.pm  view on Meta::CPAN

sub as_hash( $self ) {
    return { $self->%* }
}

=head1 PROPERTIES

=head2 C<< name >>

The model name.

Model names follow a `model:tag` format. Some examples are `orca-mini:3b-q4_1` and `llama2:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.

=cut

has 'name' => (
    is       => 'ro',
    isa      => Str,
    required => 1,
);


lib/AI/Ollama/PullModelRequest.pm  view on Meta::CPAN

=cut

has 'insecure' => (
    is       => 'ro',
);

=head2 C<< name >>

The model name.

Model names follow a `model:tag` format. Some examples are `orca-mini:3b-q4_1` and `llama2:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.

=cut

has 'name' => (
    is       => 'ro',
    isa      => Str,
    required => 1,
);

=head2 C<< stream >>

ollama/ollama-curated.json  view on Meta::CPAN

{"openapi":"3.0.3","components":{"schemas":{"PushModelResponse":{"properties":{"total":{"type":"integer","description":"total size of the model","example":"2142590208"},"status":{"$ref":"#/components/schemas/PushModelStatus"},"digest":{"example":"sha...

ollama/ollama-curated.yaml  view on Meta::CPAN

  schemas:
    GenerateCompletionRequest:
      type: object
      description: Request class for the generate endpoint.
      properties:
        model:
          type: string
          description: &model_name |
            The model name.

            Model names follow a `model:tag` format. Some examples are `orca-mini:3b-q4_1` and `llama2:70b`. The tag is optional and, if not provided, will default to `latest`. The tag is used to identify a specific version.
          example: llama2:7b
        prompt:
          type: string
          description: The prompt to generate a response.
          example: Why is the sky blue?
        images:
          type: array
          description: (optional) a list of Base64-encoded images to include in the message (for multimodal models such as llava)
          items:
            type: string

ollama/ollama-curated.yaml  view on Meta::CPAN

      description: Details about a model including modelfile, template, parameters, license, and system prompt.
      type: object
      properties:
        license:
          type: string
          description: The model's license.
          example: <contents of license block>
        modelfile:
          type: string
          description: The modelfile associated with the model.
          example: 'Modelfile generated by \"ollama show\"\n# To build a new Modelfile based on this one, replace the FROM line with:\n# FROM llama2:latest\n\nFROM /Users/username/.ollama/models/blobs/sha256:8daa9615cce30c259a9555b1cc250d461d1bc69980...
        parameters:
          type: string
          description: The model parameters.
          example: 'stop [INST]\nstop [/INST]\nstop <<SYS>>\nstop <</SYS>>'
        template:
          type: string
          description: The prompt template for the model.
          example: '[INST] {{ if and .First .System }}<<SYS>>{{ .System }}<</SYS>>\n\n{{ end }}{{ .Prompt }} [/INST]'
    CopyModelRequest:
      description: Request class for copying a model.

ollama/ollama-curated.yaml  view on Meta::CPAN

        - removing any unused layers
        - success
      example: pulling manifest
    PushModelRequest:
      description: Request class for pushing a model.
      type: object
      properties:
        name:
          type: string
          description: The name of the model to push in the form of <namespace>/<model>:<tag>.
          example: 'mattw/pygmalion:latest'
        insecure:
          type: boolean
          description: |
            Allow insecure connections to the library.

            Only use this if you are pushing to your library during development.
          default: false
        stream:
          type: boolean
          description: *stream

scripts/describe-image.pl  view on Meta::CPAN

$ol->on('response' => sub( $ol, $tx, $err='' ) {
    if( $err ) {
        warn $err if $err;
    } else {
        #use Data::Dumper;
        warn $tx->code;
    }
});

my $tx = $ol->pullModel(
    name => 'llava:latest',
)->catch(sub {
    use Data::Dumper; warn Dumper \@_;
})->get;

my @images = @ARGV ? @ARGV : ('t/testdata/objectdetection.jpg');

for my $image (@images) {
    my $response = $ol->generateCompletion(
        model => 'llava:latest',
        prompt => 'You are tagging images. Please list all the objects in this image as tags. Also list the location where it was taken.',
        images => [
            { filename => $image },
        ],
    );
    my $responses = $response->get;

    repeat {
        my ($res) = $responses->shift;
        my $info;

t/00-load.t  view on Meta::CPAN

#!perl
use strict;
use warnings;

use Test::More tests => 1;

require './Makefile.PL';
my %module = get_module_info();

my $module = $module{ NAME };

require_ok( $module );

diag( sprintf "Testing %s %s, Perl %s", $module, $module->VERSION, $] );

testrules.yml  view on Meta::CPAN

---
# This test suite can be run fully in parallel
par:
    - t/*.t
    - xt/*.t

xt/99-changes.t  view on Meta::CPAN

#!perl -w
use warnings;
use strict;
use File::Find;
use Test::More tests => 2;

=head1 PURPOSE

This test ensures that the Changes file
mentions the current version and that a
release date is mentioned as well

=cut

require './Makefile.PL';
# Loaded from Makefile.PL
our %module = get_module_info();
my $module = $module{NAME};

xt/99-compile.t  view on Meta::CPAN

#!perl
use warnings;
use strict;
use File::Find;
use Test::More;
BEGIN {
    eval 'use Capture::Tiny ":all"; 1';
    if ($@) {
        plan skip_all => "Capture::Tiny needed for testing";
        exit 0;
    };
};

plan 'no_plan';

require './Makefile.PL';
# Loaded from Makefile.PL
our %module = get_module_info();

xt/99-manifest.t  view on Meta::CPAN

use strict;
use Test::More;

# Check that MANIFEST and MANIFEST.skip are sane :

use File::Find;
use File::Spec;

my @files = qw( MANIFEST MANIFEST.SKIP );
plan tests => scalar @files * 4
              +1 # MANIFEST existence check
              +1 # MYMETA.* non-existence check
              ;

for my $file (@files) {
  ok(-f $file, "$file exists");
  open my $fh, '<', $file
    or die "Couldn't open $file : $!";
  my @lines = <$fh>;
  is_deeply([grep(/^$/, @lines)],[], "No empty lines in $file");

xt/99-minimumversion.t  view on Meta::CPAN


eval {
  #require Test::MinimumVersion::Fast;
  require Test::MinimumVersion;
  Test::MinimumVersion->import;
};

my @files;

if ($@) {
  plan skip_all => "Test::MinimumVersion required for testing minimum Perl version";
}
else {
  all_minimum_version_from_metajson_ok();
}

xt/99-pod.t  view on Meta::CPAN

use Test::More;

# Check our Pod
# The test was provided by Andy Lester,
# who stole it from Brian D. Foy
# Thanks to both !

use File::Spec;
use File::Find;
use strict;

eval {
  require Test::Pod;
  Test::Pod->import;
};

require './Makefile.PL';
# Loaded from Makefile.PL
our %module = get_module_info();

my @files;

if ($@) {
  plan skip_all => "Test::Pod required for testing POD";
}
elsif ($Test::Pod::VERSION < 0.95) {
  plan skip_all => "Test::Pod 0.95 required for testing POD";
}
else {
  my $blib = File::Spec->catfile(qw(blib lib));
  find(\&wanted, grep { -d } ($blib));

  if( my $exe = $module{EXE_FILES}) {
    push @files, @$exe;
  };

  plan tests => scalar @files;
  foreach my $file (@files) {
    pod_file_ok($file);
  }
}

sub wanted {
  push @files, $File::Find::name if /\.p(l|m|od)$/;
}

xt/99-synopsis.t  view on Meta::CPAN

our %module = get_module_info();

my @files;
my $blib = File::Spec->catfile(qw(blib lib));
find(\&wanted, grep { -d } ($blib));

#if( my $exe = $module{EXE_FILES}) {
#    push @files, @$exe;
#};

plan tests => scalar @files;
foreach my $file (@files) {
    synopsis_file_ok($file);
}

sub wanted {
    push @files, $File::Find::name if /\.p(l|m|od)$/
        and $_ !~ /\bDSL\.pm$/; # we skip that one as it initializes immediately
}

sub synopsis_file_ok {

xt/99-test-prerequisites.t  view on Meta::CPAN

#!perl -w

use warnings;
use strict;
use Test::More;
use Data::Dumper;
use File::Find;

=head1 DESCRIPTION

This test checks whether all tests still pass when the optional test
prerequisites for the test are not present.

This is done by using L<Test::Without::Module> to rerun the test while excluding
the optional prerequisite.

=cut

BEGIN {
    eval {
        require CPAN::Meta::Prereqs;
        require Parse::CPAN::Meta;
        require Perl::PrereqScanner::Lite;
        require Module::CoreList;
        require Test::Without::Module;
        require Capture::Tiny;
        Capture::Tiny->import('capture');
        require Path::Class;
        Path::Class->import('dir');
    };
    if (my $err = $@) {
        warn "# $err";
        plan skip_all => "Prerequisite needed for testing is missing";
        exit 0;
    };
};

my @tests;
if( @ARGV ) {
    @tests = @ARGV;
} else {
    open my $manifest, '<', 'MANIFEST'
        or die "Couldn't read MANIFEST: $!";
    @tests = grep { -f $_ } grep { m!^(t/.*\.t|scripts/.*\.pl)$! } map { s!\s*$!!; $_ } <$manifest>
}
plan tests => 0+@tests;

my $meta = Parse::CPAN::Meta->load_file('META.json');

# Find what META.* declares
my $explicit_test_prereqs = CPAN::Meta::Prereqs->new( $meta->{prereqs} )->merged_requirements->as_string_hash;
my $minimum_perl = $meta->{prereqs}->{runtime}->{requires}->{perl} || 5.006;

sub distributed_packages {
    my @modules;
    for( @_ ) {
        dir($_)->recurse( callback => sub {
            my( $child ) = @_;
            if( !$child->is_dir and $child =~ /\.pm$/) {
                push @modules, ((scalar $child->slurp()) =~ m/^\s*package\s+(?:#.*?\n\s+)*(\w+(?:::\w+)*)\b/msg);
            }
        });
    };
    map { $_ => $_ } @modules;
}

# Find what we distribute:
my %distribution = distributed_packages('blib','t');

my $scanner = Perl::PrereqScanner::Lite->new;
for my $test_file (@tests) {
    my $implicit_test_prereqs = $scanner->scan_file($test_file)->as_string_hash;
    my %missing = %{ $implicit_test_prereqs };
    #warn Dumper \%missing;

    for my $p ( keys %missing ) {
        # remove core modules
        if( Module::CoreList::is_core( $p, undef, $minimum_perl)) {
            delete $missing{ $p };
            #diag "$p is core for $minimum_perl";
        } else {
            #diag "$p is not in core for $minimum_perl";
        };
    };

    # remove explicit (test) prerequisites
    for my $k (keys %$explicit_test_prereqs) {
        delete $missing{ $k };
    };
    #warn Dumper $explicit_test_prereqs->as_string_hash;

    # Remove stuff from our distribution
    for my $k (keys %distribution) {
        delete $missing{ $k };
    };

    # If we have no apparent missing prerequisites, we're good
    my @missing = sort keys %missing;

    # Rerun the test without these modules and see whether it crashes
    my @failed;
    for my $candidate (@missing) {
        diag "Checking that $candidate is not essential";
        my @cmd = ($^X, "-MTest::Without::Module=$candidate", "-Mblib", '-w', $test_file);
        my $cmd = join " ", @cmd;

        my ($stdout, $stderr, $exit) = capture {
            system( @cmd );
        };
        if( $exit != 0 ) {
            push @failed, [ $candidate, [@cmd]];
        } elsif( $? != 0 ) {
            push @failed, [ $candidate, [@cmd]];
        };
    };
    is 0+@failed, 0, $test_file
        or diag Dumper \@failed;

};

done_testing;

xt/99-todo.t  view on Meta::CPAN

use Test::More;
use File::Spec;
use File::Find;
use strict;

# Check that all files do not contain any
# lines with "XXX" - such markers should
# either have been converted into Todo-stuff
# or have been resolved.
# The test was provided by Andy Lester.

require './Makefile.PL';
# Loaded from Makefile.PL
our %module = get_module_info();

my @files;
my $blib = File::Spec->catfile(qw(blib lib));
find(\&wanted, grep { -d } ($blib));

if( my $exe = $module{EXE_FILES}) {
    push @files, @$exe;
};

plan tests => 2* @files;
foreach my $file (@files) {
  source_file_ok($file);
}

sub wanted {
  push @files, $File::Find::name if /\.p(l|m|od)$/;
}

sub source_file_ok {
    my $file = shift;



( run in 0.550 second using v1.01-cache-2.11-cpan-3cd7ad12f66 )