Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

various updates

  • Loading branch information...
commit 42120bd9bdeffc32e44d32414bf078a823f124bf 1 parent 89a5e29
@masak authored
View
201 create-new-structure
@@ -2,17 +2,19 @@
use 5.010;
use strict;
use YAML;
+use Encode;
-sub titlify {
+my %old2new;
+
+sub urlify {
my ($old_title) = @_;
my $title = $old_title;
$title = lc($title);
- $title =~ s/[,:'\-!"?#;]//g;
- $title =~ s/\.(?!\w)//g;
+ $title =~ s/[,:'\-!"?#;.]//g;
$title =~ s/ +/-/g;
$title =~ s/\[|\]|\(|\)//g;
die $old_title
- if $title !~ /^[\w\-.]+$/;
+ if $title !~ /^[\w\-]+$/;
return $title;
}
@@ -39,6 +41,7 @@ sub markdownify {
if ($stack[-1]->{'children'}[-1]{'name'} eq 'nobr') {
# kill with fire
pop @{$stack[-1]->{'children'}};
+ push @{$stack[-1]->{'children'}}, ' ';
}
}
else {
@@ -65,12 +68,12 @@ sub markdownify {
if ($content ne '') {
push @{$dom->{'children'}}, $content;
}
- my $markdown = handle_divs($dom->{'children'});
+ my $markdown = handle_divs($dom->{'children'}, $filename);
return $markdown;
}
sub handle_divs {
- my ($childrenref) = @_;
+ my ($childrenref, $filename) = @_;
my @children = @{$childrenref};
my $result = '';
if (@children && !ref $children[0]) {
@@ -84,6 +87,19 @@ sub handle_divs {
&& $children[0]->{'name'} ne 'blockquote';
unshift @children, { name => 'p', children => [@really_p] };
}
+ for my $i (1..@children-1) {
+ my ($prevnode, $node) = @children[$i - 1, $i];
+ if (ref($prevnode) && $prevnode->{'name'} eq 'div'
+ && ref($node) && $node->{'name'} eq 'div'
+ && $prevnode->{'attrs'}{'class'} eq 'quote'
+ && $node->{'attrs'}{'class'} eq 'quote') {
+
+ unshift @{$children[$i]->{'children'}},
+ @{$children[$i-1]->{'children'}};
+ $children[$i-1] = '[[GONE]]';
+ }
+ }
+ @children = grep { $_ ne '[[GONE]]' } @children;
for my $node (@children) {
if (ref $node eq 'HASH') {
given ($node->{'name'}) {
@@ -94,7 +110,9 @@ sub handle_divs {
if (@p_children == 1
&& ref($p_children[0]) eq 'HASH'
&& ($p_children[0]->{'name'} eq 'strong'
- || $p_children[0]->{'name'} eq 'b')) {
+ || $p_children[0]->{'name'} eq 'b')
+ && $p_children[0]->{'children'}[0] !~ /Update/
+ && $filename ne 'posts/40167') {
$result .= '## '
. handle_spans($p_children[0]->{'children'})
. "\n\n";
@@ -103,32 +121,51 @@ sub handle_divs {
&& ref($p_children[0]) eq 'HASH'
&& ($p_children[0]->{'name'} eq 'code'
|| $p_children[0]->{'name'} eq 'tt')) {
- my @fragments = @{$p_children[0]->{'children'}};
- my $line = '';
- my @lines;
- for my $fragment (@fragments) {
- if (!ref $fragment) {
- $fragment =~ s/ / /g;
- $fragment =~ s/&lt;/</g;
- $fragment =~ s/&gt;/>/g;
- $line .= $fragment;
+ if (grep { ref($_) && ($_->{'name'} eq 'a'
+ || $_->{'name'} eq 'strong'
+ || $_->{'name'} eq 'b')}
+ @{$p_children[0]->{'children'}}) {
+ $p_children[0]->{'name'} = 'code';
+ $p_children[0]->{'children'}
+ = [grep { !ref($_) || $_->{'name'} ne 'br' }
+ @{$p_children[0]->{'children'}}];
+ $p_children[0]->{'children'}[0]
+ =~ s/^\n//;
+ $result .= '<pre>';
+ $result .= handle_verbatim($p_children[0]);
+ $result .= '</pre>';
+ $result .= "\n\n";
+ }
+ else {
+ my @fragments = @{$p_children[0]->{'children'}};
+ my $line = '';
+ my @lines;
+ for my $fragment (@fragments) {
+ if (!ref $fragment) {
+ $fragment =~ s/&nbsp;/ /g;
+ $fragment =~ s/&lt;/</g;
+ $fragment =~ s/&gt;/>/g;
+ $fragment =~ s/&amp;/&/g;
+ $fragment =~ s/&#(\d+);/chr($1)/ge;
+ $line .= $fragment;
+ }
+ elsif ($fragment->{'name'} eq 'br') {
+ $line =~ s/^\s*\n//;
+ push @lines, $line;
+ $line = '';
+ }
+ elsif ($fragment->{'name'} eq 'a') {
+ $line .= handle_spans([$fragment]);
+ }
}
- elsif ($fragment->{'name'} eq 'br') {
+ if ($line ne '') {
$line =~ s/^\s*\n//;
push @lines, $line;
- $line = '';
- }
- elsif ($fragment->{'name'} eq 'a') {
- $line .= handle_spans([$fragment]);
}
+ $result .= " $_\n"
+ for @lines;
+ $result .= "\n";
}
- if ($line ne '') {
- $line =~ s/^\s*\n//;
- push @lines, $line;
- }
- $result .= " $_\n"
- for @lines;
- $result .= "\n";
}
elsif (@p_children == 1
&& ref($p_children[0]) eq 'HASH'
@@ -140,6 +177,12 @@ sub handle_divs {
$result .= handle_spans($p_children[0]->{'children'});
}
}
+ elsif (@p_children == 1
+ && $p_children[0] eq '&#10086;') {
+ $node->{'attrs'}{'class'} = 'separator';
+ $result .= handle_verbatim($node)
+ . "\n\n";
+ }
else {
$result .= handle_spans(\@p_children)
. "\n\n";
@@ -205,10 +248,10 @@ sub handle_divs {
}
}
elsif ($elem->{'name'} eq 'dt') {
- $result .= "<dt>" . handle_spans($elem->{'children'}) . "</dt>";
+ $result .= handle_verbatim($elem);
}
elsif ($elem->{'name'} eq 'dd') {
- $result .= "<dd>" . handle_spans($elem->{'children'}) . "</dd>";
+ $result .= handle_verbatim($elem);
}
else {
die "Unknown ", $elem->{'name'}, " in dl";
@@ -218,10 +261,29 @@ sub handle_divs {
$result .= "</dl>\n\n";
}
when ('div') {
- $result .= handle_divs($node->{'children'});
+ if (exists $node->{'attrs'}{'class'}
+ && $node->{'attrs'}{'class'} eq 'quote') {
+
+ $result .= handle_verbatim($node);
+ $result .= "\n\n";
+ }
+ else {
+ $result .= handle_divs($node->{'children'});
+ }
}
when ('blockquote') {
- $result .= handle_divs($node->{'children'});
+ if (@{$node->{'children'}} > 1
+ && $node->{'children'}[0]{'name'} eq 'div'
+ && @{$node->{'children'}[0]{'children'}} == 1
+ && $node->{'children'}[0]{'children'}[0]{'name'} eq 'p'
+ && @{$node->{'children'}[0]{'children'}[0]{'children'}} > 1
+ && $node->{'children'}[0]{'children'}[0]{'children'}[1]{'name'} eq 'tt') {
+ $result .= handle_divs($node->{'children'}[0]{'children'});
+ }
+ else {
+ $result .= handle_verbatim($node);
+ $result .= "\n\n";
+ }
}
default {
die "Encountered a $_, don't know how to handle", Dump($childrenref);
@@ -245,7 +307,12 @@ sub handle_spans {
next if $node->{'name'} eq 'nobr';
given ($node->{'name'}) {
when ('a') {
- $result .= '[' . handle_spans($node->{'children'}) . '](' . $node->{'attrs'}{'href'} . ')';
+ my $href = $node->{'attrs'}{'href'};
+ if ($href =~ m[http://use.perl.org/~masak/journal/(\d+)]
+ && exists $old2new{$1}) {
+ $href = "http://strangelyconsistent.org/blog/" . $old2new{$1};
+ }
+ $result .= '[' . handle_spans($node->{'children'}) . '](' . $href . ')';
}
when (['em', 'i']) {
$result .= '*' . handle_spans($node->{'children'}) . '*';
@@ -254,9 +321,23 @@ sub handle_spans {
$result .= '**' . handle_spans($node->{'children'}) . '**';
}
when (['code', 'tt']) {
- $result .= '`'
- . handle_spans($node->{'children'})
- . '`';
+ if (@{$node->{'children'}} == 3
+ && ref $node->{'children'}[1] eq 'HASH'
+ && $node->{'children'}[1]{'name'} eq 'a') {
+ # Special case for inside-out <a>/<code>
+ $result .= handle_spans([
+ {
+ name => 'a',
+ attrs => { href => $node->{'children'}[1]{'attrs'}{'href'} },
+ children => $node->{'children'}[1]{'children'}
+ }
+ ]);
+ }
+ else {
+ $result .= '`'
+ . handle_spans($node->{'children'})
+ . '`';
+ }
}
when ('br') {
$result .= "<br>\n";
@@ -274,6 +355,9 @@ sub handle_spans {
$text =~ s/&nbsp;/ /g;
$text =~ s/&lt;/</g;
$text =~ s/&gt;/>/g;
+ $text =~ s/&amp;/&/g;
+ $text =~ s/&#(\d+);/chr($1)/ge;
+ $text =~ s/fix:<([^>]+)>/fix:&lt;$1&gt;/g;
$result .= $text;
}
}
@@ -281,6 +365,38 @@ sub handle_spans {
return $result;
}
+sub handle_verbatim {
+ my ($node) = @_;
+ my $name = $node->{'name'};
+ my %attrs = %{$node->{'attrs'}};
+ my $result = "<$name";
+ for my $attr (keys %attrs) {
+ next if $attr eq 'rel';
+ my $value = $attrs{$attr};
+ if (-1 == index($value, "'")) {
+ $result .= " $attr='$value'";
+ }
+ else {
+ $result .= qq[ $attr="$value"];
+ }
+ }
+ $result .= ">";
+ my @children = @{$node->{'children'}};
+ for my $child (@children) {
+ if (ref $child eq 'HASH') {
+ $result .= handle_verbatim($child);
+ }
+ else {
+ my $text = $child;
+ $text =~ s/_/\\_/g;
+ $text =~ s/\&nbsp;/ /g;
+ $result .= $text;
+ }
+ }
+ $result .= "</$name>";
+ return $result;
+}
+
my @months = qw<January February March April May June July
August September October November December>;
my %month_number_of = map { $months[$_] => $_ + 1 } 0..@months-1;
@@ -304,11 +420,15 @@ for my $filename (@filenames) {
my $minute = $2;
my $date = "$year-$month-$day_of_month";
- my $timestamp = $date . "T$hour:$minute CEST";
+ my $offset = $month > 3 && $month < 11 ? "+02:00" : "+01:00";
+ my $timestamp = $date . "T$hour:$minute:00$offset";
1 while shift(@lines) !~ /<h3>([^<]+)<\/h3>/;
my $title = $1;
- my $new_filename = 'new-structure/' . titlify($title) . '.markdown';
+ my $url = urlify($title);
+ $title =~ s/ -- / &#8212; /;
+ $old2new{substr($filename, index($filename, '/') + 1)} = $url;
+ my $new_filename = 'new-structure/' . $url . '.markdown';
1 while shift(@lines) !~ /<div class="intro">(.*)/;
my $content = $1;
@@ -326,11 +446,14 @@ for my $filename (@filenames) {
die "$new_filename already exists"
if !@ARGV && -e $new_filename;
+ my $author = decode("utf-8", "Carl Mäsak");
+
open my $OUTFILE, '>', $new_filename or die $!;
+ binmode $OUTFILE, ":utf8";
print $OUTFILE <<"EOF";
---
title: $title
-author: Carl Mäsak
+author: $author
created: $timestamp
---
$content
View
2  posts/37976
@@ -274,7 +274,7 @@
]
</div>
- <div class="intro"><p>131 years ago today, Thomas Edison demonstrated for the first time a device he called a "<a href="http://en.wikipedia.org/wiki/Phonograph" rel="nofollow">phonograph</a>", which plays back recorded sound. <a href="http://en.wikipedia.org/wiki/Phonograph#First_phonograph" rel="nofollow">Wikipedia</a>:</p><blockquote><div><p>Edison's early phonographs recorded onto a tinfoil sheet phonograph cylinder using an up-down ("hill-and-dale") motion of the stylus. The tinfoil sheet was wrapped around a grooved cylinder, and the sound was recorded as indentations into the foil. Edison's early patents show that he also considered the idea that sound could be recorded as a spiral onto a disc, but Edison concentrated his efforts on cylinders, since the groove on the outside of a rotating cylinder provides a constant velocity to the stylus in the groove, which Edison considered more "scientifically correct". Edison's patent specified that the audio recording be embossed, and it was not until 1886 that vertically modulated engraved recordings using wax coated cylinders were patented by Chichester Bell and Charles Sumner Tainter. They named their version the Graphophone. Emile Berliner patented his Gramophone in 1887.</p></div></blockquote><p>Dang, I kinda liked the sound of "graphophone". &#21704;&#21704;</p><p>&#10086;</p><p>Today, in order to reduce some of the <a href="http://github.com/viklund/november/tree/d58040420ba34561cf8213dfa96455cb5e7b5c7c/p6w/t/markup/mediawiki/07-italic-and-bold.t" rel="nofollow">repetitiveness</a> of the MediaWiki markup parser test suite (set input, set expected output, calculate actual output, test, rinse, repeat), I created the module <code> <a href="http://github.com/viklund/november/tree/mediawiki-markup/p6w/Test/InputOutput.pm" rel="nofollow">Test::InputOutput</a> </code>, which resembles CPAN's <code>Test::Base</code> a bit, minus the syntactic relief. Some of the MediaWiki tests now look <a href="http://github.com/viklund/november/tree/f882a653455e6eb3370f4c997fac6b52d02a2726/p6w/t/markup/mediawiki/07-italic-and-bold.t" rel="nofollow">like this</a> instead. Typical example of separating the algorithm from the specifics.</p><p>Since that wasn't what I set out to do today, I'm going to stop here, and do that instead. I want to continue passing tests concerning italic and bold.</p><p>Also, ihrd++ merged his dispatch branch today into master, so I'll review that merge.</p><p>In short, if you haven't downloaded November yet, you should. If nothing else, there's a lot of working Perl 6 code to look at. It's not even hard: look, <a href="http://github.com/viklund/november/" rel="nofollow">a link</a>! The kind folks over at github even provide a <a href="http://github.com/viklund/november/zipball/master" rel="nofollow">zipball</a> and a <a href="http://github.com/viklund/november/tarball/master" rel="nofollow">tarball</a> for those who don't have git yet. That's what I call service.</p><p>Enjoy!</p></div>
+ <div class="intro"><p>131 years ago today, Thomas Edison demonstrated for the first time a device he called a "<a href="http://en.wikipedia.org/wiki/Phonograph" rel="nofollow">phonograph</a>", which plays back recorded sound. <a href="http://en.wikipedia.org/wiki/Phonograph#First_phonograph" rel="nofollow">Wikipedia</a>:</p><blockquote><div><p>Edison's early phonographs recorded onto a tinfoil sheet phonograph cylinder using an up-down ("hill-and-dale") motion of the stylus. The tinfoil sheet was wrapped around a grooved cylinder, and the sound was recorded as indentations into the foil. Edison's early patents show that he also considered the idea that sound could be recorded as a spiral onto a disc, but Edison concentrated his efforts on cylinders, since the groove on the outside of a rotating cylinder provides a constant velocity to the stylus in the groove, which Edison considered more "scientifically correct". Edison's patent specified that the audio recording be embossed, and it was not until 1886 that vertically modulated engraved recordings using wax coated cylinders were patented by Chichester Bell and Charles Sumner Tainter. They named their version the Graphophone. Emile Berliner patented his Gramophone in 1887.</p></div></blockquote><p>Dang, I kinda liked the sound of "graphophone". &#21704;&#21704;</p><p>&#10086;</p><p>Today, in order to reduce some of the <a href="http://github.com/viklund/november/tree/d58040420ba34561cf8213dfa96455cb5e7b5c7c/p6w/t/markup/mediawiki/07-italic-and-bold.t" rel="nofollow">repetitiveness</a> of the MediaWiki markup parser test suite (set input, set expected output, calculate actual output, test, rinse, repeat), I created the module <a href="http://github.com/viklund/november/tree/mediawiki-markup/p6w/Test/InputOutput.pm" rel="nofollow"><code>Test::InputOutput</code></a>, which resembles CPAN's <code>Test::Base</code> a bit, minus the syntactic relief. Some of the MediaWiki tests now look <a href="http://github.com/viklund/november/tree/f882a653455e6eb3370f4c997fac6b52d02a2726/p6w/t/markup/mediawiki/07-italic-and-bold.t" rel="nofollow">like this</a> instead. Typical example of separating the algorithm from the specifics.</p><p>Since that wasn't what I set out to do today, I'm going to stop here, and do that instead. I want to continue passing tests concerning italic and bold.</p><p>Also, ihrd++ merged his dispatch branch today into master, so I'll review that merge.</p><p>In short, if you haven't downloaded November yet, you should. If nothing else, there's a lot of working Perl 6 code to look at. It's not even hard: look, <a href="http://github.com/viklund/november/" rel="nofollow">a link</a>! The kind folks over at github even provide a <a href="http://github.com/viklund/november/zipball/master" rel="nofollow">zipball</a> and a <a href="http://github.com/viklund/november/tarball/master" rel="nofollow">tarball</a> for those who don't have git yet. That's what I call service.</p><p>Enjoy!</p></div>
View
2  posts/38212
@@ -275,7 +275,7 @@
</div>
<div class="intro"><p>I wanted an overview of S29. More exactly, I wanted a list of functions. The table of contents in <a href="http://perlcabal.org/syn/S29.html" rel="nofollow">S29 itself</a> didn't cut it, because it stopped short at the level of classes, and left out the functions. That's when I decided to extract the relevant information using a script of my own. I mean, how hard can it be?</p><p>Turns out it was easy.</p><p>Duh, right? We have <em>Perl</em> this is what Perl <em>does</em>: extract and report. (Practically.) Because it turned out to be a three-minute one-liner in Perl 5, I decided to turn it into a Perl 5 script file, and then into a Perl 6 script file.</p><p>The results were a bit interesting, and I thought I'd share.</p><p>First, a description of the problem:</p><ul>
- <li>S29 is a POD file, which means we're in luck: all the directives we need to extract are on their own lines.</li><li>Furthermore, all the classes are headed by <code>=head2 $class</code>, and the functions by <code>=item $function</code>.</li><li>There's some <code>=over 4</code> and <code>=back</code> stuff that we don't care about.</li><li>Oh, an the action doesn't start until after the line <code>=head1 Function Packages</code>.</li><li>Now, produce a list of functions, indented under their respecitve class.</li></ul><p>Here's my one-line solution:</p><blockquote><div><p> <tt>$ perl -e '$_ = &lt;&gt; until<nobr> <wbr></nobr>/Function Packages/; while (&lt;&gt;) { if (/^=(\S+) (.*)/) { next if $1 eq "over"; print " " x 4 if $1 eq "item"; print $2, "\n" } }' S29-functions.pod</tt></p></div> </blockquote><p>If you're interested in the output it produces, try running it after <code>cd</code>-ing into the directory <code>docs/Perl6/Spec</code> in the <a href="http://svn.pugscode.org/" rel="nofollow">Pugs repo</a>.</p><p>Here's the corresponding turned-into-a-file script (still Perl 5):</p><blockquote><div><p> <tt>use strict;<br> <br>open my $S29, '&lt;', 'S29-Functions.pod' or die $!;<br> <br>until (&lt;$S29&gt; =~<nobr> <wbr></nobr>/Function Packages/) {}<br> <br>while (my $line = &lt;$S29&gt;) {<br>&nbsp; &nbsp; if ($line =~ / ^ = (\S+) ' ' (.*)<nobr> <wbr></nobr>/x) {<br>&nbsp; &nbsp; &nbsp; &nbsp; next if $1 eq 'over';<br>&nbsp; &nbsp; &nbsp; &nbsp; if ($1 eq 'item') {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print ' ' x 4;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; print $2, "\n"<br>&nbsp; &nbsp; }<br>}</tt></p></div> </blockquote><p>Things are a bit more indented, a bit more Best Practices, but no revolutionary changes. It's the same script.</p><p>Now, take a look at the Perl 6 script:</p><blockquote><div><p> <tt>use v6;<br> <br>my $S29 = open('S29-Functions.pod',<nobr> <wbr></nobr>:r) or die $!;<br> <br>repeat {} until =$S29 ~~<nobr> <wbr></nobr>/'Function Packages'/;<br> <br>for =$S29 -&gt; $line {<br>&nbsp; &nbsp; if $line ~~ / ^ '=' (\S+) ' ' (.*) / {<br>&nbsp; &nbsp; &nbsp; &nbsp; next if $0 eq 'over';<br>&nbsp; &nbsp; &nbsp; &nbsp; if $0 eq 'item' {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print ' ' x 4;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; say $1;<br>&nbsp; &nbsp; }<br>}</tt></p></div> </blockquote><p>Noteworthy differences:</p><ul>
+ <li>S29 is a POD file, which means we're in luck: all the directives we need to extract are on their own lines.</li><li>Furthermore, all the classes are headed by <code>=head2 $class</code>, and the functions by <code>=item $function</code>.</li><li>There's some <code>=over 4</code> and <code>=back</code> stuff that we don't care about.</li><li>Oh, an the action doesn't start until after the line <code>=head1 Function Packages</code>.</li><li>Now, produce a list of functions, indented under their respecitve class.</li></ul><p>Here's my one-line solution:</p><blockquote><div><p> <tt>$ perl -e '$_ = &lt;&gt; until<nobr> <wbr></nobr>/Function Packages/; while (&lt;&gt;) { if (/^=(\S+) &#8617;<br>(.*)/) { next if $1 eq "over"; print " " x 4 if $1 eq "item"; print $2,&#8617;<br>"\n" } }' S29-functions.pod</tt></p></div> </blockquote><p>If you're interested in the output it produces, try running it after <code>cd</code>-ing into the directory <code>docs/Perl6/Spec</code> in the <a href="http://svn.pugscode.org/" rel="nofollow">Pugs repo</a>.</p><p>Here's the corresponding turned-into-a-file script (still Perl 5):</p><blockquote><div><p> <tt>use strict;<br> <br>open my $S29, '&lt;', 'S29-Functions.pod' or die $!;<br> <br>until (&lt;$S29&gt; =~<nobr> <wbr></nobr>/Function Packages/) {}<br> <br>while (my $line = &lt;$S29&gt;) {<br>&nbsp; &nbsp; if ($line =~ / ^ = (\S+) ' ' (.*)<nobr> <wbr></nobr>/x) {<br>&nbsp; &nbsp; &nbsp; &nbsp; next if $1 eq 'over';<br>&nbsp; &nbsp; &nbsp; &nbsp; if ($1 eq 'item') {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print ' ' x 4;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; print $2, "\n"<br>&nbsp; &nbsp; }<br>}</tt></p></div> </blockquote><p>Things are a bit more indented, a bit more Best Practices, but no revolutionary changes. It's the same script.</p><p>Now, take a look at the Perl 6 script:</p><blockquote><div><p> <tt>use v6;<br> <br>my $S29 = open('S29-Functions.pod',<nobr> <wbr></nobr>:r) or die $!;<br> <br>repeat {} until =$S29 ~~<nobr> <wbr></nobr>/'Function Packages'/;<br> <br>for =$S29 -&gt; $line {<br>&nbsp; &nbsp; if $line ~~ / ^ '=' (\S+) ' ' (.*) / {<br>&nbsp; &nbsp; &nbsp; &nbsp; next if $0 eq 'over';<br>&nbsp; &nbsp; &nbsp; &nbsp; if $0 eq 'item' {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print ' ' x 4;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; say $1;<br>&nbsp; &nbsp; }<br>}</tt></p></div> </blockquote><p>Noteworthy differences:</p><ul>
<li> <code>use strict</code> is implicit in <code>use v6</code>.</li><li>The <code>open</code> syntax is different. I stumbled on this, and had to go look in a spectest file to remind myself.</li><li>I use <code>repeat {} until $cond</code> unstead of <code>{} until $cond</code>, because I think it looks better. The old way still works, too.</li><li>The <code>while</code> loop is a <code>for</code> loop. Beware, young Perl 6 hatchlings! In Perl 6 land, we <code>for</code> loop over our files and other stream-like things. That way, we don't have to do an assignment (explicit as in my Perl 5 script, or implicit with <code>$_</code>). Things are more lazy in Perl 6, so the <code>for</code> loop doesn't cause the file to be slurped or anything like that. (For what it's worth, I forgot to use a <code>for</code> loop and used a <code>while</code> loop instead, with segfaults as a result. That was an indication that I was doing something wrong.)</li><li>No parens are needed after <code>for</code> and <code>if</code>.</li><li>Perl 6 regexes are automatically<nobr> <wbr></nobr><code>/x</code>.</li><li>The family of <code>$1, $2,<nobr> <wbr></nobr>...</code> match variables are pushed down one step. For great justice. And consistency.</li><li>I'm not sure it's kosher to use <code>say</code> like I did (i.e. to finish off a line that has been printed in several stages), but it seemed nice, so I decided to give it a try. So far, I like it.</li></ul><p>There you have it. A Perl one-liner grows up.</p></div>
View
12 posts/39716
@@ -274,8 +274,8 @@
]
</div>
- <div class="intro"><p>People reacted approvingly to <a href="http://use.perl.org/~masak/journal/39639" rel="nofollow">tote</a>, the nicest piece of vaporware I've never written. I received an interesting email pointing out that research on this goes back to "50s and 60s as part of the psychological movement of behaviourism"; my post was featured on <a href="http://www.reddit.com/r/programming/comments/9lkmt/helpfully_addictive_tdd_on_crack/" rel="nofollow">reddit</a>, and there were some <a href="http://irclog.perlgeek.de/perl6/2009-09-17#i_1508568" rel="nofollow">mentions</a> <a href="http://irclog.perlgeek.de/perl6/2009-09-18#i_1512051" rel="nofollow">on</a> <a href="http://irclog.perlgeek.de/november-wiki/2009-09-23#i_1530194" rel="nofollow">IRC</a>. All of this makes for a nice data point on how much attention you can make people pay something that isn't written yet. I don't think it's likely that tote, even if it turns out to be a nice harness, will ever get that kind of attention again. &#9786;</p><p>Speaking of capturing people's attention, I tend to make it a habit of including something bolded in the second paragraph, sort of my take-home message. I don't really have such a message today, except perhaps to say that in the past few weeks, <strong>I've tried tote, and it works</strong>. I've already spent hours in it, playing it like a game. Unfortunately, the versions I used are too hard-coded to the two projects I tried them on, so I still need to write the real thing from scratch. But I've learned some new things along the way, which I thought I'd relay here, partly for my future self, and partly for any readers interested in the (imminent) development of tote.</p><ul>
- <li>I used my tote prototype on two projects. To abstract away non-essentials, let's call them "project A" and "project B", respectively. They were different enough to make me think about the different TDD styles that tote needs to support.</li><li>Project A is a port. Its tests need to be ported along with the implementation, so the general workflow becomes (1) write test, (2) write code to make it pass, (3) refactor, if needed. Also known as <a href="http://www.agileprogrammer.com/dotnetguy/archive/2006/08/01/17795.aspx" rel="nofollow">red-green-refactor</a>. Except that, as the image given by that link shows, the 'red' portion of the loop might be missing, and that might be fine, too. All talk about 'the test should fail' aside, sometimes (such as when porting the test suite) a test will succeed on the first run. We cannot mandate a red part.</li><li>Project B is also a port, but one in which the tests could be adapted from the ported project. So I have only steps (2) and (3) above. This had the advantage of making me think more clearly about test results and checkpoints.</li><li>My concept of "checkpoint" is akin to "leveling up" in role-playing games. It's when all your tests that used to pass still pass, but also some new test passes. The idea is that tote should be able to parse the test output, and be able to recognize checkpoints, and compare the latest test run against such a checkpoint to see if we've regressed, progressed, or neither. The checkpoint is also a good place to make a commit, maybe automatically with an appropriate commit message calculated from the test messages of the new test that was just made to pass.</li><li>Passing/not-passing is a two-state thing, so one way to look at a particular test run is as a long bit string. Now, let's say I want to compare a test run just made to that of the last checkpoint, to see whether we've regressed, progressed, or neither. My first idea was to classify the current test run as 'regressed' if bits had flipped over from 1 to 0, 'progressed' if bits had flipped over from 0 to 1, and 'neither' if the bit strings were equal, or if bits had flipped over in both directions. Here it is in Perl 5 code:</li></ul><p> <code>
+ <div class="intro"><p>People reacted approvingly to <a href="http://use.perl.org/~masak/journal/39639" rel="nofollow">tote</a>, the nicest piece of vaporware I've never written. I received an interesting email pointing out that research on this goes back to "50s and 60s as part of the psychological movement of behaviourism"; my post was featured on <a href="http://www.reddit.com/r/programming/comments/9lkmt/helpfully_addictive_tdd_on_crack/" rel="nofollow">reddit</a>, and there were some <a href="http://irclog.perlgeek.de/perl6/2009-09-17#i_1508568" rel="nofollow">mentions</a> <a href="http://irclog.perlgeek.de/perl6/2009-09-18#i_1512051" rel="nofollow">on</a> <a href="http://irclog.perlgeek.de/november-wiki/2009-09-23#i_1530194" rel="nofollow">IRC</a>. All of this makes for a nice data point on how much attention you can make people pay something that isn't written yet. I don't think it's likely that tote, even if it turns out to be a nice harness, will ever get that kind of attention again. &#9786;</p><p>Speaking of capturing people's attention, I tend to make it a habit of including something bolded in the second paragraph, sort of my take-home message. I don't really have such a message today, except perhaps to say that in the past few weeks, <strong>I've tried tote, and it works</strong>. I've already spent hours in it, playing it like a game. Unfortunately, the versions I used are too hard-coded to the two projects I tried them on, so I still need to write the real thing from scratch. But I've learned some new things along the way, which I thought I'd relay here, partly for my future self, and partly for any readers interested in the (imminent) development of tote.</p>
+ <p>I used my tote prototype on two projects. To abstract away non-essentials, let's call them "project A" and "project B", respectively. They were different enough to make me think about the different TDD styles that tote needs to support.</p><p>Project A is a port. Its tests need to be ported along with the implementation, so the general workflow becomes (1) write test, (2) write code to make it pass, (3) refactor, if needed. Also known as <a href="http://www.agileprogrammer.com/dotnetguy/archive/2006/08/01/17795.aspx" rel="nofollow">red-green-refactor</a>. Except that, as the image given by that link shows, the 'red' portion of the loop might be missing, and that might be fine, too. All talk about 'the test should fail' aside, sometimes (such as when porting the test suite) a test will succeed on the first run. We cannot mandate a red part.</p><p>Project B is also a port, but one in which the tests could be adapted from the ported project. So I have only steps (2) and (3) above. This had the advantage of making me think more clearly about test results and checkpoints.</p><p>My concept of "checkpoint" is akin to "leveling up" in role-playing games. It's when all your tests that used to pass still pass, but also some new test passes. The idea is that tote should be able to parse the test output, and be able to recognize checkpoints, and compare the latest test run against such a checkpoint to see if we've regressed, progressed, or neither. The checkpoint is also a good place to make a commit, maybe automatically with an appropriate commit message calculated from the test messages of the new test that was just made to pass.</p><p>Passing/not-passing is a two-state thing, so one way to look at a particular test run is as a long bit string. Now, let's say I want to compare a test run just made to that of the last checkpoint, to see whether we've regressed, progressed, or neither. My first idea was to classify the current test run as 'regressed' if bits had flipped over from 1 to 0, 'progressed' if bits had flipped over from 0 to 1, and 'neither' if the bit strings were equal, or if bits had flipped over in both directions. Here it is in Perl 5 code:</p><p> <code>
sub compare_passes {<br>
&nbsp;&nbsp;&nbsp;&nbsp;my ($new, $old) = @_;<br>
<br>
@@ -292,8 +292,8 @@ sub compare_passes {<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;return $progression - $regression;<br>
}
-</code> </p><ul>
- <li>It's a mathematically elegant idea, but unfortunately it's flawed in practice. Think of project B, where all of the tests were already written. Those will count in the bitstream, and the bits after the point where you're currently working can distort the test result negatively in three ways: (1) you might have passed the test you were working on, but later tests failed randomly, so the state counts as 'neither' and you get no checkpoint; (2) you might have regressed on some tests before the one you were working on, but later tests succeeded randomly, so the state counts as 'neither', and you don't get a 'regression' notification; (3) the tests up to the test you were working on might be unchanged, but the tests after that might have passed or failed randomly, leading to spurious 'progression' or 'regression' states.</li><li>Notice how the idea of 'the test you were working on' spontaneously forced itself into the data model. It can be seen as an emergent attribute of the checkpoint bit string: it's simply the length of the initial run of 1's in that bit string. Expressing the 'regression', 'progression' and 'neither' states in this model is much simpler than before:</li></ul><p> <code>
+</code> </p>
+ <p>It's a mathematically elegant idea, but unfortunately it's flawed in practice. Think of project B, where all of the tests were already written. Those will count in the bitstream, and the bits after the point where you're currently working can distort the test result negatively in three ways: (1) you might have passed the test you were working on, but later tests failed randomly, so the state counts as 'neither' and you get no checkpoint; (2) you might have regressed on some tests before the one you were working on, but later tests succeeded randomly, so the state counts as 'neither', and you don't get a 'regression' notification; (3) the tests up to the test you were working on might be unchanged, but the tests after that might have passed or failed randomly, leading to spurious 'progression' or 'regression' states.</p><p>Notice how the idea of 'the test you were working on' spontaneously forced itself into the data model. It can be seen as an emergent attribute of the checkpoint bit string: it's simply the length of the initial run of 1's in that bit string. Expressing the 'regression', 'progression' and 'neither' states in this model is much simpler than before:</p><p> <code>
sub compare_passes {<br>
&nbsp;&nbsp;&nbsp;&nbsp;my ($new, $old) = @_;<br>
<br>
@@ -302,8 +302,8 @@ sub compare_passes {<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;return $passing_new_tests &lt;=&gt; $passing_old_tests;<br>
}
-</code> </p><ul>
- <li>When I tried out <em>this</em> idea in practice, it turned out to have a slight flaw as well, but not a fatal one this time: in project B type projects, some tests you can't reasonably make pass right now, but the "length of the initial run of 1's" model kinda demands that you do. You could move the tests, but that might not always be practical, and suddenly we're doing the tool favors, which sets a bad precedent. But having '# TODO' tests count as 1's in the bit string does the trick. Perhaps a more refined future model will even recognize when a TODO test starts passing, and consider that a checkpoint. But for now, this slightly muddled version will do.</li><li>After using the tote prototype for a while, I get that feeling one gets when tests do what they should. First, they form a dialogue between the programmer and the test suite: "Now?" - "Nope." - "Now?" - "Still not." - "How about now?" - "Yes, SUCCESS! Oh yay!". That's nice. An additional bonus, and quite a large one at that, is that the test suite might at any point say "Whoa! If you do that, then this (which used to work) will break. Careful." And that's a safety net, just as version control is a safety net, which actually allows me to be more reckless and try different ideas. And that's really, really nice. None of this is news, of course. But if you're still uncertain about whether to do unit tests, that's the reason you should consider it.</li><li>Also, a bit disappointingly, I find myself thrown out of the loop every time I save and the tote prototype goes into compile-then-test mode. I usually automatically Cmd-Tab to the browser and read a paragraph or two in the open tab. It's disappointing because the idea of tote is to keep me inside the loop, and not give me such a loophole. Maybe it's completely OK that this happens, or maybe I should find some way to stay focused on the code... looking for ways to refactor, or looking at the 'git diff' so far. I bring this up because it feels like a weakness of the system. Partly this is because Rakudo is slow, both when compiling and when running the tests. I think with a faster cycle overall, I'd distract myself less often.</li><li>Oh, and sometimes I wish there were a way to enter a 'narrow mode', where the tote framework would focus on one test, and one test only. That'd mostly solve the speed problem, actually. Once the test in question passes, 'wide mode' is turned on again and the whole test suite is run to check against regressions. Hm, I like that. The problem is that in the general case, it's not possible to pry out just one test from a test file and run only that. Maybe with some testing frameworks it might be. My old <a href="http://github.com/masak/druid/blob/master/t/01-game-rules.t" rel="nofollow">Test::Ix</a> could probably be made to work that way, for example.</li></ul><p>Each time I mention tote, I want it a little bit more.</p></div>
+</code> </p>
+ <p>When I tried out <em>this</em> idea in practice, it turned out to have a slight flaw as well, but not a fatal one this time: in project B type projects, some tests you can't reasonably make pass right now, but the "length of the initial run of 1's" model kinda demands that you do. You could move the tests, but that might not always be practical, and suddenly we're doing the tool favors, which sets a bad precedent. But having '# TODO' tests count as 1's in the bit string does the trick. Perhaps a more refined future model will even recognize when a TODO test starts passing, and consider that a checkpoint. But for now, this slightly muddled version will do.</p><p>After using the tote prototype for a while, I get that feeling one gets when tests do what they should. First, they form a dialogue between the programmer and the test suite: "Now?" - "Nope." - "Now?" - "Still not." - "How about now?" - "Yes, SUCCESS! Oh yay!". That's nice. An additional bonus, and quite a large one at that, is that the test suite might at any point say "Whoa! If you do that, then this (which used to work) will break. Careful." And that's a safety net, just as version control is a safety net, which actually allows me to be more reckless and try different ideas. And that's really, really nice. None of this is news, of course. But if you're still uncertain about whether to do unit tests, that's the reason you should consider it.</p><p>Also, a bit disappointingly, I find myself thrown out of the loop every time I save and the tote prototype goes into compile-then-test mode. I usually automatically Cmd-Tab to the browser and read a paragraph or two in the open tab. It's disappointing because the idea of tote is to keep me inside the loop, and not give me such a loophole. Maybe it's completely OK that this happens, or maybe I should find some way to stay focused on the code... looking for ways to refactor, or looking at the 'git diff' so far. I bring this up because it feels like a weakness of the system. Partly this is because Rakudo is slow, both when compiling and when running the tests. I think with a faster cycle overall, I'd distract myself less often.</p><p>Oh, and sometimes I wish there were a way to enter a 'narrow mode', where the tote framework would focus on one test, and one test only. That'd mostly solve the speed problem, actually. Once the test in question passes, 'wide mode' is turned on again and the whole test suite is run to check against regressions. Hm, I like that. The problem is that in the general case, it's not possible to pry out just one test from a test file and run only that. Maybe with some testing frameworks it might be. My old <a href="http://github.com/masak/druid/blob/master/t/01-game-rules.t" rel="nofollow">Test::Ix</a> could probably be made to work that way, for example.</p><p>Each time I mention tote, I want it a little bit more.</p></div>
View
2  posts/39872
@@ -274,7 +274,7 @@
]
</div>
- <div class="intro"><p>40 years ago today, a <a href="http://en.wikipedia.org/wiki/Sesame_Street" rel="nofollow">children's TV show</a>, which was to turn out to be very successful and educational to boot, debuted:</p><div class="quote"><p>In Sesame Street's first season, the Educational Testing Service (ETS) reported that the cognitive skills of its young viewers had increased by 62%. They found that children who viewed the show the most often did 62% better at correctly recognizing a rectangle than less frequent viewers.</p></div><p>How long before we see a children's show teaching programming?</p><p>&#10086;</p><p>Since it's <a href="http://use.perl.org/~masak/journal/39836" rel="nofollow">Temporal Tuesday</a> today, I've been making commits on the <a href="http://github.com/masak/rakudo" rel="nofollow">temporal Rakudo fork</a>. Things are moving forward, if a bit slowly.</p><p>The only challenging part today was <a href="http://github.com/masak/rakudo/commit/72fd37f7117461629a75807b447c0c0c5b707c4d" rel="nofollow">converting day-of-year to month and day-of-month</a>. I'm not sure I got that 100% right (i.e. need to write more tests); also, I cheated a bit and disregarded leap years for now. I have a feeling this detail might undergo some change before the dust lands. Still, I like the feature (specifying year and day-of-year), and can see its use in some situations. It's valid ISO 8601, just as all the other datetime formats I'm implementing.</p><p>The reason I'm doing this work at all, is because I think the current way Rakudo handles dates and times is too bare-bones. I also think that adding a few convenience methods here and there to make it more useable out-of-the box &#8212; scratch that; I want to make it <i>super-simple</i> &#8212; is important, because most every semi-large application one writes will involve date and time. My argument boils down to not wanting to write</p><p> <code>Temporal::DateTime.new(:date(Temporal::Date.new(:year(2010),<nobr> <wbr></nobr>:month(4),<nobr> <wbr></nobr>:day(1))),<nobr> <wbr></nobr>:time(Temporal::Time.new(:hour(0),<nobr> <wbr></nobr>:minute(0),<nobr> <wbr></nobr>:second(0))),<nobr> <wbr></nobr>:timezone(Temporal::Timezone::Observance.new(:offset(0),<nobr> <wbr></nobr>:isdst(False),<nobr> <wbr></nobr>:abbreviation(''))))</code> </p><p>when I want to refer to April 1st, 2010. I'd prefer something like</p><p> <code>DateTime.new('2010-04-01')</code> </p><p>(You think the former syntax is a joke? Go look at the <a href="http://github.com/rakudo/rakudo/blob/master/src/setting/Temporal.pm" rel="nofollow">Rakudo source</a>!)</p><p> <b>Update: </b> and in no way whatsoever do I wish to blame mberends++, the chief author of Rakudo's current Temporal.pm. He's basically implemented things to spec... which is why the spec needs <a href="http://github.com/masak/temporal-flux-perl6syn/blob/master/S32-setting-library/Temporal.pod" rel="nofollow">changing</a>, too.</p></div>
+ <div class="intro"><p>40 years ago today, a <a href="http://en.wikipedia.org/wiki/Sesame_Street" rel="nofollow">children's TV show</a>, which was to turn out to be very successful and educational to boot, debuted:</p><div class="quote"><p>In Sesame Street's first season, the Educational Testing Service (ETS) reported that the cognitive skills of its young viewers had increased by 62%. They found that children who viewed the show the most often did 62% better at correctly recognizing a rectangle than less frequent viewers.</p></div><p>How long before we see a children's show teaching programming?</p><p>&#10086;</p><p>Since it's <a href="http://use.perl.org/~masak/journal/39836" rel="nofollow">Temporal Tuesday</a> today, I've been making commits on the <a href="http://github.com/masak/rakudo" rel="nofollow">temporal Rakudo fork</a>. Things are moving forward, if a bit slowly.</p><p>The only challenging part today was <a href="http://github.com/masak/rakudo/commit/72fd37f7117461629a75807b447c0c0c5b707c4d" rel="nofollow">converting day-of-year to month and day-of-month</a>. I'm not sure I got that 100% right (i.e. need to write more tests); also, I cheated a bit and disregarded leap years for now. I have a feeling this detail might undergo some change before the dust lands. Still, I like the feature (specifying year and day-of-year), and can see its use in some situations. It's valid ISO 8601, just as all the other datetime formats I'm implementing.</p><p>The reason I'm doing this work at all, is because I think the current way Rakudo handles dates and times is too bare-bones. I also think that adding a few convenience methods here and there to make it more useable out-of-the box &#8212; scratch that; I want to make it <i>super-simple</i> &#8212; is important, because most every semi-large application one writes will involve date and time. My argument boils down to not wanting to write</p><p> <code>Temporal::DateTime.new(:date(Temporal::Date.new(:year(2010),<nobr> <wbr></nobr>:month(4),<nobr> <wbr></nobr>:day(1))),<nobr> <wbr></nobr>:time(Temporal::Time.new(:hour(0),<nobr> <wbr></nobr>:minute(0),<nobr> <wbr></nobr>:second(0))),<nobr> <wbr></nobr>:timezone(Temporal::Timezone::Observance.new(:offset(0),<nobr> <wbr></nobr>:isdst(False),<nobr> <wbr></nobr>:abbreviation(''))))</code> </p><p>when I want to refer to April 1st, 2010. I'd prefer something like</p><p> <code>DateTime.new('2010-04-01')</code> </p><p>(You think the former syntax is a joke? Go look at the <a href="http://github.com/rakudo/rakudo/blob/master/src/setting/Temporal.pm" rel="nofollow">Rakudo source</a>!)</p><p> <b>Update:</b> and in no way whatsoever do I wish to blame mberends++, the chief author of Rakudo's current Temporal.pm. He's basically implemented things to spec... which is why the spec needs <a href="http://github.com/masak/temporal-flux-perl6syn/blob/master/S32-setting-library/Temporal.pod" rel="nofollow">changing</a>, too.</p></div>
View
2  posts/40107
@@ -274,7 +274,7 @@
]
</div>
- <div class="intro"><p>A class hierarchy of expression nodes: it's so much the prototypical use case for run-time method polymorphism that it's almost a clich&#233;. One can close one's eyes and picture the way parts of the expression tree interact in rich, complex ways, shaped by the very types of the nodes themselves, in a dynamic dance of late bindings and virtual methods. Switch statmement, get thee behind me. Et cetera.</p><p>I'm <a href="http://github.com/masak/gge" rel="nofollow">building one</a>. And I'm having almost too much fun doing it. In between trying to use the strengths of Perl 6 and keeping true to the <a href="http://github.com/leto/parrot/tree/master/compilers/pge/" rel="nofollow">original program</a> I'm porting, I've discovered an important thing: Ovid is right about roles.</p><p>Specifically, I'm having trouble picturing how I would cram all the type information into my expression node class hierarchy, were I not using roles. The roles definitely help manage complexity in my case.</p><p> <a href="http://masak.org/carl/exp-class-hierarchy.png" rel="nofollow">Here's a pretty diagram</a> of my class hierarchy.</p><p>It's a flat beast. Apart from everything deriving from <code>Exp</code>, I have only one case of old-skool inheritance in the diagram. And even that one is more making a point than actually shortening the code.</p><p>Then there's all the colorful dots, representing the roles I'm mixing into my types. Some are for convenience (like the blue ones), others are vital for my program (like the green ones), and the rest are somewhere in between on the convenient/vital scale.</p><p>I even have a case of inheritance between two of the roles! Which means, in practice, that those classes with an orange dot also act as if they had a red dot. Very handy.</p><p>During the infancy of Rakudo, I've gotten used to learning to live without various features. Were I to do what I'm doing here without using roles, I could use two other mechanisms. The first is regular inheritance. The very thought gives me a bit of vertigo; I don't think I'd be able to turn the colored dots into base classes. Definitely not all of them at once; I'd have to choose. And that choice would affect the entire design of the program, probably resulting in loss of clarity.</p><p>The second way I could compensate for not having roles would be by using<nobr> <wbr></nobr><code>.can</code> a lot. The presence of a given role in a class is isomorphic to the presence of a given method in a class. So that would definitely work, but I don't think I would like it as much. There's something to be said for declaring <code>is</code> and <code>does</code> relationships at the very top of the class declaration.</p><p>All in all, I'm very happy about the way things work. I'm wondering whether, had I not read all of Ovid's posts <a href="http://use.perl.org/~Ovid/journal/38373" rel="nofollow">on</a> <a href="http://use.perl.org/~Ovid/journal/38586" rel="nofollow">managing</a> <a href="http://use.perl.org/~Ovid/journal/38649" rel="nofollow">the</a> <a href="http://use.perl.org/~Ovid/journal/38662" rel="nofollow">complexity</a> <a href="http://use.perl.org/~Ovid/journal/38761" rel="nofollow">of</a> <a href="http://use.perl.org/~Ovid/journal/38862" rel="nofollow">class</a> <a href="http://use.perl.org/~Ovid/journal/38885" rel="nofollow">hierarchies</a> <a href="http://use.perl.org/~Ovid/journal/39039" rel="nofollow">with</a> <a href="http://use.perl.org/~Ovid/journal/39977" rel="nofollow">roles</a>, I would have come up with this design myself. Maybe, maybe not. But anyway: thanks, Ovid! This rocks!</p><p>A still-open question for me is whether the topmost type, <code>Exp</code>, should be a class or a role. <a href="http://feather.perl6.nl/syn/S12.html#Classes" rel="nofollow">Synopsis 12</a> has this to say about when to use roles:</p><div class="quote"><p>Classes are primarily for instance management, not code reuse.
+ <div class="intro"><p>A class hierarchy of expression nodes: it's so much the prototypical use case for run-time method polymorphism that it's almost a clich&#233;. One can close one's eyes and picture the way parts of the expression tree interact in rich, complex ways, shaped by the very types of the nodes themselves, in a dynamic dance of late bindings and virtual methods. Switch statmement, get thee behind me. Et cetera.</p><p>I'm <a href="http://github.com/masak/gge" rel="nofollow">building one</a>. And I'm having almost too much fun doing it. In between trying to use the strengths of Perl 6 and keeping true to the <a href="http://github.com/leto/parrot/tree/master/compilers/pge/" rel="nofollow">original program</a> I'm porting, I've discovered an important thing: Ovid is right about roles.</p><p>Specifically, I'm having trouble picturing how I would cram all the type information into my expression node class hierarchy, were I not using roles. The roles definitely help manage complexity in my case.</p><p> <a href="http://masak.org/carl/exp-class-hierarchy.png" rel="nofollow">Here's a pretty diagram</a> of my class hierarchy.</p><p>It's a flat beast. Apart from everything deriving from <code>Exp</code>, I have only one case of old-skool inheritance in the diagram. And even that one is more making a point than actually shortening the code.</p><p>Then there's all the colorful dots, representing the roles I'm mixing into my types. Some are for convenience (like the blue ones), others are vital for my program (like the green ones), and the rest are somewhere in between on the convenient/vital scale.</p><p>I even have a case of inheritance between two of the roles! Which means, in practice, that those classes with an orange dot also act as if they had a red dot. Very handy.</p><p>During the infancy of Rakudo, I've gotten used to learning to live without various features. Were I to do what I'm doing here without using roles, I could use two other mechanisms. The first is regular inheritance. The very thought gives me a bit of vertigo; I don't think I'd be able to turn the colored dots into base classes. Definitely not all of them at once; I'd have to choose. And that choice would affect the entire design of the program, probably resulting in loss of clarity.</p><p>The second way I could compensate for not having roles would be by using<nobr> <wbr></nobr><code>.can</code> a lot. The presence of a given role in a class is isomorphic to the presence of a given method in a class. So that would definitely work, but I don't think I would like it as much. There's something to be said for declaring <code>is</code> and <code>does</code> relationships at the very top of the class declaration.</p><p>All in all, I'm very happy about the way things work. I'm wondering whether, had I not read all of Ovid's posts <a href="http://use.perl.org/~Ovid/journal/38373" rel="nofollow">on</a> <a href="http://use.perl.org/~Ovid/journal/38586" rel="nofollow">managing</a> <a href="http://use.perl.org/~Ovid/journal/38649" rel="nofollow">the</a> <a href="http://use.perl.org/~Ovid/journal/38662" rel="nofollow">complexity</a> <a href="http://use.perl.org/~Ovid/journal/38761" rel="nofollow">of</a> <a href="http://use.perl.org/~Ovid/journal/38862" rel="nofollow">class</a> <a href="http://use.perl.org/~Ovid/journal/38885" rel="nofollow">hierarchies</a> <a href="http://use.perl.org/~Ovid/journal/39039" rel="nofollow">with</a> <a href="http://use.perl.org/~Ovid/journal/39977" rel="nofollow">roles</a>, I would have come up with this design myself. Maybe, maybe not. But anyway: thanks, Ovid! This rocks!</p><p>A still-open question for me is whether the topmost type, <code>Exp</code>, should be a class or a role. <a href="http://feather.perl6.nl/syn/S12.html#Classes" rel="nofollow">Synopsis 12</a> has this to say about when to use roles:</p><div class="quote"><p>Classes are primarily for instance management, not code reuse.
Consider using <code>roles</code> when you simply want to factor out
common code.</p></div><p>I <em>am</em> using <code>Exp</code> for code reuse, and for giving all of the other classes in the hierarchy a common base type. So I guess I could indeed turn it into a role. But it's just that... I don't see a <em>reason</em> to do so, and I still feel instinctively reluctant about it. Maybe I'm a bit hung up about it being a <em>class</em> hierarchy.</p><p>This point has <a href="http://irclog.perlgeek.de/perl6book/2009-11-11#i_1717258" rel="nofollow">come up before</a> on IRC, and I've yet to hear a satisfactory way to resolve it: when faced with making a base type a class or a role, which way should one go?</p></div>
View
2  posts/40361
@@ -277,7 +277,7 @@
<div class="intro"><p> <i>My trip to Moscow was a pleasant one,<br>
The city has <a href="http://www.munnecke.com/islands/qwan.htm" rel="nofollow">a certain feel</a> I like.<br>
<a href="http://engl.mosmetro.ru/flash/scheme01.html" rel="nofollow">The metro</a> is so big and full of win!<br>
-And so too was <a href="http://irclog.perlgeek.de/perl6/2010-05-16#i_2336857" rel="nofollow">the room</a> at my hotel.</i> </p><p> <i> <a href="http://masak.org/carl/devconf-2010/talk.pdf" rel="nofollow">My talk</a> was well-received and fun to give,<br>
+And so too was <a href="http://irclog.perlgeek.de/perl6/2010-05-16#i_2336857" rel="nofollow">the room</a> at my hotel.</i> </p><p> <i><a href="http://masak.org/carl/devconf-2010/talk.pdf" rel="nofollow">My talk</a> was well-received and fun to give,<br>
on Yapsi, Tardis, Sigmund and Perl 6.<br>
<a href="http://twitter.com/sharifulin" rel="nofollow">sharifulin</a>++ for speedy help<br>
with <a href="http://twitpic.com/1ol9ms" rel="nofollow">setting up his laptop</a> for my talk.</i> </p><p> <i>The guys at <a href="http://moscow.pm.org/" rel="nofollow">Moscow.pm</a> made me feel<br>
View
6 posts/40516
@@ -364,11 +364,11 @@ say @pascal.perl;
<b>my @pascal<nobr> <wbr></nobr>:= do [1], -&gt; @p { [0, @p Z+ @p, 0] }<nobr> <wbr></nobr>... *;</b> <br>
<br>
say <b>@pascal[^10]</b>.perl;
-</code> </p><p>(The extra <code>do</code> required because of a <a href="http://rt.perl.org/rt3/Ticket/Display.html?id=77462" rel="nofollow">shortcoming in Rakudo</a>.)</p><p>Now. Something very much like this code was posted first <a href="http://rosettacode.org/wiki/Pascal's_triangle#Perl_6" rel="nofollow">on Rosetta code</a> and then <a href="http://perlgeek.de/blog-en/perl-6/pascal-triangle.html" rel="nofollow">on Moritz' blog</a>. (TimToady used a sub, but said later that he'd have preferred binding.)</p><p>A couple of Perl 5 people's reactions were &#8212; somewhat uncharacteristically &#8212; of a negative flavour, similar to how people <a href="http://use.perl.org/~masak/journal/40339" rel="nofollow">seem to react</a> to the periodic table of operators:</p><p> <code>
+</code> </p><p>(The extra <code>do</code> required because of a <a href="http://rt.perl.org/rt3/Ticket/Display.html?id=77462" rel="nofollow">shortcoming in Rakudo</a>.)</p><p>Now. Something very much like this code was posted first <a href="http://rosettacode.org/wiki/Pascal's_triangle#Perl_6" rel="nofollow">on Rosetta code</a> and then <a href="http://perlgeek.de/blog-en/perl-6/pascal-triangle.html" rel="nofollow">on Moritz' blog</a>. (TimToady used a sub, but said later that he'd have preferred binding.)</p><p>A couple of Perl 5 people's reactions were &#8212; somewhat uncharacteristically &#8212; of a negative flavour, similar to how people <a href="http://use.perl.org/~masak/journal/40339" rel="nofollow">seem to react</a> to the periodic table of operators:</p><p class='quote'>
<a href="http://twitter.com/shadowcat_mst/status/22112066276" rel="nofollow">@shadowcat_mst</a>: an excellent example of why I consider camelia perl to be a language research project more than a production language
-</code> </p><p> <code>
+</p><p class='quote'>
<a href="http://twitter.com/pedromelo/status/22110965152" rel="nofollow">@pedromelo</a>: I'm seriously considering this post as an example of what I don't want Perl6 to become...
-</code> </p><p>I think these reactions are mainly feature shock. Higher-order operators, pointy blocks, and the series operator... they're all good, well-established features, which find daily use in Perl 6 programs. Maybe using them all together like that flung some people off the deep end. Never mind that the resulting script is all <a href="http://en.wikipedia.org/wiki/Essential_complexity" rel="nofollow">essential complexity</a>, with virtually no boilerplate from the original script left.</p><p>This is the first time that's happened. I think it's important to listen to what Perl 5 people think and to try to respond to that. But I also think that this time, it's a case of them seeing some highly idiomatic Perl 6, and freaking out a bit.</p><p>And I think that that, in some odd sense, is a good thing. Well, not freaking people out, per se. But the fact that we did shows that there's something forming which might be tentatively called "idiomatic Perl 6": people on the inside can read it quite easily, but those on the outside, even Perl 5 folks looking in, instinctively go "eeeeew!".</p><p>That's OK. You're not meant to start with the idiomatic stuff. <em>Language acquisition takes place step by step</em>, and that goes for learning Perl 6 as well. On the way there, just don't confuse distaste with lack of familiarity.</p></div>
+</p><p>I think these reactions are mainly feature shock. Higher-order operators, pointy blocks, and the series operator... they're all good, well-established features, which find daily use in Perl 6 programs. Maybe using them all together like that flung some people off the deep end. Never mind that the resulting script is all <a href="http://en.wikipedia.org/wiki/Essential_complexity" rel="nofollow">essential complexity</a>, with virtually no boilerplate from the original script left.</p><p>This is the first time that's happened. I think it's important to listen to what Perl 5 people think and to try to respond to that. But I also think that this time, it's a case of them seeing some highly idiomatic Perl 6, and freaking out a bit.</p><p>And I think that that, in some odd sense, is a good thing. Well, not freaking people out, per se. But the fact that we did shows that there's something forming which might be tentatively called "idiomatic Perl 6": people on the inside can read it quite easily, but those on the outside, even Perl 5 folks looking in, instinctively go "eeeeew!".</p><p>That's OK. You're not meant to start with the idiomatic stuff. <em>Language acquisition takes place step by step</em>, and that goes for learning Perl 6 as well. On the way there, just don't confuse distaste with lack of familiarity.</p></div>
Please sign in to comment.
Something went wrong with that request. Please try again.