File Coverage

blib/lib/Art/World.pm
Criterion Covered Total %
statement 862 975 88.4
branch 18 22 81.8
condition 27 144 18.7
subroutine 165 183 90.1
pod 0 24 0.0
total 1072 1348 79.5


line stmt bran cond sub pod time code
1 15     15   1610704 use 5.20.0;
  15         205  
2 15     15   91 use strict;
  15         30  
  15         395  
3 15     15   77 use warnings;
  15         27  
  15         1306  
4              
5             package Art::World {
6              
7             our $VERSION = '0.18_18';
8              
9             use Zydeco
10 15         282 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             'Idea',
18             'Place',
19             'Theory',
20             ],
21 15     15   11469 version => $VERSION;
  15         5892272  
22              
23 15     15   527296 use feature qw( postderef );
  15         104  
  15         661  
24 15     15   97 no warnings qw( experimental::postderef );
  15         34  
  15         723  
25 15     15   107 use Carp qw( carp cluck );
  15         30  
  15         1074  
26 15     15   96 use utf8;
  15         31  
  15         139  
27 15     15   10780 use Config::Tiny;
  15         15681  
  15         654  
28 15     15   112 use List::Util qw( max any );
  15         30  
  15         1163  
29 15     15   7917 use Math::Round;
  15         17180  
  15         997  
30 15     15   121 use Try::Tiny;
  15         35  
  15         2062  
31              
32 15     15   666332 role Abstraction {
  15         44  
  15         207  
  15         387  
33 15         138 has discourse ( type => Str );
34 15         612 # TODO should only be a table in the database
35 15         151 has file! ( type => ArrayRef[ Idea ], );
  15         55852  
36 15         119 has idea! ( type => Str, is => rw, trigger => true );
  15         441  
37 15         147 has process ( type => ArrayRef );
  15         442  
38 15         82 has project ( type => Str );
  15         302  
39 15         145 has time ( type => Int );
40 15         314 # Here should exist all the possible interractions of Concept entities
41             method initiate_process {
42 0   0 0 0 0 return $self->idea;
  0         0  
  0         0  
  0         0  
43 0         0 }
  15         350  
44 15         206 method insert_to_file {}
45 15         274 # etc.
46 15   0 0 0 135 method _trigger_idea {
  0         0  
  0         0  
  0         0  
  0         0  
47 3   33 3   11 push $self->file->@*, $self->idea;
  3         18  
  3         5  
  3         18839  
48 3         96 }
49 15     15   8685241 }
  15     15   45  
  15         247  
  15         135  
  15         6499  
  15         215  
  15         64  
50              
51 15     15   21125 role Active {
  15         34  
  15         227  
  15         261  
52             method participate {
53 0   0 0 0 0 say "That's interesting";
  0         0  
  0         0  
  0         0  
54 0         0 }
55 15     15   17231 }
  15     15   31  
  15         157  
  15         139  
  15         5456  
  15         40  
  15         69  
56              
57 15     15   40100 role Buyer {
  15         35  
  15         108  
58 15         401  
59 15         100 requires money;
60 15         494  
61             multi method acquire ( Artwork $art ) {
62 4   33     22504 $self->pay( $art, $self );
  4         35  
  4         216  
63 4         30 $art->change_owner( $self );
64 4         188 }
65 15     15   4655648 }
  15     15   51  
  15         281  
  15         249  
  15         7911  
  15         37  
  15         66  
66              
67 15     15   69612 role Collective {
  15         40  
  15         106  
  15         366  
68 15         142 has members! ( type => ArrayRef[ Object ] );
  15         11431  
69             multi method acquire ( Artwork *art, Collective *collective ) {
70 2   33     5543 for my $member ( $arg->collective->members->@* ) {
  2         10  
  2         5  
71 2         15 $member->pay( $arg->art, $arg->collective );
72 4         68 }
73             $arg->art->change_owner( $arg->collective );
74 2         100 }
75 15     15   1674797 }
  15     15   42  
  15         258  
  15         249  
  15         7013  
  15         38  
  15         65  
76              
77             # Dunno how but the fact of being collected should bump artist reputation
78 15     15   254998 role Collectionable {
  15         46  
  15         142  
  15         377  
79             has owner (
80 15   33     155 lazy => true,
  1         8643  
  1         7  
  1         21  
81             is => rw,
82             clearer => true,
83             writer => 'set_owner',
84 15         20676 type => ArrayRef[ Agent ]) = $self->creator;
85 15         115 has value ( is => rw );
  15         347  
86             has status (
87 15         124 enum => ['for_sale', 'sold'],
88             # Create a delegated method for each value in the enumeration
89             handles => 1,
90             default => 'for_sale' );
91 15         309  
92             method $remove_from_seller_collection {
93             my $meta = Art::World::Util->new_meta;
94 6   33     17 # Removal of the to-be-sold Artwork in seller collection
  6         23  
  6         11  
95 6         175 for my $owner ( $self->owner->@* ) {
96             # Artists don't have a collection
97 6         257 # Or maybe they can... So we should add a specific case
98             if ( $meta->get_class( $owner ) !~ '^Art::World::Artist$' ) {
99             while ( my ( $i, $art ) = each( $owner->collection->@* )) {
100 9 100       131 if ( $art->title =~ $self->title ) {
101 8         258 # Wish I would use List::UtilsBy extract_by() for this
102 5 100       167 splice $owner->collection->@*, $i, 1;
103             }
104 3         53 }
105             }
106             }
107             }
108 15         28  
109 15         387 multi method change_owner ( Collector $buyer ) {
  15         320  
110              
111 4   33     24107 # From seller collection
  4         24  
  4         10  
112             $self->$remove_from_seller_collection;
113              
114 4         23 $self->clear_owner;
115             $self->set_owner([ $buyer ]);
116 4         119 push $buyer->collection->@*, $self;
117 4         100 # TODO guess it should bump some people reputation and artwork aura now
118 4         272 }
119 15         480  
120 15         228 multi method change_owner ( Coinvestor $buyers ) {
121              
122 2   33     905 # From Collector point of view
  2         11  
  2         3  
123             $self->$remove_from_seller_collection;
124              
125 2         8 # From Artwork point of view
126             $self->clear_owner;
127             $self->set_owner( $buyers->members );
128 2         59 push $buyers->collection->@*, $self;
129 2         47 # TODO guess it should bump some people reputation and artwork aura now
130 2         120 }
131              
132 15     15   4543710 }
  15     15   43  
  15         265  
  15         144  
  15         6837  
  15         42  
  15         140  
