Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
npe
Oct 15, 2004
Perl 6 is just so different that it's really a different language altogether. That means it has to overcome the same inertia to switch that every other language has to overcome today to get people off perl. I guess what I'm saying is, what is keeping me on perl today is what's going to keep me from using perl 6 tomorrow.

Adbot
ADBOT LOVES YOU

npe
Oct 15, 2004

Triple Tech posted:

Let's say I have a super class and a program that's supposed to handle N sub classes of that... Is there a way to load all of those based on their existance on the file system, and not hard code use statements somewhere?

Super class Fruit. Sub classes Apple, Orange, Strawberry, and whatever else I happen to include on the file system...

You can use require to do this if you specify the file name, assuming you know the file names you're looking for. We dynamically load in modules based on command line arguments, which sounds similar to what you're talking about, in that we don't know until run time what we want to load. The idea is, given --class=Foo::Bar, we want to "use Foo::Bar". To do this we have to do something like:

code:
    my $classfile = $class.'.pm';
    $classfile =~ s/::/\//g;

    require $classfile;

    my %versions = Class::ISA::self_and_super_versions($class);

    if (!exists($versions{'Fruit'})) {
      die "$class is not a fruit!";
    }   

    my $instance = $class->new();
    $instance->go();
I'm not sure if that helps or not. It seems like you would be looking on disk for a file to exist, and if it does, doing something like the above to import it.

npe
Oct 15, 2004
The "official" method in the camel book is something like

code:
 sub getMessage {
   my $self = shift;
   my $class_func = ref($self).'::message';
   
   no strict 'refs';
   $class_func->();
 }
It's still ugly but at least you're not forcing a string eval.

npe
Oct 15, 2004
That's not exactly what he had asked and if the function is not expecting the classname to be passed in as $_[0] then he's going to have problems, although I do prefer those solutions if it's possible to do so.

Edit to clarify: if he has the following sub declared in package Foo:

code:

 sub message
 {
   my $text = shift;

   # do something with the message
 }

And he does this:

code:

 my $class = ref($self);
 $class->message('hello!');

...then he's passed in 'hello!' as $_[1] and 'Foo' as $_[0]. This is probably not what was intended.

npe fucked around with this message at 02:12 on Nov 15, 2007

npe
Oct 15, 2004

leedo posted:

Not exactly a question, but I thought someone might get a kick out of it...

Here is a horrible "IMAP to Google Calendar" program that I wrote last night. I thought it might help me in filling out my time sheets at work. Turns out that it is completely useless!

You may want to remove your login and password from that...

npe
Oct 15, 2004
It looks like it doesn't affect the builtin warn(), however if you want to make all warnings die you can pretty safely trap the __WARN__ signal as recommended in the camel book:

code:
[~] $ cat foo.pl
 $SIG{__WARN__} = sub{die shift};
 warn "foo!";
 print "hi!\n";
[~] $ perl foo.pl
foo! at foo.pl line 2.
[~] $ 

npe
Oct 15, 2004

mister_gosh posted:

I have a question. I have a filehandle I'm printing to:

code:
open(OUT, ">C:/example.txt");
...
print OUT "something";
...
close OUT
If someone CTRL-C's this script, nothing gets put in to C:/example.txt. Is there a way to ensure it closes properly or a better way of doing this?

Edit: thinking about this some more, is there a way to do something like if a user does CTRL-C or if there is an abrupt end or big error, can the program say "on exit, close this file handle?"

Override the SIGINT handler:

code:

 open(OUT, ">C:/example.txt");
 $SIG{INT} = sub{ close(OUT) };
 ...

npe
Oct 15, 2004

Ninja Rope posted:

All file handles are always closed when your program exits. Are you sure that something else isn't going on when users ctrl+c out of the program?

This is true but he wants the buffer flushed to the file first, which does not happen if you ctrl-c (at least on the systems I have available to me to experiment with).

npe
Oct 15, 2004

Ninja Rope posted:

I was under the impression that dirty write buffers are flushed when the handle is closed, but I don't really care enough to double check that. If we're sure that's what's happening, then you're right and the signal handler is the best way to go. However, I'd probably wrap the code that works on OUT inside a lexical block and use local $SIG{INT} = sub( close(OUT); exit; }.

