Acme::MetaSyntactic - Themed metasyntactic variables names


Acme-MetaSyntactic documentation Contained in the Acme-MetaSyntactic distribution.

Index


Code Index:

NAME

Top

Acme::MetaSyntactic - Themed metasyntactic variables names

SYNOPSIS

Top

    use Acme::MetaSyntactic; # loads the default theme
    print metaname();

    # this sets the default theme and loads Acme::MetaSyntactic::shadok
    my $meta = Acme::MetaSyntactic->new( 'shadok' );

    print $meta->name();          # return a single name
    my @names = $meta->name( 4 ); # return 4 distinct names (if possible)

    # you can temporarily switch theme
    # (though it shifts your metasyntactical paradigm in other directions)
    my $foo = $meta->name( 'foo' );       # return 1 name from theme foo
    my @foo = $meta->name( toto => 2 );   # return 2 names from theme toto

    # but why would you need an instance variable?
    use Acme::MetaSyntactic qw( batman robin );

    # the first loaded theme is the default (here batman)
    print metaname;
    my @names = metaname( 4 );

    print join ',', metabatman(3), metarobin;

    # the convenience functions are only exported
    # - via the Acme::MetaSyntactic import list
    # - when an individual theme is used
    print join $/, metabatman( 5 );

    use Acme::MetaSyntactic::donmartin;
    print join $/, metadonmartin( 7 );

    # but a one-liner is even better
    perl -MAcme::MetaSyntactic=batman -le 'print metaname'

DESCRIPTION

Top

When writing code examples, it's always easy at the beginning:

    my $foo = "bar";
    $foo .= "baz";   # barbaz

But one gets quickly stuck with the same old boring examples. Does it have to be this way? I say "No".

Here is Acme::MetaSyntactic, designed to fulfill your metasyntactic needs. Never again will you scratch your head in search of a good variable name!

METHODS (& FUNCTIONS)

Top

Acme::MetaSyntactic has an object-oriented interface, but can also export a few functions (see EXPORTS).

Methods

If you choose to use the OO interface, the following methods are available:

new( $theme )

Create a new instance of Acme::MetaSyntactic with the theme $theme. If $theme is omitted, the default theme is foo.

name( [ $theme, ] $count )

Return $count items from theme $theme. If no theme is given, the theme is the one passed to the constructor.

If $count is omitted, it defaults to 1.

If $count is 0, the whole list is returned (this may vary depending on the "behaviour" of the theme) in list context, and the size of the list in scalar context.

There are also some class methods:

themes( )

Return the sorted list of all available themes.

has_theme( $theme )

Return true if the theme $theme exists.

add_theme( theme => [ @items ], ... )

This class method adds a new theme to the list. It also creates and exports all the convenience functions (metatheme()) needed.

Note that this method can only create themes that implement the Acme::MetaSyntactic::List behaviour.

load_data( $class )

This method is used by the "behaviour" classes (such as Acme::MetaSyntactic::List) to read the content of the DATA filehandle and fetch the theme data.

The format is very simple. If the DATA filehandle contains the following data:

    # names
    bam zowie plonk
    powie kapow
    # multi level
      abc    def
    # empty
    # multi lingual
    fr de

load_data() will return the following data structure (the string is trimmed, newlines and duplicate whitespace characters are squashed):

    {
        names => "bam zowie plonk powie kapow",
        multi => {
            level   => "abc def",
            lingual => "fr de",
        },
        empty => ""
    }

For example, Acme::MetaSyntactic::List uses the single parameter names to fetch the lists of names for creating its subclasses.

Convenience methods also exists for all the themes. The methods are named after the theme. They are exported only when the theme is actually used or when it appear in the Acme::MetaSyntactic import list. The first imported theme is the default, used by the metaname() function.

EXPORTS

Top

Depending on how Acme::MetaSyntactic is used, several functions can be exported. All of them behave like the following:

metaname( [ $theme, ] $count )