133              
134 15     15   215642 role Crud {
  15         38  
  15         125  
  15         368  
135 15         163 has dbh! ( type => InstanceOf[ 'Art::World::Model' ], builder => true, lazy => true );
  15         72694  
136 15         167 has db! ( type => HashRef[ Str ], builder => true, lazy => true );
137 15         43007  
138             method insert ( Str $table, HashRef $attributes ) {
139             # TODO IT MUST BE TESTED
140 100   33 100 0 353 unless ( $self->does( 'Art::World::Unserializable' )) {
  100   66     403  
  100         197  
  100         1505218  
  100         476  
  100         3127  
  100         2402  
141             try {
142 100 50       496 my $row = $self->dbh->insert( ucfirst lc $table, $attributes);
143             } catch {
144             cluck 'You tried to insert to ' . $table . ' but this table doesn\'t exist';
145 100         3936 }
146             }
147             }
148 15         362  
149 15         358 method _build_dbh {
150             use DBI;
151 3   33 3   10 use Teng;
  3         16  
  3         7  
  3         110  
152 15     15   3452032 use Teng::Schema::Loader;
  15         233661  
  15         1386  
153 15     15   10201 my $dbh = Teng::Schema::Loader->load(
  15         631835  
  15         839  
154 15     15   7875 dbh => DBI->connect(
  15         129408  
  15         2658  
155             'dbi:' . $self->db->{ kind } .
156             ':dbname=' . $self->db->{ name },
157             '', '' ),
158             namespace => __PACKAGE__ . '::Model'
159 3         77 );
160             return $dbh;
161             }
162 3         69314  
  15         268  
163 15         202 method _build_db {
164 3   33 3   9 return {
  3         13  
  3         441  
  3         49  
165             name => $self->config->{ DB }->{ NAME },
166             kind => $self->config->{ DB }->{ KIND },
167             };
168 3         129 }
169 15     15   39308 }
  15     15   44  
  15         243  
  15         150  
  15         6732  
  15         43  
  15         73  
170              
171 15     15   71042 role Event {
  15         41  
  15         116  
  15         427  
172 15         121 has place ( type => Place );
  15         3241  
173 15         189 has datetime ( type => InstanceOf['Time::Moment'] );
174 15         9615 # "guests"
175 15         117 has participant ( type => ArrayRef[ Agent ] );
  15         2701  
176 15         132 has title ( type => Str, is => ro );
177 15     15   4570665 }
  15     15   44  
  15         293  
  15         7756  
  15         36  
  15         84  
178              
179 15     15   62221 role Exhibit {
  15         44  
  15         126  
  15         394  
180 15         127 has public;
  15         546  
181 15         126 has exhibition ( type => ArrayRef );
  15         521  
182 15         82 has artist ( type => ArrayRef );
  15         392  
183 15         72 has artwork ( type => ArrayRef );
184 15         366  
185             method display {
186 0   0 0 0 0 say "Shoooow";
  0         0  
  0         0  
  0         0  
187 0         0 }
188 15     15   4533389 }
  15     15   48  
  15         264  
  15         217  
  15         7624  
  15         39  
  15         72  
189              
190             # TODO If an Agent work is collected, it's reputation should go up
191 15     15   168265 role Fame {
  15         518  
  15         135  
192 15         837 # Private
193             method $update_fame( Num $difference ) {
194             # Dynamic attribute accessor
195 33   33     72 my $attribute = $self->isa( 'Art::World::Work' ) ?
  33         85  
  33         54  
196             'aura' : 'reputation';
197 33 100       233 if ( $self->can( $attribute )) {
198             if ( $self->$attribute + $difference >= 0 ) {
199 33 50       146 $self->$attribute( $self->$attribute + $difference )
200 33 100       798 } else {
201 32         871 carp 'You tried to update ' . $attribute . ' to a value smaller ' .
202             'than zero. Nothing changed.';
203 1         229 }
204             return $self->$attribute;
205             } else {
206 33         1594 require Art::World::Util;
207             carp 'No such attribute ' . $attribute .
208 0         0 ' or we don\'t manage this kind of entity ' . Art::World::Util->new_meta->get_class( $self );
209 0         0 }
210             }
211 15         28  
212 15         389 multi method bump_fame( PositiveNum $gain ) {
  15         345  
213             $self->$update_fame( $gain );
214 22   33     1599 }
  22         81  
  22         35  
215 22         61  
  15         640  
216 15         229 multi method bump_fame( NegativeNum $loss ) {
217             $self->$update_fame( $loss )
218 8   33     702 }
  8         32  
  8         15  
219 8         19  
  15         318  
220 15         168 multi method bump_fame {
221 3   33     101 $self->$update_fame( $self->config->{ FAME }->{ DEFAULT_BUMP });
  3         16  
  3         7  
222 3         91 }
223 15     15   1552824 }
  15     15   44  
  15         259  
  15         137  
  33         37604  
  15         7212  
  15         37  
  15         66  
