Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Creating App-QuoteCC

  • Loading branch information...
commit f6b080370fbbd77e3a0a40df264c3ce41d642bfb 0 parents
Ævar Arnfjörð Bjarmason authored May 17, 2010
2  .gitignore
... ...
@@ -0,0 +1,2 @@
  1
+/*-*
  2
+/.build
5  Changes
... ...
@@ -0,0 +1,5 @@
  1
+Revision history for App::QuoteCC
  2
+
  3
+{{$NEXT}}
  4
+
  5
+    - 
32  bin/quotecc
... ...
@@ -0,0 +1,32 @@
  1
+#!/usr/bin/env perl
  2
+use v5.10;
  3
+use perl5i::latest;
  4
+use App::QuoteCC;
  5
+
  6
+# Show help if run without arguments
  7
+@ARGV = qw(--help) unless @ARGV;
  8
+
  9
+exit(App::QuoteCC->new_with_options->run // 0);
  10
+
  11
+=encoding utf8
  12
+
  13
+=head1 NAME
  14
+
  15
+quotecc - Command-line interface L<App::QuoteCC>
  16
+
  17
+=head1 DESCRIPTION
  18
+
  19
+See the documentation for L<App::QuoteCC> for more information.
  20
+
  21
+=head1 AUTHOR
  22
+
  23
+E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@cpan.org>
  24
+
  25
+=head1 LICENSE AND COPYRIGHT
  26
+
  27
+Copyright 2010 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@cpan.org>
  28
+
  29
+This program is free software, you can redistribute it and/or modify
  30
+it under the same terms as Perl itself.
  31
+
  32
+=cut
8  dist.ini
... ...
@@ -0,0 +1,8 @@
  1
+name             = App-QuoteCC
  2
+author           = Ævar Arnfjörð Bjarmason <avar@cpan.org>
  3
+copyright_holder = Ævar Arnfjörð Bjarmason
  4
+license          = Perl_5
  5
+
  6
+[@AVAR]
  7
+dist          = App-QuoteCC
  8
+bugtracker    = rt
198  lib/App/QuoteCC.pm
... ...
@@ -0,0 +1,198 @@
  1
+package App::QuoteCC;
  2
+
  3
+use perl5i::latest;
  4
+use Moose;
  5
+use File::Slurp qw/ write_file /;
  6
+use Template;
  7
+use namespace::clean -except => [ qw< meta plugins > ];
  8
+
  9
+with qw/ MooseX::Getopt::Dashes /;
  10
+
  11
+has help => (
  12
+    traits        => [ qw/ Getopt / ],
  13
+    cmd_aliases   => 'h',
  14
+    cmd_flag      => 'help',
  15
+    isa           => 'Bool',
  16
+    is            => 'ro',
  17
+    default       => 0,
  18
+    documentation => 'This help message',
  19
+);
  20
+
  21
+has quotes => (
  22
+    traits        => [ qw/ Getopt / ],
  23
+    cmd_aliases   => 'q',
  24
+    cmd_flag      => 'quotes',
  25
+    isa           => 'Str',
  26
+    is            => 'ro',
  27
+    documentation => 'The quotes file to compile from. - for STDIN',
  28
+);
  29
+
  30
+has format => (
  31
+    traits        => [ qw/ Getopt / ],
  32
+    cmd_aliases   => 'f',
  33
+    cmd_flag      => 'format',
  34
+    isa           => 'Str',
  35
+    is            => 'ro',
  36
+    documentation => 'The format of the file. Any App::QuotesCC::Format::*',
  37
+);
  38
+
  39
+has output => (
  40
+    traits        => [ qw/ Getopt / ],
  41
+    cmd_aliases   => 'o',
  42
+    cmd_flag      => 'output',
  43
+    isa           => 'Str',
  44
+    is            => 'ro',
  45
+    default       => '-',
  46
+    documentation => 'Where to output the compiled file, - for STDOUT',
  47
+);
  48
+
  49
+sub run {
  50
+    my ($self) = @_;
  51
+
  52
+    # Get quotes
  53
+    my $quotes = do {
  54
+        my $quotes_class_short = $self->format;
  55
+        my $quotes_class = "App::QuoteCC::Format::" . $quotes_class_short;
  56
+        $quotes_class->require;
  57
+        $quotes_class->new(
  58
+            file => $self->quotes,
  59
+        )->quotes;
  60
+    };
  61
+
  62
+    # Get output
  63
+    my $out = $self->process_template($quotes);
  64
+
  65
+    # Spew output
  66
+    given ($self->output) {
  67
+        when ('-') {
  68
+            print $out;
  69
+        }
  70
+        default {
  71
+            write_file($_, $out);
  72
+        }
  73
+    }
  74
+
  75
+    return;
  76
+}
  77
+
  78
+sub process_template {
  79
+    my ($self, $quotes) = @_;
  80
+    my $out;
  81
+
  82
+    Template->new->process(
  83
+        \*DATA,
  84
+        {
  85
+            quotes => $quotes,
  86
+            size => scalar(@$quotes),
  87
+            escape => sub {
  88
+                my $text = shift;
  89
+                $text =~ s/"/\\"/g;
  90
+                my $was = $text;
  91
+                $text =~ s/\\(\$)/\\\\$1/g;
  92
+                given ($text) {
  93
+                    when (/\n/) {
  94
+                        return join(qq[\\n"\n], map { qq["$_] } split /\n/, $text). q["];
  95
+                    }
  96
+                    default {
  97
+                        return qq["$text"];
  98
+                    }
  99
+                }
  100
+            },
  101
+        },
  102
+        \$out
  103
+    );
  104
+
  105
+    return $out;
  106
+}
  107
+
  108
+__PACKAGE__->meta->make_immutable;
  109
+
  110
+=encoding utf8
  111
+
  112
+=head1 NAME
  113
+
  114
+App::QuoteCC - Take a quote file and emit a C program that spews a random quote
  115
+
  116
+=head1 SYNOPSIS
  117
+
  118
+Compile a quotes file to a stand-alone binary:
  119
+
  120
+    curl http://v.nix.is/~failo/quotes.yml | quotecc --quotes=- --format=YAML | gcc -x c -o /usr/local/bin/failo-wisdom -
  121
+    curl http://www.trout.me.uk/quotes.txt | quotecc --quotes=- --format=Fortune | gcc -x c -o /usr/local/bin/perl-wisdom -
  122
+
  123
+See how small it is!:
  124
+
  125
+    du -sh /usr/local/bin/*-wisdom
  126
+    56K     /usr/local/bin/failo-wisdom
  127
+    80K     /usr/local/bin/perl-wisdom
  128
+
  129
+Emit a random quote:
  130
+
  131
+    time /usr/local/bin/failo-wisdom
  132
+    Support Batman - vote for the British National Party
  133
+
  134
+    real    0m0.003s
  135
+    user    0m0.000s
  136
+    sys     0m0.004s
  137
+
  138
+Emit all quotes:
  139
+
  140
+    /usr/local/bin/failo-wisdom --all > /usr/local/bin/quotes.txt
  141
+
  142
+=head1 AUTHOR
  143
+
  144
+E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@cpan.org>
  145
+
  146
+=head1 LICENSE AND COPYRIGHT
  147
+
  148
+Copyright 2010 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@cpan.org>
  149
+
  150
+This program is free software, you can redistribute it and/or modify
  151
+it under the same terms as Perl itself.
  152
+
  153
+=cut
  154
+
  155
+__DATA__
  156
+#include <stdio.h>
  157
+#include <stdlib.h>
  158
+#include <string.h>
  159
+#include <sys/types.h>
  160
+#include <unistd.h>
  161
+#include <sys/time.h>
  162
+
  163
+const char* const quotes[[% size %]] = {
  164
+[% FOREACH quote IN quotes
  165
+%]    [% escape(quote) %],
  166
+[% END
  167
+%]};
  168
+
  169
+/* returns random integer between min and max, inclusive */
  170
