package Pluto;

use 5.014;

use strict;
use warnings;

no warnings 'redefine';

use Pluto::Engine;

sub core {
  my ($config) = @_;

  {
    array => {
      package => 'Data/Object/Array'
    },
    bool => {
      package => 'Data/Object/Boolean'
    },
    code => {
      package => 'Data/Object/Code'
    },
    false => {
      package => 'Data/Object/Boolean',
      argument_as => 'list',
      argument => 0
    },
    float => {
      package => 'Data/Object/Float'
    },
    hash => {
      package => 'Data/Object/Hash'
    },
    number => {
      package => 'Data/Object/Number'
    },
    regexp => {
      package => 'Data/Object/Regexp'
    },
    scalar => {
      package => 'Data/Object/Scalar'
    },
    space => {
      package => 'Data/Object/Space'
    },
    string => {
      package => 'Data/Object/String'
    },
    true => {
      package => 'Data/Object/Boolean',
      argument_as => 'list',
      argument => 1
    },
    (
      $config ? %$config : ()
    )
  }
}

my %seen;

sub import {
  my ($class, $config) = @_;

  return $class if $seen{$class}++;

  unless (ref($config ||= $ENV{PLUTO_CONFIG})) {
    $config = do $config if $config;
  }

  my $caller = caller;
  my $planet = Pluto::Engine->new(package => $caller, config => core($config));

  {
    no strict 'refs';

    # callable
    *{"${caller}::call"} = sub {
      $planet->execute(@_);
    };

    # autoloading
    *{"${caller}::AUTOLOAD"} = sub {
      $planet->resolve([our $AUTOLOAD =~ m[^(.+)::(.+)$]], @_);
    };

    # destruction
    *{"${caller}::DESTROY"} = sub {
      # noop
    };
  }

  return $class;
}

1;
=encoding utf8

=head1 NAME

Pluto - Functional Programming

=cut

=head1 ABSTRACT

Functional Scripting for Perl 5

=cut

=head1 SYNOPSIS

  package Cosmos;

  use Pluto;

  call(string('hello world'), 'titlecase');

  # Hello World

=cut

=head1 DESCRIPTION

This package enables functional programming for Perl 5 via indirect routine
dispatching and dependency injection, operating in a way that plays nicely with
third-party libraries without having to switch over to object-oriented
programming.

=head1 WHY

Perl is a multi-paradigm programming language that supports functional
programming, but, Perl has an intentionally limited standard library with an
emphasis on providing library support via the CPAN which is overwhelmingly
object-oriented. This makes developing in a functional style difficult as
you'll eventually need to rely on a CPAN library that requires you to switch
over to object-oriented programming.

=cut

=head1 LIBRARIES

This package uses type constraints from:

L<Types::Standard>

=cut

=head1 AUTHOR

Al Newkirk, C<awncorp@cpan.org>

=head1 LICENSE

Copyright (C) 2011-2019, Al Newkirk, et al.

This is free software; you can redistribute it and/or modify it under the terms
of the The Apache License, Version 2.0, as elucidated in the L<"license
file"|https://github.com/iamalnewkirk/pluto/blob/master/LICENSE>.

=head1 PROJECT

L<Wiki|https://github.com/iamalnewkirk/pluto/wiki>

L<Project|https://github.com/iamalnewkirk/pluto>

L<Initiatives|https://github.com/iamalnewkirk/pluto/projects>

L<Milestones|https://github.com/iamalnewkirk/pluto/milestones>

L<Contributing|https://github.com/iamalnewkirk/pluto/blob/master/CONTRIBUTE.md>

L<Issues|https://github.com/iamalnewkirk/pluto/issues>

=cut