This was based on experience and a short test, incidentally here's what I did:

code:
[~] $ cat sigint_me.pl
open(my $file, ">blargh.txt");
print $file "hello!";
sleep(1000);
[~] $ perl sigint_me.pl

[~] $ cat blargh.txt
[~] $
Interestingly, setting the handler to any sub at all seems to force the handle to be flushed, so I'm not entirely sure why that is. Setting it to "sub{exit}" forces a flush on my system.

quote:

Also, it's best to use actual variables to hold your file handles (eg, open($fh, 'file') instead of open(FH, 'file')).

Yes, I realize, I was simply tacking onto his example for clarity. :)

npe fucked around with this message at 05:28 on Dec 9, 2007

npe
Oct 15, 2004

Triple Tech posted:

And then verbosity gets into how people think in terms of chunks and lines of code, despite what language they're in... Terseness rules, Perl wins.

I won't get involved in the perl6 debate, but I want to address this. Perl is "more terse" for a limited set of things, but not all things. The biggest offender here is perl's support for OOP, which involves doing a lot of crap yourself and makes perl a lot more verbose.

Compare:

code:
package Foo;
use base 'Bar';

sub new
{
 bless {}, shift;
}

sub do_something
{
 my ($self, $arg1, $arg2) = @_;
 defined($arg1) or die "arg1 required";
 $arg2 ||= 'default_value';

 # do something
}
with python:

code:
class Foo(Bar):
    def do_something(self, arg1, arg2='default_value'):
        # do something
If you spend most of your time writing classes, perl loses the terseness war pretty quickly.

npe
Oct 15, 2004

Triple Tech posted:


And given your example in Python, I bet for fleshing out OOP concepts, Python would beat the pants off of Perl any day.

So what you really mean is, "perl is more terse, except when it isn't"? What's the point of boasting about how perl is "more terse" and "wins" when you concede there are extremely large domains that it ends up being klumsy and verbose in?

npe
Oct 15, 2004
Holy crap, how come I didn't know about this a little while ago when I needed a very simple way to generate XML output (and was getting very annoyed at the overhead of XML::Twig). :mad:

npe
Oct 15, 2004

quote:


Is there a way to test if the line is already utf8? I think I need a good encode tutorial.

