UR::Observer(3pm)
π UR::Observer β bind callbacks to object changes π
okay so bestie, welcome to UR::Observer, part of the User Contributed Perl Documentation collection, and honestly? it's giving observer pattern realness. no cap.
β¨ SYNOPSIS β¨
$rocket = Acme::Rocket->create(
fuel_level => 100
);
$observer = $rocket->add_observer(
aspect => 'fuel_level',
callback =>
sub {
print "fuel level is: " . shift->fuel_level . "\n"
},
priority => 2,
);
$observer2 = UR::Observer->create(
subject_class_name => 'Acme::Rocket',
subject_id => $rocket->id,
aspect => 'fuel_level',
callback =>
sub {
my($self,$changed_aspect,$old_value,$new_value) = @_;
if ($new_value == 0) {
print "Bail out!\n";
}
},
priority => 0
);
for (3 .. 0) {
$rocket->fuel_level($_);
}
# fuel level is: 3
# fuel level is: 2
# fuel level is: 1
# Bail out!
# fuel level is: 0
$observer->delete;
π DESCRIPTION π
so UR::Observer implements the observer pattern for UR objects, and it's lowkey iconic. these observers can be attached to individual object instances, or to whole classes β your choice, main character energy either way.
they can send notifications for changes to object attributes, or to other state changes like when an object is loaded from its datasource or deleted. periodt.
π CONSTRUCTOR π
you can make observers two ways, bestie:
- by using the method
add_observer()on another class, or - by calling
create()on theUR::Observerclass.
my $o1 = Some::Other::Class->add_observer(...);
my $o2 = $object_instance->add_observer(...);
my $o3 = UR::Observer->create(...);
the constructor accepts these parameters, and yes we're going through every single one π«Ά
subject_class_nameβ the name of the class the observer is watching. if this observer is being created viaadd_observer(), then it figures out thesubject_class_namefrom the class or object it is being called on. it's giving detective work πsubject_idβ the ID of the object the observer is watching. if this observer is being created viaadd_observer(), then it figures out thesubject_idfrom the object it was called on. and here's the tea: ifadd_observer()was called as a class method, thensubject_idis omitted, and that means the observer should fire for changes on any instance of the class or sub-class. so many vibes.priorityβ a numeric value that determines the order the callbacks are fired in. lower numbers are higher priority, and they run before callbacks with a numerically higher priority. the default priority is1. negative numbers are ok, no judgement πaspectβ the attribute the observer is watching for changes on. the aspect is commonly one of the properties of the class, and in that case the callback is fired after the property's value changes.aspectcan be omitted, which means the observer should fire for any change in the object state. and if bothsubject_idandaspectare omitted, then the observer will fire for any change to any instance of the class. obsessed.
there are other, system-level aspects that can be watched for, and they correspond to other types of state change:
createβ after a new object instance is created β¨deleteβ after an n object instance is deleted πloadβ after an object instance is loaded from its data source πcommitβ after an object instance has changes saved to its data source πΎ
callbackβ a coderef that is called after the observer's event happens. the coderef is passed four parameters:$self,$aspect,$old_value,$new_value. and important: in this case,$selfis the object that is changing, not theUR::Observerinstance (unless, of course, you have created an observer onUR::Observerπ). the return value of the callback is ignored. it just does its thing and we move on.onceβ if the'once'attribute is true, the observer is deleted immediately after the callback is run. this has the effect of running the callback only once, no matter how many times the observer condition is triggered. one and done, iconic behaviour πnoteβ a text string that is ignored by the system. it's just there for you. journaling, basically π
π Custom aspects π
you can create an observer for an aspect that is neither a property nor one of the system aspects β you just list the aspect names in the metadata for the class. custom queen behaviour π
class My::Class {
has => [ 'prop_a', 'another_prop' ],
valid_signals => ['custom', 'pow' ],
};
my $o = My::Class->add_observer(
aspect => 'pow',
callback => sub { print "POW!\n" },
);
My::Class->__signal_observers__('pow'); # POW!
my $obj = My::Class->create(prop_a => 1);
$obj->__signal_observers__('custom'); # not an error
and here's the helpful part β to help catch typos, creating an observer for a non-standard aspect throws an exception unless the named aspect is in the list of 'valid_signals' in the class metadata. typos? we don't know her π«
nothing in the system will trigger these observers, but they can be triggered in your own code using the "__signal_observers()__" class or object method. and sending a signal for an aspect that no observers are watching for is not an error. so go off, honestly.
π quick vibe check reminder:$selfin the callback = the changing object, not the observer. unless you made an observer onUR::Observer, in which case... plot twist. π
and that's the whole page, bestie! this was perl v5.32.1, dated 2022-01-17, filed under UR::Observer(3pm). slay, bye πβ¨π
π¦ where this page comes from
- debian bookworm: libur-perl 0.470+ds-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu jammy: libur-perl 0.470+ds-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libur-perl 0.470+ds-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms