PlusPlus - [Delphi|VB|Java]-like Perl preprocessor
### Case 1: plain script use PlusPlus; /* This is a long awaited multiline comment */ my $nested_hash = {outer => {inner => {a => 1, b => [19, 73], c => 3}}} $nested_hash.outer.inner.a = 5; # colon in variable names $nested_hash.outer.inner.b.[1] = 37; $dbh.do ("DROP DATABASE TEST"); # colon in method names with ($nested_hash.outer.inner) { # 'with' operator ($.a, $.c) = (10, 30); print " b[0] = $.b.[0]\n"; }; function f ($x, $y = 0) { # named parameters and default values return sin ($x) * cos ($y) }; ### Case 2: working with a database use PlusPlus; use DBI; my $dbh = DBI -> connect ($dsn, $user, $password); select name, phone from staff where salary between ? and ? -> my $sth; forsql $sth (1000, 1500) { print "<tr> <td> $.name </td> <td> $.phone </td> </tr>" } ### Case 3: procedural module use PlusPlus; module Child (Ancestor::Mother, Ancestor::Father); sub foo { ... }; # not exported export sub bar { ... }; # exported by default export_ok sub baz { ... }; # can be imported explicitly ### Case 4: class class Child (Ancestor::Mother, Ancestor::Father); method init { # constructor callback ($.x, $.y) = (10, 3); } method diag { # some method sqrt ($.x * $.x + $.y * $.y) } method do_it_to_me ($coderef) { # one more method &$coderef ($self); } getter fldname { # getter method print "They asked my value!\n"; return $.fldname; } setter fldname ($value) { # setter method $.setting_counter ++; $.fldname = $value; }
PlusPlus is a quick hack providing many features that are to be implemented in Perl6 but a lot of people would use right now.
PlusPlus is a preprocessor based on the Filter distribution available from CPAN. It alters the standard Perl synax transparently: you don't need to recompile the interpreter or launch your scripts in some specific way. All you need is to install Filter - and
use PlusPlus;
Using PlusPlus, you can dramatically clearify your code by typing
$foo.bar.[$i].baz
each time instead of
$foo -> {bar} -> [$i] -> {baz}
Yes, of course, the colon means the concatenation. So, you might suppose a collision in case like
$foo.$bar
What would it be: "$foo.$bar" or $foo-{$bar}>? Please, remind: when using PlusPlus, always type at least one space aside of your concatenation colon. So,
$foo.$bar eq $foo->{$bar} $foo . $bar eq "$foo$bar"
And what about the method calls? It's very similar (see SYNOPSYS). But, note: the method call must be followed by an open paranthesis, even if the argument list is void.
$st.finish eq $st -> {finish} $st.finish () eq $st -> finish ()
The PlusPlus preprocessor introduces the with statement in the manner similar to Borland (C) Delphi (R) and MS ($) VB (...). Each fragment of code like
with ($foo) { ... };
is mapped to
do { my $__with__prefix__ = ($foo); ... };
All variables like $.bar are renamed to $__with__prefix__.bar. It is very unprobably that you use the variable named $__with__prefix__, but, in any case, you are warned.
And, please, don't forget to put a semicolon after the closing brace: with is do, not while.
As you know, there is whole a lot of ways to access argument values passed to a sub from within its body (shift, $_[$n]...). But usually you write a sub that receive a predefined set of args that you want to access by name. In this case, your code looks like
sub mySub { my ($arg1, $arg2, @all_other) = @_; ... }
With PlusPlus, you can obtain the same with
function mySub ($arg1, $arg2, @all_other) { ... }
Moreover, often some of parameters have default values to be set if an undef is passed as argument. Using not PlusPlus, you make something like
sub mySub { my ($arg1, $arg2, $arg3, @all_other) = @_; $arg2 = 2 unless defined ($arg2); $arg3 ||= 3; ... }
With PlusPlus:
function mySub ($arg1, $arg2 = 2, $arg3 = 3, @all_other) { ... }
When using DBI, it's very usual to code like this:
$sth -> execute ($arg1, $arg2); while (my $hash_ref = $sth -> fetchrow_hashref) { do_somthing ($hash_ref -> {a}, $hash_ref -> {b}) }
OK, it's really nice (when comparing to JDBC :-), but with PlusPlus you can express yourself a little bit cleaner:
forsql $sth ($arg1, $arg2) { do_somthing ($.a, $.b) }
Simple, isn't it? But it is not all. PlusPlus allows to use pretty plain SQL in your perl scripts. The source line
SELECT * FROM foo WHERE id = 6535 -> my $sth;
my $sth = $dbh -> prepare ("SELECT * FROM foo WHERE id = 6535");
The $dbh name is hardcoded, sorry. Currently only SELECT statements are allowed.
PlusPlus simplifies the creation of Perl modules. You don't need to use Export.pm explicitly nor fill manually @ISA, @EXPORT and @EXPORT_OK arrays.
The string
module Child (Ancestor::Mother, Ancestor::Father);
package Child; use Exporter; use vars qw(\@ISA \@EXPORT \@EXPORT_OK);
Moreover, the last (additional) line of your source will contain the needed @ISA expression.
You can add a modifier export or export_ok to any sub, then its name will appear in @EXPORT or @EXPORT_OK list at the end of source.
And, finally, you don't ever need to put a 1; after all: it is done automatically.
PlusPlus provides a simple OO-syntax addon to the Perl interpreter. The string like
class MyObject (Ancestor::Mother, Ancestor::Father);
does the same thing as the module statement described above, but creates a standard constructor called new that blesses a void anonymous hashref. Now you can create the appropriate objects with expressions like
my $object = new MyObject ('blah', "blah");
in any script that uses your module.
PlusPlus introduces a special kind of sub for class modules: methods. The source
method do_it ($x, $y, @foo) { ... }
sub do_it { my $self = shift; my $__with__prefix__ = $self; my ($x, $y, @foo) = @_; ... }
The metod named init is called by the constructor new with the arglist passed to it.
From the OO point of view, explicit use of class members is not good practice. In theory, you'd never access to object's fields but always call appropriate getter/setter methods when you want to obtain/change its values. Good OO programming languages have some special syntax that allows an implicit binding of getters/setters to some fake class members. (I mean the Borland Delphi's feature called 'properties'). PlusPlus have something similar.
Suppose you want to have some side effect when the field bar of an instance of class Foo changes. Write
class Foo; setter bar ($value) { print "And now bar = $value\n"; # side effect $.bar = $value; }
Now, if $foo is an instance of Foo, a statement
$foo.bar = 666;
will dump the message
And now bar = 666
to the stdout. If you're afraid of some kind of numbers or just want to overload the getting procedure, add a getter method:
getter bar { return $.bar == 666 ? 'Oh no!' : $.bar; }
D. E. Ovsyanko, do@rambler.ru
Filter(3).
To install Component, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Component
CPAN shell
perl -MCPAN -e shell install Component
For more information on module installation, please visit the detailed CPAN module installation guide.