File Coverage

src/class_plain_class.c
Criterion Covered Total %
statement 67 80 83.7
branch 45 80 56.2
condition n/a
subroutine n/a
pod n/a
total 112 160 70.0


line stmt bran cond sub pod time code
1             /* vi: set ft=xs : */
2             #define PERL_NO_GET_CONTEXT
3              
4             #include "EXTERN.h"
5             #include "perl.h"
6             #include "XSUB.h"
7              
8             #include "class_plain_class.h"
9             #include "class_plain_field.h"
10             #include "class_plain_method.h"
11              
12             #include "perl-backcompat.c.inc"
13              
14 41           ClassMeta *ClassPlain_create_class(pTHX_ IV type, SV* name) {
15             ClassMeta *class;
16 41           Newxz(class, 1, ClassMeta);
17              
18 41           class->name = SvREFCNT_inc(name);
19              
20 41           class->role_names = newAV();
21 41           class->fields = newAV();
22 41           class->methods = newAV();
23              
24 41           return class;
25             }
26              
27 11           void ClassPlain_class_apply_attribute(pTHX_ ClassMeta *class, const char *name, SV* value) {
28 11 50         if(value && (!SvPOK(value) || !SvCUR(value))) {
    50          
    100          
29             value = NULL;
30             }
31            
32             // The isa attribute
33 11 50         if (strcmp(name, "isa") == 0) {
    50          
    50          
    50          
34 11 50         if(class->is_role) {
35 0           croak("The role can't have the isa attribute");
36             }
37            
38             SV* super_class_name = value;
39            
40 11 100         if (value) {
41 9           HV *superstash = gv_stashsv(super_class_name, 0);
42            
43             IV is_load_module;
44 9 100         if (superstash) {
45             // The new method
46 8           SV** new_method = hv_fetchs(superstash, "new", 0);
47            
48             // The length of the classes in @ISA
49 8           SV* super_class_isa_name = newSVpvf("%" SVf "::ISA", super_class_name);
50 8           SAVEFREESV(super_class_isa_name);
51 8 50         AV* super_class_isa = get_av(SvPV_nolen(super_class_isa_name), GV_ADD | (SvFLAGS(super_class_isa_name) & SVf_UTF8));
52 8 50         IV super_class_isa_classes_length = av_count(super_class_isa);
53            
54 8 100         if (new_method) {
55             is_load_module = 0;
56             }
57 5 100         else if (super_class_isa_classes_length > 0) {
58             is_load_module = 0;
59             }
60             else {
61             is_load_module = 1;
62             }
63             }
64             else {
65             is_load_module = 1;
66             }
67            
68             // Original logic: if(!superstash || !hv_fetchs(superstash, "new", 0)) {
69 9 100         if(is_load_module) {
70             /* Try to `require` the module then attempt a second time */
71             /* load_module() will modify the name argument and take ownership of it */
72 2           load_module(PERL_LOADMOD_NOIMPORT, newSVsv(super_class_name), NULL, NULL);
73 2           superstash = gv_stashsv(super_class_name, 0);
74             }
75              
76 9 50         if(!superstash)
77 0           croak("Superclass %" SVf " does not exist", super_class_name);
78              
79             // Push the super class to @ISA
80             {
81 9           SV* isa_name = newSVpvf("%" SVf "::ISA", class->name);
82 9           SAVEFREESV(isa_name);
83 9 50         AV *isa = get_av(SvPV_nolen(isa_name), GV_ADD | (SvFLAGS(isa_name) & SVf_UTF8));
84 9           av_push(isa, SvREFCNT_inc(super_class_name));
85             }
86             }
87             else {
88 2           class->isa_empty = 1;
89             }
90            
91             }
92             // The does attribute
93 0 0         else if (strcmp(name, "does") == 0) {
94             SV* role_name = value;
95 0           ClassPlain_add_role_name(aTHX_ class, role_name);
96             }
97             else {
98 0           croak("Unrecognised class attribute :%s", name);
99             }
100 11           }
101              
102 0           void ClassPlain_add_role_name(pTHX_ ClassMeta* class, SV* role_name) {
103 0           AV *role_names = class->role_names;
104            
105 0 0         if (role_name) {
106 0           av_push(role_names, SvREFCNT_inc(role_name));
107             }
108 0           }
109              
110 41           void ClassPlain_begin_class_block(pTHX_ ClassMeta* class) {
111 41           SV* isa_name = newSVpvf("%" SVf "::ISA", class->name);
112 41           SAVEFREESV(isa_name);
113 41 50         AV *isa = get_av(SvPV_nolen(isa_name), GV_ADD | (SvFLAGS(isa_name) & SVf_UTF8));
114            
115 41 100         if (!class->isa_empty) {
116 39 50         if(!av_count(isa)) {
    100          
117 29           av_push(isa, newSVpvs("Class::Plain::Base"));
118             }
119             }
120              
121 41 100         if (class->is_role) {
122             // The source code of Role::Tiny->import
123 1           SV* sv_source_code = sv_2mortal(newSVpv("", 0));
124 1           sv_catpv(sv_source_code, "{\n");
125 1           sv_catpv(sv_source_code, " package ");
126 1 50         sv_catpv(sv_source_code, SvPV_nolen(class->name));
127 1           sv_catpv(sv_source_code, ";\n");
128 1           sv_catpv(sv_source_code, " Role::Tiny->import;\n");
129 1           sv_catpv(sv_source_code, "}\n");
130            
131             // Role::Tiny->import
132 1 50         Perl_eval_pv(aTHX_ SvPV_nolen(sv_source_code), 1);
133             }
134 41           }
135              
136 62           MethodMeta* ClassPlain_class_add_method(pTHX_ ClassMeta* class, SV* method_name) {
137 62           AV *methods = class->methods;
138              
139 62 50         if(!method_name || !SvOK(method_name) || !SvCUR(method_name))
    50          
    0          
    0          
    50          
140 0           croak("method_name must not be undefined or empty");
141              
142             MethodMeta* method;
143 62           Newx(method, 1, MethodMeta);
144              
145 62           method->name = SvREFCNT_inc(method_name);
146 62           method->class = class;
147              
148 62           av_push(methods, (SV*)method);
149            
150 62           return method;
151             }
152              
153 38           FieldMeta* ClassPlain_class_add_field(pTHX_ ClassMeta* class, SV* field_name) {
154 38           AV *fields = class->fields;
155              
156 38 50         if(!field_name || !SvOK(field_name) || !SvCUR(field_name))
    50          
    0          
    0          
    50          
157 0           croak("field_name must not be undefined or empty");
158              
159             U32 i;
160 58 50         for(i = 0; i < av_count(fields); i++) {
    100          
161 20           FieldMeta* field = (FieldMeta* )AvARRAY(fields)[i];
162 20 100         if(SvCUR(field->name) < 2)
163 13           continue;
164              
165 7 50         if(sv_eq(field->name, field_name))
166 0           croak("Cannot add another field named %" SVf, field_name);
167             }
168              
169 38           FieldMeta* field = ClassPlain_create_field(aTHX_ field_name, class);
170              
171 38           av_push(fields, (SV*)field);
172              
173 38           return field;
174             }