+const int rand_range(const int min, const int max)
  171
+{
  172
+    struct timeval tv;
  173
+    gettimeofday(&tv, NULL);
  174
+    const long int n = tv.tv_usec * getpid();
  175
+    srand(n);
  176
+
  177
+    return (rand() % (max + 1 - min) + min);
  178
+}
  179
+
  180
+const int main(const int argc, const char **argv)
  181
+{
  182
+    int i;
  183
+    const char* const all = "--all";
  184
+    const size_t all_length = strlen(all);
  185
+
  186
+    if (argc == 2 &&
  187
+        strlen(argv[1]) == all_length &&
  188
+        !strncmp(argv[1], all, all_length)) {
  189
+        for (i = 0; i < [% size %]; i++) {
  190
+            puts(quotes[i]);
  191
+        }
  192
+    } else {
  193
+        const int quote = rand_range(0, [% size %]);
  194
+        puts(quotes[quote]);
  195
+    }
  196
+
  197
+    return EXIT_SUCCESS;
  198
+}
37  lib/App/QuoteCC/Format/Fortune.pm
... ...
@@ -0,0 +1,37 @@
  1
+package App::QuoteCC::Format::Fortune;
  2
+
  3
+use perl5i::latest;
  4
+use Moose;
  5
+use namespace::clean -except => 'meta';
  6
