You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by ma...@apache.org on 2009/08/25 03:59:40 UTC

svn commit: r807455 - in /lucene/lucy/trunk/boilerplater: lib/Boilerplater/File.pm lib/Boilerplater/Parser.pm t/403-file.t

Author: marvin
Date: Tue Aug 25 01:59:39 2009
New Revision: 807455

URL: http://svn.apache.org/viewvc?rev=807455&view=rev
Log:
Commit LUCY-25, adding Boilerplater::File.

Added:
    lucene/lucy/trunk/boilerplater/lib/Boilerplater/File.pm   (with props)
    lucene/lucy/trunk/boilerplater/t/403-file.t   (with props)
Modified:
    lucene/lucy/trunk/boilerplater/lib/Boilerplater/Parser.pm

Added: lucene/lucy/trunk/boilerplater/lib/Boilerplater/File.pm
URL: http://svn.apache.org/viewvc/lucene/lucy/trunk/boilerplater/lib/Boilerplater/File.pm?rev=807455&view=auto
==============================================================================
--- lucene/lucy/trunk/boilerplater/lib/Boilerplater/File.pm (added)
+++ lucene/lucy/trunk/boilerplater/lib/Boilerplater/File.pm Tue Aug 25 01:59:39 2009
@@ -0,0 +1,200 @@
+use strict;
+use warnings;
+
+package Boilerplater::File;
+use Boilerplater::Util qw( verify_args a_isa_b );
+use Boilerplater::Parcel;
+use Scalar::Util qw( blessed );
+use File::Spec::Functions qw( catfile );
+use Carp;
+
+our %new_PARAMS = (
+    blocks       => undef,
+    source_class => undef,
+    parcel       => undef,
+);
+
+sub new {
+    my $either = shift;
+    verify_args( \%new_PARAMS, @_ ) or confess $@;
+    my $self = bless {
+        %new_PARAMS,
+        blocks       => [],
+        source_class => undef,
+        modified     => 0,
+        @_,
+        },
+        ref($either) || $either;
+    if ( defined $self->{parcel} ) {
+        if ( !blessed( $self->{parcel} ) ) {
+            $self->{parcel}
+                = Boilerplater::Parcel->singleton( name => $self->{parcel} );
+        }
+        confess("Not a Boilerplater::Parcel")
+            unless $self->{parcel}->isa('Boilerplater::Parcel');
+    }
+    for my $block ( @{ $self->{blocks} } ) {
+        next if a_isa_b( $block, "Boilerplater::Parcel" );
+        next if a_isa_b( $block, "Boilerplater::Class" );
+        next if a_isa_b( $block, "Boilerplater::CBlock" );
+        confess("Invalid block: $block");
+    }
+    confess("Missing required param 'source_class'")
+        unless $self->{source_class};
+    return $self;
+}
+
+sub get_modified     { shift->{modified} }
+sub set_modified     { $_[0]->{modified} = $_[1] }
+sub get_source_class { shift->{source_class} }
+
+sub blocks { @{ shift->{blocks} } }
+
+sub classes {
+    my $self = shift;
+    return
+        grep { ref $_ and $_->isa('Boilerplater::Class') }
+        @{ $self->{blocks} };
+}
+
+# Return a string used for an include guard, unique per file.
+sub guard_name {
+    my $self       = shift;
+    my $guard_name = "H_" . uc( $self->{source_class} );
+    $guard_name =~ s/\W+/_/g;
+    return $guard_name;
+}
+
+# Return a string opening the include guard.
+sub guard_start {
+    my $self       = shift;
+    my $guard_name = $self->guard_name;
+    return "#ifndef $guard_name\n#define $guard_name 1\n";
+}
+
+# Return a string closing the include guard.  Other classes count on being
+# able to match this string.
+sub guard_close {
+    my $self       = shift;
+    my $guard_name = $self->guard_name;
+    return "#endif /\* $guard_name \*/\n";
+}
+
+sub c_path  { return $_[0]->_some_path( $_[1], '.c' ) }
+sub h_path  { return $_[0]->_some_path( $_[1], '.h' ) }
+sub bp_path { return $_[0]->_some_path( $_[1], '.bp' ) }
+
+sub _some_path {
+    my ( $self, $base_dir, $ext ) = @_;
+    my @components = split( '::', $self->{source_class} );
+    unshift @components, $base_dir
+        if defined $base_dir;
+    $components[-1] .= $ext;
+    return catfile(@components);
+}
+
+1;
+
+__END__
+
+__POD__
+
+=head1 NAME
+
+Boilerplater::File - Structured representation of the contents of a
+Boilerplater source file.
+
+=head1 DESCRIPTION
+
+An abstraction representing a file which contains Boilerplater code.
+
+=head1 METHODS
+
+=head2 new
+
+    my $file_obj = Boilerplater::File->new(
+        blocks       => \@blocks,            # required
+        source_class => 'Dog::Dalmation',    # required
+        parcel       => 'Dog',               # default: special
+    );
+
+=over
+
+=item * B<blocks> - An arrayref.  Each element must be either a
+Boilerplater::Class, a Boilerplater::Parcel, or a Boilerplater::CBlock.
+
+=item * B<source_class> - The class name associated with the source file,
+regardless of how what classes are defined in the source file. Example: If
+source_class is "Foo::Bar", that implies that the source file could be found
+at 'Foo/Bar.bp' within the source directory and that the output C header file
+should be 'Foo/Bar.h' within the target include directory.
+
+=item * B<parcel> - A Boilerplater::Parcel or parcel name.
+
+=back
+
+=head2 blocks
+
+    my @blocks = $file->blocks;
+
+Return all blocks as a list.
+
+=head2 classes
+
+    my @classes = $file->classes;
+
+Return all Boilerplater::Class blocks from the file as a list.
+
+=head2 get_modified set_modified
+
+Accessors for the file's "modified" property, which is initially false.
+
+=head2 get_source_class
+
+Accessor.
+
+=head2 c_path h_path bp_path
+
+    # '/path/to/Source/Class.c', etc.
+    my $c_path  = $file->c_path('/path/to');
+    my $h_path  = $file->h_path('/path/to');
+    my $bp_path = $file->bp_path('/path/to');
+
+Given a base directory, return a path name derived from the File's
+source_class with the specified extension.
+
+=head2 guard_name
+
+    # e.g. "H_DOG_DALMATION"
+    my $guard_name = $file->guard_name
+
+Return a string used for an include guard in a C header, unique per file.
+
+=head2 guard_start
+
+Return a string opening the include guard.
+
+=head2 guard_close
+
+Return a string closing the include guard.  Other classes count on being able
+to match this string.
+
+=head1 COPYRIGHT AND LICENSE
+
+    /**
+     * Copyright 2009 The Apache Software Foundation
+     *
+     * Licensed under the Apache License, Version 2.0 (the "License");
+     * you may not use this file except in compliance with the License.
+     * You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+     * implied.  See the License for the specific language governing
+     * permissions and limitations under the License.
+     */
+
+=cut

