Help language development. Donate to The Perl Foundation
Proxee — A more usable Proxy with bells
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.
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.
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
Callable
s have been set to behave like functionality offered by Proxee
. Possible arguments are:
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.
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 Pair
s 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
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)»
Zoffix Znet
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.