File Coverage

blib/lib/RPerl.pm
Criterion Covered Total %
statement 103 103 100.0
branch 14 16 87.5
condition 10 18 55.5
subroutine 12 12 100.0
pod 0 1 0.0
total 139 150 92.6


line stmt bran cond sub pod time code
1 2     2   206 use rperltypesconv; # DEV NOTE, CORRELATION #rp008: import from Exporter for code outside of a package or class
  2         5  
  2         68  
2              
3             # [[[ HEADER SPECIAL ]]]
4             package RPerl;
5 2     2   12 use strict;
  2         4  
  2         39  
6 2     2   9 use warnings;
  2         4  
  2         102  
7              
8             # DEV NOTE, CORRELATION #rp016: CPAN's underscore-is-beta (NOT RPerl's underscore-is-comma) numbering scheme utilized here, to preserve trailing zeros
9             our $VERSION = '3.200000';
10              
11             #our $VERSION = 20171031; # NON-RELEASE VERSION NUMBER, OFFICIAL LONGDATE
12             #our $VERSION = 2017.304; # NON-RELEASE VERSION NUMBER, OFFICIAL STARDATE
13              
14             # [[[ CRITICS ]]]
15             ## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls) # USER DEFAULT 1: allow numeric values & print operator
16             ## no critic qw(ProhibitConstantPragma ProhibitMagicNumbers) # USER DEFAULT 3: allow constants
17             ## no critic qw(ProhibitExplicitStdin) # USER DEFAULT 4: allow <STDIN> prompt
18             ## no critic qw(ProhibitStringyEval) # SYSTEM DEFAULT 1: allow eval()
19             ## no critic qw(RequireInterpolationOfMetachars) # USER DEFAULT 2: allow single-quoted control characters & sigils
20              
21             # [[[ INCLUDES ]]]
22              
23             # NEED FIX: pre-load all RPerl deps instead of only these?
24             # force pre-loading so they make it into $inc_skip
25 2     2   9 use parent qw();
  2         3  
  2         36  
26 2     2   10 use IPC::Cmd;
  2         4  
  2         101  
27             #use re 'strict'; # doesn't work in all versions of Perl
28 2     2   9 use re 'taint'; # hopefully doesn't actually do anything!
  2         7  
  2         82  
29              
30             # actually used in this file
31 2     2   11 use Data::Dumper;
  2         3  
  2         86  
32              
33 2     2   652 use Filter::Simple;
  2         21245  
  2         16  
34              
35             $Data::Dumper::Sortkeys = 1; # Dumper() output must be sorted for lib/RPerl/Tests/Type_Types/* etc.
36              
37             FILTER { $_ = filter($_) };
38              
39 2     2   197 use rperlnamespaces;
  2         5  
  2         46  
40              
41             # DEV NOTE: causes circular (or other weird) dependencies, error "Subroutine import redefined...",
42             # so we can't use RPerl::diag, RPerl types, or subroutines in this files;
43             # UPDATE: and yet now it works (and in fact seems required) after further development, gotta love unpredictable high-magic code! :-/
44 2     2   8 use RPerl::AfterSubclass;
  2         4  
  2         236  
45              
46 2     2   818 use Module::ScanDeps;
  2         17676  
  2         1394  