Not really. I think some software tries to guess (there's a famous bug in notepad about this) but there is no foolproof way. A string of utf-8 characters can be interpreted as a (somewhat nonsensical) string of iso-8859 characters.

npe
Oct 15, 2004
There might be a better way to do this, but using Getopt::Long::Configure to set pass_through (which preserves unspecified options in @ARGV without warning) lets you test to see if any are left. I tried the following:

code:
[~] $ cat test.pl
use strict;
use Getopt::Long;
Getopt::Long::Configure('pass_through');

my %options;
GetOptions(\%options, "domain:s", "all", "help", "verbose");

if ($options{help} or scalar @ARGV) {
    print "help!\n";
    exit;
}

print "run time!\n";

[~] $ perl test.pl --domain=blah --what
help!
[~] $ perl test.pl --domain=blah
run time!

npe
Oct 15, 2004
I've been doing some dangerous mucking around (too much reading source code to Damian Conway modules...). I actually got a module working which enables this syntax:

code:
    sub my_func :Arguments(String, OneOf(Int, String(xyz), Instance(File))) {
        print "yarr!\n";
    }


    my_func('foo', 'bar');
When run...

code:
 "bar" for argument 2 of main::my_func() is invalid, must be one of: a valid integer, a scalar string matching /xyz/, an instance of File() at ArgumentValidator.pm:665
  at main::my_func('foo', 'bar')  (args.pl:13)
It's only run-time checking, of course, but it's an interesting (ab)use of subroutine attributes.

The fact that perl lets me pull this off is sort of simultaneously entertaining and frightening.

npe
Oct 15, 2004

heeen posted:

Someone posted a module that, when ncluded, would change all string literals to pirate speak or something like that, does someone remember the link?

I wrote that and mentioned it in one of the earlier perl threads, but I don't think I ever posted it. Let me see if I can dig it up.

Edit: Found it. In Pirate.pm:

code:
    package Pirate;

    use overload;

    # stole this from some website, add or replace as ye see fit
    my %filter = (
        '\bhello\b'         => 'avast, ye',
        '\bit\'s\b'         => '\'tis',
        '\bthere\b'         => 'thar',
        '\bbetween\b'       => 'betwixt',
        '\bdied\b'          => 'snuffed it',
        'ing\b'             => 'in\'',
        'ings\b'            => 'in\'s',
        '\berror\b'         => 'scallywag',
        '\berrors\b'        => 'scallywags',
        '\bbad\b'           => 'vile',
        '\bwas\b'           => 'was bein\'',
        '\buser\b'          => 'landlubber',
        '\bpassword\b'      => 'secret word',
        '\binvalid\b'       => 'wretched',
        '\bfile\b'          => 'dead man\'s chest',
        '\blogfile\b'       => 'captain\'s log',
        '\byou\b'           => 'ye',
        '\byes\b'           => 'aye',
        '\bno\b'            => 'nay',
        '\bwrite\b'         => 'scribe',
        '\bis\b'            => 'be',
        '\bis not\b'        => 'ain\'t',
        '\bisn\'t\b'        => 'ain\'t',
        '\bserver\b'        => 'serving wench',
        '\bper\b'           => 'fer\' ev\'ry',
        '\bdocument\b'      => 'treasure map',
        '\bfiles\b'         => 'bucket \'o booty',
        '\binformation\b'   => 'loose talkin\'', 
        '\bdata\b'          => 'booty',
        '\band\b'           => '\'n', 
        'rs the\b'          => 'rin\' th\'',

    );

    sub import {
        overload::constant(
            q => sub {
                foreach my $word (keys %filter) {
                    my $target = $filter{$word};
                    $_[1] =~ s/$word/$target/gi;
                }

                return $_[1];
            },
        );
    }

    1;
In use:

code:
[~] $ cat test.pl

use Pirate;
print "hello\n";
[~] $ perl test.pl
avast, ye
Just so you know, it absolutely breaks the poo poo out of just about any real script. ALL string literals get filtered, so it makes a mess of all sorts of things (the first thing that broke when I tried it on some existing scripts as a joke was it broke the Getopt::Long specifications for arguments). Still a funny prank.

npe fucked around with this message at 19:01 on Apr 3, 2008

npe
Oct 15, 2004
Of course, although tied hashes are actually a sane way to accomplish this sort of thing, whereas I was trying to come up with a hilariously inappropriate prank abusing one of the most wtf aspects of perl (being able to overload string literals).

I'm thinking of replacing the pirate stuff (which seemed novel at the time but is pretty cliche by now) with something more insidious, like replacing ascii numerals with similar-but-different unicode versions.

Edit: Sub::Sealed is pretty funny. Somewhere I have a module I wrote that will set UNIVERSAL::AUTOLOAD to a routine that will search for any semi-close matches for undefined subroutines that get called, including pawing through local directories for .pm files. Prank perl is the best.

npe fucked around with this message at 02:53 on Apr 4, 2008

npe
Oct 15, 2004
Oh, awesome. Great, now I'm going to waste more time on Evil.pm today...

LightI3ulb, you have to post source, you'll probably get an answer within minutes if you do.

npe
Oct 15, 2004
That program works fine for me:

code:
[~] $ cat test.pl
#!/usr/bin/perl

sub total{
        my $sum;
        foreach(@_){
                $sum += $_;
                   }
        $sum;
        }
my @fred = qw{ 1 3 5 7 9};
my $fred_total = &total(@fred);
print "The total of \@fred is $fred_total.\n";
print "Enter some numbers on seperate lines.";
my $user_total = &total(<STDIN>);
print "The total of those numbers is $user_total";
[~] $ perl test.pl
The total of @fred is 25.
Enter some numbers on seperate lines.1
2
3
The total of those numbers is 6

npe
Oct 15, 2004
Switch is evil, and the problems it has with /'s in your code are fairly well documented. Good riddance. :)

npe
Oct 15, 2004
I don't think you're reading that right, it's not trying to create new connections, those are just ACK's on the existing connection.

[Edit: forget this, it's just the window update and dupe acks...]

What's happening is, you're initiating the connection, sending a segment with 6 bytes of data, which the printer responds to with 7 empty segments before you finally terminate the connection from the client end (the FIN).

In short, it's just not sending you anything back. The next step for you would be to look at the contents of the segment with the 6 bytes and see if you're actually transmitting what you should be. Having all of those duplicate ACK segments makes me wonder if there's something sketchy on the printer end of things, but first find out if you're sending the right data.

npe fucked around with this message at 16:15 on May 20, 2008

npe
Oct 15, 2004
The "upside down question mark" is probably your editor/terminal/whatever program's way of indicating that there is an unsupported character of some sort there (wide unicode character in a terminal expecting 7bit ASCII or latin-1). You should examine the data in hex and see what it really is, it may be iso-8859 of some form, or unicode.

npe
Oct 15, 2004
Yeah, I meant UTF-8.

npe
Oct 15, 2004

leedo posted:

edit: annnnd I quickly answered my own question with
code:
perldoc -f wantarray

Just an obscure word of warning (since this somewhat unlikely to crop up for most people) but man did it ruin my day once: "list context" can crop up when you aren't always thinking about it, and due to perl flattening lists when you're not looking this can have interesting results.

For example:

code:
sub get_nothing
{
  if (wantarray)
  {
    # return empty list
    return ();
  }
  else
  {
    return "";
  }
}

# works as you would expect
my $scalar = get_nothing();
my @empty = get_nothing();

# uh oh! 
my %hash = (
  foo => 1,
  bar => get_nothing(),
  baz => 2
);
Data::Dumper shows the problem:

code:
scalar: $VAR1 = '';
array: $VAR1 = [];
hash: $VAR1 = {
          'bar' => 'baz',
          'foo' => 1,
          '2' => undef
        };
So, just be careful with wantarray.

npe
Oct 15, 2004

Fenderbender posted:

You're placing an empty array as a value, so it's compiled as essentially just nothing, and so it offsets all the key/value pairs in the hash.

Sure, we know why it happens, but the point is that it's a gotcha that can cause problems due to the sneaky ways that list context will suddenly appear without you realizing it.

I consider it a gotcha because wantarray is precisely the sort of thing that is tempting to use when you need to retroactively modify an existing function that is already in use. "Man, I'd really like to have an array here instead of a string. Hey, I can just have that function check wantarray, and no one will ever know!" That's when everything breaks, because that function is being used in parameterized argument lists all over the place.

Well, that's how it happened to me, anyways. The moral of the story is: either don't use wantarray at all, or if you do, it's probably best to not retroactively add it to an existing sub unless you feel really good about your unit test coverage.

npe
Oct 15, 2004
I know DBI (or at least DBD::Oracle) clobbers some signal handlers, although I'm not sure what it's doing with them.

npe
Oct 15, 2004

Dr.Khron posted:

Ug, this is why I have no desire to learn PERL... All those limited scopes must be hard to keep track of. Also, the "Loosely Typed" thing drives me nuts: I'm sort of OCD with numbers, and it just makes me SO happy to plan out my variable use and properly declare both type and scope at the begining of each sub.

Explicit Variable Declaration: its just feels right!

Perl has "use strict", which forces you to declare all of your variables with either "my" or the somewhat rarely used "our".

Most perl programmers won't do anything without "use strict" for good reason.

npe
Oct 15, 2004
Back when I had to solve this problem, I did it by installing an "agent" script , either on the local machines, or on a machine close to them on the network, which would gather up the data and store it locally so that I could poll it in one big chunk. Sped things up tremendously, but I have no idea how applicable that solution is to you.

Adbot
ADBOT LOVES YOU

npe
Oct 15, 2004
It's funny, because for many people (myself included), the functional approach of map seems much easier to translate into english.

code:
my @name_lengths = map { length } @names;
In pseudo code that's something like:
code:
 "Name lengths" is a list of the lengths of "names". 
It's descriptive, as opposed to a set of instructions, which is much more natural-language like. YMMV I suppose.

  • Locked thread