Propchange: lucene/lucy/trunk/boilerplater/lib/Boilerplater/File.pm
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: lucene/lucy/trunk/boilerplater/lib/Boilerplater/Parser.pm
URL: http://svn.apache.org/viewvc/lucene/lucy/trunk/boilerplater/lib/Boilerplater/Parser.pm?rev=807455&r1=807454&r2=807455&view=diff
==============================================================================
--- lucene/lucy/trunk/boilerplater/lib/Boilerplater/Parser.pm (original)
+++ lucene/lucy/trunk/boilerplater/lib/Boilerplater/Parser.pm Tue Aug 25 01:59:39 2009
@@ -20,10 +20,21 @@
 use Boilerplater::Method;
 use Boilerplater::Class;
 use Boilerplater::CBlock;
+use Boilerplater::File;
 use Carp;
 
 our $grammar = <<'END_GRAMMAR';
 
+file:
+    { Boilerplater::Parser->set_parcel(undef); 0; }
+    major_block[%arg](s) eofile
+    { Boilerplater::Parser->new_file( \%item, \%arg ) }
+
+major_block:
+      class_declaration[%arg]
+    | embed_c
+    | parcel_definition
+
 parcel_definition:
     'parcel' class_name cnick(?) ';'
     { 
@@ -285,6 +296,9 @@
        |short|inert|struct|typedef|union|unsigned|void)(?!\w)/x
     | chy_integer_specifier
 
