Rand Stats

Proxee

zef:raku-community-modules

Actions Status

NAME

Proxee — A more usable Proxy with bells

SYNOPSIS

use Proxee;

General use:

# No self as first arg; simply use a regular block in both code blocks:
my @stuff;
my $stuff := Proxee.new: :STORE{ @stuff.push: $_ }, :FETCH{ @stuff.join: ' | ' }
$stuff = 42;
$stuff = 'meow';
say $stuff; # OUTPUT: «42 | meow␤»

# Single block as arg; keep all related bits in one place
my $stuff2 := Proxee.new: {
    my @stuff;
    :STORE{ @stuff.push: $_    },
    :FETCH{ @stuff.join: ' | ' }
}
$stuff2 = 42;
$stuff2 = 'meow';
say $stuff2; # OUTPUT: «42 | meow␤»

Special shared dynamic variable:

# Or just use the special shared variable:
my $stuff2 := Proxee.new: :STORE{ $*PROXEE.push: $_ }, :FETCH{ $*PROXEE.join: ' | ' }
$stuff2 = 42;
$stuff2 = 'meow';
say $stuff2; # OUTPUT: «42 | meow␤»

# Default STORErer
my $cuber := Proxee.new: :FETCH{ $*PROXEE³ };
$cuber = 11;
say $cuber; # OUTPUT: «1331␤»

# Default FETCHer
my $squarer := Proxee.new: :STORE{ $*PROXEE = $_² };
$squarer = 11;
say $squarer; # OUTPUT: «121␤»

# Shortcut to assign to $*PROXEE
my $squarer := Proxee.new: :PROXEE{ $_² };
$squarer = 11;
say $squarer; # OUTPUT: «121␤»

Coercers (for backward compatibility only):

# Coercer types on variables:
my $integral := Proxee.new: Int();
$integral = ' 42.1e0 ';
say $integral; # OUTPUT: «42␤»

# Coercer types on attributes:
class Foo {
    has $.foo is rw;
    submethod TWEAK (:$foo) { ($!foo := Proxee.new: Int()) = $foo }
}
my $o = Foo.new: :foo('42.1e0');
say $o.foo;       # OUTPUT: «42␤»
$o.foo = 12.42;
say $o.foo;       # OUTPUT: «12␤»

Note: this option is only provided for backwards compatibility. Recent version of Rakudo support coercion types out of the box in variable, parameter and attribute declarations.

DESCRIPTION

The core Proxy type is a bit clunky to use. This module provides an alternative class Proxee with an improved interface, and with a few extra features.

METHODS

new

multi method new(\coercer where {.HOW ~~ Metamodel::CoercionHOW})
multi method new(:&PROXEE, :&STORE, :&FETCH)
multi method new(&block)

Creates and returns a new Proxy object whose :STORE and :FETCH Callables have been set to behave like functionality offered by Proxee. Possible arguments are:

An Improved Proxy

The regular functionality of a Proxy remains, except the Proxy object is no longer passed to neither :FETCH nor :STORE callables. :FETCH gets no args; :STORE gets 1 arg, the value being stored:

my @stuff;
my $stuff := Proxee.new: :STORE{ @stuff.push: $_ }, :FETCH{ @stuff.join: ' | ' }
$stuff = 42;
$stuff = 'meow';
say $stuff; # OUTPUT: «42 | meow␤»

In addition, automated storage is available. Assign (do not bind, or you'll break it) to $*PROXEE variable to store the value in the automated storage and read from it to retrieve that value:

my $stuff2 := Proxee.new:
  :STORE{ $*PROXEE.push: $_ },
  :FETCH{ $*PROXEE.join: ' | ' }
$stuff2 = 42;
$stuff2 = 'meow';
say $stuff2; # OUTPUT: «42 | meow␤»

The :STORE argument is optional and defaults to { $*PROXEE = $_ }. The :FETCH argument is optional and defaults to { $*PROXEE }. The :PROXEE argument is like :STORE, except it also assigns itsi return value to $*PROXEE:

my $squarer := Proxee.new: :PROXEE{ $_² };
$squarer = 11;
say $squarer; # OUTPUT: «121␤»

Attempting to use both :PROXEE and :STORE arguments at the same time will throw Proxee::X::CannotProxeeStore exception.

A Callable

You can also pass a single codeblock as an argument. It will be evaluated and its return value will be used as arguments to Proxee.new (after slight massaging to make Pairs in a List be passed as named args).

This feature exists to make it slightly simpler to use closures with a Proxy:

my $stuff2 := Proxee.new: {
    my @stuff;
    :STORE{ @stuff.push: $_    },
    :FETCH{ @stuff.join: ' | ' }
}
$stuff2 = 42;
$stuff2 = 'meow';
say $stuff2; # OUTPUT: «42 | meow␤»

The above is equivalent to:

my $stuff2 := do {
    my @stuff;
    Proxee.new: :STORE{ @stuff.push: $_    },
                :FETCH{ @stuff.join: ' | ' }
}
$stuff2 = 42;
$stuff2 = 'meow';
say $stuff2; # OUTPUT: «42 | meow␤»

Watch out you don't accidentally pass a block that would be interpreted as a Hash:

Proxy.new:    { :STORE{;}, :FETCH{;} } # WRONG; It's a Hash
Proxy.new: -> { :STORE{;}, :FETCH{;} } # RIGHT; It's a Block

Coercer

Pass a coercer as a positional argument to create a coercing proxy that coerces stored values to specified type:

my  $Cool-to-Int := Proxee.new: Int(Cool);
$Cool-to-Int = ' 42.70 ';
say $Cool-to-Int; # OUTPUT: «42␤»

$Cool-to-Int = Date.today
# OUTPUT: «Type check failed in Proxee; expected Cool but got Date (Date)␤»

Note: none of :&PROXEE, :&STORE, :&FETCH can be used together with the coercer argument.

Note: this option is only provided for backwards compatibility. Recent version of Rakudo support coercion types out of the box in variable, parameter and attribute declarations.

my Int(Cool) $Cool-to-Int = ' 42.70';
say $Cool-to-Int; # OUTPUT: «42␤»

$Cool-to-Int = Date.today
# OUTPUT: «Type check failed in Proxee; expected Cool but got Date (Date)␤»

AUTHOR

Zoffix Znet

COPYRIGHT AND LICENSE

Copyright 2017 - 2018 Zoffix Znet

Copyright 2019 - 2023 Raku Community

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.