The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package WWW::MenuGrinder::Plugin::SimpleLoader;
BEGIN {
  $WWW::MenuGrinder::Plugin::SimpleLoader::VERSION = '0.06';
}

# ABSTRACT: WWW::MenuGrinder plugin that loads menus with XML::Simple.

use Moose;
use Parse::RecDescent;
use File::Slurp qw(read_file);

with 'WWW::MenuGrinder::Role::Loader';

has 'filename' => (
  is => 'rw',
);

has 'parser' => (
  is => 'ro',
  default => sub {
    my $grammar = do { local $/; <DATA> };
    return Parse::RecDescent->new($grammar);
  },
);


sub load {
  my ($self) = @_;
  my $parser = $self->parser;
  my $menu_text = read_file($self->filename);
  my $menu = $parser->menu(\$menu_text);

  return $menu;
}

sub BUILD {
  my ($self) = @_;

  my $filename = $self->grinder->config->{filename};
  die "config->{filename} is required" unless defined $filename;

  $self->filename($filename);
}

__PACKAGE__->meta->make_immutable;

no Moose;

1;




=pod

=head1 NAME

WWW::MenuGrinder::Plugin::SimpleLoader - WWW::MenuGrinder plugin that loads menus with XML::Simple.

=head1 VERSION

version 0.06

=head1 DESCRIPTION

C<WWW::MenuGrinder::Plugin::SimpleLoader> is a plugin for C<WWW::MenuGrinder>.
You should not use it directly, but include it in the C<plugins> section of a
C<WWW::MenuGrinder> config.

This is an experimental input plugin that uses a custom
L<Parse::RecDescent>-based grammar designed as a lightweight format for menu
files and reminiscent of the BIND config format.

=head2 Configuration

The key C<filename> in the global configuration holds the name of the file to be
read.

=head1 AUTHOR

Andrew Rodland <andrew@hbslabs.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by HBS Labs, LLC..

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut


__DATA__

menu: item(s) {
  if (@{ $item[1] } == 1) {
    ($return) = values %{ $item[1][0] };
  } else {
    my %ret;
    for my $i (@{ $item[1] } ) {
      my ($key, $val) = each %$i;
      $ret{$key} = [] unless defined $ret{$key};
      push @{ $ret{$key} }, $val;
    }
    $return = \%ret;
  }
}

item: key bareitem { $return = { $item[1], $item[2] } }

bareitem: string(?) '{' elem(s?) '}' {
  my @subitems = map $_->[1], grep $_->[0] eq "item", @{ $item[3] };
  my @kvs = map %{ $_->[1] }, grep $_->[0] eq "decl", @{ $item[3] };

  my %ret = @kvs;
  $ret{label} = $item[1][0] if @{ $item[1] };
  for my $subi (@subitems) {
    my ($key, $val) = each %$subi;
    $ret{$key} = [] unless defined $ret{$key};
    push @{ $ret{$key} }, $val;
  }
  $return = \%ret;
}

elem: item /;?/ { $return = [ "item", $item[1] ] } 
  | decl /;?/ { $return = [ "decl", $item[1] ] }

decl: key value { $return = { $item{key} => $item{value} }; }

key: bareword 

value: bareword | number | string

bareword: /[A-Za-z0-9_-]+/

number: /[+-]?\d+(?:\.\d+)?/

string: '"' stringpart(s?) '"' { 
  $return = ($item[2]) ? join'', @{ $item[2] } : '';
  1;
}

stringpart: /[^"]+/
  | '\"'
  | '\\'