+eofile:
+    /^\Z/
+
 END_GRAMMAR
 
 sub new { return shift->SUPER::new($grammar) }
@@ -452,6 +466,16 @@
     );
 }
 
+sub new_file {
+    my ( undef, $item, $arg ) = @_;
+
+    return Boilerplater::File->new(
+        parcel       => $parcel,
+        blocks       => $item->{'major_block(s)'},
+        source_class => $arg->{source_class},
+    );
+}
+
 sub new_parcel {
     my ( undef, $item ) = @_;
     Boilerplater::Parcel->singleton(

Added: lucene/lucy/trunk/boilerplater/t/403-file.t
URL: http://svn.apache.org/viewvc/lucene/lucy/trunk/boilerplater/t/403-file.t?rev=807455&view=auto
==============================================================================
--- lucene/lucy/trunk/boilerplater/t/403-file.t (added)
+++ lucene/lucy/trunk/boilerplater/t/403-file.t Tue Aug 25 01:59:39 2009
@@ -0,0 +1,57 @@
+use strict;
+use warnings;
+
+use Test::More tests => 17;
+
+use Boilerplater::File;
+use Boilerplater::Parser;
+
+my $parser = Boilerplater::Parser->new;
+
+my $parcel_declaration = "parcel Stuff;";
+my $class_content      = qq|
+    class Stuff::Thing {
+        Foo *foo;
+        Bar *bar;
+    }
+|;
+my $c_block = "__C__\nint foo;\n__END_C__\n";
+
+my $file = $parser->file( "$parcel_declaration\n$class_content\n$c_block",
+    0, source_class => 'Stuff::Thing' );
+
+is( $file->get_source_class, "Stuff::Thing", "get_source_class" );
+
+my $guard_name = $file->guard_name;
+is( $guard_name, "H_STUFF_THING", "guard_name" );
+like( $file->guard_start, qr/$guard_name/, "guard_start" );
+like( $file->guard_close, qr/$guard_name/,
+    "guard_close includes guard_name" );
+
+ok( !$file->get_modified, "modified false at start" );
+$file->set_modified(1);
+ok( $file->get_modified, "set_modified, get_modified" );
+
+is( $file->bp_path('/path/to'), "/path/to/Stuff/Thing.bp", "bp_path" );
+is( $file->c_path('/path/to'),  "/path/to/Stuff/Thing.c",  "c_path" );
+is( $file->h_path('/path/to'),  "/path/to/Stuff/Thing.h",  "h_path" );
+
+my @classes = $file->classes;
+is( scalar @classes, 1, "classes() filters blocks" );
+my $class = $classes[0];
+my ( $foo, $bar ) = $class->member_vars;
+is( $foo->get_type->get_specifier,
+    'stuff_Foo', 'file production picked up parcel def' );
+is( $bar->get_type->get_specifier, 'stuff_Bar', 'parcel def is sticky' );
+
+my @blocks = $file->blocks;
+is( scalar @blocks, 3, "all three blocks" );
+isa_ok( $blocks[0], "Boilerplater::Parcel" );
+isa_ok( $blocks[1], "Boilerplater::Class" );
+isa_ok( $blocks[2], "Boilerplater::CBlock" );
+
+$file = $parser->file( $class_content, 0, source_class => 'Stuff::Thing' );
+($class) = $file->classes;
+( $foo, $bar ) = $class->member_vars;
+is( $foo->get_type->get_specifier, 'Foo', 'file production resets parcel' );
+

Propchange: lucene/lucy/trunk/boilerplater/t/403-file.t
------------------------------------------------------------------------------
    svn:eol-style = native