Commit | Line | Data |
c79239a2 |
1 | package Moose::Cookbook::Roles::Recipe3; |
9a823f26 |
2 | |
daa0fd7d |
3 | # ABSTRACT: Applying a role to an object instance |
4 | |
5 | __END__ |
6 | |
7 | package Moose::Cookbook::Roles::Recipe3; |
8 | |
9a823f26 |
9 | =pod |
10 | |
5547fba7 |
11 | =begin testing-SETUP |
c79239a2 |
12 | |
13 | { |
14 | # Not in the recipe, but needed for writing tests. |
15 | package Employee; |
16 | |
17 | use Moose; |
18 | |
19 | has 'name' => ( |
20 | is => 'ro', |
21 | isa => 'Str', |
22 | required => 1, |
23 | ); |
24 | |
25 | has 'work' => ( |
26 | is => 'rw', |
27 | isa => 'Str', |
28 | predicate => 'has_work', |
29 | ); |
30 | } |
31 | |
5547fba7 |
32 | =end testing-SETUP |
c79239a2 |
33 | |
9a823f26 |
34 | =head1 SYNOPSIS |
35 | |
36 | package MyApp::Role::Job::Manager; |
37 | |
38 | use List::Util qw( first ); |
39 | |
40 | use Moose::Role; |
41 | |
42 | has 'employees' => ( |
43 | is => 'rw', |
44 | isa => 'ArrayRef[Employee]', |
45 | ); |
46 | |
47 | sub assign_work { |
48 | my $self = shift; |
49 | my $work = shift; |
50 | |
51 | my $employee = first { !$_->has_work } @{ $self->employees }; |
52 | |
53 | die 'All my employees have work to do!' unless $employee; |
54 | |
c79239a2 |
55 | $employee->work($work); |
9a823f26 |
56 | } |
57 | |
58 | package main; |
59 | |
60 | my $lisa = Employee->new( name => 'Lisa' ); |
61 | MyApp::Role::Job::Manager->meta->apply($lisa); |
62 | |
63 | my $homer = Employee->new( name => 'Homer' ); |
64 | my $bart = Employee->new( name => 'Bart' ); |
65 | my $marge = Employee->new( name => 'Marge' ); |
66 | |
67 | $lisa->employees( [ $homer, $bart, $marge ] ); |
68 | $lisa->assign_work('mow the lawn'); |
69 | |
70 | =head1 DESCRIPTION |
71 | |
72 | In this recipe, we show how a role can be applied to an object. In |
73 | this specific case, we are giving an employee managerial |
74 | responsibilities. |
75 | |
76 | Applying a role to an object is simple. The L<Moose::Meta::Role> |
77 | object provides an C<apply> method. This method will do the right |
78 | thing when given an object instance. |
79 | |
80 | MyApp::Role::Job::Manager->meta->apply($lisa); |
81 | |
82 | We could also use the C<apply_all_roles> function from L<Moose::Util>. |
83 | |
84 | apply_all_roles( $person, MyApp::Role::Job::Manager->meta ); |
85 | |
86 | The main advantage of using C<apply_all_roles> is that it can be used |
87 | to apply more than one role at a time. |
88 | |
89 | We could also pass parameters to the role we're applying: |
90 | |
91 | MyApp::Role::Job::Manager->meta->apply( |
92 | $lisa, |
c8b8d92f |
93 | -alias => { assign_work => 'get_off_your_lazy_behind' }, |
9a823f26 |
94 | ); |
95 | |
96 | We saw examples of how method exclusion and alias working in L<roles |
97 | recipe 2|Moose::Cookbook::Roles::Recipe2>. |
98 | |
99 | =head1 CONCLUSION |
100 | |
101 | Applying a role to an object instance is a useful tool for adding |
102 | behavior to existing objects. In our example, it is effective used to |
103 | model a promotion. |
104 | |
105 | It can also be useful as a sort of controlled monkey-patching for |
106 | existing code, particularly non-Moose code. For example, you could |
107 | create a debugging role and apply it to an object at runtime. |
108 | |
c79239a2 |
109 | =begin testing |
110 | |
111 | { |
112 | my $lisa = Employee->new( name => 'Lisa' ); |
113 | MyApp::Role::Job::Manager->meta->apply($lisa); |
114 | |
115 | my $homer = Employee->new( name => 'Homer' ); |
116 | my $bart = Employee->new( name => 'Bart' ); |
117 | my $marge = Employee->new( name => 'Marge' ); |
118 | |
119 | $lisa->employees( [ $homer, $bart, $marge ] ); |
120 | $lisa->assign_work('mow the lawn'); |
121 | |
122 | ok( $lisa->does('MyApp::Role::Job::Manager'), |
123 | 'lisa now does the manager role' ); |
124 | |
125 | is( $homer->work, 'mow the lawn', |
126 | 'homer was assigned a task by lisa' ); |
127 | } |
128 | |
129 | =end testing |
130 | |
9a823f26 |
131 | =cut |