Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"


by Bod (Parson)
on Nov 15, 2020 at 00:48 UTC ( [id://11123653] : user . print w/replies, xml ) Need Help??

Long time amateur coder since growing up with a ZX Spectrum and BBC Micro...

Introduced to Perl in the early 1990's which quickly became the language of choice. Built many websites and backend applications using Perl including the sites for my property business:
Lets Delight - company site
Lets Stay - booking site
Also a few simple TK based desktop apps to speed things up.

Guilty of only learning what I need to get the job done - a recipe for propagating bad practice and difficult to maintain code...difficult for me so good luck to anyone else!

Now (Nov 2020) decided to improve my coding skills although I'm not really sure what "improve" means in this context. It seems Perl and best practice have come along way since I last checked in and my programming is approach is stuck in the last decade.

Onwards and upwards...

20th October 2021 - added to Saint in our Book 😀
2nd October 2022 - promoted to Priest
7th July 2023 - promoted to Vicar
15th December 2023 - promoted to Parson

Find me on LinkedIn, or on Twitter

CPAN Releases



Nodes I find helpful


Re: What do I use to release a module to CPAN for the first time?
Basic Testing Tutorial

Posts by Bod
Anonymous subroutines in Seekers of Perl Wisdom
7 direct replies — Read more / Contribute
by Bod
on Dec 10, 2023 at 18:00

    Recently, I've noticed a few places where anonymous subroutines have been declared for no apparent reason:

    my $function = sub { # stuff... }; # Call the sub $function->('param');
    I would write the same subroutine as such:
    sub function { # stuff... } # Call the sub function('param);
    The above two code snippets appear to do exactly the same thing. But is there a subtle difference lurking there that I have overlooked? Is there a reason to write the first form instead of the second?

    I don't think I have ever written a stand-alone anonymous subroutine like this. The only place I generally use anonymous subs is as a 'value' in a hash. Typically, to pass to Template to keep logic separated from display like this:

    my $vars = { 'date' => $date, 'format' => sub { return ucfirst lc $_[0]; }, }; $template->process('', $vars);

Character encoding in emails in Seekers of Perl Wisdom
8 direct replies — Read more / Contribute
by Bod
on Dec 05, 2023 at 16:59

    I have two email-sending processes. Both are seemingly the same but they produce different results. Both use MIME::Lite.

    One sends emails immediately, the other is for larger numbers of emails and consists of an email queue held in a MariaDB database. The sending script runs every 20 minutes from CRON. The body text for both gets to them from an HTML textarea and they have been tested using identical body text.

    If we add an emoji character to the body text, the queue sends it correctly. But the immediate sending script produces ��� instead of the emoji.

    As far as I can tell the only differences between the scripts is that one runs under CRON and stores and retrieves the body using a database. Other than that they seem identical.

    Both scripts use utf8;

    I am at a loss how to debug the problem...what would you try to get to the root of this problem?

XS Modules - why and when? in Seekers of Perl Wisdom
9 direct replies — Read more / Contribute
by Bod
on Dec 04, 2023 at 19:22

    I know little about XS modules but I was looking at RPi::DHT11 and noticed that it is an XS module which seemed a little strange. Hence the question here. I was going to email stevieb, the author and ask but thought it would be good to get other people's take on this.

    My understanding of an XS module is that it uses XSLoader to load C / C++ / C# code. The Perl is just a wrapper around the loaded code with the Perl doing little processing. I believe the main reason to do this is for speed as compiled languages of the C family are faster than interpreted languages such as Perl. Is that about right so far?

    Assuming that is something like correct...
    Why would the RPi::DHT11 module use XS? The DHT11 is a temperature and humidity sensor with a maximum frequency of 0.5Hz (one read per 2 seconds). So speed is not the issue here!

    What reason would there be for creating an XS module in this use case? Would it not be easier and simpler and just as fast given the speed of the sensor, to write all the code in Perl?

    I'm hoping for more insights into the world of XS modules here...

Capture Groups in Seekers of Perl Wisdom
3 direct replies — Read more / Contribute
by Bod
on Nov 14, 2023 at 15:11

    I've had cause to run some code from the console that usually only gets run on a webserver. In its usual environment, it doesn't give me warnings. But, from the console, I get a warning...

    $result =~ s/(Mr(s)?) a/\1 A/s; \1 better written as $1 at...

    I have always been under the impression (or perhaps illusion) that \1 should be used within the regular expression and $1 outside of it. Like this:

    if ($test =~ /some_test/) { $foo = $1; }

    Has something changed in the preferred way to capture in a regular expression, or have I been doing it wrong all the time?

Wide characters and UTF8 in Seekers of Perl Wisdom
1 direct reply — Read more / Contribute
by Bod
on Nov 08, 2023 at 11:00

    Could you please help me with this little script?

    I am trying to pre-parse (i.e. check that I can get the data I need) a JSON file from the UK Charity Commision. The data source is not known for being well-formated but I am pretty sure the issue here is with my code and (lack of) understanding of character encoding!

    use strict; use warnings; use Data::Dumper; use utf8; use JSON; $/ = undef; open my $fh, '<:encoding(UTF-8)', '' or die +$!; my $data = <$fh>; close $fh; $data =~ s/^\x{feff}//; # Strip off BOM my $json = decode_json $data; # <-- Wide character in subroutine ent +ry at line 15. foreach my $j(@$json) { print "$j->{'charity_contact_phone'},$j->{'charity_contact_email'} +\n"; } print "\nComplete!\n\n";

    The documentation for decode_json says it takes a UTF8 encoded string. So I have saved the JSON file as UTF8 using TextPad and opened the file with the same encoding. But, decode_json is croaking Wide character in subroutine entry

    What have I overlooked?

Displaying POD like MetaCPAN in Seekers of Perl Wisdom
5 direct replies — Read more / Contribute
by Bod
on Nov 07, 2023 at 16:50

    Do you know of any modules or services that can display POD in the same (or similar) style as MetaCPAN?

    We want to document internal modules consistently and it seems sensible to keep the layout and style in one with public modules.

LICENCE file in Seekers of Perl Wisdom
3 direct replies — Read more / Contribute
by Bod
on Oct 15, 2023 at 16:42

    I've added a LICENCE file following advice from SankoR in Re: GitHub perl-ci.yml

    I have used App::Software::License as suggested in this Perl blog

    However, both the blog and the module are quite old. Plus, the blog comment suggests this might not be the best methodology...

    Is there a 'better' method that Monks are using?

    As an aside, for the benefit of anyone stumbling this way looking at using App::Software::License. The documentation is wrong - at least for Strawberry Perl on Windows. The documentation shows single quotes for the --holder attribute. If single quotes are used, just the firstname is shown in the LICENCE file. Using double quotes solves this problem: --holder "Joe Bloggs"

GitHub perl-ci.yml in Seekers of Perl Wisdom
3 direct replies — Read more / Contribute
by Bod
on Oct 12, 2023 at 19:36

    Whilst attempting to test a previous module, pryrt very helpfully introduced me to GitHub Continuous Integration.

    I tried using this when I released WWW::Crawl and got lots of test configurations to pass, but others failed. When the tests ran again, different configurations passed and different configurations failed!

    From this test run it seems much of the problem is from the $VERSION string. But this inconsistency is not reflected in the CPAN Testers results.

    Is this an anomaly of GitHub Continuous Integration or have I got something wrong in the per-ci.yml file?

Storable for user preferences in Seekers of Perl Wisdom
7 direct replies — Read more / Contribute
by Bod
on Sep 30, 2023 at 14:17

    I need to store user preferences...

    Currently, there are only two user preferences and these are stored as fields in the User table of the database. However, the number of preferences is going to increase. I guess there will be around 20 or so eventually. Experience suggests that most users won't change most of their preferences from the default setting. Therefore, I don't really want to add all the preferences to the User table when nearly all of them will be set to the default values.

    I could implement the preferences in the database with an EAV model. But I wondered if Perl's core Storable might be a better solution.

    I've not used Storable before so I'd appreciate the monastic wisdom about any issues I might face using Storable generally and it's suitability for this specific application...

Testing with Test::Mock::HTTP::Tiny in Seekers of Perl Wisdom
2 direct replies — Read more / Contribute
by Bod
on Sep 26, 2023 at 16:11

    I am writing some tests of a module that fetches a webpage using HTTP::Tiny->get

    To test it, I am trying to use Test::Mock::HTTP::Tiny but I've never tried to use a Test::Mock module before. It's been on my radar since kcott mentioned their existence many moons ago. Now I have the need for one...but the documentation is lacking (to put it mildly!)

    First I've run this code to get the mock data:

    use strict; use warnings; use HTTP::Tiny; use Test::Mock::HTTP::Tiny; my $http = HTTP::Tiny->new; my $resp = $http->get(''); open my $fh, '>', 'mock_html.dat'; print $fh Test::Mock::HTTP::Tiny->captured_data_dump; close $fh;
    Then I've renamed all the references to the domain (a real domain) to www.testing.crawl (a mock domain). I've done this because I don't want the tests going out to a live site as it will change over time invalidating the tests.

    My test file looks like this:

    use strict; use warnings; use Test::More; use Test::Mock::HTTP::Tiny; use WWW::Crawl; plan tests => 1; $/ = undef; open my $fh, '<', 't/mock_html.dat' or die "Can't open datafile"; my $replay = <$fh>; close $fh; die "Nothing to replay" unless $replay; Test::Mock::HTTP::Tiny->set_mocked_data($replay); my $crawl = WWW::Crawl->new( 'timestamp' => 'a', ); my @links = $crawl->crawl('https://www.testing.crawl', \&link); cmp_ok ( scalar @links, '==', 8, 'Correct link count'); sub link { diag ($_[0]); }
    The method $crawl->crawl uses HTTP::Tiny->get to get the web address.

    My expectation was that Test::Mock::HTTP::Tiny would replay the website to HTTP::Tiny but instead it gives the HTTP error 599 - Internal Exception

    Is this the right way to use Test::Mock objects or am I completely off track here?

    Corrected typo in title

    Corrected module in title!