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'
    },
    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) = @_;

  my $caller = caller;
  return $class if $seen{$caller}++;

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

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

  # call function
  $planet->space->inject('call', sub {
    $planet->call(@_);
  });

  # service functions
  for my $name (keys %{$planet->config}) {
    unless ($planet->space->routine($name)) {
      $planet->space->inject($name, sub {
        $planet->services->process($name, @_);
      });
    }
  }

  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 SCENARIOS

This package supports the following scenarios:

=cut

=head2 array

  # given: synopsis

  array;

This package supports making the C<array> function available in the calling
package if it doesn't exist already. This function creates a
L<Data::Object::Array> object.

=cut

=head2 bool

  # given: synopsis

  bool;

This package supports making the C<bool> function available in the calling
package if it doesn't exist already. This function creates a
L<Data::Object::Boolean> object.

=cut

=head2 call

  # given: synopsis

  call('Test', 'ok');

This package supports making the C<call> function available in the calling
package. This function dispatches function and method calls to a package.

=cut

=head2 code

  # given: synopsis

  code;

This package supports making the C<code> function available in the calling
package if it doesn't exist already. This function creates a
L<Data::Object::Code> object.

=cut

=head2 false

  # given: synopsis

  false;

This package supports making the C<false> function available in the calling
package if it doesn't exist already. This function creates a
L<Data::Object::Boolean> object.

=cut

=head2 float

  # given: synopsis

  float;

This package supports making the C<float> function available in the)calling
package if it doesn't exist already. This function creates a
L<Data::Object::Float> object.

=cut

=head2 hash

  # given: synopsis

  hash;

This package supports making the C<hash> function available in the)calling
package if it doesn't exist already. This function creates a
L<Data::Object::Hash> object.

=cut

=head2 number

  # given: synopsis

  number;

This package supports making the C<number> function available in the)calling
package if it doesn't exist already. This function creates a
L<Data::Object::Number> object.

=cut

=head2 regexp

  # given: synopsis

  regexp;

This package supports making the C<regexp> function available in the)calling
package if it doesn't exist already. This function creates a
L<Data::Object::Regexp> object.

=cut

=head2 space

  # given: synopsis

  space;

This package supports making the C<space> function available in the)calling
package if it doesn't exist already. This function creates a
L<Data::Object::Space> object.

=cut

=head2 string

  # given: synopsis

  string;

This package supports making the C<string> function available in the)calling
package if it doesn't exist already. This function creates a
L<Data::Object::String> object.

=cut

=head2 true

  # given: synopsis

  true;

This package supports making the C<true> function available in the)calling
package if it doesn't exist already. This function creates a
L<Data::Object::Boolean> object.

=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