Return $count items from theme $theme. If no theme is given, the theme is "default" theme. See below how to change what the default is.

Use cases

use Acme::MetaSyntactic;

This exports the metaname() function only.

use Acme::MetaSyntactic 'theme';

This exports the metaname() function and the metatheme() function. metaname() default to the theme theme.

use Acme::MetaSyntactic qw(theme1 theme2);

This exports the metaname(), metatheme1(), metatheme2() functions. metaname() default to the first theme of the list (theme1).

use Acme::MetaSyntactic ':all';

This exports the metaname() function and the meta* functions for all themes. metaname() default to the standard default theme (foo).

use Acme::MetaSyntactic::theme;

This exports the metatheme() function only. The metaname() function is not exported.

THEMES

Top

The list of available themes can be obtained with the following one-liner:

    $ perl -MAcme::MetaSyntactic -le 'print for Acme::MetaSyntactic->themes'

The themes are all the Acme::MetaSyntactic::theme classes, with theme starting with a lowercase letter.

Theme behaviours

Acme::MetaSyntactic provides theme authors with the capability of creating theme "behaviours". Behaviours are implemented as classes from which the individual themes inherit.

The themes are all the Acme::MetaSyntactic::theme classes, with theme starting with an uppercase letter.

Here are the available behaviours:

Acme::MetaSyntactic::List

The theme is a simple collection of names. An object instance will return names at random from the list, and not repeat any until the list is exhausted.

Acme::MetaSyntactic::Locale

The theme is made of several collections of names, each associated with a "language". The language is either passed as a constructor parameter, extracted from the environment or a default is selected.

Acme::MetaSyntactic::MultiList

The theme is made of several collections of names, each associated with a "category". Categories can include sub-categories, etc, ad infinitum (or when disk space or memory is exhausted, whichever happens first). The category is either passed as a constructor parameter or the default value is selected.

Acme::MetaSyntactic::Alias

The theme is simply an alias of another theme. All items are identical, as the original behaviour. The only difference is the theme name.

Over time, new theme "behaviours" will be added.

AUTHOR

Top

Philippe 'BooK' Bruhat, <book@cpan.org>

BUGS

Top

Please report any bugs or feature requests to bug-acme-metasyntactic@rt.cpan.org, or through the web interface at http://rt.cpan.org. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

If you think this modules lacks a particular set of metasyntactic variables, please send me a list, as well as a generation algorithm (either one of the built-ins (Acme::MetaSyntactic::List, Acme::MetaSyntactic::Locale), or a new one of your invention).

ACKNOWLEDGEMENTS

Top

Individual contributors are listed in the individual theme files. Look at the included CONTRIBUTORS file for the list of all contributors (43 in this version).

However, this module could not have been possible without:

COPYRIGHT & LICENSE

Top


Acme-MetaSyntactic documentation Contained in the Acme-MetaSyntactic distribution.

package Acme::MetaSyntactic;

use strict;
use warnings;
use Carp;
use File::Basename;
use File::Spec;
use File::Glob;

our $VERSION = '0.99';

# some class data
our $Theme = 'foo'; # default theme
our %META;

# fetch the list of standard themes
{
    my @themes;
    for my $dir (@INC) {
        $META{$_} = 0 for grep !/^[A-Z]/,    # remove the non-theme subclasses
          map { ( fileparse( $_, qr/\.pm$/ ) )[0] }
          File::Glob::bsd_glob(
            File::Spec->catfile( $dir, qw( Acme MetaSyntactic *.pm ) ) );
    }
}

# the functions actually hide an instance
my $meta = Acme::MetaSyntactic->new( $Theme );

# END OF INITIALISATION

