summaryrefslogtreecommitdiff
path: root/lib/Class/Template.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Class/Template.pm')
-rw-r--r--lib/Class/Template.pm241
1 files changed, 241 insertions, 0 deletions
diff --git a/lib/Class/Template.pm b/lib/Class/Template.pm
new file mode 100644
index 0000000000..e45a5d3f17
--- /dev/null
+++ b/lib/Class/Template.pm
@@ -0,0 +1,241 @@
+package Class::Template;
+require 5.000;
+require Exporter;
+
+@ISA = qw(Exporter);
+@EXPORT = qw(members struct);
+use strict;
+
+# Template.pm --- struct/member template builder
+# 12mar95
+# Dean Roehrich
+#
+# changes/bugs fixed since 28nov94 version:
+# - podified
+# changes/bugs fixed since 21nov94 version:
+# - Fixed examples.
+# changes/bugs fixed since 02sep94 version:
+# - Moved to Class::Template.
+# changes/bugs fixed since 20feb94 version:
+# - Updated to be a more proper module.
+# - Added "use strict".
+# - Bug in build_methods, was using @var when @$var needed.
+# - Now using my() rather than local().
+#
+# Uses perl5 classes to create nested data types.
+# This is offered as one implementation of Tom Christiansen's "structs.pl"
+# idea.
+
+=head1 NAME
+
+Class::Template - struct/member template builder
+
+=head1 EXAMPLES
+
+=item * Example 1
+
+ use Class::Template;
+
+ struct( rusage => {
+ ru_utime => timeval,
+ ru_stime => timeval,
+ });
+
+ struct( timeval => [
+ tv_secs => '$',
+ tv_usecs => '$',
+ ]);
+
+ my $s = new rusage;
+
+=item * Example 2
+
+ package OBJ;
+ use Class::Template;
+
+ members OBJ {
+ 'a' => '$',
+ 'b' => '$',
+ };
+
+ members OBJ2 {
+ 'd' => '@',
+ 'c' => '$',
+ };
+
+ package OBJ2; @ISA = (OBJ);
+
+ sub new {
+ my $r = InitMembers( &OBJ::InitMembers() );
+ bless $r;
+ }
+
+=head1 NOTES
+
+Use '%' if the member should point to an anonymous hash. Use '@' if the
+member should point to an anonymous array.
+
+When using % and @ the method requires one argument for the key or index
+into the hash or array.
+
+Prefix the %, @, or $ with '*' to indicate you want to retrieve pointers to
+the values rather than the values themselves.
+
+=cut
+
+Var: {
+ $Class::Template::print = 0;
+ sub printem { $Class::Template::print++ }
+}
+
+
+sub struct {
+ my( $struct, $ref ) = @_;
+ my @methods = ();
+ my %refs = ();
+ my %arrays = ();
+ my %hashes = ();
+ my $out = '';
+
+ $out = "{\n package $struct;\n sub new {\n";
+ parse_fields( $ref, \$out, \@methods, \%refs, \%arrays, \%hashes, 0 );
+ $out .= " bless \$r;\n }\n";
+ build_methods( $ref, \$out, \@methods, \%refs, \%arrays, \%hashes );
+ $out .= "}\n1;\n";
+
+ ( $Class::Template::print ) ? print( $out ) : eval $out;
+}
+
+sub members {
+ my( $pkg, $ref ) = @_;
+ my @methods = ();
+ my %refs = ();
+ my %arrays = ();
+ my %hashes = ();
+ my $out = '';
+
+ $out = "{\n package $pkg;\n sub InitMembers {\n";
+ parse_fields( $ref, \$out, \@methods, \%refs, \%arrays, \%hashes, 1 );
+ $out .= " bless \$r;\n }\n";
+ build_methods( $ref, \$out, \@methods, \%refs, \%arrays, \%hashes );
+ $out .= "}\n1;\n";
+
+ ( $Class::Template::print ) ? print( $out ) : eval $out;
+}
+
+
+sub parse_fields {
+ my( $ref, $out, $methods, $refs, $arrays, $hashes, $member ) = @_;
+ my $type = ref $ref;
+ my @keys;
+ my $val;
+ my $cnt = 0;
+ my $idx = 0;
+ my( $cmt, $n );
+
+ if( $type eq 'HASH' ){
+ if( $member ){
+ $$out .= " my(\$r) = \@_ ? shift : {};\n";
+ }
+ else{
+ $$out .= " my(\$r) = {};\n";
+ }
+ @keys = keys %$ref;
+ foreach (@keys){
+ $val = $ref->{$_};
+ if( $val =~ /^\*(.)/ ){
+ $refs->{$_}++;
+ $val = $1;
+ }
+ if( $val eq '@' ){
+ $$out .= " \$r->{'$_'} = [];\n";
+ $arrays->{$_}++;
+ }
+ elsif( $val eq '%' ){
+ $$out .= " \$r->{'$_'} = {};\n";
+ $hashes->{$_}++;
+ }
+ elsif( $val ne '$' ){
+ $$out .= " \$r->{'$_'} = \&${val}::new();\n";
+ }
+ else{
+ $$out .= " \$r->{'$_'} = undef;\n";
+ }
+ push( @$methods, $_ );
+ }
+ }
+ elsif( $type eq 'ARRAY' ){
+ if( $member ){
+ $$out .= " my(\$r) = \@_ ? shift : [];\n";
+ }
+ else{
+ $$out .= " my(\$r) = [];\n";
+ }
+ while( $idx < @$ref ){
+ $n = $ref->[$idx];
+ push( @$methods, $n );
+ $val = $ref->[$idx+1];
+ $cmt = "# $n";
+ if( $val =~ /^\*(.)/ ){
+ $refs->{$n}++;
+ $val = $1;
+ }
+ if( $val eq '@' ){
+ $$out .= " \$r->[$cnt] = []; $cmt\n";
+ $arrays->{$n}++;
+ }
+ elsif( $val eq '%' ){
+ $$out .= " \$r->[$cnt] = {}; $cmt\n";
+ $hashes->{$n}++;
+ }
+ elsif( $val ne '$' ){
+ $$out .= " \$r->[$cnt] = \&${val}::new();\n";
+ }
+ else{
+ $$out .= " \$r->[$cnt] = undef; $cmt\n";
+ }
+ ++$cnt;
+ $idx += 2;
+ }
+ }
+}
+
+
+sub build_methods {
+ my( $ref, $out, $methods, $refs, $arrays, $hashes ) = @_;
+ my $type = ref $ref;
+ my $elem = '';
+ my $cnt = 0;
+ my( $pre, $pst, $cmt, $idx );
+
+ foreach (@$methods){
+ $pre = $pst = $cmt = $idx = '';
+ if( defined $refs->{$_} ){
+ $pre = "\\(";
+ $pst = ")";
+ $cmt = " # returns ref";
+ }
+ $$out .= " sub $_ {$cmt\n my \$r = shift;\n";
+ if( $type eq 'ARRAY' ){
+ $elem = "[$cnt]";
+ ++$cnt;
+ }
+ elsif( $type eq 'HASH' ){
+ $elem = "{'$_'}";
+ }
+ if( defined $arrays->{$_} ){
+ $$out .= " my \$i;\n";
+ $$out .= " \@_ ? (\$i = shift) : return \$r->$elem;\n";
+ $idx = "->[\$i]";
+ }
+ elsif( defined $hashes->{$_} ){
+ $$out .= " my \$i;\n";
+ $$out .= " \@_ ? (\$i = shift) : return \$r->$elem;\n";
+ $idx = "->{\$i}";
+ }
+ $$out .= " \@_ ? (\$r->$elem$idx = shift) : $pre\$r->$elem$idx$pst;\n";
+ $$out .= " }\n";
+ }
+}
+
+1;