Acme-Locals

 view release on metacpan or  search on metacpan

lib/Acme/Locals.pm  view on Meta::CPAN

sub printx      ($@); ## no critic
sub sprintfx    ($@); ## no critic

sub import {
    my ($this_class, @tags) = @_;
    my $call_class = caller 0;

    my @to_export;
    for my $tag (@tags) {
        if ($tag =~ m/^:/xms) {
            croak __PACKAGE__, " does not support the tag  $tag"
                if not exists $EXPORT_TAGS{$tag};

            push @to_export, @{ $EXPORT_TAGS{$tag} };
        }
        elsif ($tag =~ m/^-/xms) {
            $mode_for_class{$call_class} = $tag;
        }
        else {
            push @to_export, $tag;
        }
    }
    $mode_for_class{$call_class} ||= $DEFAULT_MODE;
    if (not exists $MODES{ $mode_for_class{$call_class} }) {
        my $cur_mode = $mode_for_class{$call_class};
        carp "Unknown mode $cur_mode. Switching to default mode $DEFAULT_MODE";
        $mode_for_class{$call_class} = $DEFAULT_MODE;
    }

    no strict 'refs'; ## no critic
    for my $export_sub (@to_export) {
        croak __PACKAGE__, " does not export $export_sub"
            if not exists $EXPORT_OK{$export_sub};
    
        *{ $call_class . "::$export_sub" } = $EXPORT_OK{$export_sub};
    }

    return;
}

sub sayx ($@){ ## no critic
    say sprintx([caller 0], @_);
}

sub printx ($@) { ## no critic
    print sprintx([caller 0], @_);
}

sub sprintx ($@) { ## no critic
    my $peek_level = 1;
    my $call_class;
    if (_ARRAY( $_[0] )) {
        $call_class = shift->[0];
        $peek_level++;
    }
    $call_class ||= caller 0;

    my ($fmt, %bind_vars) = @_;

    my @binds;
    my $map_bind_var = sub {
        my ($bind_var_name, $format_char) = @_;
        local *__ANON__ = 'map_bind_var'; ## no critic

        my $internal_name = $bind_var_name;
        if (exists $bind_vars{$internal_name}) {
            # pass
        }
        elsif (exists $bind_vars{q{$}.$internal_name}) {
            $internal_name = q{$}.$internal_name;
        }
        else {
            croak "No such bind var: $bind_var_name";
        }

        my $value_ref = $bind_vars{$internal_name};
        croak 'Bind var must be scalar'
            if not _SCALAR($value_ref);

        push @binds, ${ $value_ref };

        return defined $format_char ? q{%} . $format_char
                                    : $DEFAULT_FORMAT;
    };

    my $mode = $mode_for_class{$call_class} || $DEFAULT_MODE;
    my $re   = $MODES{ $mode };

    if ($mode eq '-ruby' && !scalar keys %bind_vars) {
        %bind_vars = %{ PadWalker::peek_my($peek_level) };
    }
    
    $fmt =~ s/$re/$map_bind_var->($1, $2)/xmseg;

    return sprintf $fmt, @binds;
}

sub lexicals {
    goto &locals;
}

sub locals {
    return wantarray ? %{ PadWalker::peek_my(1) }
                     :    PadWalker::peek_my(1);
}

sub globals {
    return wantarray ? %{ PadWalker::peek_our(1) }
                     :    PadWalker::peek_our(1);
}

1;

__END__

=begin wikidoc

= NAME

Acme::Locals - Interpolate like Python/Ruby.

= VERSION

This document describes Acme::Locals version v0.0.1

= SYNOPSIS

    # Python mode

    use Acme::Locals qw(-python :all);

    sub foo {
        my $x   = 10;
        my $y   = 100;
        my $who = "world";
        sayx '%(x)d %(y)d hello %(who)s!', locals();
    }


    # Ruby mode

    use Acme::Locals qw(-ruby :all);

    sub bar {
        my $x   = 10;
        my $y   = 100;
        my $who = "world";

        sayx '#{x} #{y} hello #{who}';
    }


= DESCRIPTION



( run in 1.650 second using v1.01-cache-2.11-cpan-d8267643d1d )