[LA.pm] Thanks for letting me present

Ben Tilly btilly at gmail.com
Thu Jun 21 02:05:23 PDT 2012


Hrm, I guess I gave all of the architecture, but didn't show what the
answer to Eric's problem could look like.  Let me do that.

  {
    range => sub {
      my ($expander, $hashref, $from, $to) = @_;
      return [$from..$to];
    },
    insert_foreach => sub {
      my ($expander, $hashref, $var, $range, $key, $value) = @_;
      for (@$range) {
        my $expanded = $expander->expand({
          $var => $_,
          key => $key,
          value => $value,
        });
        $hashref->{$expanded->{$key}} = $expanded->{$value};
      }
      return undef; # We do not use this again.
    },
    subdomain_count => 5,
    subdomain_template => {
      domain => '%%m[% i %].campusexplorer.com',
      foo => 'bar',
    },
    dummy => '[%
        insert_foreach(
          i,
          [% range(1, [% subdomain_count %]) %],
          %%m[%i],
          [% subdomain_template %],
        ) %]',
  }

And then expanded we would get:

  {
    range => sub {
      my ($expander, $hashref, $from, $to) = @_;
      return [$from..$to];
    },
    insert_foreach => sub {
      my ($expander, $hashref, $var, $range, $key, $value) = @_;
      for (@$range) {
        my $expanded = $expander->expand({
          $var => $_,
          key => $key,
          value => $value,
        });
        $hashref->{$expanded->{$key}} = $expanded->{$value};
      }
      return undef; # We do not use this again.
    },
    subdomain_count => 5,
    subdomain_template => {
      domain => 'm[% i %].campusexplorer.com',
      foo => 'bar',
    },
    dummy => undef,
    m1 => {
      domain => 'm1.campusexplorer.com',
      foo => 'bar',
    },
    m2 => {
      domain => 'm2.campusexplorer.com',
      foo => 'bar',
    },
    m3 => {
      domain => 'm3.campusexplorer.com',
      foo => 'bar',
    },
    m4 => {
      domain => 'm4.campusexplorer.com',
      foo => 'bar',
    },
    m5 => {
      domain => 'm5.campusexplorer.com',
      foo => 'bar',
    },
  }

I guess that it is a matter of opinion whether this proposed cure is
worse than the disease...

By the way where I randomly chose %%, a better Lisp analogy would be `
(backtick).

On Thu, Jun 21, 2012 at 1:20 AM, Ben Tilly <btilly at gmail.com> wrote:
> I have put my presentation up at
> http://elem.com/~btilly/template-hashexpand/ for anyone who wants to
> go through the slides.
>
> I gave thought to Eric's comment about adding looping, and came up
> with a weird suggestion for how to do it.  Add function calls to code
> references stored elsewhere in the hash.  So we might allow:
>
>  {
>    joiner => sub {
>      my ($expander, $hashref, $sep, @args) = @_;
>      return join $sep, @args;
>    },
>    foo => '{% joiner( ' ', Hello, world) %}',
>  }
>
> And this would expand to:
>
>  {
>    joiner => sub {
>      my ($expander, $hashref, $sep, @args) = @_;
>      return join $sep, @args;
>    },
>    foo => 'Hello world',
>  }
>
> *However* the function would have complete access to an object that
> can trigger hash expansion inside of the current context, and also the
> hash reference.  So if you wanted to, you could have it loop, and
> insert a bunch of stuff into the hash, using hash expansion to
> customize them.  Thus you can have your config expansion insert this
> looping capability, and then you can use it wherever it makes sense.
>
> Let's take this idea a few steps further off towards insanity.  The
> next utility step would be to allow multi-level expansion in a string.
>  So, for instance, you can have:
>
>  {
>    foo => '[% foo[% bar %] %]',
>    bar => 'blat',
>    fooblat => 'gotcha',
>  }
>
> which would expand to:
>
>  {
>    foo => 'gotcha',
>    bar => 'blat',
>    fooblat => 'gotcha',
>  }
>
> But you could do this with function calls instead if you wanted.  So
> one parameter can be expanded to something dynamically determined by
> another parameter.  (You could implement this yourself inside of the
> function, but why not make it easy.)
>
> The third step is that if a template expansion is *exactly* a variable
> expansion, we get that value inserted as is (instead of stringified).
> So:
>
>  {
>    foo => {
>      this => 'that',
>    },
>    bar => '[% foo %]',
>  }
>
> should expand to:
>
>  {
>    foo => {
>      this => 'that',
>    },
>    bar => {
>      this => 'that',
>    },
>  }
>
> Combined with the second step, this would allow us to pass real data
> structures to function calls inside of hash values that we are
> expanding.
>
> And while we're at it, we can always allow an easier quoted string
> syntax.  So for instance no expansion would happen if you started the
> string with %%.  So:
>
>  {
>    foo => '%%[% Hello %]',
>  }
>
> would expand to:
>
>  {
>    foo => '[% Hello %]',
>  }
>
> Now if you squint right, the ability to call functions looks like Lisp
> macros.  The ability to suppress template expansion before the call,
> then have it happen inside of the function gives us an equivalent to
> Lisp macros.  And we can implement the special forms directly in Perl
> functions.
>
> Any template expansion system that gives you something with a
> recognizable parallel to Lisp (albeit with a different syntax)
> qualifies in my books as "sufficiently powerful" for any reasonable
> need...
>
> Does anyone have any reaction other than, "He just went off the deep end"?


More information about the Losangeles-pm mailing list