224              
225 15     15   34404 role Identity {
  15         39  
  15         117  
  15         434  
226 15         155 has id ( type => Int );
  15         672  
227 15         119 has name! ( type => Str );
228 15     15   2316129 }
  15     15   48  
  15         322  
  15         8038  
  15         36  
  15         93  
229              
230             # From the documentation
231             #
232             # A `Place` must `invite()` all kind of `Agents` that produce `Work` or other kind
233             # of valuable social interactions. Depending of the total `reputation` of the
234             # `Place` it will determine it's `underground` status: when going out of the
235             # `underground`, it will become an institution.
236             #
237 15     15   24215 role Invitation {
  15         36  
  15         146  
238 15         325 # In case a group of Agents are invited, for an Event like a performance, a concert
239             multi method invite ( ArrayRef[ Agent ] *people, Event *event ) {
240 0   0     0 }
  0         0  
  0         0  
241 15     15   29730 }
  15     15   41  
  15         196  
  15         249  
  15         6772  
  15         40  
  15         75  
242              
243             # The idea here is producing discourse about art
244 15     15   23018 role Language {
  15         46  
  15         116  
  15         371  
245             method speak ( Str $paroles) {
246 0   0 0 0 0 say $paroles;
  0   0     0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
247 0         0 # TODO Could write to a log file
248             }
249 15     15   482331 }
  15     15   43  
  15         257  
  15         242  
  15         7960  
  15         35  
  15         71  
250              
251 15     15   49174 role Manager {
  15         43  
  15         131  
  15         424  
252 15         116 has places ( type => ArrayRef[ Place ] );
253 15         19763  
254             method organize {}
255 15         369  
256 15   0 0 0 262 method influence ( Int $reputation) {
  0         0  
  0         0  
  0         0  
  0         0  
257 7   33 7 0 21 return $self->config->{ FAME }->{ MANAGER_BUMP } * $reputation;
  7   66     24  
  7         14  
  7         754  
  7         52  
  7         1919  
  7         132  
258 7         190 }
259 15     15   1677653 }
  15     15   47  
  15         305  
  15         180  
  15         6831  
  15         49  
  15         79  
260              
261 15     15   117671 role Market {
  15         43  
  15         131  
262 15         388  
263 15         161 has money! ( type => Num, is => rw, default => 0 );
264              
265 15         676 # Can be a personal collector or a Coinvestor
266             method pay ( Artwork $piece, Collector $collector ) {
267 8   33 8 0 27 # Divide what must be paid by each buyer
  8   66     32  
  8         16  
  8         254  
  8         69  
  8         3868  
  8         160  
268             my $must_give = Art::World::Util
269 8 100       235 ->new_meta
270             ->get_class( $collector ) !~ /^Art::World::Coinvestor$/ ?
271             $piece->value :
272             $piece->value / scalar $collector->members->@*;
273              
274             # The money must be divided in equal between all owners
275             my $part = $must_give / scalar $piece->owner->@*;
276 8         210 # Seller(s) got their money given
277             map { $_->money( $_->money + $part ) } $piece->owner->@*;
278 8         201 # Buyer gives the money
  12         386  
279             $self->money( $self->money - $must_give );
280 8         378 }
281 15     15   2213633 }
  15     15   49  
  15         277  
  15         265  
  15         7699  
  15         41  
  15         78  
282              
283 15     15   21362 role Showable {
  15         46  
  15         112  
284 15         292 #requires exhibition;
285             method exhibit {
286 0   0 0 0 0 say "Show";
  0         0  
  0         0  
  0         0  
287 0         0 }
288 15     15   17611 }
  15     15   39  
  15         186  
  15         192  
  15         6117  
  15         49  
  15         80  
289              
290 15     15   13614 role Space {
  15         42  
  15         106  
291             # Like a small space or a large space
292 15         409 # Could limit the number of person coming during an event for example
293 15         108 has space;
294 15     15   1180087 }
  15     15   56  
  15         577  
  15         8014  
  15         42  
  15         75  
295              
296 15     15   21193 role Underground {
  15         41  
  15         116  
  15         305  
297             method experiment {
298 0   0 0 0 0 say "Underground";
  0         0  
  0         0  
  0         0  
299 0         0 }
300 15     15   17972 }
  15     15   39  
  15         191  
  15         222  
  15         6242  
  15         46  
  15         98  
301              
302 15     15   15554 role Writing {
  15         40  
  15         117  
  15         346  
303             method write ( Theory $concepts ) {}
304 15   0 15 0 474366 }
  15   0 15   47  
  15     0   240  
  15         283  
  0         0  
  0         0  
  0         0  
  15         7078  
  15         52  
  15         83  
  0         0  
  0         0  
  0         0  
  0         0  
