File Coverage

blib/lib/Art/World.pm
Criterion Covered Total %
statement 867 988 87.7
branch 18 24 75.0
condition 27 150 18.0
subroutine 165 184 89.6
pod 0 25 0.0
total 1077 1371 78.5


line stmt bran cond sub pod time code
1 15     15   1564286 use 5.20.0;
  15         197  
2 15     15   78 use strict;
  15         30  
  15         377  
3 15     15   93 use warnings;
  15         25  
  15         1222  
4              
5             package Art::World {
6              
7             our $VERSION = '0.19';
8              
9             use Zydeco
10 15         220 authority => 'cpan:SMONFF',
11             # Predeclaration of types avoid use of quotes in args types declarations or
12             # signatures. See https://codeberg.org/smonff/art-world/issues/37
13             declare => [
14             'Agent',
15             'Artwork',
16             'Collector',
17             'Event',
18             'Idea',
19             'Place',
20             'Theory',
21             ],
22 15     15   11037 version => $VERSION;
  15         5677949  
23              
24 15     15   504993 use feature qw( postderef );
  15         37  
  15         979  
25 15     15   90 no warnings qw( experimental::postderef );
  15         35  
  15         638  
26 15     15   98 use Carp qw( carp cluck );
  15         34  
  15         919  
27 15     15   85 use utf8;
  15         30  
  15         116  
28 15     15   9402 use Config::Tiny;
  15         14664  
  15         617  
29 15     15   122 use List::Util qw( max any );
  15         31  
  15         1045  
30 15     15   7212 use Math::Round;
  15         17444  
  15         990  
31 15     15   120 use Try::Tiny;
  15         32  
  15         2192  
32              
33 15     15   646788 role Abstraction {
  15         40  
  15         135  
  15         397  
34 15         201 has discourse ( type => Str );
35 15         885 # TODO could be a table in the database
36 15         152 has file! ( type => ArrayRef[ Idea ], );
  15         55405  
37 15         126 has idea! ( type => Str, is => rw, trigger => true );
  15         389  
38 15         94 has process ( type => ArrayRef );
  15         443  
39 15         93 has project ( type => Str );
  15         309  
40 15         139 has time ( type => Int );
41 15         371 # Here should exist all the possible interractions of Concept entities
42             method initiate_process {
43 0   0 0 0 0 return $self->idea;
  0         0  
  0         0  
  0         0  
44 0         0 }
  15         340  
45 15         224 method insert_to_file {}
46 15         266 # etc.
47 15   0 0 0 178 method _trigger_idea {
  0         0  
  0         0  
  0         0  
  0         0  
48 3   33 3   8 push $self->file->@*, $self->idea;
  3         13  
  3         6  
  3         15191  
49 3         80 }
50 15     15   8610697 }
  15     15   43  
  15         317  
  15         144  
  15         6508  
  15         334  
  15         70  
51              
52 15     15   21496 role Active {
  15         34  
  15         245  
  15         270  
53             method participate {
54 0   0 0 0 0 say "That's interesting";
  0         0  
  0         0  
  0         0  
55 0         0 }
56 15     15   17851 }
  15     15   32  
  15         163  
  15         149  
  15         5673  
  15         35  
  15         63  
57              
58 15     15   40498 role Buyer {
  15         36  
  15         107  
59 15         373  
60 15         96 requires money;
61 15         501  
62             multi method acquire ( Artwork $art ) {
63 4   33     20076 $self->pay( $art, $self );
  4         20  
  4         8  
64 4         20 $art->change_owner( $self );
65 4         192 }
66 15     15   4520168 }
  15     15   37  
  15         287  
  15         230  
  15         7620  
  15         40  
  15         70  
67              
68             # Dunno how but the fact of being collected should bump artist reputation
69 15     15   249734 role Collectionable {
  15         40  
  15         161  
  15         388  
70             has owner (
71 15   33     156 lazy => true,
  1         8075  
  1         180  
  1         30  
72             is => rw,
73             clearer => true,
74             writer => 'set_owner',
75 15         20170 type => ArrayRef[ Agent ]) = $self->creator;
76 15         121 has value ( is => rw );
  15         330  
77             has status (
78 15         118 enum => ['for_sale', 'sold'],
79             # Create a delegated method for each value in the enumeration
80             handles => 1,
81             default => 'for_sale' );
82 15         300  
83             method $remove_from_seller_collection {
84             my $meta = Art::World::Util->new_meta;
85 6   33     9 # Removal of the to-be-sold Artwork in seller collection
  6         23  
  6         8  
86 6         156 for my $owner ( $self->owner->@* ) {
87             # Artists don't have a collection
88 6         293 # Or maybe they can... So we should add a specific case
89             if ( $meta->get_class( $owner ) !~ '^Art::World::Artist$' ) {
90             while ( my ( $i, $art ) = each( $owner->collection->@* )) {
91 9 100       139 # Removing if a matching artwork is found
92 8         149 # Should be removed by id, but we don't manage that yet
93             if ( $art->title =~ $self->title ) {
94             # Wish I would use List::UtilsBy extract_by() for this
95 5 100       121 splice $owner->collection->@*, $i, 1;
96             }
97 3         59 }
98             }
99             }
100             }
101 15         27  
102 15         337 multi method change_owner ( Collector $buyer ) {
  15         403  
103              
104 4   33     21722 # From seller collection
  4         21  
  4         7  
105             $self->$remove_from_seller_collection;
106              
107 4         16 $self->clear_owner;
108             $self->set_owner([ $buyer ]);
109 4         104 push $buyer->collection->@*, $self;
110 4         90 # TODO guess it should bump some people reputation and artwork aura now
111 4         229 }
112 15         470  
113 15         343 multi method change_owner ( Coinvestor $buyers ) {
114 2   33     868  
  2         8  
  2         6  
115             # From Collector point of view
116             $self->$remove_from_seller_collection;
117 2         7  
118             # From Artwork point of view
119             $self->clear_owner;
120 2         53 $self->set_owner( $buyers->members );
121 2         43 push $buyers->collection->@*, $self;
122 2         104 # TODO guess it should bump some people reputation and artwork aura now
123             }
124 15     15   4467835 }
  15     15   41  
  15         279  
  15         157  
  15         6632  
  15         37  
  15         66  
125              
126 15     15   68935 role Collective {
  15         41  
  15         127  
127 15         372  
128 15         130 has members! ( type => ArrayRef[ Agent ] );
129 15         4372  
130             multi method acquire ( Artwork *art, Collective *collective ) {
131 2   33     4573 for my $member ( $arg->collective->members->@* ) {
  2         9  
  2         4  
132 2         12 $member->pay( $arg->art, $arg->collective );
133 4         110 }
134             $arg->art->change_owner( $arg->collective );
135 2         90 }
136 15     15   1645144 }
  15     15   39  
  15         269  
  15         244  
  15         6875  
  15         35  
  15         177  
137              
138 15     15   211365 role Crud {
  15         43  
  15         145  
  15         380  
139 15         174 has dbh! ( type => InstanceOf[ 'Art::World::Model' ], builder => true, lazy => true );
  15         74787  
140 15         196 has db! ( type => HashRef[ Str ], builder => true, lazy => true );
141 15         44405  
142             method insert ( Str $table, HashRef $attributes ) {
143             # TODO IT MUST BE TESTED
144 100   33 100 0 402 unless ( $self->does( 'Art::World::Unserializable' )) {
  100   66     453  
  100         210  
  100         1605094  
  100         440  
  100         2010  
  100         2264  
145             try {
146 100 50       500 my $row = $self->dbh->insert( ucfirst lc $table, $attributes);
147             } catch {
148             cluck 'You tried to insert to ' . $table . ' but this table doesn\'t exist';
149 100         3886 }
150             }
151             }
152 15         364  
153 15         450 method _build_dbh {
154             use DBI;
155 3   33 3   147 use Teng;
  3         286  
  3         11  
  3         117  
156 15     15   3311716 use Teng::Schema::Loader;
  15         230427  
  15         1449  
157 15     15   10630 my $dbh = Teng::Schema::Loader->load(
  15         638879  
  15         1027  
158 15     15   8826 dbh => DBI->connect(
  15         128947  
  15         3072  
159             'dbi:' . $self->db->{ kind } .
160             ':dbname=' . $self->db->{ name },
161             '', '' ),
162             namespace => __PACKAGE__ . '::Model'
163 3         96 );
164             return $dbh;
165             }
166 3         68689  
  15         272  
167 15         242 method _build_db {
168 3   33 3   8 return {
  3         12  
  3         5  
  3         58  
169             name => $self->config->{ DB }->{ NAME },
170             kind => $self->config->{ DB }->{ KIND },
171             };
172 3         81 }
173 15     15   40950 }
  15     15   39  
  15         262  
  15         186  
  15         6676  
  15         47  
  15         76  
174              
175 15     15   70875 role Event {
  15         44  
  15         137  
  15         420  
176 15         131 has place ( type => Place );
  15         3130  
177 15         159 has datetime ( type => InstanceOf['Time::Moment'] );
178 15         9415 # "guests"
179 15         137 has participant ( type => ArrayRef[ Agent ] );
  15         2761  
180 15         126 has title ( type => Str, is => ro );
181 15     15   4461740 }
  15     15   47  
  15         308  
  15         7541  
  15         38  
  15         74  
182              
183 15     15   59030 role Exhibit {
  15         47  
  15         125  
  15         385  
184 15         115 has public;
  15         543  
185 15         124 has exhibition ( type => ArrayRef );
  15         522  
186 15         78 has artist ( type => ArrayRef );
  15         363  
187 15         80 has artwork ( type => ArrayRef );
188 15         356  
189             method display {
190 0   0 0 0 0 say "Shoooow";
  0         0  
  0         0  
  0         0  
191 0         0 }
192 15     15   4508964 }
  15     15   44  
  15         264  
  15         206  
  15         7447  
  15         39  
  15         67  
193              
194             # TODO If an Agent work is collected, it's reputation should go up
195 15     15   165002 role Fame {
  15         493  
  15         129  
196 15         801 # Private
197             method $update_fame( Num $difference ) {
198             # Dynamic attribute accessor
199 33   33     172 my $attribute = $self->isa( 'Art::World::Work' ) ?
  33         97  
  33         52  
200             'aura' : 'reputation';
201 33 100       260 if ( $self->can( $attribute )) {
202             if ( $self->$attribute + $difference >= 0 ) {
203 33 50       142 $self->$attribute( $self->$attribute + $difference )
204 33 100       787 } else {
205 32         689 carp 'You tried to update ' . $attribute . ' to a value smaller ' .
206             'than zero. Nothing changed.';
207 1         254 }
208             return $self->$attribute;
209             } else {
210 33         1460 require Art::World::Util;
211             carp 'No such attribute ' . $attribute .
212 0         0 ' or we don\'t manage this kind of entity ' . Art::World::Util->new_meta->get_class( $self );
213 0         0 }
214             }
215 15         27  
216 15         356 multi method bump_fame( PositiveNum $gain ) {
  15         323  
217             $self->$update_fame( $gain );
218 22   33     1538 }
  22         78  
  22         33  
219 22         64  
  15         547  
220 15         217 multi method bump_fame( NegativeNum $loss ) {
221             $self->$update_fame( $loss )
222 8   33     708 }
  8         30  
  8         14  
223 8         25  
  15         307  
224 15         157 multi method bump_fame {
225 3   33     273 $self->$update_fame( $self->config->{ FAME }->{ DEFAULT_BUMP });
  3         19  
  3         7  
226 3         99 }
227 15     15   1483814 }
  15     15   41  
  15         243  
  15         139  
  33         41209  
  15         6529  
  15         36  
  15         67  
228              
229 15     15   33228 role Identity {
  15         41  
  15         99  
  15         417  
230 15         134 has id ( type => Int );
  15         634  
231 15         119 has name ( type => Str );
232 15     15   2222506 }
  15     15   42  
  15         639  
  15         7579  
  15         40  
  15         62  
233              
234             # From the documentation
235             #
236             # A `Place` must `invite()` all kind of `Agents` that produce `Work` or other
237             # kind of valuable social interactions. Depending of the total `reputation` of
238             # the `Place` it will determine it's `underground` status: when going out of
239             # the `underground`, it will become an institution.
240             #
241 15     15   23445 role Invitation {
  15         44  
  15         109  
242             # In case a group of Agents are invited, for an Event like a performance, a
243 15         281 # concert
244             multi method invite ( ArrayRef[ Agent ] *people, Event *event ) {
245 0   0     0 }
  0         0  
  0         0  
246 15     15   28490 }
  15     15   49  
  15         171  
  15         212  
  15         6040  
  15         32  
  15         72  
247              
248             # The idea here is producing discourse about art
249 15     15   22489 role Language {
  15         41  
  15         104  
  15         353  
250             method speak ( Str $paroles) {
251 0   0 0 0 0 say $paroles;
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
252 0         0 # TODO Could write to a log file
253             }
254 15     15   464575 }
  15     15   39  
  15         240  
  15         235  
  15         7439  
  15         39  
  15         68  
255              
256 15     15   47223 role Manager {
  15         39  
  15         118  
  15         374  
257 15         132 has places ( type => ArrayRef[ Place ] );
258 15         19098  
259             method organize {}
260 15         378  
261 15   0 0 0 232 method influence ( Int $reputation) {
  0         0  
  0         0  
  0         0  
  0         0  
262 7   33 7 0 18 return $self->config->{ FAME }->{ MANAGER_BUMP } * $reputation;
  7   66     26  
  7         10  
  7         666  
  7         36  
  7         2173  
  7         132  
263 7         133 }
264 15     15   1604573 }
  15     15   45  
  15         314  
  15         162  
  15         6678  
  15         40  
  15         64  
265              
266 15     15   114065 role Market {
  15         42  
  15         119  
267 15         385  
268 15         142 has money! ( type => Num, is => rw, default => 0 );
269              
270 15         740 # Can be a personal collector or a Coinvestor
271             method pay ( Artwork $piece, Collector $collector ) {
272 8   33 8 0 28 # Divide what must be paid by each buyer
  8   66     29  
  8         14  
  8         25  
  8         149  
  8         3382  
  8         251  
273             my $must_give = Art::World::Util
274 8 100       213 ->new_meta
275             ->get_class( $collector ) !~ /^Art::World::Coinvestor$/ ?
276             $piece->value :
277             $piece->value / scalar $collector->members->@*;
278              
279             # The money must be divided in equal between all owners
280             my $part = $must_give / scalar $piece->owner->@*;
281 8         187 # Seller(s) got their money given
282             map { $_->money( $_->money + $part ) } $piece->owner->@*;
283 8         175 # Buyer gives the money
  12         362  
284             $self->money( $self->money - $must_give );
285 8         341 }
286 15     15   2088469 }
  15     15   42  
  15         273  
  15         287  
  15         7415  
  15         38  
  15         66  
287              
288 15     15   21012 role Showable {
  15         36  
  15         106  
289 15         273 #requires exhibition;
290             method exhibit {
291 0   0 0 0 0 say "Show";
  0         0  
  0         0  
  0         0  
292 0         0 }
293 15     15   17706 }
  15     15   37  
  15         176  
  15         171  
  15         5566  
  15         54  
  15         71  
294              
295 15     15   13627 role Space {
  15         53  
  15         105  
296             # Like a small space or a large space
297 15         378 # Could limit the number of person coming during an event for example
298 15         101 has space;
299 15     15   1112282 }
  15     15   41  
  15         535  
  15         7359  
  15         43  
  15         78  
300              
301 15     15   20827 role Underground {
  15         46  
  15         108  
  15         286  
302             method experiment {
303 0   0 0 0 0 say "Underground";
  0         0  
  0         0  
  0         0  
304 0         0 }
305 15     15   17844 }
  15     15   38  
  15         205  
  15         179  
  15         5994  
  15         37  
  15         74  
306              
307 15     15   15344 role Writing {
  15         45  
  15         110  
  15         336  
308             method write ( Theory $concepts ) {}
309 15   0 15 0 456049 }
  15   0 15   39  
  15     0   236  
  15         261  
  0         0  
  0         0  
  0         0  
  15         6778  
  15         41  
  15         67  
  0         0  
  0         0  
  0         0  
  0         0  
310              
311 15     15   1404237 class Art {
  15         45  
  15         174  
  0         0  
312 15         240  
313             has config (
314             is => ro,
315             lazy => true,
316 4         83 default => sub { Config::Tiny->read( './art.conf' )}
317 15         171 );
318              
319             # TODO an implemented project (Work, Exhibition) should inherit of this
320 15         375 # TODO some stuff should extends this
321 15     15   1645113 abstract class Concept {
  15         46  
  15         152  
  15         304  
  15         34  
322 15     15   1401161 class Idea with Abstraction {
  15         49  
  15         168  
  15         462  
  15         33  
  0         0  
323 15         521 method express {
324 0   0 0 0 0 say $self->discourse if $self->discourse;
  0         0  
  0         0  
  0         0  
325 0 0       0 }
326 15     15   25338 }
  15     15   39  
  15         245  
  15         200  
  15         7625  
  15         44  
  15         69  
  15         39  
327 15     15   10576 class Theory with Abstraction { }
  15     15   35  
  15     15   105  
  15         1499  
  15         34  
  15         151  
  15         275  
  15         370  
  15         5071  
  15         33  
  15         75  
328 15     15   842 }
  15     15   38  
  15         142  
  15         352  
  15         4810  
  15         48  
  15         82  
329 15         42  
330 15     15   46471 class Opening with Event, Fame {
  15         46  
  15         128  
  15         440  
  15         36  
331 15         517 has treat ( type => ArrayRef[ Str ]);
  15         142  
  15         11021  
332 15         112 has smalltalk;
333              
334 15         267 # TODO must take as parameter what is served
335             method serve {
336 1   33 1 0 3 return $self->treat->@*;
  1         6  
  1         4  
  1         6461  
337 1         11 }
338 15     15   2236669 }
  15     15   43  
  15         257  
  15         204  
  15         7136  
  15         42  
  15         71  
339              
340 15         39 # TODO Guess this is more like an Agent method or role
341 15     15   8473 class Sex with Event;
  15     15   42  
  15     15   106  
  15         1510  
  15         37  
  15         151  
  15         284  
  15         378  
  15         5094  
  15         40  
  15         84  
342 15         34  
343 15     15   172944 class Playground with Crud, Identity {
  15         45  
  15         137  
  15         276  
344 15         27  
345 15     15   37176 class Magazine {
  15         40  
  15         113  
  0         0  
346 15         398  
347 15         113 has reader;
  15         539  
348 15         99 has writer ( type => ArrayRef[ Agent ] );
349 15         4122  
350 15   0 0 0 210 method publish {};
  0         0  
  0         0  
  0         0  
  0         0  
351 15     15   2229222 }
  15     15   46  
  15         249  
  15         7162  
  15         40  
  15         67  
352 15         25  
353 15     15   132889 class Place with Fame, Invitation, Space {
  15         47  
  15         132  
  15         277  
354              
355 15         33 # Like, dunno, a city ? Could be in a Geo role I guess
356 15         140 has location ( type => Str );
  0         0  
357 15         462  
358 15     15   1238703 class Institution with Market {
  15         47  
  15         151  
  15         306  
  15         28  
359 15     15   52275 class Gallery with Exhibit, Buyer {
  15         40  
  15         125  
  15         554  
  15         51  
  0         0  
360 15         591 has artwork ( type => ArrayRef );
  15         137  
  15         622  
361 15         83 has artist ( type => ArrayRef );
  15         382  
362 15         75 has event ( type => ArrayRef );
  15         353  
363 15         74 has owner;
364 15     15   4410482 }
  15     15   49  
  15         327  
  15         7996  
  15         43  
  15         73  
365 15         24  
366 15     15   11292 class Museum with Exhibit, Buyer;
  15     15   57  
  15     15   104  
  15         1563  
  15         37  
  15         149  
  15         281  
  15         368  
  15         5122  
  15         48  
  15         78  
367 15         33  
368 15     15   43772 class School {
  15         145  
  15         136  
369 15         419 # TODO much underground
370 15         106 has student ( type => ArrayRef[ Agent ]);
371 15         5577 # TODO Should enforce a minimum reputation
372 15         104 has teachers ( type => ArrayRef[ Agent ]);;
373 15     15   2217543 }
  15     15   45  
  15         302  
  15         9607  
  15         37  
  15         69  
374 15     15   1632 }
  15     15   50  
  15         172  
  15         405  
  15         4986  
  15         32  
  15         65  
375 15         29  
376 15     15   8660 class Squat with Underground;
  15     15   35  
  15     15   103  
  15         1539  
  15         30  
  15         141  
  15         638  
  15         393  
  15         5116  
  15         36  
  15         67  
  15         28  
377 15     15   5200 class Workshop;
  15     15   36  
  15     15   98  
  15         1409  
  15         37  
  15         146  
  15         4985  
  15         36  
  15         62  
378              
379 15     15   982 }
  15     15   29  
  15         150  
  15         379  
  15         5116  
  15         35  
  15         65  
380 15         31  
381 15     15   5322 class Website;
  15     15   31  
  15     15   107  
  15         1312  
  15         35  
  15         138  
  15         4841  
  15         37  
  15         63  
382              
383 15     15   997 }
  15     15   32  
  15         154  
  15         359  
  15         4897  
  15         33  
  15         68  
384 15         31  
385 15     15   528691 class Agent with Active, Crud, Fame, Identity {
  15         49  
  15         156  
  15         283  
386 15         34  
387 15         483 has relationship;
  15         357  
  0         0  
388 15         174 has reputation ( is => rw, type => PositiveOrZeroNum ) = 0;
  22         69625  
389             # TODO it would improve a lot the networking
390              
391             # TODO Should be done during an event
392             # TODO In case the networker is a Manager, the reputation bump
393 15         391 # should be higher
394             method networking( ArrayRef $people ) {
395              
396 3   33 3 0 11 $self->dbh;
  3   66     21  
  3         7  
  3         15126  
  3         265  
  3         2495  
  3         49  
397             my $highest_reputation = max map { $_-> reputation } $people->@*;
398 3         108 my $bump = $highest_reputation > 1 ?
399 3         100 round( $highest_reputation * $self->config->{ FAME }->{ BUMP_COEFFICIENT } / 100) :
  9         234  
400             $self->config->{ FAME }->{ DEFAULT_BUMP };
401             for my $agent ( $people->@* ) {
402 3 50       94 $agent->bump_fame( $bump );
403 3         169 }
404 9         241  
405             if ( any { $_->does( 'Art::World::Manager' ) } $people->@* ) {
406             my @managers = grep { $_->does( 'Art::World::Manager' )} $people->@*;
407 3 50       67 my $highest_influence_manager = max map { $self } @managers;
  7         160  
408 3         63 # Bump all the other persons with the Manager->influence thing
  9         125  
409 3         41 # but not the Manager with the highest influence otherwise it would
  4         21  
410             # increase it's own reputation
411             my @all_the_other = grep { $_->id != $highest_influence_manager->id } $people->@*;
412             for my $agent ( @all_the_other ) {
413 3         8 # The influence() methode is only a way of bumping_fame() with a special bumper
  9         45  
414 3         12 $agent->bump_fame( $highest_influence_manager->influence( $agent->reputation ));
415             }
416 6         127 }
417             }
418 15         303  
419 15     15   3020294 class Artist with Market {
  15         42  
  15         160  
  15         560  
  15         264  
420 15         34  
421 15         547 has artworks ( type => ArrayRef );
  15         159  
  15         626  
422 15         123 has collectors ( type => ArrayRef[ Collector ], default => sub { [] });
  108         96394  
  15         20786  
423 15         149 has collected ( type => Bool, default => false, is => rw );
  15         392  
424             has status (
425             enum => [ 'underground', 'homogenic' ],
426             # Create a delegated method for each value in the enumeration
427             handles => 1,
428             default => sub {
429 111         11233 my $self = shift;
430 15 100       138 $self->has_collectors ? 'homogenic' : 'underground' });
  111         300  
431 15         309  
432             method create {
433             say $self->name . " create !";
434 0   0 0 0 0 }
  0         0  
  0         0  
  0         0  
435 0         0  
  15         418  
436 15         204 method have_idea {
437             say $self->name . ' have shitty idea' if true;
438 0   0 0 0 0 }
  0         0  
  0         0  
  0         0  
439 0         0  
  15         271  
440 15         161 method perform {}
441              
442             # factory underground_artist does underground
443              
444 15         263 # TODO Zydeco already provides a shortcut for this through predicates
445 15   0 0 0 135 method has_collectors {
  0         0  
  0         0  
  0         0  
  0         0  
446 111   33 111 0 196 if ( scalar $self->collectors->@* > 1 ) {
  111         330  
  111         155  
  111         308  
447 111 100       2526 $self->collected( true );
448 3         68 }
449             }
450 15     15   4610770 }
  15     15   43  
  15         287  
  15         131  
  15         7106  
  15         43  
  15         71  
451 15         35  
452 15     15   62836 class Collector with Active, Buyer, Market {
  15         39  
  15         123  
  15         278  
  15         32  
453 0         0 has collection (
454             type => ArrayRef[ Artwork, 0 ],
455 11         42284 default => sub { [] },
456 15         112 is => rw, );
  15         19508  
457 15     15   1156651 class Coinvestor with Collective {
  15         46  
  15         149  
  15         401  
458             # TODO the Coinvestor money should be automatically build from all the
459             # investors
460 15     15   1652 }
  15     15   37  
  15         228  
  15         507  
  15         6720  
  15         36  
  15         65  
461 15     15   1059 }
  15     15   33  
  15         149  
  15         406  
  15         5395  
  15         36  
  15         75  
462 15         27  
463 15     15   12393 class Critic with Language, Writing {};
  15     15   44  
  15     15   103  
  15         1489  
  15         38  
  15         158  
  15         290  
  15         373  
  15         5120  
  15         41  
  15         81  
464 15         27  
465 15     15   60225 class Curator with Manager, Writing {
  15         39  
  15         128  
  15         468  
  15         33  
466 15         563 has exhibition( type => ArrayRef );
  15         139  
  15         618  
467             method select( Artwork $art ) {
468 0   0 0 0 0 push $self->exhibition->@*, $art;
  0   0     0  
  0         0  
  0            
  0            
  0            
  0            
469 0         0 }
  15         384  
470 15         259 method define( Theory $thematic ) { }
  15         260  
471 15   0 0 0 166 method setup( Place $space ) { }
  0   0     0  
  0         0  
  0         0  
  15         382  
  0            
  0            
  0            
  0            
472 15   0 0 0 158 method write( Theory $catalog ) { }
  0   0     0  
  0         0  
  0         0  
  0            
  0            
  0            
  0            
473 15   0 15 0 2918126 }
  15   0 15   44  
  15     0   306  
  15         140  
  0         0  
  0         0  
  0         0  
  15         7457  
  15         39  
  15         69  
  0            
  0            
  0            
  0            
474 15         31  
475 15     15   8070 class Director with Manager;
  15     15   36  
  15     15   106  
  15         1496  
  15         66  
  15         153  
  15         278  
  15         402  
  15         5398  
  15         38  
  15         65  
476 15         38  
477 15     15   30799 class Public with Unserializable? {
  15         37  
  15         114  
  15         387  
478 15         31 # TODO could have an ArrayRef of Agents attribute
479 15         493 method visit( ConsumerOf[ Event ] $event ) {
480 0   0 0 0 0 say "I visited " . $event->title;
  0   0     0  
  0         0  
  0            
  0            
  0            
  0            
481 0         0 }
482 15     15   471941 }
  15     15   47  
  15         243  
  15         217  
  15         6915  
  15         36  
  15         71  
483 15     15   1110 }
  15     15   48  
  15         152  
  15         411  
  15         5065  
  15         37  
  15         72  
484              
485              
486 15     15   128304 class Work extends Concept with Fame, Identity {
  15         41  
  15         125  
  15         332  
  15         529  
487 15         32  
488 15         115 has creation_date;
  15         359  
  0         0  
489             has creator!(
490 15         143 is => ro,
491             type => ArrayRef[ Agent ] );
492              
493 15         11902 # TODO it conflicts a bit with the Identity's name attribute
494             has title(
495 15         157 is => ro,
496             type => Str );
497              
498 15         425 # Same as Agent->reputation
499 15         149 has aura( is => rw, type => PositiveOrZeroNum );
500 15         319  
501 15     15   4472002 class Article
  15     15   50  
  15     15   162  
  15         1737  
  15         39  
  15         235  
  15         7133  
  15         38  
  15         72  
502 15         41  
503 15     15   22377 class Artwork with Showable, Collectionable {
  15         51  
  15         115  
  15         472  
  15         32  
504 15         562 has material;
  15         109  
  15         383  
505 15         78 has size;
506 15     15   2174289 }
  15     15   49  
  15         297  
  15         8375  
  15         45  
  15         72  
507 15         30  
508 15     15   5474 class Book;
  15     15   41  
  15     15   111  
  15         1335  
  15         58  
  15         163  
  15         4887  
  15         39  
  15         70  
509              
510             # BUG doesn't have the Work attributes.
511 15         37 # Multiple inheritance is not fine
512 15     15   34370 class Exhibition with Event {
  15         42  
  15         116  
  15         446  
  15         36  
513 15         509 has curator! (
514 15         94 is => ro,
515             type => ArrayRef[ Curator ] );
516 15     15   1118460 }
  15     15   44  
  15         277  
  15         27459  
  15         57  
  15         73  
517 15     15   1361 }
  15     15   34  
  15         166  
  15         321  
  15         4990  
  15         59  
  15         76  
518 15     15   893 }
  15     15   46  
  15         170  
  15         4880  
  15         40  
  15         73  
519             }
520              
521             1;
522             __END__
523              
524             =encoding UTF-8
525              
526             =head1 NAME
527              
528             Art::World - Modeling of creative processes
529              
530             =head1 SYNOPSIS
531              
532             use Art::World;
533              
534             my $artwork = Art::World->new_artwork(
535             creator => [ $artist, $another_artist ] ,
536             owner => 'smonff'
537             title => 'Corrupted art institutions likes critical art'
538             value => 100, );
539              
540             my $museum = Art::World->new_museum(
541             money => 1000,
542             name => 'Contemporary Museum of Art::World'
543             );
544              
545             $museum->acquire( $artwork );
546              
547             =head1 DESCRIPTION
548              
549             C<Art::World> is an attempt to model and simulate a system describing the
550             interactions and influences between the various I<agents> of the art world.
551              
552             It tries to draw a schematization of the interactions between art, institutions,
553             influences and unexpected parameters during the social processes of artistic
554             creation.
555              
556             More informations about the purposes and aims of this project can be found in
557             it's L<Art::World::Manual>. Especially, the
558             L<HISTORY|Art::World::Manual/"HISTORY"> and the
559             L<OBJECTIVES|Art::World::Manual/"OBJECTIVES"> section could be very handy to
560             understand how this is an artwork using programming.
561              
562             =head1 MOTIVATIONS
563              
564             This project is a self-teaching experiment around the modern Perl
565             object-oriented programming toolkit. In late 2020, I read a bit about
566             L<Corrina|https://github.com/Ovid/Cor/wiki> and immediatly wanted to restart and
567             experiment my old C<Art::World> project. While searching for something somewhat
568             close to Corrina, since Corrina was only a draft and RFC, I discovered the
569             Zydeco toolkit by Toby Inkster and immediatly felt very enthusiastic to use it
570             to implement my idea. I hope it is a decent example of the possibilities this
571             wonderful framework make possible.
572              
573             It is possible that this toolkit may be used by an art management software as it
574             could be needed in an art galery or a museum.
575              
576             =head1 ROLES
577              
578             =head2 Abstraction
579              
580             This is were all kind of weird phenomenons between abstract artistic entities happen. See the
581             L<Manual|Art::World::Manual> about how it works.
582              
583             =head2 Active
584              
585             Is used to dissociate behaviors belonging to performers as opposed to the
586             public. Provide a C<participate> method.
587              
588             =head2 Buyer
589              
590             All those behaviors and attributes are encapsulated in the C<Buyer> role because
591             there is no such thing as somebody in the art world that buy but doesn't sale.
592              
593             The C<aquire> method is requiring some C<money>. The C<money> is provided by the
594             C<Market> role.
595              
596             $collector->acquire( $artwork );
597              
598             Those behaviors are delegated to the C<change_owner()> method, and to
599             the C<pay()> method from the C<Market> role.
600              
601             When a C<Collector> C<acquire()> an C<Artwork>, the C<Artwork> C<ArrayRef> of
602             owners is automatically cleared and substituted by the new owner(s).
603             C<acquire()> will remove the value of the C<Artwork> from the owner's money.
604              
605             $artwork->change_owner( $self );
606              
607             When the paiement occurs, the money is allocated to all the artwork owners
608             involved and removed from the buyer's fortune.
609              
610             $self->pay( $artwork );
611              
612             It delegate the payment to the C<pay()> method of the C<Market> role. If the
613             payment is provided by an individual C<Buyer>, only one payment is done an the
614             money is dispatched to all the sellers. If a C<Collective> buy the good, each
615             member procede to a paiement from the C<Co-investors> point of view.
616              
617             =head2 Collectionable
618              
619             The C<collectionnable> provide a series of attributes for the ownership and
620             collectionability of artworks.
621              
622             If it's collectionable, it can go to a C<Collector> collection or in a
623             C<Museum>. A collectionable item is automatically owned by it's creator.
624              
625             C<Collectionable> provides a C<change_owner()> multi method that accepts either
626             C<Collectors> or C<Coinvestors> as an unique parameter. It takes care of setting
627             appropriately the new artwork owners and delegate the removal of the item from
628             the seller's collection.
629              
630             A private methode, C<$remove_from_seller_collection> is also available to take
631             care of the removal of the I<to-be-sold> C<Artwork> in the seller collection.
632             Since those can be owned by many persons, and that C<Artists> can own their own
633             artworks, but for now cannot be collectors, they are excluded from this
634             treatment.
635              
636             =head2 Collective
637              
638             They do stuff together. You know, art is not about lonely C<Artists> in their
639             C<Workshop>.
640              
641             This has first been designed for collectors, but could be used to
642             activate any kind of collective behavior.
643              
644             This is quite a problem because what if a group of people wants to buy? We have
645             a C<Coinvestor> class implementing the C<Collective> role that provide a
646             I<collective-acquirement> method.
647              
648             It's C<acquire()> multi method provide a way to collectively buy an item by
649             overriding the C<Buyer> role method. C<Coinvestor> is a class
650             inheriting from C<Collector> that implement the C<Collective> role so it would
651             be able to collectively acquire C<Works>.
652              
653             Note that the signatures are different between C<Buyer> and C<Collective> roles:
654              
655             $collector->acquire( $artwork );
656             # ==> using the method from the Buyer role
657              
658             $coinvestors->acquire({ art => $artwork, collective => $coinvestors });
659             # ==> using the method from the Collective role
660              
661             Just pass a self-reference to the coinvestor object and they will be able to organize and buy together.
662              
663             =head2 Crud
664              
665             The C<Crud> role makes possible to serialize most of the entities. For this to be
666             possible, they need to have a corresponding table in the database, plus they
667             need to not have a C<unserializable?> tag attribute. A Zydeco tag role is a role
668             without behavior that can only be checked using C<does>.
669              
670             The Crud role is made possible thanks to L<Teng>, a simple DBI wrapper and O/R
671             Mapper. C<Teng> is used through it's L<schema loader|Teng::Schema::Loader> that
672             directly instanciate an object schema from the database.
673              
674             When trying to update a value, it is necessary to pass a table name and a
675             hashref of attributes corresponding to the columns values. The table name is not case
676             sensitive when using C<Art::World> C<Crud> helpers.
677              
678             my $row = $self->dbh
679             ->insert( 'agent', {
680             name => $artist->name,
681             reputation => $artist->reputation });
682              
683             Note that it is extremely important that the testing of the database should be
684             done in the C<t/crud.t> file. If you want to test database or model
685             functionnalities in other tests, remind to create objects by specifiying the
686             config parameter that use the C<test.conf> file: only the database referenced in
687             C<test.conf> will be available on cpantesters and C<art.db> wont be available there,
688             only C<t/test.db> is available.
689              
690             =head2 Event
691              
692             All the necessary attributes and methodes for having fun between Art::world's Agents.
693              
694             =head2 Exhibit
695              
696             Role for L<C<Places>|Art::World/"Place"> that display some L<C<Artworks>|Art::World/"Artwork">.
697              
698             =head2 Fame
699              
700             C<Fame> role provide ways to control the aura and reputation that various
701             C<Agents>, C<Places> or C<Works> have. Cannot be negative.
702              
703             It has an handy C<bump_fame()> method that I<self-bump> the fame count. It can
704             be used in three specific maneers:
705              
706             =over 2
707              
708             =item pass a C<PositiveNum>
709              
710             The fame will go higher
711              
712             =item pass a C<NegativeNum>
713              
714             The fame he fame will go lower
715              
716             =item no parameter
717              
718             In that case the value defined by C<< $self->config->{ FAME }->{ DEFAULT_BUMP } >>
719             will be used to increase the reputation.
720              
721             =back
722              
723             my $artist = Art::World->new_artist(
724             reputation => 0.42,
725             name => 'Questular Rontok'
726             );
727              
728             say $artist->bump_fame; # ==> 1.42
729             say $artist->bump_fame( 0.0042 ); # ==> 1.4242
730              
731             If you try to update the fame to a negative value, nothing happens and a nice
732             warning is displayed.
733              
734             The fame can be consummed by pretty much everything. A C<Place> or and C<Agent>
735             have a fame through it's reputation, and an C<Artwork> too through it's
736             aura.
737              
738             Classes that consume C<Fame> can have two different kind of attributes for
739             storing the C<Fame>:
740              
741             =over 2
742              
743             =item aura
744              
745             For C<Works> only.
746              
747             =item reputation
748              
749             For C<Agents>, C<Places>, etc.
750              
751             =back
752              
753             =head2 Identity
754              
755             Provide C<id> and a C<name> attributes.
756              
757             =head2 Invitation
758              
759             =head2 Language
760              
761             Useful when criticizing art or participating to all kind of events, especially
762             fo networking.
763              
764             =head2 Manager
765              
766             A role for those who I<take care> of exhibitions and other organizational
767             matters. See how being a C<Manager> influence an C<Agent> in the L<CLASSES>
768             section.
769              
770             =head2 Market
771              
772             It is all about offer, demand and C<money>. It is possible that a day, the
773             discourse that some people have can influence the C<Market>.
774              
775             It provide a C<pay()> method that can be used by entities consumming this role
776             to exchange artworks on the market. This method accept an C<Artwork> as an and a
777             Collector as parameters. It smartly find how many people bought the good
778             and to how many sellers the money should be dispatched.
779              
780             =head2 Showable
781              
782             Only an object that does the C<Showable> role can be exhibited. An object should
783             be exhibited only if it reached the C<Showable> stage.
784              
785             =head2 Space
786              
787             Could limit the number of person attending an event for example
788              
789             =head2 Underground
790              
791             Provide an C<experiment()> method.
792              
793             =head2 Writing
794              
795             This is much more than small talk.
796              
797             =head1 CLASSES
798              
799             =head2 Agent
800              
801             They are the activists of the Art World, previously known as the I<Wildlife>.
802              
803             my $agent = Art::World->new_agent(
804             id => 1,
805             name => Art::World::Util->new_person->fake_name,
806             reputation => 10 # Would default to zero if none specified
807             );
808              
809             $agent->participate; # ==> "That's interesting"
810              
811             A generic entity that can be any activist of the C<Art::World>. Provides all
812             kind of C<Agent> classes and roles.
813              
814             The C<Agent> got an a C<networking( $people )> method that makes possible to
815             leverage it's C<relationships>. When it is passed and C<ArrayRef> of various implementation
816             classes of C<Agents> (C<Artist>, C<Curator>, etc.) it bumps the C<reputation>
817             attributes of all of 1/10 of the C<Agent> with the highest reputation. If this
818             reputation is less than 1, it is rounded to the C<< $self->config->{ FAME }->{
819             DEFAULT_BUMP } >> constant.
820              
821             The bump coefficient can be adjusted in the configuration through C<< { FAME }->{
822             BUMP_COEFFICIENT } >>.
823              
824             There is also a special way of bumping fame when C<Manager>s are in a Networking
825             activity: The C<influence()> method makes possible to apply the special
826             C<< $self->config->{ FAME }->{ MANAGER_BUMP } >> constant. Then the C<Agent>s
827             reputations are bumped by the C<MANAGER_BUMP> value multiplicated by the highest
828             networking C<Manager> reputation. This is what the C<influence()> method
829             returns:
830              
831             return $self->config->{ FAME }->{ MANAGER_BUMP } * $reputation;
832              
833             The default values can be edited in C<art.conf>.
834              
835             =head2 Art
836              
837             Will be what you decide it to be depending on how you combine all the entities.
838              
839             This is where we are waiting to receive some I<unexpected parameters>: in other
840             words, an C<INI> file can be provided.
841              
842             =head2 Article
843              
844             Something in a C<Magazine> of C<Website> about C<Art>, C<Exhibitions>, etc.
845              
846             =head2 Artist
847              
848             In the beginning of their carreer they are usually underground and produce
849             experimental art, but this can change in time.
850              
851             my $artist = Art::World->new_artist(
852             name => 'Andy Cassrol',
853             );
854              
855             say $artist->is_homogenic;
856             #==> false
857              
858              
859             After getting collected, artists become homogenic.
860              
861             $artist->is_underground if not $artist->has_collectors;
862              
863             The artist got a lots of wonderful powers:
864              
865             =over
866              
867             =item C<create>
868              
869             When the basic abstractions of Art are articulated, a creation occurs. It
870             doesn't mean that it will create an C<Artwork>, because it requires the
871             intervention of other C<Agents>. The C<Artist> creates through a work concept.
872             This articulation can group the different attributes of the C<Abstraction> role:
873             C<discourse>, C<file>, C<idea>, C<process>, C<project> and C<time>.
874              
875             =item C<have_idea>
876              
877             All day long
878              
879             =back
880              
881             =head2 Artwork
882              
883             The base thing producted by artists. Artwork is subclass of
884             L<C<Work>|Art::World#Work> that have a C<Showable> and C<Collectionable> role.
885             They are usually considered as goods by the C<Market> but are also subject of
886             appreciation by the C<Public>. A lot of C<Event> happen around them.
887              
888             The C<collectionable> role provide their C<value> while they have their own
889             attributes for C<material> and C<size>. The later limits the amount of atworks
890             that can be put in a C<Place>'s space during an C<Event>.
891              
892             =head2 Book
893              
894             Where a lot of theory is written by C<Critics>
895              
896             =head2 Coinvestor
897              
898             C<Coinvestor> extend the C<Collector> class by providing an arrayref attribute
899             of C<members> through the C<Collective> role. This role makes also possible to
900             invest in artworks I<collectively>.
901              
902             =head2 Collector
903              
904             A C<Collector> is mostly an C<Agent> that consume the C<Buyer> and C<Market>
905             roles and that have a C<collection> attribute.
906              
907             my $collector = Art::World
908             ->new_collector(
909             name => Art::World::Util->new_person->fake_name,
910             money => 10_000,
911             id => 4 );
912              
913             my $artwork = Art::World
914             ->new_artwork(
915             creator => $artist ,
916             title => 'Destroy capitalism',
917             value => 9_999 );
918              
919             $collector->acquire( $artwork ),
920              
921             say $collector->money;
922             #==> 1
923              
924             say $_->title for ( $collector->collection->@* );
925             #==> Destroy capitalism
926              
927             =head2 Concept
928              
929             C<Concept> is an abstract class that does the C<Abstraction> role. It should be
930             extended but cannot be instanciated.
931              
932             =head2 Critic
933              
934             =head2 Curator
935              
936             A special kind of Agent that I<can> select Artworks, define a thematic, setup
937             everything in the space and write a catalog. They mostly do C<Exhibition>.
938              
939             =head2 Director
940              
941             =head2 Exhibition
942              
943             An C<Event> that is organised by a C<Curator>.
944              
945             my $exhibition = Art::World->new_exhibition(
946             curator => [ $curator ],
947             title => $title,
948             creator => [ $curator ]);
949              
950             =head2 Gallery
951              
952             Just another kind of L<C<Place>|Art::World/"Place">, mostly commercial.
953              
954             Since it implements the L<C<Buyer>|Art::World/"Buyer"> role, a gallery can both
955             C<acquire()> and C<sell()>.
956              
957             Major place for C<Agent->networking> activities. Always check it's C<space>
958             though!
959              
960             =head2 Idea
961              
962             When some abstractions starts to become something in the mind of an C<Agent>.
963              
964             my $art_concept = Art::World->new_idea(
965             discourse => 'I have idead. Too many ideas. I store them in a file.',
966             file => [ $another_concept, $weird_idea ],
967             idea => 'idea',
968             name => 'Yet Another Idea',
969             process => [],
970             project => 'My project',
971             time => 5,
972             );
973              
974             =head2 Institution
975              
976             A C<Place> that came out of the C<Underground>.
977              
978             =head2 Magazine
979              
980             =head2 Museum
981              
982             Yet another kind of C<Place>, an institution with a lot of L<C<Artworks>|Art::World/"Artwork"> in the basement.
983              
984             =head2 Opening
985              
986             An C<Event> where you can consume free treats and speak with other networkers
987             from the art world.
988              
989             my $t = Art::World::Util->new_time( source => '2020-02-16T08:18:43' );
990             my $opening_event = Art::World->new_opening(
991             place => $place,
992             datetime => $t->datetime,
993             name => 'Come See Our Stuff',
994             smalltalk => $chat,
995             treat => [ 'Red wine', 'White wine', 'Peanuts', 'Candies' ]);
996              
997             =head2 Place
998              
999             A C<Place> must C<invite()> all kind of C<Agents> that produce C<Work> or other kind
1000             of valuable social interactions. Depending of the total C<reputation> of the
1001             C<Place> it will determine it's C<underground> status: when going out of the
1002             C<underground>, it will become an institution.
1003              
1004             =head2 Playground
1005              
1006             A generic space where C<Art::World> C<Agents> can do all kind of weird things.
1007              
1008             =head2 Public
1009              
1010             They participate and visit events.
1011              
1012             =head2 School
1013              
1014             =head2 Sex
1015              
1016             =head2 Squat
1017              
1018             A place were art world agents are doing things. A squat that is not underground
1019             anymore become an institution.
1020              
1021             =head2 Theory
1022              
1023             When some abstract concept turns to some said or written stuff.
1024              
1025             =head2 Website
1026              
1027             =head2 Work
1028              
1029             There are not only C<Artworks>. All C<Agent>s produce various kind of work or
1030             help consuming or implementing C<Art>.
1031              
1032             It got an C<aura> attribute, see the L<C<Fame>|Art::World/"Fame"> about it or
1033             read about L<Walter
1034             Benjamin|https://en.wikipedia.org/wiki/Walter_Benjamin#%22The_Work_of_Art_in_the_Age_of_Mechanical_Reproduction%22>.
1035              
1036             =head2 Workshop
1037              
1038             A specific kind of L<C<Playground>|Art::World/"Playground"> where you can build things tranquilly.
1039              
1040             =head1 AUTHOR
1041              
1042             Sébastien Feugère <sebastien@feugere.net>
1043              
1044             =head1 ACKNOWLEDGEMENTS
1045              
1046             Thanks to everyone who has contributed to ack in any way, including Adrien
1047             Lucca, Toby Inkster, Ezgi Göç, Pierre Aubert, Seb. Hu-Rillettes, Joseph Balicki,
1048             Nicolas Herubel and Nadia Boursin-Piraud.
1049              
1050             This project was made possible by the greatness of the L<Zydeco|https://zydeco.toby.ink/> toolkit.
1051              
1052             =head1 COPYRIGHT AND LICENSE
1053              
1054             Copyright 2006-2021 Sebastien Feugère
1055              
1056             This library is free software; you can redistribute it and/or modify it under
1057             the Artistic License 2.0.