File Coverage

src/class_plain_class.c
Criterion Covered Total %
statement 57 62 91.9
branch 40 68 58.8
condition n/a
subroutine n/a
pod n/a
total 97 130 74.6


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