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