Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Meditations

( #480=superdoc: print w/replies, xml ) Need Help??

If you've discovered something amazing about Perl that you just need to share with everyone, this is the right place.

This section is also used for non-question discussions about Perl, and for any discussions that are not specifically programming related. For example, if you want to share or discuss opinions on hacker culture, the job market, or Perl 6 development, this is the place. (Note, however, that discussions about the PerlMonks web site belong in PerlMonks Discussion.)

Meditations is sometimes used as a sounding-board — a place to post initial drafts of perl tutorials, code modules, book reviews, articles, quizzes, etc. — so that the author can benefit from the collective insight of the monks before publishing the finished item to its proper place (be it Tutorials, Cool Uses for Perl, Reviews, or whatever). If you do this, it is generally considered appropriate to prefix your node title with "RFC:" (for "request for comments").

User Meditations
Improve readability of Perl code. Naming reference variables.
7 direct replies — Read more / Contribute
by hakonhagland
on Jan 19, 2017 at 15:05
    Hello Monks!

    I've been learning Perl for some years now. At the same time, moving from writing awk scripts to writing Perl scripts, I have found Perl to be an amazing resource for getting things done.

    Still, I have some minor issues with the language design that I have not yet been able to understand/resolve. This is what I want to discuss here.

    Background

    It sometimes bugs me that it is so difficult to write Perl code that is readable (easy to follow) when working with references. For example, if I see a variable $var in the middle of some code, it can be a scalar variable, a scalar reference, an array reference, a hash reference, and so on. Hence, I often end up guessing or having to scan source code nearby in order to determine the type of the variable. I find this workflow less than optimal. Would it not be better if the variable could (optionally) be made self-documenting with respect to reference type?

    In the book Perl Best Practices, the problem is mentioned in another setting, and the solution suggested is to add the suffix _ref to the variable name. So one could write,

    $var_href = { a => 1 };
    to create a hash ref, and
    $var_aref = [ 1, 2, 3];
    to create an array reference.

    However, a problem with this convention could be that the suffix is not optional. You should not be forced to used the more verbose form of the variable name. I think, the programmer should have a choice to decide whether he finds it advantageous to include the suffix at given place or not. For example, when declaring the variable as

    $var = [ 1, 2, 3 ];
    it is rather obvious that it is an array reference, and there is no need to write:
    $var_aref = [ 1, 2, 3 ];
    The latter is in my opinion too verbose. However, if the reference is just defined as
    my $var;
    it would often be better to include the suffix. If there is no indication on the next lines or so whether $var will be used as an array reference or not, it would be more readable to define it as
    my $var_aref;

    A new idea for reference variable naming syntax

    So this lead me to an idea: Could the postfix dereferencing syntax be extended for this use case?

    The Postfix Dereferening Syntax (PDS) was introduced as experimental in 5.20. And starting from 5.24 it is included in the Perl language by default.

    Currently PDS is used for dereferencing:

    my @array = $var->@*;
    Notice that the PDS includes a star after the sigil. It is a syntax error not to include the star. But let's say for the moment that if the star was omitted, the dereferencing was to be simply ignored instead. So
    my $var->@;
    would mean the same as
    my $var;
    and produce no syntax error.

    Let's denote this new syntax by Optional Postfix Reference Declaration Syntax (OPRDS). So when using OPRDS, should it be entirely up to the user to ensure that he used the correct sigil. For example, if I write

    $var->@ = 12;
    when I really meant
    $var->@ = [ 12 ];
    should it produce a compile time error? I think it would be very helpful if the compiler could use OPRDS to check for consistency. But it might be difficult to implement? I do not know. If it is difficult to implement, some alternatives might be used instead? I don't know much of Perl internals, so this is a point where I need help.

    When I started out with this idea, compile time type-checking was not on my mind at all. But I see now that OPRDS would offer the opportunity for stricter type checking.

    But type checking was not the main issue I wanted to discuss. What I would like to discuss is how to deal with reference variable names. Reading and understanding written Perl code can be difficult since the $ sigil can be used for many data types. How could this situation be improved?

RFC: Module for testing asynchronous event series
No replies — Read more | Post response
by Dallaylaen
on Jan 18, 2017 at 16:57

    Let's say we are going to test a module that is supposed to be run asynchronously - using threads, AnyEvent, or Coro, or some other means. And we need to check that certain events happen in certain sequence, because some of them depend on the others.

    Probably the best way to achieve this would be of course to minimize interdependencies and use mathematically correct synchronization for whatever is left. Of course, that is not always achievable, due to limited time.

    So I'm going to propose a primitive that I think should deal with a huge subclass of such tasks.

    The code goes as follows:

    use Test::AsyncSeq; my $id = Test::AsyncSeq->get_sequence_id; my $id2 = Test::AsyncSeq->get_sequence_id( "frobnicate" ); # would be "frobnicate1" or smth # somewhere in threads/callbacks is_after( $id, "start" ); # elsewhere is_after( $id, "event2", "start" ); # more elsewhere is_after( $id, "event3", "start" ); # finally is_after( $id, "finish", "event2", "event3" );

    The is_after( $id, $event, @dependencies ); passes if and only if:

    • sequence named $id was created;
    • $event was not seen in the sequence yet;
    • all of the @dependencies have been seen at the moment of the call.

    The id is just a string, and is required since Perl is not very good at passing blessed references across threads. And multiple tests MAY be needed in the same script, say to catch a race condition.

    Does such interface make sense? Would it be of use to anyone?

[RFC] Building Regex Alternations Dynamically
5 direct replies — Read more / Contribute
by haukex
on Jan 18, 2017 at 07:57

    Dear Monks, this is a suggestion for a tutorial, any comments or suggestions are welcome. Update 1: Fixed up explanation of metacharacters a bit. Update 2: Implemented some things from kcott's comments. Update 3: Added TL;DR, inspired by LanX.

    TL;DR: The two code samples below are working pieces of code that can be copied into your Perl script and adapted for your purposes.

    I thought it might be useful to explain the technique of building regular expressions dynamically from a set of strings. Let's say you have a list of strings, like ("abc", "def", "ghi"), and you want to build a regex that matches any of them, like /(?:abc|def|ghi)/. This also works well with s/search/replacement/ if you have a hash where the keys are the search strings and the values are the replacements, as I'll show below. If you're uncertain on some of the regex concepts used here, like alternations a|b and non-capturing groups (?:...), I recommend perlretut.

    First, the basic code, which I explain below - note the numbering on the lines of code.

    my @values = qw/ a ab. d ef def g|h /; my $regex_str = join '|', # 4. map {quotemeta} # 3. sort { length $b <=> length $a } # 2. @values; # 1. my $regex = qr/$regex_str/; # 5. print "$regex\n"; # 6.
    1. We begin with the list of strings stored in the array @values. This could be any list, such as a literal qw/.../, or return values from functions, including keys or values.
    2. We sort the list so that the longer strings appear first. This is necessary because if our regular expression was /foo|foobar/, then applied to the string "foobarfoofoobar", it would only match "foo" three times, and never "foobar". But if the regex is /foobar|foo/, then it would correctly match "foobar", "foo", and again "foobar".
    3. Next, we apply the quotemeta function to each string, which escapes any metacharacters that might have special meaning in a regex, such as . (dot, matches anything) or | (alternation operator). In our example, we want the string "g|h" to be matched literally, and not to mean "match g or h". Unescaped metacharacters can also break the syntax of the regex, like stray opening parentheses or similar. Note that quotemeta is the same as using \Q...\E in a regex. As discussed here, you should only drop \Q...\E or quotemeta in the case that you explicitly want metacharacters in your input strings to be special, they come from a trusted source, and you are certain that your strings don't contain any characters that would break your regular expression or expose security holes!
    4. Then, we join the strings into one long string using the regex alternation operator |. If you want to use this string without the qr// of step 5, note this potential pitfall: For example, if your input is qw/a b c/, then at this point your string will look like $regex_str="a|b|c". Then, saying /^$regex_str$/ will be interpolated to /^a|b|c$/, which means "match a only at the beginning of the string, or b anywhere in the string, or c only at the end of the string", which is probably not what you meant, you probably meant /^(?:a|b|c)$/, that is /^(?:$regex_str)$/!
    5. Finally, we compile the regular expression using qr//. This is not strictly necessary, you could just interpolate the string you've just created into a regex, but I prefer to turn them into regex objects explicitly. It also has the advantages that you can apply modifiers such as /i to the regex in a (IMO) more natural way, and that qr// implicitly adds a non-capturing group (?:...) around the regex, which takes care of the problem described in step 4 above.
    6. When we print the regular expression, we see that it has become this:
      (?^:ab\.|def|g\|h|ef|a|d)
      You can now use this precompiled regular expression anywhere, as explained in Compiling and saving regular expressions and perlop, such as if ($input=~$regex) { ... } or while ($input=~/$regex/g) { ... }.

    Search and Replace Using a Hash

    my %map = ( a=>1, ab=>23, cd=>45 ); # 1. my $regex_str = join '|', # 2. map {quotemeta} sort { length $b <=> length $a or $a cmp $b } # 3. keys %map; my $regex = qr/$regex_str/; print "$regex\n"; # 4. # Now, use the regex my @strings = qw/ abcd aacd abaab /; # 5. for (@strings) { my $before = $_; s/($regex)/$map{$1}/g; # 6. print "$before -> $_\n"; # 7. }
    1. This is the hash in which the keys are the search strings, and the values are the replacements. As above, this can come from any source.
    2. This code to build the regex is mostly the same as the above, with differences noted here.
    3. Instead of only sorting by length, this sort first sorts by length, and sorts values with the same length with a stringwise sort. While not strictly necessary, I would recommend this because hashes are unordered by default, meaning that your regex would be in a different order across different runs of the program. Sorting the hash keys like this causes the regex to be in the same order in every run of the program.
    4. We print the regex for debugging, and see that it looks like this: (?^:ab|cd|a)
    5. These are the test strings we will apply the regular expression against.
    6. This is the search and replace operation that matches the keys of the hash, and as a replacement value gets the corresponding value from the hash. Note that the /g modifier is not strictly required (s///g will replace all matches in the string, not just the first), and you can adapt this regex any way you like. So for example, to only make one replacement anchored at the beginning of the string, you can say s/^($regex)/$map{$1}/;.
    7. The output of the code is:
      abcd -> 2345 aacd -> 1145 abaab -> 23123

    Hope this helps,
    -- Hauke D

URL encoding and decoding
No replies — Read more | Post response
by $h4X4_&#124;=73}{
on Jan 12, 2017 at 06:33

    While testing a module I found a bug in the way it encodes a URL. So I hit the web to find out why.
    The subroutines it uses for encoding and decoding where very old and had many more bugs then the one I found, so I installed URL::Encode and because the module complained I then installed URL::Encode::XS also.

    I used URL::Encode to test the two output and fix the broken code, because most of the time using a cpan module just slows the main project down a lot when the included modules are providing a very small chunk of code.

    So my fix for the broken URL encode and decode is below and outputs the same as URL::Encode.
    It looks like it would be a lot faster then including a module (URL::Encode) to do the same actions.

    sub url_encode { my $rv = shift; $rv =~ s/([^a-z\d\Q.-_~ \E])/sprintf("%%%2.2X", ord($1))/geix; $rv =~ tr/ /+/; return $rv; } sub url_decode { my $rv = shift; $rv =~ tr/+/ /; $rv =~ s/\%([a-f\d]{2})/ pack 'C', hex $1 /geix; return $rv; }
    But with URL::Encode::XS module installed the code above is very, very slow.
    This bench script can show the speed difference.
    #!/usr/bin/perl #################### # LOAD CORE MODULES #################### use strict; use warnings FATAL => 'all'; # Autoflush ON local $| = 1; use URL::Encode; use Benchmark qw(cmpthese); my $thing = '%&copy; <> []"\'=?.-_^&*(){}@#!|,;:`~$/\\ 1 + 2 = 3 1 +s sd sds'; my $thing22 = '%25%26copy%3B+%A9+%3C%3E+%5B%5D%22%27%3D%3F.-_%5E%26%2A +%28%29%7B%7D%40%23%21%7C%2C%3B%3A%60~%24%2F%5C+1+%2B+2+%3D+3+++1s+sd+ +sds'; my $num_of_iters = '1000000'; #################### # RUN BENCH #################### print "\n\nBenchmarking $num_of_iters iterations on Perl $] ($^O)\n\n" +; cmpthese( $num_of_iters, { 'MY::Decoder' => sub { url_decode( $thing22 ); }, 'URL::Decode' => sub { URL::Encode::url_decode( $thing22 ); }, 'MY::Encoder' => sub { url_encode( $thing ); }, 'URL::Encode' => sub { URL::Encode::url_encode($thing); }, } ); print "\n"; my $thing2 = URL::Encode::url_encode($thing); print $thing2."\n"; $thing2 = URL::Encode::url_decode($thing2); print $thing2."\n"; print "\n\n"; my $thing3 = url_encode($thing); print $thing3."\n"; $thing3 = url_decode($thing3); print $thing3."\n"; sub url_encode { my $rv = shift; $rv =~ s/([^a-z\d\Q.-_~ \E])/sprintf("%%%2.2X", ord($1))/geix; $rv =~ tr/ /+/; return $rv; } sub url_decode { my $rv = shift; $rv =~ tr/+/ /; $rv =~ s/\%([a-f\d]{2})/ pack 'C', hex $1 /geix; return $rv; }

Win32::SerialPort finally fixed for 64 bit Perl
No replies — Read more | Post response
by kschwab
on Jan 07, 2017 at 19:01

    Some kind soul finally posted a patch that fixes Win32::SerialPort for 64 bit installations of Perl on Windows.

    The patch is here.

    Thought it might be worth noting here...I can't be the only person that's suffered 32 bit perl on Windows for this reason. This has been broken for quite some time.

Perl vs Python revisited
5 direct replies — Read more / Contribute
by QuillMeantTen
on Jan 06, 2017 at 04:08

    edit: I don't know enough to write a web server with the full stack, but a web application. corrected that typo
    Now that I'm through the first semester and have three days to gather my bearings and prepare for the next one I decided to jot down some of my conclusions here.

    When I heard that we would do networking and security related programming in python I was kinda miffed. As some here might now perl was my first scripting language and the fondness that I have for it is in no small part due to the number of libraries and the ease of building new things from them. And of course its wonderful way of handling text analysis.

    After a day of two of brooding I decided to give it a go (really I didn't have any choice, still the teachers quips about me already being old for using perl bothered me quite a bit).
    He did not say perl was useless mind you, he admitted to not having followed it's recent development and being mostly interested in the use of the scapy python library.

    So here I went, full of expectations. I had heard much about python, how it was gentle on the beginner, object oriented and made you write nice code... How wrong I was.

    Yes, you HAVE to indent. After I got to working on a project with someone else who (even after we discussed coding conventions) kept using tabs instead of a set number of spaces, I understood why so many people complained about the rigidity of obligatory indentation. I mean if I wanted to code in whitespace I'd have chosen whitespace. This is not a python problem but rather a programmer's own issues there, it didn't really bother me at any time, thanks to an airtight vimrc.

    Now onto the next issue. Python will make you write nice code. I call bull on this one. Sure you'll have to indent your loops so they work but that won't make you write nice code. I have a hefty slab of absolutely unreadable UI code sitting in a repository on a university server to prove it.

    Interface with other languages: I found doing C code unit testing in python very easy and I hear that calling java or c++ from python isn't that hard either, so that's a very good thing for me.

    To sum it up I'm glad I've learned a bit of python this semester (enough to be able to code web applications, udp/tcp custom servers or simple AI algorithms) because it gave me another point of view on the topic of interpreted languages. I recommend anyone using perl to give python a try just to have that alternative point of view (the same way I'd recommend that any programmer use a functional language at least once just to see how it feels). but in the end? I think that for me perl's TIMTOWTDI approach is best, because it allows me to really express myself. I don't think it's the language's job to make me respect other programmer's work by sticking to discussed APIs and using coding standards. I do so by my own free will and what this semester has proven to me is that another neophyte can be using the exact same constraining language without giving a proverbial flying one about coding standards and end up with a steaming pile of unreadable code. Could have happened with perl too, albeit with a lot more $, @ and other #.

RFC: Test::Refute - extensible unified assertion & testing tool
1 direct reply — Read more / Contribute
by Dallaylaen
on Jan 05, 2017 at 03:28

    I would like to present a new assertion/testing tool project. Now there's excellent Test::More with a whole ecosystem built around it and a dozen assertion tools (typically optimizing themselves out in prod environment) available on CPAN. So WHY?

    RATIONALE

    1. It's more or less compatible with Test::More. Actually it aims to be 100% compatible condition-wise and somewhat compatible regarding the test flow, sans black magic like TODO: and SKIP:. (Saner substitutes planned).

    2. It has both functional AND object-oriented ("contract") interface. Contracts can be used in production code, say to check user input or plugin module meet requirements. Nesting contracts is possible (that's how subtest is implemented).

    3. It's very easy to extend (see below). A Builder is still required, but all it does is wrapping a given condition around for export AND OO-based usage. The internal check logic does NOT depend on it. Writing a custom Contract backend (e.g. outputting XML, or dying after a certain error count) is also possible.

    4. Built with testability in mind. Custom tests' failure modes can be easily checked.

    5. It's faster. Up to 5x-7x in a synthetic test (see t/speed.t) and up to 30-50% in real life test suite.

    I'd rather continue dreaming about the contract feature, if this rant wasn't the last drop.

    SYNOPSIS

    The test script usage is quite simple (read: ripped off Test::More):

    use Test::Refute; is 42, 42, "this holds"; like "foo", qr/bar/, "this fails"; done_testing; # this is mandatory, even if plan declared

    Or the object-oriented interface, runs just happily inside production code (on "oks" on STDOUT, no influence on return code etc):

    use Test::Refute::Contract; my $c = Test::Refute::Contract->new; $c->is($user_input, 42); $c->like($another_input, qr/f?o?r?m?a?t/); if ($c->is_valid) ...

    Or combining best of both worlds:

    use Test::Refute qw(no_init); my $c = contract { is $user_input, 42; like $another_input, qr/f?o?r?m?a?t/; }; # analyze $c here ...

    The project is in deep alpha stage right now, but I hope it evolves into something usable. Looking forward to your support, critique, suggestions, and prior art links.

    https://github.com/dallaylaen/perl-test-refute
Leap second coming up. Check your date handling code
5 direct replies — Read more / Contribute
by 1nickt
on Dec 25, 2016 at 16:18

    Hi all,

    A friendly reminder that a leap second will be added to the clock at the end of 2016. If you do date math at all, you may want to check that your date handling code is ready for it.

    For example, versions of DateTime below 1.34 won't handle it correctly:

    $ perl -MDateTime -E 'say $DateTime::VERSION' 1.33 $ perl -MDateTime -E ' my $dt = DateTime->new( time_zone => "UTC", year => 2016, month => 12, day => 31, hour => 23, minute => 59, second => 60 ); say $dt->datetime; $dt->add( months => 1 ); say $dt->datetime; ' Invalid second value (60) at -e line 2.
    $ perl -MDateTime -E 'say $DateTime::VERSION' 1.39 $ perl -MDateTime -E ' my $dt = DateTime->new( time_zone => "UTC", year => 2016, month => 12, day => 31, hour => 23, minute => 59, second => 60 ); say $dt->datetime; $dt->add( months => 1 ); say $dt->datetime; ' 2016-12-31T23:59:60 2017-02-01T00:00:00

    Hope this helps somebody :-)


    The way forward always starts with a minimal test.
RFC: new.pm - a perl -e use/new shortener
7 direct replies — Read more / Contribute
by Dallaylaen
on Dec 24, 2016 at 06:20

    I tend to use perl one-liners extensively, mostly for testing purposes. In particular, I often load a module with a loooooooooong name only to instantiate it once. And it's boooooooring to type the whole name twice.

    So I came up with an idea of a one-liner shortener along the lines of:

    perl -we 'use new qw(My::Very::Long::Module x foo 42); print $x->get_f +oo;'
    Which is a rough equivalent of
    perl -we 'use My::Very::Long::Module; our $x = My::Very::Long::Module- +>new( foo => 42 ); print $x->get_foo;'

    And I have a proof-of-concept implementation that works as follows:

    • require module being called;
    • create a new instance;
    • create a package variable in the calling package (so that strict doesn't complain);
    • set that variable to instance from above.

    Here it is.

    package new; use strict; use warnings; =head1 NAME new - shorted require Foo; Foo->new(...) to just one call =head1 SYNOPSYS use new qw(My::Very::Long::Module x foo 42); is an exact equivalent of our $x; BEGIN { require My::Very::Long::Module; $x = My::Very::Long::Module->new( foo => 42 ); }; or a rough equivalent of use My::Very::Long::Module; our $x = My::Very::Long::Module->new( foo => 42 ); Not a big deal in a real program, but may save some typing in a one-liner test script. Works well under C<use strict;>. =cut $Carp::Internal{ (__PACKAGE__) }++; sub import { my ($self, $target, $name, @args) = @_; my $filename = $target; $filename =~ s#::#/#g; $filename .= ".pm"; require $filename; my $obj = $target->new( @args ); my $caller = caller; $name ||= 'new'; my $sym = join "::", $caller, $name; no strict qw(refs vars); *$sym = \$$sym; $$sym = $obj; }; 1;

    Made purely for fun, but maybe there's some point in it after all.

    UPDATE Available as gist.

Typing Perl with Speech Recognition
2 direct replies — Read more / Contribute
by Anonymous Monk
on Dec 22, 2016 at 17:43
Perl denormalized-to-normalized schema translation, maybe with DBIx::Class (maybe)
2 direct replies — Read more / Contribute
by gryphon
on Dec 20, 2016 at 12:09

    Greetings all,

    I have a strange situation, wondering if there's a DBIx::Class-ish option that might help me. We've got a very large, old, spaghetti, denormalized Oracle database and a sea of CGIs with embedded, hardcoded SQL. Ultimately, I'd like to refactor the schema, normalize it, add FK constraints, and all the usual good things. But I can't without considerable destabilization risk to the CGIs.

    The strategy at this point is to carve out chunks of CGI functionality and refactor each chunk into an isolated web service with its own data store. But in doing this, we'll need to maintain two data stores for a while: the existing legacy denormalized store and the new and smaller/better normalized store. We need to keep these in sync for a while until we have refactored enough to deprecate the old schema. So what we need then is a "translation layer" behind each new web service that sees changes to the local data store and pushes those changes to the legacy database (until we can eventually deprecate the legacy db).

    I'm envisioning this "translation layer" would need to understand both schemas (the new local store and the legacy Oracle), and would need to understand how to map data between the two. A lot of this will be heavily manual at the detail level, I understand. But I'm wondering if anyone knows of a scaffolding/framework option I should consider before starting something custom from scratch.

    The intent is to use DBIx::Class::Schema::Loader to auto-build the Perl schema classes from the legacy database schema, and we'll probably use it also for the new schema. But once we have these two sets of schema classes, I'd like a way to link them. Certainly, the details of this linking will have to be very custom.

    Thanks.

The state of Perl
3 direct replies — Read more / Contribute
by FreeBeerReekingMonk
on Nov 30, 2016 at 15:01
    Some other monks made comments about the quietness on this site... here are some visual clues and trends:

    As measured by github changes and stackoverflow tags....

    Programming Language Popularity Chart

    And also:

    job-trends for perl and similar

    If you add C++ to the latter, you will see nobody is looking for C++ jobs (but they search for C instead).

(Placeholder) Imagine!
5 direct replies — Read more / Contribute
by BrowserUk
on Nov 29, 2016 at 22:24

    This place excels in starting with a single, clearly defined, abstracted problem, and refining the set of proposed solutions down to a clear, concise, efficient solution. Many hands make light work!

    Now, imagine if each of the Perl(5) opcodes was proffered here -- say: one per weekend -- on a Friday night - say: US West Coast time -- in the form of a hack-a-thon task for that weekend.

    What might result from that exposure of a clearly defined task to the assembled (and usually quite bored on weekends), diverse populous?

    If those more enlightened tolorant members of p5p were enthused to cast a critical eye over the proceedings -- to catch the less obvious pitfalls in the evolution of solutions -- then the results might be usefully fed back into the p5p process and result in benefits for all.

    Thoughts on: Is the idea viable?

    Thoughts on: Are any members of p5p willing to participate?

    Caveats?


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". The enemy of (IT) success is complexity.
    In the absence of evidence, opinion is indistinguishable from prejudice.
Propose addition to use warnings?
6 direct replies — Read more / Contribute
by perldigious
on Nov 28, 2016 at 09:30

    I'm not sure what the official mechanism for making such a suggestion would be, but I recently had to go on a bug hunt in my code that left me surprised use warnings didn't give me some sort of, "are you SURE you aren't doing something silly here at line x?" message. Maybe it isn't practical to expect use warnings to save me from myself in this case, but I figured I'd throw it out here as a meditation for discussion and to get opinions from Monks far wiser than I am.

    I'm of course simplifying and paraphrasing, but essentially I had some code that did the following:

    open(my $first_fh, "<", "file1.txt") or die "Cannot open \"file1.txt\" +: $!."; open(my $second_fh, "<", "file2.txt") or die "Cannot open \"file2.txt\ +": $!."; my @file1_lines = <$first_fh>; close $first_fh; while (my $line = <$second_fh>) { my @data = my_sub($first_fh, $line); # copy/paste error, should ha +ve passed $second_fh here # and of course a bunch of non-relevant stuff here }

    So I accidentally passed the $first_fh that I had previously closed to my_sub, but as it turns out use warnings didn't make a peep about this. I did of course get warnings from inside my_sub when it attempted to make use of the filehandle, but the kicker was that any such use was wrapped inside of a conditional that actually made it very rare it would ever get used (maybe once every 100,000 lines or so of typical data).

    DISCLAIMER: The fact that I didn't have something in my standard test data that ensured the conditional that used the filehandle was exercised is entirely on me (forgive me, for I have sinned). I accept full responsibility for that mistake and the initial copy/paste laziness error that forced me to engage in my bug hunt. I'm only pointing out that usually use strict, use warnings, or perl itself is pretty good about preemptively saving me from myself, and in this case it didn't.

    Any thoughts from the Monastery?

    Just another Perl hooker - will code for food
storeBackup - A Gem of a Backup Solution
1 direct reply — Read more / Contribute
by wjw
on Nov 20, 2016 at 11:49

    I was recently in a position where I needed a backup solution that was flexible enough to handle my laptop as well as my home server. I back up to a couple of older USB drives; A 1.5T for my laptop, and a 750G for my home server. The plethora of options out there is daunting, and the most obvious like rsync (which I really like and use often) are very nice. But I wanted something that I could set up quickly and would meet a couple of other needs easily.

    • I wanted it to conform to a standard backup scheme where there are a couple backups each day, a daily backup for a week or so, a monthly backup, and a yearly.
    • I wanted it to delete outdated backups
    • I wanted it to be tolerant of the backup drive not being available, such as when I am out of town with my laptop, but don't have the USB drive to back up to.
    • and ... I also wanted it to do something like rsync in that it stores only the differences, not an entire copy of everything in each backup.

    What I found was a Perl application called storeBackup. It has been around for a while, claims to be production ready/stable, and it seems to me as if it is.

    I did a non-exhaustive search here on perlmonks and did not find a reference to this handy tool, so thought I would mention it here in meditations....as I was sitting here meditating about it. The darn thing works really well! It does exactly what I want it to do in that it meets all the requirements listed above, and has the added benefit that it is written in Perl.

    For anyone looking for a very sweet backup solution that is simple to set up, is tolerant of a dynamic environment, and provides efficient, accessible, and easily recoverable backup data, I would certainly recommend looking at this solution. From my perspective, it just plain rocks!

    ...the majority is always wrong, and always the last to know about it...

    A solution is nothing more than a clearly stated problem...


Add your Meditation
Title:
Meditation:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":


  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and all is quiet...

    How do I use this? | Other CB clients
    Other Users?
    Others about the Monastery: (6)
    As of 2017-01-23 17:48 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?
      Do you watch meteor showers?




      Results (194 votes). Check out past polls.