305              
306 15     15   1434295 class Art {
  15         44  
  15         176  
  0         0  
307 15         248  
308             has config (
309             is => ro,
310             lazy => true,
311 4         81 default => sub { Config::Tiny->read( './art.conf' )}
312 15         178 );
313              
314             # TODO an implemented project (Work, Exhibition) should inherit of this
315 15         391 # TODO some stuff should extends this
316 15     15   1693283 abstract class Concept {
  15         45  
  15         167  
  15         309  
  15         31  
317 15     15   1444381 class Idea with Abstraction { }
  15     15   53  
  15     15   184  
  15         2156  
  15         40  
  15         260  
  15         460  
  15         561  
  15         7621  
  15         39  
  15         77  
  15         35  
  0         0  
318 15     15   11292 class Theory with Abstraction { }
  15     15   37  
  15     15   142  
  15         1536  
  15         41  
  15         155  
  15         286  
  15         375  
  15         5245  
  15         38  
  15         80  
319 15     15   956 }
  15     15   37  
  15         153  
  15         382  
  15         5257  
  15         40  
  15         78  
320 15         29  
321 15     15   48070 class Opening with Event, Fame {
  15         45  
  15         126  
  15         462  
  15         36  
322 15         599 has treat ( type => ArrayRef[ Str ]);
  15         140  
  15         11580  
323 15         113 has smalltalk;
324              
325 15         287 # TODO must take as parameter what is served
326             method serve {
327 1   33 1 0 4 return $self->treat->@*;
  1         5  
  1         2  
  1         7029  
328 1         14 }
329 15     15   2337487 }
  15     15   49  
  15         272  
  15         214  
  15         7459  
  15         47  
  15         77  
330              
331 15         33 # TODO Guess this is more like an Agent method or role
332 15     15   7991 class Sex with Event;
  15     15   49  
  15     15   111  
  15         1565  
  15         36  
  15         160  
  15         293  
  15         383  
  15         5338  
  15         41  
  15         70  
333 15         31  
334 15     15   176145 class Playground with Crud, Identity {
  15         49  
  15         140  
  15         288  
335 15         35  
336 15     15   37538 class Magazine {
  15         46  
  15         113  
  0         0  
337 15         399  
338 15         124 has reader;
  15         523  
339 15         97 has writer ( type => ArrayRef[ Agent ] );
340 15         4170  
341 15   0 0 0 215 method publish {};
  0         0  
  0         0  
  0         0  
  0         0  
342 15     15   2315613 }
  15     15   50  
  15         265  
  15         7379  
  15         44  
  15         73  
343 15         27  
344 15     15   136461 class Place with Fame, Invitation, Space {
  15         57  
  15         131  
  15         299  
345              
346 15         30 # Like, dunno, a city ? Could be in a Geo role I guess
347 15         155 has location ( type => Str );
  0         0  
348 15         407  
349 15     15   1262380 class Institution with Market {
  15         51  
  15         154  
  15         340  
  15         34  
350 15     15   52133 class Gallery with Exhibit, Buyer {
  15         52  
  15         112  
  15         566  
  15         36  
  0         0  
351 15         581 has artwork ( type => ArrayRef );
  15         140  
  15         650  
352 15         80 has artist ( type => ArrayRef );
  15         413  
353 15         95 has event ( type => ArrayRef );
  15         392  
354 15         81 has owner;
355 15     15   4527870 }
  15     15   47  
  15         316  
  15         8205  
  15         44  
  15         73  
356 15         24  
357 15     15   11761 class Museum with Exhibit, Buyer;
  15     15   47  
  15     15   144  
  15         1664  
  15         58  
  15         155  
  15         300  
  15         403  
  15         5611  
  15         47  
  15         77  
358 15         33  
359 15     15   44160 class School {
  15         49  
  15         130  
360 15         422 # TODO much underground
361 15         111 has student ( type => ArrayRef[ Agent ]);
362 15         4483 # TODO Should enforce a minimum reputation
363 15         108 has teachers ( type => ArrayRef[ Agent ]);;
364 15     15   2278421 }
  15     15   52  
  15         290  
  15         10751  
  15         46  
  15         88  
365 15     15   1245 }
  15     15   41  
  15         714  
  15         443  
  15         5433  
  15         39  
  15         69  
366 15         32  
367 15     15   8151 class Squat with Underground;
  15     15   38  
  15     15   128  
  15         1672  
  15         44  
  15         155  
  15         289  
  15         379  
  15         5279  
  15         79  
  15         74  
  15         38  
368 15     15   4817 class Workshop;
  15     15   38  
  15     15   101  
  15         1693  
  15         33  
  15         191  
  15         5192  
  15         33  
  15         70  
369              
370 15     15   1090 }
  15     15   34  
  15         148  
  15         379  
  15         5612  
  15         37  
  15         66  
371 15         50  
372 15     15   4903 class Website;
  15     15   37  
  15     15   97  
  15         1389  
  15         37  
  15         177  
  15         5041  
  15         34  
  15         70  
373              
374 15     15   1060 }
  15     15   33  
  15         153  
  15         492  
  15         5121  
  15         37  
  15         71  
375 15         31  
376 15     15   534455 class Agent with Active, Crud, Fame, Identity {
  15         49  
  15         153  
  15         298  
377 15         40  
378 15         161 has reputation ( is => rw, type => PositiveOrZeroNum );
  0         0  
379              
380             # TODO Should be done during an event
381             # TODO In case the networker is a Manager, the reputation bump
382 15         440 # should be higher
383             method networking( ArrayRef $people ) {
384              
385 3   33 3 0 13 $self->dbh;
  3   66     23  
  3         193  
  3         15063  
  3         44  
  3         2561  
  3         47  
386             my $highest_reputation = max map { $_-> reputation } $people->@*;
387 3         294 my $bump = $highest_reputation > 1 ?
388 3         101 round( $highest_reputation * $self->config->{ FAME }->{ BUMP_COEFFICIENT } / 100) :
  9         221  
389             $self->config->{ FAME }->{ DEFAULT_BUMP };
390             for my $agent ( $people->@* ) {
391 3 50       91 $agent->bump_fame( $bump );
392 3         125 }
393 9         239  
394             if ( any { $_->does( 'Art::World::Manager' ) } $people->@* ) {
395             my @managers = grep { $_->does( 'Art::World::Manager' )} $people->@*;
396 3 50       59 my $highest_influence_manager = max map { $self } @managers;
  7         146  
397 3         68 # Bump all the other persons with the Manager->influence thing
  9         133  
398 3         43 # but not the Manager with the highest influence otherwise it would
  4         20  
399             # increase it's own reputation
400             my @all_the_other = grep { $_->id != $highest_influence_manager->id } $people->@*;
401             for my $agent ( @all_the_other ) {
402 3         7 # The influence() methode is only a way of bumping_fame() with a special bumper
  9         52  
403 3         10 $agent->bump_fame( $highest_influence_manager->influence( $agent->reputation ));
404             }
405 6         134 }
406             }
407 15         362  
408 15     15   2012125 class Artist with Market {
  15         43  
  15         166  
  15         498  
  15         650  
409 15         36  
410 15         640 has artworks ( type => ArrayRef );
  15         169  
  15         666  
411 15         132 has collectors ( type => ArrayRef[ Collector ], default => sub { [] });
  108         96678  
  15         21358  
412 15         188 has collected ( type => Bool, default => false, is => rw );
  15         432  
413             has status (
414             enum => [ 'underground', 'homogenic' ],
415             # Create a delegated method for each value in the enumeration
416             handles => 1,
417             default => sub {
418 111         22394 my $self = shift;
419 15 100       147 $self->has_collectors ? 'homogenic' : 'underground' });
  111         314  
420 15         313  
421             method create {
422             say $self->name . " create !";
423 0   0 0 0 0 }
  0         0  
  0         0  
  0         0  
424 0         0  
  15         440  
425 15         254 method have_idea {
426             say $self->name . ' have shitty idea' if true;
427 0   0 0 0 0 }
  0         0  
  0         0  
  0         0  
428 0         0  
  15         280  
429 15         176 method perform {}
430              
431             # factory underground_artist does underground
432 15         267  
433 15   0 0 0 172 method has_collectors {
  0         0  
  0         0  
  0         0  
  0         0  
434 111   33 111 0 177 if ( scalar $self->collectors->@* > 1 ) {
  111         309  
  111         164  
  111         315  
435 111 100       2667 $self->collected( true );
436 3         97 }
437             }
438 15     15   4832774 }
  15     15   48  
  15         291  
  15         142  
  15         7197  
  15         40  
  15         73  
439 15         35  
440 15     15   64358 class Collector with Active, Buyer, Market {
  15         51  
  15         147  
  15         292  
  15         35  
441 0         0 has collection (
442             type => ArrayRef[ Artwork, 0 ],
443 11         46369 default => sub { [] },
444 15         104 is => rw, );
  15         20726  
445 15     15   1190519 class Coinvestor with Collective {
  15         43  
  15         153  
  15         432  
446             # TODO the Coinvestor money should be automatically build from all the investors
447 15     15   2092 }
  15     15   39  
  15         231  
  15         579  
  15         7310  
  15         39  
  15         73  
448 15     15   1060 }
  15     15   34  
  15         168  
  15         435  
  15         5734  
  15         60  
  15         86  
449 15         29  
450 15     15   13172 class Critic with Language, Writing {};
  15     15   51  
  15     15   104  
  15         1712  
  15         39  
  15         164  
  15         311  
  15         422  
  15         5298  
  15         130  
  15         77  
451 15         31  
452 15     15   62974 class Curator with Manager, Writing {
  15         52  
  15         131  
  15         476  
  15         31  
453 15         571 has exhibition( type => ArrayRef );
  15         149  
  15         634  
454             method select( Artwork $art ) {
455 0   0 0 0 0 push $self->exhibition->@*, $art;
  0   0     0  
  0         0  
  0            
  0            
  0            
  0            
456 0         0 }
  15         386  
457 15         284 method define( Theory $thematic ) { }
  15         275  
458 15   0 0 0 181 method setup( Place $space ) { }
  0   0     0  
  0         0  
  0         0  
  15         277  
  0            
  0            
  0            
  0            
459 15   0 0 0 156 method write( Theory $catalog ) { }
  0   0     0  
  0         0  
  0         0  
  0            
  0            
  0            
  0            
460 15   0 15 0 3036257 }
  15   0 15   50  
  15     0   286  
  15         138  
  0         0  
  0         0  
  0         0  
  15         7815  
  15         43  
  15         73  
  0            
  0            
  0            
  0            
461 15         24  
462 15     15   7889 class Director with Manager;
  15     15   103  
  15     15   119  
  15         1641  
  15         39  
  15         172  
  15         297  
  15         388  
  15         5448  
  15         37  
  15         82  
463 15         39  
464 15     15   22792 class Public with Unserializable? {
  15         40  
  15         116  
  15         334  
  15         32  
465 15         434 method visit {
466 0   0 0 0 0 say "I visited";
  0         0  
  0         0  
  0            
467 0         0 }
468 15     15   17404 }
  15     15   54  
  15         186  
  15         166  
  15         6270  
  15         41  
  15         139  
469             #use Art::Behavior::Crudable;
470             # does Art::Behavior::Crudable;
471             # has relations
472 15     15   1228 }
  15     15   35  
  15         165  
  15         402  
  15         5314  
  15         39  
  15         86  
473              
474              
475 15     15   130311 class Work extends Concept with Fame {
  15         47  
  15         140  
  15         319  
  15         484  
476 15         36  
477 15         103 has creation_date;
  15         317  
  0         0  
478             has creator!(
479 15         107 is => ro,
480             type => ArrayRef[ Agent ] );
481 15         12823  
482             has title(
483 15         165 is => ro,
484             type => Str );
485              
486 15         356 # Same as Agent->reputation
487 15         173 has aura( is => rw, type => PositiveOrZeroNum );
488 15         338  
489 15     15   4612434 class Article
  15     15   54  
  15     15   155  
  15         1875  
  15         39  
  15         242  
  15         7253  
  15         51  
  15         73  
490 15         37  
491 15     15   22565 class Artwork with Showable, Collectionable {
  15         46  
  15         115  
  15         483  
  15         32  
492 15         613 has material;
  15         124  
  15         393  
493 15         81 has size;
494 15     15   2268739 }
  15     15   49  
  15         297  
  15         8102  
  15         45  
  15         78  
495 15         31  
496 15     15   5247 class Book;
  15     15   44  
  15     15   112  
  15         1386  
  15         42  
  15         177  
  15         5165  
  15         51  
  15         78  
497              
498             # BUG doesn't have the Work attributes.
499 15         44 # Multiple inheritance is not fine
500 15     15   34886 class Exhibition with Event {
  15         45  
  15         116  
  15         475  
  15         39  
501 15         582 has curator! (
502 15         100 is => ro,
503             type => ArrayRef[ Curator ] );
504 15     15   1167844 }
  15     15   53  
  15         325  
  15         28287  
  15         46  
  15         74  
505 15     15   1340 }
  15     15   37  
  15         168  
  15         437  
  15         5244  
  15         41  
  15         73  
506 15     15   910 }
  15     15   38  
  15         169  
  15         5165  
  15         45  
  15         69  