+
  7
+with qw/ App::QuoteCC::Role::Format /;
  8
+
  9
+sub quotes {
  10
+    my ($self) = @_;
  11
+    my $handle = $self->file_handle;
  12
+
  13
+    my $content = join '', <$handle>;
  14
+    my @quotes = split /\n%\n/, $content;
  15
+    return \@quotes;
  16
+}
  17
+
  18
+__PACKAGE__->meta->make_immutable;
  19
+
  20
+=encoding utf8
  21
+
  22
+=head1 NAME
  23
+
  24
+App::QuoteCC::Format::Fortune - Read quotes from a L<fortune(1)> file
  25
+
  26
+=head1 AUTHOR
  27
+
  28
+E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@cpan.org>
  29
+
  30
+=head1 LICENSE AND COPYRIGHT
  31
+
  32
+Copyright 2010 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@cpan.org>
  33
+
  34
+This program is free software, you can redistribute it and/or modify
  35
+it under the same terms as Perl itself.
  36
+
  37
+=cut
38  lib/App/QuoteCC/Format/YAML.pm
... ...
@@ -0,0 +1,38 @@
  1
+package App::QuoteCC::Format::YAML;
  2
+
  3
+use perl5i::latest;
  4
+use Moose;
  5
+use YAML::Syck qw/ Load /;
  6
+use namespace::clean -except => 'meta';
  7
+
  8
+with qw/ App::QuoteCC::Role::Format /;
  9
+
  10
+sub quotes {
  11
+    my ($self) = @_;
  12
+    my $handle = $self->file_handle;
  13
+
  14
+    my $content = join '', <$handle>;
  15
+    my $yaml = Load( $content );
  16
+    return $yaml;
  17
+}
  18
+
  19
+__PACKAGE__->meta->make_immutable;
  20
+
  21
+=encoding utf8
  22
+
  23
+=head1 NAME
  24
+
  25
+App::QuoteCC::Format::YAML - Read quotes from a YAML file with L<YAML::XS>
  26
+
  27
+=head1 AUTHOR
  28
+
  29
+E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@cpan.org>
  30
+
  31
+=head1 LICENSE AND COPYRIGHT
  32
+
  33
+Copyright 2010 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@cpan.org>
  34
+
  35
+This program is free software, you can redistribute it and/or modify
  36
+it under the same terms as Perl itself.
  37
+
  38
