Stories
Slash Boxes
Comments

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

educated_foo (3106)

educated_foo
  (email not shown publicly)

Journal of educated_foo (3106)

Sunday December 16, 2007
04:29 PM

TIMTOWTDI in Emacs, too.

Devel::PerlySense has been getting quite a bit of (apparently well-deserved) attention lately. As the author of Sepia, a long-existing but apparently little-used Emacs Perl development module, I thought now would be a good time to post a diary here. For those of you who tried an earlier version, Sepia is considerably more stable and better-documented in versions 0.9x, but needs more users to acquire polish.

Sepia aims to make Emacs the kind of interactive development environment for Perl that it already is for Emacs Lisp. This involves a number of components:

  • Interactive evaluation: Supports both a REPL and a scratch buffer. The REPL uses the Perl debugger hooks to allow breakpoints and recovery from die, and Devel::LexAlias to inspect and change lexicals.
  • Source navigation: Finds definitions, callers, and callees. This is supported by querying the running Perl process rather than through PPI.
  • Documentation: Displays minibuffer documentation (eldoc) for builtins and some user functions, and supports POD browsing.
  • Completion: Completes variable, function, and module names based on the running Perl process.

Not having used Devel::PerlySense, I won't try to make a detailed comparison, but my impression is that Devel::PerlySense is geared toward off-line development (uses PPI, has a class browser, etc.), while Sepia is geared toward on-line development (supports interaction, value inspection, debugging). So give both a try, and see which style suits you best.

Monday May 21, 2007
01:54 PM

Defining "DSL", or eternal recurrence in software

(Inspired by chromatic's recent musings...)

I want a function to take the mean of some data:

$x = mean \@data;

Hm.... I want to ignore NaN and Inf sometimes; I'll add a flag for it:

$x = mean \@data, 1;

But I may also want to trim outliers; I'll use keyword arguments:

$x = mean \@data, skipinf => 1, trim => 0.1;

Whoa, this is getting complicated; I'll make it an Object:

$x = new Mean(@data);
$x->{skipinf}=1;
$x->{trim}=0.1;
$y = $x->value

OMG, no encapsulation, I'll make accessors:

$x = new Mean;
$x->setData(\@data);
$x->setSkipInf(1);
$x->setTrim(0.1);
$y = $x->value

But now I have to do this just to do a simple mean:

$x = new Mean;
$x->setData(\@data);
$y = $x->value

I know, I'll create a little language for means:

$x = mean \@data, trim => 0.1, skipinf => 1;

Then I can write in the domain terminology, and taking the mean is easy:

$x = mean \@data;

...and thus we see how "writing interfaces that don't suck" became "creating little languages."

Friday October 01, 2004
12:27 AM

script vs. applescript

So I need something to kill time during the debates and further
increase my level of frustration. Safari doesn't have a saved
sessions. Let's try a bit of applescript...

tell application "Safari"
        set urls to URL of every document
        -- tbd: how do I write a file in AS?
end tell

No love -- this only saves the first tab of each window. Curse.
Google around a bit. Curse a bit more when I find out what's
involved, and when I can't make the cut-and-paste code to write a file
work...

#!/usr/bin/env perl

sub osascript($)
{
        my $cmd = shift;
        local *O;
        open O, "|osascript > /tmp/osa.$$";
        $cmd =~ s/\n/\r/g;
        print O $cmd;
        close O;
        open IN, "/tmp/osa.$$" or die $!;
        unlink "/tmp/osa.$$";
        return split /\r/, join '', <IN>;
}

sub get_docs
{
        osascript <<'END';
tell application "System Events"
        set urls to {}
        tell process "Safari"
                repeat with w in every window
                        tell w
                                repeat with b in every radio button
                                        click b
                                        tell application "Safari"
                                                set urls to urls & (URL of first document)
                                        end tell
                                end repeat
                        end tell
                end repeat
        end tell
        set old_delim to AppleScript's text item delimiters
        set AppleScript's text item delimiters to return
        set urls to urls as text
        set AppleScript's text item delimiters to old_delim
        urls
end tell
END
}

sub restore_docs
{
        my $docthing = '{'.(join ',', map { qq{"$_"} } grep $_, @_).'}';
        osascript <<END;
tell application "System Events"
        set urls to $docthing
        tell application "Safari"
                repeat with u in urls
                        open location u
                end repeat
        end tell
end tell
END
}

@ARGV = grep $_,@ARGV; # wtf: quicksilver passes us an empty arg.
if (@ARGV) {
        $op = shift;
} else {
        $pf = "$ENV{HOME}/.safari-state";
        if ($0 =~ /safari-save(?:\.pl)?$/) {
                $op = 'save';
                open STDOUT, ">$pf" or die "$0: $pf: $!";
        } elsif ($0 =~ /safari-load(?:\.pl)?$/) {
                $op = 'load';
                open STDIN, $pf or die $!;
        } else {
                die;
        }
}

if ($op =~ /^s/) {
        print STDOUT "$_\n" for get_docs;
} elsif ($op =~ /^l/) {
        my @docs = map {chomp;$_} <STDIN>;
        restore_docs(@docs);
}
...add it to my Quicksilver path. Hack-tastic.