507             }
508              
509             1;
510             __END__
511              
512             =encoding UTF-8
513              
514             =head1 NAME
515              
516             Art::World - Modeling of creative processes
517              
518             =head1 SYNOPSIS
519              
520             use Art::World;
521              
522             my $artwork = Art::World->new_artwork(
523             creator => [ $artist, $another_artist ] ,
524             owner => 'smonff'
525             title => 'Corrupted art institutions likes critical art'
526             value => 100, );
527              
528             my $museum = Art::World->new_museum(
529             money => 1000,
530             name => 'Contemporary Museum of Art::World'
531             );
532              
533             $museum->acquire( $artwork );
534              
535             =head1 DESCRIPTION
536              
537             C<Art::World> is an attempt to model and simulate a system describing the
538             interactions and influences between the various I<agents> of the art world.
539              
540             It tries to draw a schematization of the interactions between art, institutions,
541             influences and unexpected parameters during the social processes of artistic
542             creation.
543              
544             More informations about the purposes and aims of this project can be found in
545             it's L<Art::World::Manual>. Especially, the
546             L<HISTORY|Art::World::Manual/"HISTORY"> and the
547             L<OBJECTIVES|Art::World::Manual/"OBJECTIVES"> section could be very handy to
548             understand how this is an artwork using programming.
549              
550             =head1 MOTIVATIONS
551              
552             This project is a self-teaching experiment around the modern Perl
553             object-oriented programming toolkit. In late 2020, I read a bit about
554             L<Corrina|https://github.com/Ovid/Cor/wiki> and immediatly wanted to restart and
555             experiment my old C<Art::World> project. While searching for something somewhat
556             close to Corrina, since Corrina was only a draft and RFC, I discovered the
557             Zydeco toolkit by Toby Inkster and immediatly felt very enthusiastic to use it
558             to implement my idea. I hope it is a decent example of the possibilities this
559             wonderful framework make possible.
560              
561             It is possible that this toolkit may be used by an art management software as it
562             could be needed in an art galery or a museum.
563              
564             =head1 ROLES
565              
566             =head2 Abstraction
567              
568             This is were all kind of weird phenomenons between abstract artistic entities happen. See the
569             L<Manual|Art::World::Manual> about how it works.
570              
571             =head2 Active
572              
573             Is used to dissociate behaviors belonging to performers as opposed to the
574             public. Provide a C<participate> method.
575              
576             =head2 Buyer
577              
578             All this behavior and attributes are encapsulated in the C<Buyer> role because
579             there is no such thing as somebody in the art world that buy but doesn't sale.
580              
581             The C<aquire> method is requiring some C<money>. The C<money> is provided by the
582             C<Market> role.
583              
584             $collector->acquire({ art => $artwork });
585              
586             Those behaviors are delegated to the private C<$change_owner()> method, and to
587             the C<pay()> method from the C<Market> role.
588              
589             When a C<Collector> C<acquire()> an C<Artwork>, the C<Artwork> C<ArrayRef> of
590             owners is automatically cleared and substituted by the new owner(s).
591             C<acquire()> will remove the value of the C<Artwork> from the owner's money.
592              
593             $artwork->change_owner({ buyer => $sef });
594              
595             When the paiement occurs, the money is allocated to all the artwork owners
596             involved and removed from the buyer's fortune.
597              
598             $self->pay( $artwork );
599              
600             =head2 Collectionable
601              
602             The C<collectionnable> provide a series of attributes.
603              
604             If it's collectionable, it can go to a C<Collector> collection or in a
605             C<Museum>. A collectionable item is automatically owned by it's creator.
606              
607             =head2 Collective
608              
609             They do stuff together. You know, art is not about lonely C<Artists> in their
610             C<Workshop>.
611              
612             This has first been designed for collectors, but could be used to
613             activate any kind of collective behavior.
614              
615             This is quite a problem because what if a group of people wants to buy? We have
616             a C<Coinvestor> class implementing the C<Collective> role that provide a
617             I<collective-acquirement> method.
618              
619             It's C<acquire()> multi method provide a way to collectively buy an item.
620             C<Coinvestor> is a class inheriting from C<Collector> that implement the
621             C<Collective> role so it would be able to collectively acquire C<Works>.
622              
623             Note that the signatures are different between C<Buyer> and C<Collective> roles:
624              
625             $collector->acquire({ art => $artwork });
626             # ==> using the method from the Buyer role
627              
628             $coinvestors->acquire({ art => $collector->collection->[2], collective => $coinvestors });
629             # ==> using the method from the Collective role
630              
631             Just pass a self-reference to the coinvestor object and they will be able to organize and buy together.
632              
633             =head2 Crud
634              
635             The C<Crud> role makes possible to serialize most of the entities. For this to be
636             possible, they need to have a corresponding table in the database, plus they
637             need to not have a C<unserializable?> tag attribute. A Zydeco tag role is a role
638             without behavior that can only be checked using C<does>.
639              
640             The Crud role is made possible thanks to L<Teng>, a simple DBI wrapper and O/R
641             Mapper. C<Teng> is used through it's L<schema loader|Teng::Schema::Loader> that
642             directly instanciate an object schema from the database.
643              
644             When trying to update a value, it is necessary to pass a table name and a
645             hashref of attributes. The table name is not case sensitive.
646              
647             Note that it is extremely important that the testing of the database should be
648             done in the C<t/crud.t> file. If you want to test database or model
649             functionnalities in other tests, remind to create objects by specifiying the
650             config parameter that use the C<test.conf> file: only the database referenced in
651             C<test.conf> will be available on cpantesters and C<art.db> wont be available there,
652             only C<t/test.db> is available.
653              
654             =head2 Event
655              
656             All the necessary attributes and methodes for having fun between Art::world's Agents.
657              
658             =head2 Exhibit
659              
660             Role for L<C<Places>|Art::World/"Place"> that display some L<C<Artworks>|Art::World/"Artwork">.
661              
662             =head2 Fame
663              
664             C<Fame> role provide ways to control the aura and reputation that various
665             C<Agents>, C<Places> or C<Works> have. Cannot be negative.
666              
667             It has an handy C<bump_fame()> method that I<self-bump> the fame count. It can
668             be used in three specific maneers:
669              
670             =over 2
671              
672             =item pass a C<PositiveNum>
673              
674             The fame will go higher
675              
676             =item pass a C<NegativeNum>
677              
678             The fame he fame will go lower
679              
680             =item no parameter
681              
682             In that case the value defined by C<< $self->config->{ FAME }->{ DEFAULT_BUMP } >>
683             will be used to increase the reputation.
684              
685             =back
686              
687             my $artist = Art::World->new_artist(
688             reputation => 0.42,
689             name => 'Questular Rontok'
690             );
691              
692             say $artist->bump_fame; # ==> 1.42
693             say $artist->bump_fame( 0.0042 ); # ==> 1.4242
694              
695             If you try to update the fame to a negative value, nothing happens and a nice
696             warning is displayed.
697              
698             The fame can be consummed by pretty much everything. A C<Place> or and C<Agent>
699             have a fame through it's reputation, and an C<Artwork> too through it's
700             aura.
701              
702             Classes that consume C<Fame> can have two different kind of attributes for
703             storing the C<Fame>:
704              
705             =over 2
706              
707             =item aura
708              
709             For C<Works> only.
710              
711             =item reputation
712              
713             For C<Agents>, C<Places>, etc.
714              
715             =back
716              
717             =head2 Market
718              
719             It is all about offer and demand. Involve C<money>. It provide a C<pay()> method
720             that can be using by entities consumming this role. This method accept an
721             C<Artwork> as an unique required parameter.
722              
723             The C<pay()> method is used by an entity that is designed by C<$self>.
724              
725             TODO How many people can buy a thing together?
726              
727             =head2 Manager
728              
729             A role for those who I<take care> of exhibitions and other organizational
730             matters. See how being a C<Manager> influence an C<Agent> in the L<CLASSES>
731             section.
732              
733             =head2 Showable
734              
735             Only an object that does the C<Showable> role can be exhibited. An object should
736             be exhibited only if it reached the C<Showable> stage.
737              
738             =head1 CLASSES
739              
740             =head2 Agent
741              
742             They are the activists of the Art World, previously known as the I<Wildlife>.
743              
744             my $agent = Art::World->new_agent( name => $f->person_name );
745              
746             $agent->participate; # ==> "That's interesting"
747              
748             A generic entity that can be any activist of the C<Art::World>. Provides all
749             kind of C<Agent> classes and roles.
750              
751             The C<Agent> got an a C<networking( $people )> method. When it is passed and
752             C<ArrayRef> of various implementation classes of C<Agents> (C<Artist>,
753             C<Curator>, etc.) it bumps the C<reputation> attributes of all of 1/10 of the
754             C<Agent> with the highest reputation. If this reputation is less than 1, it is
755             rounded to the C<< $self->config->{ FAME }->{ DEFAULT_BUMP } >> constant.
756              
757             The bump coefficient can be adjusted in the configuration through C<< { FAME }->{
758             BUMP_COEFFICIENT } >>.
759              
760             There is also a special way of bumping fame when C<Manager>s are in a Networking
761             activity: The C<influence()> method makes possible to apply the special
762             C<< $self->config->{ FAME }->{ MANAGER_BUMP } >> constant. Then the C<Agent>s
763             reputations are bumped by the C<MANAGER_BUMP> value multiplicated by the highest
764             networking C<Manager> reputation. This is what the C<influence()> method
765             returns:
766              
767             return $self->config->{ FAME }->{ MANAGER_BUMP } * $reputation;
768              
769             The default values can be edited in C<art.conf>.
770              
771             =head2 Art
772              
773             Will be what you decide it to be depending on how you combine all the entities.
774              
775             =head2 Article
776              
777             Something in a C<Magazine> of C<Website> about C<Art>, C<Exhibitions>, etc.
778              
779             =head2 Artist
780              
781             In the beginning of their carreer they are usually underground and produce
782             experimental art, but this can change in time.
783              
784             my $artist = Art::World->new_artist(
785             name => 'Andy Cassrol',
786             );
787              
788             say $artist->is_homogenic;
789             #==> false
790              
791              
792             After getting collected, artists become homogenic.
793              
794             $artist->is_underground if not $artist->has_collectors;
795              
796             The artist got a lots of wonderful powers:
797              
798             =over
799              
800             =item C<create>
801              
802             When the basic abstractions of Art are articulated, a creation occurs. It
803             doesn't mean that it will create an C<Artwork>, because it requires the
804             intervention of other C<Agents>. The C<Artist> creates through a work concept.
805             This articulation can group the different attributes of the C<Abstraction> role:
806             C<discourse>, C<file>, C<idea>, C<process>, C<project> and C<time>.
807              
808             =item C<have_idea> all day long
809              
810             =back
811              
812             =head2 Artwork
813              
814             The base thing producted by artists. Artwork is subclass of
815             L<C<Work>|Art::World#Work> that have a C<Showable> and C<Collectionable> role.
816              
817             =head2 Book
818              
819             Where a lot of theory is written by C<Critics>
820              
821             =head2 Collector
822              
823             =head2 Concept
824              
825             C<Concept> is an abstract class that does the C<Abstraction> role.
826              
827             =head2 Critic
828              
829             =head2 Curator
830              
831             A special kind of Agent that I<can> select Artworks, define a thematic, setup
832             everything in the space and write a catalog.
833              
834             =head2 Exhibition
835              
836             An C<Event> that is organised by a C<Curator>.
837              
838             =head2 Gallery
839              
840             Just another kind of L<C<Place>|Art::World/"Place">, mostly commercial.
841              
842             Since it implements the L<C<Buyer>|Art::World/"Buyer"> role, a gallery can both
843             C<acquire()> and C<sell()>.
844              
845             =head2 Idea
846              
847             When some abstractions starts to become something in the mind of an C<Agent>
848              
849             =head2 Institution
850              
851             A C<Place> that came out of the C<Underground>.
852              
853             =head2 Magazine
854              
855             =head2 Museum
856              
857             Yet another kind of C<Place>, an institution with a lot of L<C<Artworks>|Art::World/"Artwork"> in the basement.
858              
859             =head2 Opening
860              
861             =head2 Place
862              
863             A C<Place> must C<invite()> all kind of C<Agents> that produce C<Work> or other kind
864             of valuable social interactions. Depending of the total C<reputation> of the
865             C<Place> it will determine it's C<underground> status: when going out of the
866             C<underground>, it will become an institution.
867              
868             =head2 Playground
869              
870             A generic space where C<Art::World> C<Agents> can do all kind of weird things.
871              
872             =head2 Public
873              
874             =head2 School
875              
876             =head2 Sex
877              
878             =head2 Squat
879              
880             A place were art world agents are doing things. A squat that is not underground
881             anymore become an institution.
882              
883             =head2 Theory
884              
885             When some abstract concept turns to some said or written stuff.
886              
887             =head2 Website
888              
889             =head2 Work
890              
891             There are not only C<Artworks>. All C<Agent>s produce various kind of work or
892             help consuming or implementing C<Art>.
893              
894             =head2 Workshop
895              
896             A specific kind of L<C<Playground>|Art::World/"Playground"> where you can build things tranquilly.
897              
898             =head1 AUTHOR
899              
900             Sébastien Feugère <sebastien@feugere.net>
901              
902             =head1 ACKNOWLEDGEMENTS
903              
904             Thanks to everyone who has contributed to ack in any way, including Adrien
905             Lucca, Toby Inkster, Ezgi Göç, Pierre Aubert, Seb. Hu-Rillettes, Joseph Balicki,
906             Nicolas Herubel and Nadia Boursin-Piraud.
907              
908             This project was made possible by the greatness of the L<Zydeco|https://zydeco.toby.ink/> toolkit.
909              
910             =head1 COPYRIGHT AND LICENSE
911              
912             Copyright 2006-2021 Sebastien Feugère
913              
914             This library is free software; you can redistribute it and/or modify it under
915             the Artistic License 2.0.