File Coverage

src/class_plain_class.c
Criterion Covered Total %
statement 66 78 84.6
branch 44 78 56.4
condition n/a
subroutine n/a
pod n/a
total 110 156 70.5


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