47              
48             our $INC_SCANNED = {}; # global variable to avoid repeated calls to scan_deps()
49              
50             sub filter {
51 53     53 0 238 ( my $input ) = @ARG;
52              
53 53         240 my $output = q{};
54 53         154 my $namespace_root;
55 53         209 my $package = q{};
56 53         197 my $package_line = q{};
57 53         193 my $post_package_lines = q{};
58 53         220 my $use_parent_line = q{};
59              
60 53         133 my $dependencies;
61             # my $dependencies_rperl = {};
62             # my $dependencies_rperl_package_names = [];
63             # my $dependencies_nonsystem = {};
64             # my $dependencies_nonsystem_package_names = [];
65 53         154 my $inc_skip = {};
66              
67 53         301 my $rand_serial = rand();
68              
69             # pre-generate $inc_skip to use in this file and in Module::ScanDeps::scan_deps()
70 53         28107 foreach my $included_filename_short ( sort keys %INC ) {
71             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', top of $inc_skip loop, have $included_filename_short = ' . $included_filename_short . "\n";
72 39926         72480 $namespace_root = filename_short_to_namespace_root_guess($included_filename_short);
73             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', in $inc_skip loop, have $namespace_root = ' . $namespace_root . "\n";
74 39926 100 100     168207 if (( $namespace_root ne q{} )
      100        
75             and ( ( exists $rperlnamespaces_generated::CORE->{$namespace_root} )
76             or ( exists $rperlnamespaces_generated::RPERL_DEPS->{$namespace_root} )
77             or ( exists $rperlnamespaces_generated::RPERL->{$namespace_root} ) )
78             )
79             {
80             # DEV NOTE, CORRELATION #rp019: need remove hard-coded allowance of RPerl::Test namespace, at least move to rperlnamespaces.pm or friends
81 39611 100       61333 if ( $namespace_root eq 'RPerl::' ) {
82             # $package = filename_short_to_package_guess($included_filename_short);
83             # if ( $package !~ /^RPerl::Test/xms ) {
84 9136 100       22856 if ( $included_filename_short !~ /^RPerl[\\\/]Test/xms ) {
85             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', in $inc_skip loop, noting-to-skip RPerl non-RPerl::Test $included_filename_short = ' . $included_filename_short . "\n";
86 7728         28149 $inc_skip->{$included_filename_short} = $INC{$included_filename_short};
87             }
88             }
89             else {
90             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', in $inc_skip loop, noting-to-skip non-RPerl $included_filename_short = ' . $included_filename_short . "\n";
91 30475         95632 $inc_skip->{$included_filename_short} = $INC{$included_filename_short};
92             }
93             }
94             # else { print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', in $inc_skip loop, NOT noting-to-skip $included_filename_short = ' . $included_filename_short . "\n"; }
95             }
96 53         5306 $inc_skip = { %{$inc_skip}, %{$INC_SCANNED} };
  53         6790  
  53         24799  
97 53         6031 $package = q{};
98              
99             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', have $INC_SCANNED = ' . Dumper( $INC_SCANNED ) . "\n";
100             # print {*STDERR} 'in RPerl::filter(), have $inc_skip = ' . Dumper( $inc_skip ) . "\n";
101             # print {*STDERR} 'in RPerl::filter(), have [sort keys %{$inc_skip}] = ' . Dumper( [ sort keys %{$inc_skip} ] ) . "\n";
102              
103             # ORIGINAL PURPOSE: generate $dependencies_rperl & $dependencies_nonsystem
104             # NEW PURPOSE: recursively filter all non-skipped dependencies and sub-dependencies
105 53         28677 foreach my $included_filename_short ( sort keys %INC ) {
106 39926 100       555876 if ( not exists $inc_skip->{$included_filename_short} ) {
107 63         313 $INC_SCANNED->{$included_filename_short} = $INC{$included_filename_short};
108              
109             # print {*STDERR} 'in RPerl::filter(), $rand_serial = ' . $rand_serial . ', SCANNING non-system $included_filename_short = ' . $included_filename_short . "\n";
110              
111             # DEV NOTE: Easter Egg!! scan_deps() plus filter() equals recursive source filtering!!!
112 63         273 $dependencies = scan_deps( files => [ $INC{$included_filename_short} ], skip => { reverse %{$inc_skip} }, recurse => 1, execute => 0 );
  63         58186  
113             # scan_deps( files => [ $INC{$included_filename_short} ], skip => { reverse %{$inc_skip} }, recurse => 1, execute => 0 );
114              
115             # print {*STDERR} 'in RPerl::filter(), have $INC{$included_filename_short} = ' . $INC{$included_filename_short} . ' and $dependencies = ' . Dumper($dependencies) . "\n";
116             # print {*STDERR} 'in RPerl::filter(), have $INC{$included_filename_short} = ' . $INC{$included_filename_short} . ' and [sort keys %{$dependencies}] = ' . Dumper( [ sort keys %{$dependencies} ] ) . "\n";
117              
118             }
119             # else { print {*STDERR} 'in RPerl::filter(), SKIPPING system $included_filename_short = ' . $included_filename_short . "\n"; }
120             }
121              
122             # print {*STDERR} 'in RPerl::filter(), have $INC_SCANNED = ' . Dumper( $INC_SCANNED ) . "\n";
123             # print {*STDERR} 'in RPerl::filter(), have %INC = ' . Dumper( \%INC ) . "\n";
124             # print {*STDERR} 'in RPerl::filter(), have [sort keys %{$dependencies_rperl}] = ' . Dumper( [ sort keys %{$dependencies_rperl} ] ) . "\n";
125             # print {*STDERR} 'in RPerl::filter(), have [sort keys %{$dependencies_nonsystem}] = ' . Dumper( [ sort keys %{$dependencies_nonsystem} ] ) . "\n";
126              
127             # print {*STDERR} 'in RPerl::filter(), have $dependencies_rperl = ' . Dumper($dependencies_rperl) . "\n";
128             # print {*STDERR} 'in RPerl::filter(), have $dependencies_nonsystem = ' . Dumper($dependencies_nonsystem) . "\n";
129              
130             # print {*STDERR} "\n" . 'in RPerl::filter(), have pre-modification $input = ' . "\n" . '<<<<<<<<<<<<<<<<================ BEGIN INPUT FILE ================>>>>>>>>>>>>>>' . "\n" . $input . "\n" . '<<<<<<<<<<<<<<<<================ END INPUT FILE ================>>>>>>>>>>>>>>' . "\n\n";
131              
132             # look for all user-defined classes, create subclasses
133 53         3695 foreach my $input_line ( split /\n/, $input ) {
134             # print {*STDERR} 'in RPerl::filter(), have $input_line = ' . $input_line . "\n";
135            
136 1811 100 66     5098 if ( $input_line =~ /^\s*package\s+(.*)\s*;/xms ) {
    100          
    100          
137             # not all packages are classes
138 64         177 $package_line = $input_line;
139 64         223 $package = $1;
140 64         195 $post_package_lines = q{};
141 64         188 $output .= '# [[[ HEADER, PART 1 ]]]' . "\n";
142 64         275 $output .= $input_line . "\n";
143 64         206 $output .= 'use rperltypesconv;' . "\n"; # DEV NOTE, CORRELATION #rp008: import from Exporter for code inside of a package or class
144 64         163 $output .= 'use RPerl::Config;' . "\n"; # DEV NOTE, CORRELATION #rp034: enable @ARG in all packages (class & non-class)
145              
146             # print {*STDERR} 'in RPerl::filter(), found $package_line = ' . $package_line . "\n";
147             # print {*STDERR} 'in RPerl::filter(), found $package = ' . $package . "\n";
148             }
149             elsif ( ( $input_line =~ /^\s*use\s+parent/xms ) and ( $package ne q{} ) ) {
150             # all classes are packages
151 62         161 $use_parent_line = $input_line;
152 62         353 $namespace_root = package_to_namespace_root($package);
153              
154             # print {*STDERR} q{in RPerl::filter(), have $package = '} . $package . "'\n";
155             # print {*STDERR} q{in RPerl::filter(), have $namespace_root = '} . $namespace_root . "'\n";
156             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::CORE = ' . Dumper($rperlnamespaces_generated::CORE) . "\n";
157             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::RPERL_DEPS = ' . Dumper($rperlnamespaces_generated::RPERL_DEPS) . "\n";
158             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::RPERL = ' . Dumper($rperlnamespaces_generated::RPERL) . "\n";
159             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::CORE->{' . $namespace_root . '} = ' . Dumper($rperlnamespaces_generated::CORE->{$namespace_root}) . "\n";
160             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::RPERL_DEPS->{' . $namespace_root . '} = ' . Dumper($rperlnamespaces_generated::RPERL_DEPS->{$namespace_root}) . "\n";
161             # print {*STDERR} 'in RPerl::filter(), have $rperlnamespaces_generated::RPERL->{' . $namespace_root . '} = ' . Dumper($rperlnamespaces_generated::RPERL->{$namespace_root}) . "\n";
162              
163             # DEV NOTE, CORRELATION #rp019: need remove hard-coded allowance of RPerl::Test namespace, at least move to rperlnamespaces.pm or friends
164 62 0 33     406 if (
      0        
      33        
165             ($package =~ /RPerl::Test/xms) or
166             ($package eq 'RPerl::CompileUnit::Module::Class::Template') or (
167             ( not exists $rperlnamespaces_generated::CORE->{$namespace_root} ) and
168             ( not exists $rperlnamespaces_generated::RPERL_DEPS->{$namespace_root} ) and
169             ( not exists $rperlnamespaces_generated::RPERL->{$namespace_root} ) ) )
170             {
171             # print {*STDERR} 'in RPerl::filter(), enabling subclasses for $package = ' . $package . "\n";
172              
173 62         169 my $input_line_prepend = q{};
174 62         154 $input_line_prepend .= '# <<<=== BEGIN $input_line_prepend ===>>>' . "\n";
175             # $input_line_prepend .= 'use RPerl::Config;' . "\n"; # DEV NOTE, CORRELATION #rp034: enable @ARG in all packages (class & non-class)
176 62         148 $input_line_prepend .= 'use RPerl::AfterSubclass;' . "\n";
177 62         178 $input_line_prepend .= '1; # end class, original' . "\n";
178 62         723 my $subclasses = {
179             '_raw' => [ 'RPerl::DataType::Modifier::Reference', 'ref' ],
180             '_arrayref' => [ 'RPerl::DataStructure::Array', 'arrayref' ],
181             '_hashref' => [ 'RPerl::DataStructure::Hash', 'hashref' ],
182             '::method' => [ 'RPerl::CodeBlock::Subroutine::Method', 'method' ],
183             '_arrayref::method' => [ 'RPerl::CodeBlock::Subroutine::Method', 'method' ],
184             '_hashref::method' => [ 'RPerl::CodeBlock::Subroutine::Method', 'method' ],
185             };
186 62         156 $input_line_prepend .= "\n" . '# [[[ SUBCLASSES, AUTO-GENERATED ]]]' . "\n";
187 62         132 foreach my $subclass_key ( sort keys %{$subclasses} ) {
  62         410  
188 372         740 $input_line_prepend .= 'package ' . $package . $subclass_key . ';' . "\n";
189              
190             # $input_line_prepend .= 'use strict;' . "\n";
191             # $input_line_prepend .= 'use warnings;' . "\n";
192             # $input_line_prepend .= 'use RPerl::AfterSubclass;' . "\n";
193 372         662 $input_line_prepend .= 'use ' . $subclasses->{$subclass_key}->[0] . ';' . "\n";
194 372         580 $input_line_prepend .= 'use parent -norequire, qw(' . $subclasses->{$subclass_key}->[1] . ');' . "\n";
195 372         510 $input_line_prepend .= '1; # end class, auto-generated subclass' . "\n";
196             }
197 62         161 $input_line_prepend .= '# <<<=== END $input_line_prepend ===>>>' . "\n";
198 62         274 $input_line = $input_line_prepend . "\n";
199 62         141 $input_line .= '# [[[ HEADER, PART 2 ]]]' . "\n";
200 62         212 $input_line .= $package_line . "\n";
201 62         132 $input_line .= '# <<<=== BEGIN $post_package_lines ===>>>' . "\n";
202 62         149 $input_line .= $post_package_lines; # append even if we don't enable subclasses
203 62         125 $input_line .= '# <<<=== END $post_package_lines ===>>>' . "\n";
204 62         179 $input_line .= $use_parent_line . "\n";
205              
206             # DEV NOTE: perl calls filter() but perlcritic does not, '## no critic...' & 'use strict' can be passed to perl but not perlcritic,
207             # so we must still put critics & strict in every RPerl file;
208             # 'use warnings' is checked by perl but not perlcritic, so it can be passed to perl and not put in every RPerl file;
209             # $input_line .= 'use strict;' . "\n";
210             # $input_line .= 'use warnings;' . "\n";
211 62         115 $input_line .= 'use RPerl::Config;' . "\n";
212 62         327 $input_line .= 'use RPerl::AfterSubclass;';
213              
214             # print {*STDERR} 'in RPerl::filter(), have modified $input_line = ' . "\n" . $input_line . "\n";
215             }
216             # else { print {*STDERR} 'in RPerl::filter(), NOT enabling subclasses or RPerl::AfterSubclass for $package = ' . $package . "\n"; }
217 62         261 $output .= $input_line . "\n";
218 62         146 $package = q{};
219 62         154 $package_line = q{};
220 62         123 $post_package_lines = q{};
221             }
222             elsif ( $package ne q{} ) {
223 308         581 $post_package_lines .= $input_line . "\n";
224             }
225             else {
226 1377         1781 $output .= $input_line . "\n";
227             }
228             }
229              
230             # package but not a class
231 53         244 $output .= $post_package_lines;
232            
233             # replace fake SSE infix operators with their actually-overloaded single-character selves
234 53         390 foreach my $sse_define_pair (['sse_add', '+'], ['sse_sub', '-'], ['sse_mul', '*'], ['sse_div', '/']) {
235 212         2271 $output =~ s/$sse_define_pair->[0]/$sse_define_pair->[1]/gxms;
236             }
237              
238             # print {*STDERR} "\n" . 'in RPerl::filter(), have post-modification $output = ' . "\n" . '<<<<<<<<<<<<<<<<================ BEGIN OUTPUT FILE ================>>>>>>>>>>>>>>' . "\n" . $output . '<<<<<<<<<<<<<<<<================ END OUTPUT FILE ================>>>>>>>>>>>>>>' . "\n\n";
239              
240 53         7873 return $output;
241             }
242              
243             1; # end of class
244              
245             __END__
246              
247             =encoding utf8
248              
249             =for DEV NOTE: BEGIN INLINE CSS DIV
250              
251             =begin html
252              
253             <div id="scoped-content"><style type="text/css" scoped>
254              
255             table.rperl {
256             border-style: solid;
257             border-width: 2px;
258             }
259              
260             table.rperl > tbody > tr > th {
261             background-color: #e0e0e0;
262             text-align: center;
263             }
264              
265             table.rperl > tbody > tr:nth-child(odd) { background-color: #f5f5f5; }
266             table.rperl > tbody > tr:nth-child(even) { background-color: #ffffff; }
267              
268             table.rperl > tbody > tr > th, td {
269             border-style: solid;
270             border-width: 1px;
271             border-color: #cccccc;
272             padding: 5px;
273             }
274              
275             /* disable ".pod p" margins inside tables only */
276             table.rperl > tbody > tr > th > p { margin: 0px; }
277             table.rperl > tbody > tr > td > p { margin: 0px; }
278              
279             /* right alignment for numeric precedence column of operators tables */
280             table.operators > tbody > tr > td:nth-child(5) { text-align: right; }
281              
282             </style>
283              
284             =end html
285              
286             =head1 NAME
287              
288             RPerl L<Quick-Start Checklist|/"QUICK-START CHECKLIST"> & L<Guide|/"QUICK-START GUIDE">
289              
290             Restricted Perl, The Optimizing Perl 5 Compiler
291              
292             =head1 DESCRIPTION
293              
294             B<RPerl> is a compiler. For general info:
295              
296             L<https://github.com/wbraswell/rperl/blob/master/README.md>
297              
298             L<http://rperl.org>
299              
300             =head1 SYNOPSIS, PERL PROGRAM, INPUT CODE
301              
302             Filename F<my_program.pl>:
303              
304             #!/usr/bin/perl
305            
306             # My Program Name
307             # My Program Description
308            
309             # [[[ PREPROCESSOR ]]]
310             # <<< TYPE_CHECKING: TRACE >>>
311            
312             # [[[ HEADER ]]]
313             use RPerl;
314             use strict;
315             use warnings;
316             our $VERSION = 0.001_000;
317            
318             # [[[ CRITICS ]]]
319             ## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls) # USER DEFAULT 1: allow numeric values & print operator
320             ## no critic qw(RequireInterpolationOfMetachars) # USER DEFAULT 2: allow single-quoted control characters & sigils
321             ## no critic qw(ProhibitConstantPragma ProhibitMagicNumbers) # USER DEFAULT 3: allow constants
322            
323             # [[[ INCLUDES ]]]
324             use My::FooPackage qw(foo_exported_ok);
325             use My::BarClass;
326            
327             # [[[ CONSTANTS ]]]
328             use constant PI => my number $TYPED_PI = 3.141_59;
329             use constant PIE => my string $TYPED_PIE = 'pecan';
330            
331             # [[[ SUBROUTINES ]]]
332             sub pies_are_round {
333             { my void $RETURN_TYPE };
334             print 'in pies_are_round(), having PIE() = ', PIE(), "\n";
335             return;
336             }
337            
338             sub pi_r_squared {
339             { my number $RETURN_TYPE };
340             ( my number $r ) = @ARG;
341             my number $area = PI() * $r ** 2;
342             print 'in pi_r_squared(), have $area = PI() * $r ** 2 = ', $area, "\n";
343             return $area;
344             }
345            
346             # [[[ OPERATIONS ]]]
347             pies_are_round();
348             my number $area = pi_r_squared(23.456_789);
349              
350             foo_exported_ok(42);
351             print My::PackageFoo::foo_not_exported(3), "\n";
352              
353             my My::BarClass $bar_object = My::BarClass->new(bar_number => 21.12, bar_string => 'howdy');
354             $bar_object->bar_method1(3);
355             my number $bar_method2_retval = $bar_object->bar_method2(5);
356              
357             =head1 SYNOPSIS, PERL PROGRAM, COMPILE & EXECUTE
358              
359             =for rperl X<noncode>
360              
361             $ rperl -V my_program.pl
362             $ ./my_program
363              
364             =for rperl X</noncode>
365              
366             =head1 SYNOPSIS, PERL MODULES, INPUT CODE
367              
368             Filename F<My/FooPackage.pm>:
369              
370             # [[[ HEADER ]]]
371             use RPerl;
372             package My::FooPackage;
373             use strict;
374             use warnings;
375             our $VERSION = 0.001_000;
376            
377             # [[[ EXPORTS ]]]
378             use RPerl::Exporter qw(import);
379             our @EXPORT_OK = qw(foo_exported_ok);
380            
381             # [[[ CRITICS ]]]
382             ## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls) # USER DEFAULT 1: allow numeric values & print operator
383             ## no critic qw(RequireInterpolationOfMetachars) # USER DEFAULT 2: allow single-quoted control characters & sigils
384             ## no critic qw(ProhibitConstantPragma ProhibitMagicNumbers) # USER DEFAULT 3: allow constants
385            
386             # [[[ INCLUDES ]]]
387             use My::OtherPackage; # implementation left as an exercise for the user
388             use My::OtherClass; # ditto
389            
390             # [[[ CONSTANTS ]]]
391             use constant FOO_CONSTANT => my string $TYPED_FOO_CONSTANT = 'foo constant data';
392            
393             # [[[ SUBROUTINES ]]]
394            
395             sub foo_exported_ok {
396             { my void $RETURN_TYPE };
397             ( my integer $arg ) = @ARG;
398             print 'in My::FooPackage::foo_exported_ok(), received $arg = ', $arg, "\n";
399             return;
400             }
401            
402             sub foo_not_exported {
403             { my string $RETURN_TYPE };
404             ( my integer $arg ) = @ARG;
405             print 'in My::FooPackage::foo_exported_ok(), received $arg = ', $arg, "\n";
406             return ('howdy' x $arg);
407             }
408            
409             1; # end of class
410              
411             Filename F<My/BarClass.pm>:
412              
413             # [[[ HEADER ]]]
414             use RPerl;
415             package My::BarClass;
416             use strict;
417             use warnings;
418             our $VERSION = 0.001_000;
419            
420             # [[[ OO INHERITANCE ]]]
421             # RPerl base class, no inheritance; replace with parent class as needed
422             use parent qw(RPerl::CompileUnit::Module::Class);
423             use RPerl::CompileUnit::Module::Class;
424            
425             # [[[ CRITICS ]]]
426             ## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls) # USER DEFAULT 1: allow numeric values & print operator
427             ## no critic qw(RequireInterpolationOfMetachars) # USER DEFAULT 2: allow single-quoted control characters & sigils
428             ## no critic qw(ProhibitConstantPragma ProhibitMagicNumbers) # USER DEFAULT 3: allow constants
429            
430             # [[[ INCLUDES ]]]
431             use My::OtherPackage; # implementation left as an exercise for the user
432             use My::OtherClass; # ditto
433            
434             # [[[ CONSTANTS ]]]
435             use constant BAR_CONSTANT => my string $TYPED_BAR_CONSTANT = 'bar constant data';
436            
437             # [[[ OO PROPERTIES ]]]
438             our hashref $properties = {
439             bar_number => my integer $TYPED_bar_number = 42.23,
440             bar_string => my string $TYPED_bar_string = 'default bar string data'
441             };
442            
443             # [[[ SUBROUTINES & OO METHODS ]]]
444            
445             sub bar_method1 {
446             { my void::method $RETURN_TYPE };
447             ( my My::BarClass $self, my integer $arg ) = @ARG;
448             print 'in My::BarClass->bar_method1(), received $arg = ', $arg, "\n";
449             print ($self->{bar_string} x $arg);
450             }
451            
452             sub bar_method2 {
453             { my number::method $RETURN_TYPE };
454             ( my My::BarClass $self, my integer $arg ) = @ARG;
455             print 'in My::BarClass->bar_method2(), received $arg = ', $arg, "\n";
456             return ($self->{bar_number} * $arg);
457             }
458            
459             1; # end of class
460              
461             =head1 SYNOPSIS, PERL MODULES, COMPILE & TEST LOAD
462              
463             =for rperl X<noncode>
464              
465             $ rperl -V My/FooPackage.pm My/BarClass.pm
466             $ perl -e 'use My::FooPackage; use My::BarClass;'
467              
468             =for rperl X</noncode>
469              
470             =head1 QUICK-START CHECKLIST
471              
472             =over
473              
474             =item * B<1. File Formats, Programs & Modules:> Follow Exact Syntax & Order In Synopsis Code Examples Above
475              
476             =item * B<2. Data Types, Constants & Variables & OO Properties:> X<br> Always C<use constant PI =E<gt> my number $TYPED_PI = 3.141_59;> or C<my integer $foo;> or C<our hashref $properties = { foo =E<gt> my integer $TYPED_foo = 23, ...};> ; X<br> Never C<use constant PI =E<gt> 3.141_59;> or C<my $foo;> or C<our $properties = { foo =E<gt> 23, ...};>
477              
478              
479             =item * B<3. Return Types, Subroutines & OO Methods:> Always C<sub foo {{ my integer $RETURN_TYPE }; ...}> ; Never C<sub foo ($) {...}> etc.
480              
481             =item * B<4. Argument Types, Subroutines & OO Methods:> Always C<( my integer $arg1, my string $arg2, ... ) = @ARG;> ; Never C<my $arg1 = shift; my $arg2 = shift;>
482              
483             =item * B<5. Data Structures By Reference:> Always C<my integer_arrayref $ar = [...];> & C<my integer_hashref $hr = {...};> ; Never C<my @a = (...);> or C<my %h = (...);>
484              
485             =item * B<6. Lexical Variables:> Always C<my integer $foo> ; Never C<our $foo> or C<state $foo> etc.
486              
487             =item * B<7. No Punctuation Variables:> Never Use C<$_> or C<@_> or C<$!> etc.
488              
489             =item * B<8. Perl Critic:> Always C<perlcritic --brutal my_program.pl> or C<perlcritic --brutal MyModule.pm>, Except For Specified & Allowed C<## no critic> Commands
490              
491             =item * B<9. No External Dependencies:> Always Write Your Own Code & Only Load CPAN Modules From Non-Compiled Code; Never Directly Load Non-Compilable Code or CPAN Modules etc.
492              
493             =item * B<10. Pure Perl:> Always Low-Magic Perl 5, Never XS or Non-Perl Code
494              
495             =back
496              
497             =head1 QUICK-START GUIDE
498              
499             RPerl currently supports a restricted subset of the Perl 5 programming language.
500              
501             This B<Quick-Start Guide> is meant to serve as a primer or companion for the much more in-depth textbook B<L<Learning RPerl|RPerl::Learning>>.
502              
503             Here are the most important things a Perl programmer needs to know to get started using RPerl immediately.
504              
505             =head2 1. File Formats
506              
507             All RPerl program and module files must follow specific file formats, as shown in the Synopsis code examples.
508              
509             L</"SYNOPSIS, PERL PROGRAM, INPUT CODE">
510              
511             L</"SYNOPSIS, PERL MODULES, INPUT CODE">
512              
513             The first line of Perl code in any RPerl file must be C<use RPerl;>, after which the files must be organized into the proper format for 1 of 3 file types:
514              
515             =over
516              
517             =item 1. Perl Program, F<.pl> File Name Suffix, Ex. F<foo.pl>
518              
519             =item 2. Perl Module Package, F<.pm> File Name Suffix, Ex. F<Foo.pm>
520              
521             =item 3. Perl Module Class, F<.pm> File Name Suffix, Ex. F<Foo.pm>
522              
523             =back
524              
525             You can see above that both packages and classes must use the F<*.pm> file name suffix; they are compiled differently based on the presence a class' OO inheritance C<use parent qw(...);> and OO properties C<our hashref $properties = {...};>.
526              
527             If the OO inheritance and properties are not found, a F<*.pm> file name is assumed to be a package and not a class.
528              
529             The official RPerl file format templates are here:
530              
531             L<Program Template|https://github.com/wbraswell/rperl/blob/master/script/program_template.pl>
532              
533             L<Package Template|https://github.com/wbraswell/rperl/blob/master/lib/RPerl/CompileUnit/Module/Package/Template.pm>
534              
535             L<Class Template|https://github.com/wbraswell/rperl/blob/master/lib/RPerl/CompileUnit/Module/Class/Template.pm>
536              
537             =head2 2. Data Types & Data Structures
538              
539             All RPerl constants, variables, subroutine & object method return values, and object properties must have an explicitly-specified scalar data type or non-scalar data structure.
540              
541             =head3 2a. Scalar Data Types
542              
543             =for comment DEV NOTE, CORRELATION #rp400: all POD changes must be made in both RPerl.pm & RPerl/Learning.pm
544              
545             L<RPerl::Learning/"CHAPTER 2: SCALAR VALUES & VARIABLES (NUMBERS & TEXT)">
546              
547             RPerl provides 7 scalar data types:
548              
549             =over
550              
551             =item * C<boolean>
552              
553             =item * C<unsigned_integer>
554              
555             =item * C<integer> (core)
556              
557             =item * C<gmp_integer>
558              
559             =item * C<number> (core)
560              
561             =item * C<character>
562              
563             =item * C<string> (core)
564              
565             =back
566              
567             Of the 7 RPerl scalar data types, 3 are directly (natively) supported by the Perl 5 core: C<integer>, C<number>, and C<string>. This means the Perl 5 core is capable of directly identifying and storing those 3 core types. The remaining 4 non-core types are indirectly supported by the Perl 5 interpreter: C<boolean> and C<unsigned_integer> can be stored within either an C<integer> or C<number>; C<character> can be stored within a C<string>; and C<gmp_integer> is supported by the C<use bigint;> wrapper around the C<Math::BigInt::GMP> module.
568              
569             =head3 2b. Array Data Structures
570              
571             =for comment DEV NOTE, CORRELATION #rp401: all POD changes must be made in both RPerl.pm & RPerl/Learning.pm
572              
573             L<RPerl::Learning/"CHAPTER 3: ARRAY VALUES & VARIABLES">
574              
575             For arrays with more than just a few elements, it may be impractical or impossible to pass by value, because a full copy of each array element must be made in the process, which may fill up all your program's available memory or take a prohibitively long time to complete. Also, Perl allows us to provide explicit data types only when an array is stored by reference, so we can not provide a data type for an array stored by value. Because of these reasons, all RPerl arrays are stored by reference, and are declared with an explicit RPerl data type ending with C<_arrayref>.
576              
577             my @foo_by_value = (2, 4, 6); # fine in normal Perl, error in RPerl
578             my $foo_by_reference = [2, 4, 6]; # fine in normal Perl, error in RPerl
579             my integer_arrayref $foo_by_reference_typed = [2, 4, 6]; # fine in normal Perl, fine in RPerl
580              
581             In a few special cases, Perl forces us to provide an array by value instead of by reference, in which case we need to I<"dereference"> our array variable, which is the process of converting from the stored-by-reference memory address to the stored-by-data values. This is achieved by use of Perl's closefix array dereference syntax, comprised of enclosing the scalar array variable within at-sign-curly-braces C<@{ }>. Because all arrays in RPerl are stored by reference, only necessary uses of the dereference syntax are supported by the RPerl compiler. (Please see L<RPerl::Learning/"Section 3.8: C<push> & C<pop> Operators"> for more information on C<pop>.)
582              
583             my integer_arrayref $foo_by_reference_typed = [10, 20, 30]; # fine in normal Perl, fine in RPerl
584             my integer $foo_last_element = pop @{$foo_by_reference_typed}; # fine in normal Perl, fine in RPerl, necessary dereference
585             my @foo_by_value = @{$foo_by_reference_typed}; # fine in normal Perl, error in RPerl, unnecessary dereference
586              
587             In normal Perl, a single array may contain elements with multiple different data types, such as a three-element array containing one string and one integer and one floating-point number. In RPerl, a single array must contain elements of all the same data type, so you can have a three-element array with all strings, but you can't store an integer inside an array of strings, and likewise you can't store a string inside an array of integers, etc.
588              
589             my integer_arrayref $foo = [5, 10, 15]; # fine
590             my number_arrayref $bar = [5, 10, 15.5]; # fine
591             my string_arrayref $bat = ['five', 'ten', 'fifteen']; # fine
592              
593             my integer_arrayref $foo = [5, 10, 15.5]; # error in RPerl, compiled modes
594             my number_arrayref $bar = [5, 10, 'fifteen']; # error in RPerl, compiled modes
595             my string_arrayref $bat = ['five', 'ten', 15]; # error in RPerl, compiled modes
596              
597             You can create an array with only one element, sometimes called a I<"singleton">; you can even create an empty array with zero elements:
598              
599             my integer_arrayref $foo = []; # zero elements, empty array
600             my integer_arrayref $bar = [23]; # one element, singleton array
601              
602             To display the contents of an array, you may utilize the C<*_arrayref_to_string()> family of stringification subroutines:
603              
604             my integer_arrayref $foo;
605             $foo = [23, 42, 2_112];
606             print '$foo = ', integer_arrayref_to_string($foo), "\n";
607              
608             Running the code example above generates the following output:
609              
610             =for rperl X<noncode>
611              
612             $foo = [23, 42, 2_112]
613              
614             =for rperl X</noncode>
615              
616             RPerl currently supports the following array stringification subroutines, with support for all RPerl array data types coming soon:
617              
618             =over
619              
620             =item * C<integer_arrayref_to_string()>
621              
622             =item * C<number_arrayref_to_string()>
623              
624             =item * C<string_arrayref_to_string()>
625              
626             =back
627              
628             =head3 2c. Hash Data Structures
629              
630             # NEED ADD CONTENT!
631              
632             =head2 3. Return Types
633              
634             # NEED ADD CONTENT!
635              
636             =head2 4. Argument Types
637              
638             # NEED ADD CONTENT!
639              
640             =head2 5. Data Structures By Reference
641              
642             # NEED ADD CONTENT!
643              
644             =head2 6. Lexical Variables
645              
646             # NEED ADD CONTENT!
647              
648             =head2 7. No Punctuation Variables
649              
650             # NEED ADD CONTENT!
651              
652             =head2 8. Perl Critic
653              
654             # NEED ADD CONTENT!
655              
656             =head2 9. External Dependencies
657              
658             # NEED ADD CONTENT!
659              
660             =head2 10. Pure Perl
661              
662             # NEED ADD CONTENT!
663              
664             =head1 SEE ALSO
665              
666             L<rperl>
667              
668             L<Learning RPerl e-Book, POD Format|RPerl::Learning>
669              
670             L<Learning RPerl e-Book, Web Format|http://rperl.org/learning/>
671              
672             L<The Low-Magic Perl Commandments|http://rperl.org/the_low_magic_perl_commandments.html>
673              
674             =head1 AUTHOR
675              
676             B<William N. Braswell, Jr.>
677              
678             L<mailto:wbraswell@NOSPAM.cpan.org>
679              
680             =for comment DEV NOTE: END INLINE CSS DIV
681              
682             =for html </div>
683              
684             =cut