Raku By Example
View me onGitHub
## class does a role

role Paintable {
    has $.colour is rw;
    method paint { ... }
}
class Shape {
    method area { ... }
}

class Rectangle is Shape does Paintable {
    has $.width;
    has $.height;
    method area {
        $!width * $!height;
    }
    method paint() {
        for 1..$.height {
            say 'x' x $.width;
        }
    }
}

Rectangle.new(width => 8, height => 3).paint;
# 这打印下面 3 行
xxxxxxxx
xxxxxxxx
xxxxxxxx

## role instance

role BarChart {
    has Int @.bar-values;
    has $.b is rw;
    method plot {
        say @.bar-values;
    }
}

my $chart = BarChart.new(bar-values => [1,2,3], b => "Camelia");
say $chart.b;
say $chart.bar-values;
$chart.b = "Rakuo";
say $chart.b;
say BarChart.^methods;

## role conflict

role Sleeping {
    method lie {
        say "Reclining horizontally...";
    }
}

role Lying {
    method lie {
        say "Telling an untruth...";
    }
}

class SleepingLiar does Sleeping does Lying {}    # CONFLICT!

# Method 'lie' must be resolved by class SleepingLiar because it exists in multiple roles (Lying, Sleeping)

## resolved conflict

role Sleeping {
    method lie {
        say "Reclining horizontally...";
    }
}

role Lying {
    method lie {
        say "Telling an untruth...";
    }
}

# 如果解决方法同名的冲突呢?
# 在 class 中定义一个同名的方法即可
class SleepingLiar does Sleeping does Lying {
    method lie {
        say "Lying in my sleep....";
    }
}

my $sleep = SleepingLiar.new;
$sleep.lie; # Lying in my sleep....

# 调用其中之一的 roles 的 lie 方法
class SleepingSheep does Sleeping does Lying {
    method lie {
        self.Sleeping::lie;
    }
}

my $sleepSheep = SleepingSheep.new;
$sleepSheep.lie; # Reclining horizontally...

## one example

role Observable {
    has @!observers;

    method subscribe($observer) {
        push @!observers, $observer;
        $observer
    }

    method unsubscribe($observer) {
        @!observers .= grep({ $^o !=== $observer });
    }

    method publish($obj) {
        @!observers>>.handle($obj)
    }
}

class ReadLineSource does Observable {
    has $.fh;
    method enterloop() {
        loop {
            self.publish($.fh.get());
        }
    }
}

multi grep($matcher, Observable $ob) {
    my class GrepSubscriber does Observable {
        has $.matcher;
        method handle($obj) {
            if $obj ~~ $.matcher {
                self.publish($obj);
            }
        }
    }
    $ob.subscribe(GrepSubscriber.new(:$matcher))
}

my $src = ReadLineSource.new(fh => $*IN);
$src
    ==> grep(/^\d+$/)
    ==> into my $nums;

$nums
    ==> grep(*.Int.is-prime)
    ==> call(-> $p { say "That's prime!" });

$nums
    ==> map(-> $n {
            state $total += $n;
            $total >= 100 ?? 'More than 100' !! ()
        })
    ==> first()
    ==> call(-> $msg { say $msg });

    ## copy

    role Hammering {
    method hammer($stuff) {
        say "You hammer on $stuff. BAM BAM BAM!";
    }
}

class Hammer does Hammering {}
class Gavel  does Hammering {}
class Mallet does Hammering {}

my $hammer = Hammer.new;    # create a new hammer object
say $hammer ~~ Hammer;      # "Bool::True" -- yes, this we know
say $hammer ~~ Hammering;   # "Bool::True" -- ooh!

my $unkown_object = Gavel.new;
if $unkown_object ~~ Hammering {
    $unkown_object.hammer("that nail over there");     # will always work
}