File Coverage

blib/lib/Tangence/Class.pm
Criterion Covered Total %
statement 110 112 98.2
branch 3 4 75.0
condition 7 14 50.0
subroutine 21 21 100.0
pod 4 8 50.0
total 145 159 91.1


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2010-2024 -- leonerd@leonerd.org.uk
5              
6 14     14   791 use v5.26;
  14         54  
7 14     14   101 use warnings;
  14         26  
  14         984  
8 14     14   967 use Object::Pad 0.800;
  14         11993  
  14         1069  
9              
10             package Tangence::Class 0.33;
11 14     14   10844 class Tangence::Class :isa(Tangence::Meta::Class);
  14         47  
  14         2107  
12              
13 14     14   2382 use Tangence::Constants;
  14         32  
  14         3851  
14              
15 14     14   8374 use Tangence::Property;
  14         58  
  14         932  
16              
17 14     14   9170 use Tangence::Meta::Method;
  14         51  
  14         847  
18 14     14   7435 use Tangence::Meta::Event;
  14         48  
  14         865  
19 14     14   7456 use Tangence::Meta::Argument;
  14         190  
  14         719  
20              
21 14     14   99 use Carp;
  14         107  
  14         1241  
22              
23 14     14   9211 use meta 0.007; # set_subname
  14         20081  
  14         779  
24 14     14   112 no warnings 'meta::experimental';
  14         31  
  14         57432  
25              
26             =head1 NAME
27              
28             C - server implementation of a C class
29              
30             =head1 DESCRIPTION
31              
32             This module is a component of L. It is not intended for
33             end-user use directly.
34              
35             =cut
36              
37             our %CLASSES; # cache one per class, keyed by _Tangence_ class name
38              
39 38         86 sub make ( $class, %args )
40 38     38 0 103 {
  38         129  
  38         68  
41 38         112 my $name = $args{name};
42              
43 38   33     822 return $CLASSES{$name} //= $class->new( %args );
44             }
45              
46             sub _new_type ( $sig )
47 60     60   121 {
  60         107  
  60         91  
48 60         266 return Tangence::Type->make_from_sig( $sig );
49             }
50              
51 26         75 sub declare ( $class, $perlname, %args )
  26         53  
52 26     26 0 82 {
  26         111  
  26         52  
53 26         219 ( my $name = $perlname ) =~ s{::}{.}g;
54              
55 26 50       160 if( exists $CLASSES{$name} ) {
56 0         0 croak "Cannot re-declare $name";
57             }
58              
59 26         128 my $self = $class->make( name => $name );
60              
61 26         68 my %methods;
62 26         55 foreach ( keys %{ $args{methods} } ) {
  26         122  
63 12         31 my %params = %{ $args{methods}{$_} };
  12         69  
64             $methods{$_} = Tangence::Meta::Method->new(
65             class => $self,
66             name => $_,
67             arguments => [ map {
68 12         76 Tangence::Meta::Argument->new( name => $_->[0], type => _new_type( $_->[1] ) )
69 12         181 } @{ delete $params{args} } ],
70 12         62 ret => _new_type( delete $params{ret} ),
71             %params,
72             );
73             }
74              
75 26         59 my %events;
76 26         49 foreach ( keys %{ $args{events} } ) {
  26         105  
77 38         73 my %params = %{ $args{events}{$_} };
  38         147  
78             $events{$_} = Tangence::Meta::Event->new(
79             class => $self,
80             name => $_,
81             arguments => [ map {
82 24         87 Tangence::Meta::Argument->new( name => $_->[0], type => _new_type( $_->[1] ) )
83 38         93 } @{ delete $params{args} } ],
  38         320  
84             %params,
85             );
86             }
87              
88 26         145 my %properties;
89 26         51 foreach ( keys %{ $args{props} } ) {
  26         125  
90 12         37 my %params = %{ $args{props}{$_} };
  12         63  
91             $properties{$_} = Tangence::Property->new(
92             class => $self,
93             name => $_,
94             dimension => ( delete $params{dim} ) || DIM_SCALAR,
95 12   50     88 type => _new_type( delete $params{type} ),
96             %params,
97             );
98             }
99              
100 26         85 my @superclasses;
101 26         70 foreach ( @{ $args{superclasses} } ) {
  26         92  
102 0         0 push @superclasses, Tangence::Class->for_perlname( $_ );
103             }
104              
105             $self->define(
106 26         169 methods => \%methods,
107             events => \%events,
108             properties => \%properties,
109             superclasses => \@superclasses,
110             );
111             }
112              
113             method define
114             {
115             $self->SUPER::define( @_ );
116              
117             my $class = $self->perlname;
118             my $classmeta = meta::package->get( $class );
119              
120             my %subs;
121              
122             foreach my $prop ( values %{ $self->direct_properties } ) {
123             $prop->build_accessor( \%subs );
124             }
125              
126             foreach my $name ( keys %subs ) {
127             next if $classmeta->try_get_symbol( '&' . $name );
128             $classmeta->add_symbol(
129             '&' . $name => $subs{$name}
130             )->set_subname( "${class}::${name}" );
131             }
132             }
133              
134 19         41 sub for_name ( $class, $name )
135 19     19 0 58 {
  19         73  
  19         30  
136 19   33     204 return $CLASSES{$name} // croak "Unknown Tangence::Class for '$name'";
137             }
138              
139 335         629 sub for_perlname ( $class, $perlname )
140 335     335 0 587 {
  335         596  
  335         516  
141 335         1569 ( my $name = $perlname ) =~ s{::}{.}g;
142 335   33     1872 return $CLASSES{$name} // croak "Unknown Tangence::Class for '$perlname'";
143             }
144              
145             sub superclasses
146             {
147 455     455 1 796 my $self = shift;
148              
149 455         2034 my @supers = $self->SUPER::superclasses;
150              
151 455 100 100     2461 if( !@supers and $self->perlname ne "Tangence::Object" ) {
152 296         1142 @supers = Tangence::Class->for_perlname( "Tangence::Object" );
153             }
154              
155 455         1650 return @supers;
156             }
157              
158 6     6 1 33 method method ( $name )
  6         26  
  6         14  
  6         11  
159             {
160 6         58 return $self->methods->{$name};
161             }
162              
163 49     49 1 104 method event ( $name )
  49         187  
  49         126  
  49         78  
164             {
165 49         317 return $self->events->{$name};
166             }
167              
168 194     194 1 337 method property ( $name )
  194         591  
  194         342  
  194         278  
169             {
170 194         887 return $self->properties->{$name};
171             }
172              
173             field $smashkeys;
174              
175             method smashkeys
176             {
177             return $smashkeys //= do {
178             my %smash;
179             $smash{$_->name} = 1 for grep { $_->smashed } values %{ $self->properties };
180             $Tangence::Message::SORT_HASH_KEYS ? [ sort keys %smash ] : [ keys %smash ];
181             };
182             }
183              
184             =head1 AUTHOR
185              
186             Paul Evans
187              
188             =cut
189              
190             0x55AA;