SYNOPSIS

        use 5.20.0;
    
        use MoobX;
    
        my $first_name :Observable;
        my $last_name  :Observable;
        my $title      :Observable;
    
        my $address = observer {
            join ' ', $title || $first_name, $last_name;
        };
    
        say $address;  # nothing
    
        $first_name = "Yanick";
        $last_name  = "Champoux";
    
        say $address;  # Yanick Champoux
    
        $title = 'Dread Lord';
    
        say $address;  # Dread Lord Champoux

DESCRIPTION

    As I was learning how to use https://github.com/mobxjs/mobx|MobX, I
    thought it'd be fun to try to implement something similar in Perl. So I
    did.

    To set Moose object attributes to be observers or observables, take a
    gander at MoobX::Trait::Observable and MoobX::Trait::Observer.

    To have an idea of the mechanics of MoobX, see the two blog entries in
    the SEE ALSO section.

    This is also the early stages of life for this module. Consider
    everythign as alpha quality, and the API still subject to huge changes.

EXPORTED FUNCTIONS

    The module automatically exports 3 functions: observer, observable and
    autorun.

 observable

        observable my $foo;
        observable my @bar;
        observable my %quux;

    Marks the variable as an observable, i.e. a variable which value can be
    watched by observers, which will be updated when it changes.

    Under the hood, the variable is tied to the relevant MoobX::TYPE class
    MoobX::TYPE::Observable role.

    If you want to declare the variable, assign it a value and set it as
    observable, there are a few good ways to do it, and one bad:

        my $foo = 3;
        observable $foo;            # good
    
        observable( my $foo = 3 );  # good
    
        observable my $foo;         # good
        $foo = 3;
    
        observable my $foo = 3;     # bad

    That last one doesn't work because Perl parses it as observable( my
    $foo ) = 3, and assigning values to non lvalueed functions don't work.

    Or, better, simply use the :Observable attribute when you define the
    variable.

        my $foo :Observable = 2;
        my @bar :Observable = 1..10;
        my %baz :Observable = ( a => 1, b => 2 );

 observer

        observable my $quantity;
        observable my $price;
    
        my $total = observer {
            $quantity * $price
        };
    
        $quantity = 2;
        $price = 6.00;
    
        print $total; # 12

    Creates a MoobX::Observer object. The value returned by the object will
    react to change to any observable values within its definition.

    Observers are lazy, meaning that they compute or recompute their values
    when they are accessed. If you want them to eagerly recompute their
    values, autorun is what you want.

    If an observer function is run and doesn't report any dependency, it'll
    emit the warning 'MoobX observer doesn't observe anything', because
    chances are there's something weird going on. The warning can be
    silenced via the global variable $MoobX::WARN_NO_DEPS.

        my $foo :Observable;
    
        my $debugging = 0;
    
        # if $debugging == 1, we'd get a warning
        local $MoobX::WARN_NO_DEPS = 0;
    
        my $spy = observer {
            return unless $debugging;
    
            say $foo;
        };

 autorun

        observable my $foo;
    
        autorun {
            say "\$foo is now $foo";
        };
    
        $foo = 1; # prints '$foo is now 1'
    
        $foo = 2; # prints '$foo is now 2'

    Like observer, but immediatly recompute its value when its observable
    dependencies change.

SEE ALSO

    https://github.com/mobxjs/mobx|MobX - the original inspiration

    http://techblog.babyl.ca/entry/moobx and
    http://techblog.babyl.ca/entry/moobx-2 - the two blog entries that
    introduced MobX.