# support for use Acme::MetaSyntactic 'foo'
# that automatically loads the required classes
sub import {
    my $class = shift;

    my @themes = ( grep { $_ eq ':all' } @_ )
      ? ( 'foo', grep { !/^(?:foo|:all)$/ } keys %META ) # 'foo' is still first
      : @_;

    $Theme = $themes[0] if @themes;
    $meta = Acme::MetaSyntactic->new( $Theme );

    # export the metaname() function
    no strict 'refs';
    my $callpkg = caller;
    *{"$callpkg\::metaname"} = \&metaname;    # standard theme

    # load the classes in @themes
    for my $theme( @themes ) {
        eval "require Acme::MetaSyntactic::$theme; import Acme::MetaSyntactic::$theme;";
        croak $@ if $@;
        *{"$callpkg\::meta$theme"} = sub { $meta->name( $theme, @_ ) };
    }
}

sub new {
    my ( $class, @args ) = ( @_ );
    my $theme;
    $theme = shift @args if @args % 2;
    $theme = $Theme unless $theme; # same default everywhere

    # defer croaking until name() is actually called
    bless { theme => $theme, args => { @args }, meta => {} }, $class;
}

# CLASS METHODS
sub add_theme {
    my $class  = shift;
    my %themes = @_;

    for my $theme ( keys %themes ) {
        croak "The theme $theme already exists!" if exists $META{$theme};
        my @badnames = grep { !/^[a-z_]\w*$/i } @{$themes{$theme}};
        croak "Invalid names (@badnames) for theme $theme"
          if @badnames;
        
        my $code = << "EOC";
package Acme::MetaSyntactic::$theme;
use strict;
use Acme::MetaSyntactic::List;
our \@ISA = qw( Acme::MetaSyntactic::List );
our \@List = qw( @{$themes{$theme}} );
1;
EOC
        eval $code;
        $META{$theme} = 1; # loaded

        # export the metatheme() function
        no strict 'refs';
        my $callpkg = caller;
        *{"$callpkg\::meta$theme"} = sub { $meta->name( $theme, @_ ) };
    }
}

# load the content of __DATA__ into a structure
# this class method is used by the other Acme::MetaSyntactic classes
sub load_data {
    my ($class, $theme ) = @_;
    my $data = {};

    my $fh;
    { no strict 'refs'; $fh = *{"$theme\::DATA"}{IO}; }

    my $item;
    my @items;
    $$item = "";

    {
        local $_;
        while (<$fh>) {
            /^#\s*(\w+.*)$/ && do {
                push @items, $item;
                $item = $data;
                my $last;
                my @keys = split m!\s+|\s*/\s*!, $1;
                $last = $item, $item = $item->{$_} ||= {} for @keys;
                $item = \( $last->{ $keys[-1] } = "" );
                next;
            };
            $$item .= $_;
        }
    }

    # clean up the items
    for( @items, $item ) {
        $$_ =~ s/\A\s*//;
        $$_ =~ s/\s*\z//;
        $$_ =~ s/\s+/ /g;
    }
    return $data;
}

# main function
sub metaname { $meta->name( @_ ) };

# corresponding method
sub name {
    my $self = shift;
    my ( $theme, $count );

    if (@_) {
        ( $theme, $count ) = @_;
        ( $theme, $count ) = ( $self->{theme}, $theme )
          if $theme =~ /^(?:0|[1-9]\d*)$/;
    }
    else {
        ( $theme, $count ) = ( $self->{theme}, 1 );
    }

    if( ! exists $self->{meta}{$theme} ) {
        if( ! $META{$theme} ) {
            eval "require Acme::MetaSyntactic::$theme;";
            croak "Metasyntactic list $theme does not exist!" if $@;
            $META{$theme} = 1; # loaded
        }
        $self->{meta}{$theme} =
          "Acme::MetaSyntactic::$theme"->new( %{ $self->{args} } );
    }

    $self->{meta}{$theme}->name( $count );
}

# other methods
sub themes { wantarray ? ( sort keys %META ) : scalar keys %META }
sub has_theme { $_[1] ? exists $META{$_[1]} : 0 }

1;

__END__