+=cut
49  lib/App/QuoteCC/Role/Format.pm
... ...
@@ -0,0 +1,49 @@
  1
+package App::QuoteCC::Role::Format;
  2
+
  3
+use perl5i::latest;
  4
+use Moose::Role;
  5
+use namespace::clean -except => 'meta';
  6
+
  7
+has file => (
  8
+    traits        => [ qw/ Getopt / ],
  9
+    isa           => 'Str',
  10
+    is            => 'ro',
  11
+    documentation => 'The quotes file to compile from. - for STDIN',
  12
+);
  13
+
  14
+sub file_handle {
  15
+    my ($self) = @_;
  16
+    my $file   = $self->file;
  17
+
  18
+    given ($file) {
  19
+        when ('-') {
  20
+            return *STDIN;
  21
+        }
  22
+        default {
  23
+            open my $fh, '<', $file;
  24
+            return $fh;
  25
+        }
  26
+    }
  27
+}
  28
+
  29
+1;
  30
+
  31
+=encoding utf8
  32
+
  33
+=head1 NAME
  34
+
  35
+App::QuoteCC::Role::Format - A role representing a L<App::QuoteCC> format
  36
+
  37
+=head1 AUTHOR
  38
+
  39
+E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@cpan.org>
  40
+
  41
+=head1 LICENSE AND COPYRIGHT
  42
+
  43
+Copyright 2010 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason.
  44
+
  45
+This program is free software, you can redistribute it and/or modify
  46
+it under the same terms as Perl itself.
  47
+
  48
+=cut
  49
+
51  t/compile-quotes.t
... ...
@@ -0,0 +1,51 @@
  1
+use perl5i::latest;
  2
+use Test::More;
  3
+use App::QuoteCC;
  4
+use File::Temp qw<tempdir tempfile>;
  5
+
  6
+plan skip_all => "Need curl / gcc to test" unless qx[ which curl && which gcc ];
  7
+plan 'no_plan';
  8
+
  9
+my @test = (
  10
+    {
  11
+        url => 'http://v.nix.is/~failo/quotes.yml',
  12
+        fmt => 'YAML',
  13
+    },
  14
+    # {
  15
+    #     url => 'http://www.trout.me.uk/quotes.txt',
  16
+    #     fmt => 'Fortune',
  17
+    # }
  18
+);
  19
+
  20
+for my $test (@test) {
  21
+    my $url = $test->{url};
  22
+    my $fmt = $test->{fmt};
  23
+
  24
+    # Dir to store our stuff
  25
+    my $dir = tempdir( "app-quotecc-XXXX", CLEANUP => 0, TMPDIR => 1 );
  26
+    my ($fh1, $quotes) = tempfile( DIR => $dir, SUFFIX => '.quotes', EXLOCK => 0 );
  27
+    my ($fh2, $output) = tempfile( DIR => $dir, SUFFIX => '.c', EXLOCK => 0 );
  28
+
  29
+    my $cmd = qq[curl -s '$url' --output '$quotes'];
  30
+    diag "executing $cmd";
  31
+    system $cmd;
  32
+    App::QuoteCC->new(
  33
+        quotes => $quotes,
  34
+        output => $output,
  35
+        format => $fmt,
  36
+    )->run;
  37
+    ok(-s $quotes, "$quotes is non-zero size");
  38
+    ok(-s $output, "$output is non-zero size");
  39
+
  40
+    $cmd = qq[gcc -Wall $output -o $output.exe];
  41
+    diag "executing $cmd";
  42
+    system $cmd;
  43
+
  44
+    for (1..10) {
  45
+        chomp(my $quote = qx[$output.exe]);
  46
+        ok($quote, "Got quote from $output.exe");
  47
+
  48
+        chomp($quote = qx[$output.exe --all]);
  49
+        ok($quote, "Got quote from $output.exe --all");
  50
+    }
  51
+}

0 notes on commit f6b0803

Please sign in to comment.
Something went wrong with that request. Please try again.