Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Bod

by Bod (Vicar)
on Nov 15, 2020 at 00:48 UTC ( #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


Find me on LinkedIn, or on Twitter


CPAN Releases

Business::Stripe::WebCheckout
Business::Stripe::Subs‎crip‎tion
Business::Stripe::Webhook

AI::Embedding


Nodes I find helpful

Modules

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


Posts by Bod
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('http://www.way-finder.uk/'); 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 www.way-finder.uk (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?

    EDIT:
    Corrected typo in title

    ANOTHER EDIT:
    Corrected module in title!

Finding when a feature or keyword was introduced in Seekers of Perl Wisdom
5 direct replies — Read more / Contribute
by Bod
on Sep 26, 2023 at 13:12

    Is there an easy way to find out when a feature or keyword was introduced to Perl?
    In other words, which version introduced it...

    I have a module that uses pos, a keyword I infrequently use. How can I find out when this, or any other keyword, was introduced so I can set the minimum required Perl version?

    Obviously I could go through each delta until I find it but that seems rather tedious...

chomp and regexp in Seekers of Perl Wisdom
2 direct replies — Read more / Contribute
by Bod
on Sep 14, 2023 at 10:38

    I am enforcing some rules are CRM tags and the regexps are pushing my limits. So, a follow up to a little question over at Re^3: regex in REPLACEMENT in s///

    Part A

    I have never got chomp to work so I avoid it...

    my $tag = 'test text '; chomp $tag; print $tag . '#'; > test text #

    I understood it to equivalent to s/ +$//; when used as above with no new lines.

    Part B

    The tags should be lowercase and exclude most punctuation. Extraneous punctuation removed and uppercase characters converted to lowercase. Here is what I have tried

    $tag = lc $tag; $tag =~ s/[^az09 _\-\+\.]//g;
    I expected the regexp to substitute anything that is not ^ in the character class [] with an empty string. But it seems to strip out anything that is not an 'a' character or a space.

    How should I go about properly working out how to construct a regexp to do what I want?

Stopping tests in Seekers of Perl Wisdom
3 direct replies — Read more / Contribute
by Bod
on Sep 13, 2023 at 06:51

    Is there a way to stop the CPAN Testing process?
    And if there is, should I?

    Last evening I uploaded a new version of Image::Square with new tests using PNG images for input and output instead of JPEG images. This followed the advice I got on Testing image output

    The first two test results came in just before I settled down to sleep and they were both PASS so I went to sleep content...only to check this morning and find lots of FAILs 😕

    This morning I uploaded a new version using the native GD image format and using cmp_ok instead of ok from hippo's Basic Testing Tutorial

    So now that this latest version is uploaded, is there a way to stop CPAN Testers from wasting their precious resources on a module version that will fail at least some of the time? Does it stop automatically when a new version is uploaded?

    Edit:
    Changed link to point to GitHub repo and not the CPAN Tester results.

Testing image output in Seekers of Perl Wisdom
2 direct replies — Read more / Contribute
by Bod
on Sep 07, 2023 at 06:19

    I've written Image::Square to make square images...

    One of the tests I've carried out is to visually check that the new square image is taken from the correct part of the original image.

    How can I convert that visual test into code?

    Should I manually verify the image it is supposed to create, then take a hash of that image and compare the hash from the same process during testing? If I do it this way, I will need to use a hashing module and I'm reluctant to create a dependency that is only used in the tests. Perhaps I need to skip the test if the hashing module isn't installed.

    If I do the comparison using a hash, will it work cross-platform or can I expect tests to fail on some OS's?

A small step...and a giant leap for Bod in Meditations
2 direct replies — Read more / Contribute
by Bod
on Sep 07, 2023 at 06:05

    My 1000th post!

    It's a little under 3 years since I created an account here on Perl Monks. For many years, I'd occasionally visited The Monastery thanks to Google leading me here when I asked a Perl-related question - which was quite frequently. But, back in November 2020, I had a few new projects going on and thought I needed to "raise my game". I had no concept of what that actually meant.

    My expectation was that I'd learn a few new coding styles, be a bit quicker and, perhaps, a bit clearer.

    What has actually happened, and continues to happen, is that my whole approach to writing code has changed...drastically!

    Allow me to illustrate by way of an example...

    Just this week I was writing some code for the admin part of my partner's website Pawsies. We need to be able to upload pictures of dogs that we look after, and it's helpful if those pictures are square so they display consistently.

    The whole website uses Template - something I discovered in The Monastery. The web scripts are in their own directory and not mixed up with the other site files, again a learning from The Monastery. The upshot is sites that are easier to navigate, easier to link to as everything is not in the cgi-bin and easier to maintain.

    However, it goes much further than that.

    In the past, if I wanted square images, I would have hard-coded the logic to produce them into the script that needed them. But this week, instead I wrote a module to do only that operation. It is where my thought process started, it was not an afterthought. The design started with deciding exactly what it was supposed to do and by jotting down how I would know if it was successful. The basis of a test!

    I then looked to see if there were any extra generalisations that could be made to make it more useful to other people or when I reuse it elsewhere. So, a resizing parameter was added to change the size of the square image and a position parameter was added to determine where abouts the square is taken from in the original image.

    Only then was the code written followed by the tests...

    Once the tests all ran fine, it was bundled up and uploaded to CPAN for all to use. Currently as a dev release so I get some test results before the production release. It's all looking good...

    Before joining The Monastery this would have been a bit of messy, but functional code locked away somewhere in a difficult-to-maintain script. I considered CPAN modules to be for other, superior "proper" coders...not for me. Now I look for the best way to do it for my needs now, my needs in future when I come to maintain the code or need similar functionality and for the needs of the wider Perl community as The Monastery has shown me that I have something to contribute as well as to learn.

    Watch out for a testing question coming soon - one of the tests for Image::Square required visually inspecting the output image and I don't know how to convert that into a usable test...see, lots more to learn and that's something I fully embrace!

    Thank you to everyone who has helped, inspired, questioned and critised me over the last 1000 post - it really is appreciated 👍

Last Modified for Template file in Seekers of Perl Wisdom
1 direct reply — Read more / Contribute
by Bod
on Aug 29, 2023 at 16:27

    Is there a built-in method to find when a Template file was last modified? I want something similar to JavaScript's document.lastModified which always seem to return the current timestamp for dynamically generated pages.

    For more completeness in case I'm missing something obvious...

    I have lots of web pages on a website. They share a common head.tt and foot.tt files. So (typically) 3 Template files and called for each HTTP request: head, body and foot. 'body' will change for each page. I want to be able to put a custom <meta modified="...."> at the head of the page that can be read by a sitemap generator and along with a custom priority indicator. I'd prefer not to have to update the modified time each time a body template file is changed.

    I looked at using the Last-modified HTTP header but that is missing for dynamically generated pages.

use lib "." in Seekers of Perl Wisdom
6 direct replies — Read more / Contribute
by Bod
on Aug 12, 2023 at 07:49

    I've come across some unexpected behaviour that I thought was obvious but it seems not so your input would be welcome...

    On a webserver I have a maintenance script that runs off CRON every morning. The filesystem looks like this:

    /home/username/website/prod/lib <- modules /home/username/website/prod/template <- templates /home/username/website/prod/www <- HTTP root
    There is also a test environment as well as prod
    To set @INC correctly, this line is at the top of every script that needs to run in CGI context
    use lib "$ENV{'DOCUMENT_ROOT'}/../lib";
    But, when run by CRON, the maintenance script doesn't get passed $ENV{'DOCUMENT_ROOT'}.

    However, the maintenance script is located at:

    /home/username/website/prod/lib/maintain.pl
    It needs to
    use Site::Utils;
    where the module is located at
    /home/username/website/prod/lib/Site/Utils.pm

    I thought I could simply use lib "."; to add the current directory to @INC or even leave it out altogether and Perl would find the module by searching the filepath relative to the running script.

    But both these approaches result in Perl reporting that it cannot find the module...

    What am I overlooking here?

Can you explain the difference with print? in Seekers of Perl Wisdom
5 direct replies — Read more / Contribute
by Bod
on Aug 04, 2023 at 16:30

    I've come across some unexpected behaviour and I am struggling to understand it...can you help?

    perl -e "print (localtime)[6];" syntax error at -e line 1, near ")[" Execution of -e aborted due to compilation errors.

    ...but...

    perl -e "my $test = (localtime)[6];print $test" 5

    So I thought it was a problem of print not converting the array to a scalar so I tried...

    perl -e "print scalar (localtime)[6]" syntax error at -e line 1, near ")[" Execution of -e aborted due to compilation errors.

    What is the difference here with using an intermediate variable that doesn't happen when using print directly?

Test failing during CPAN Testing in Seekers of Perl Wisdom
4 direct replies — Read more / Contribute
by Bod
on Jun 18, 2023 at 16:53

    I've released a new version of Business::Stripe::Webhook with a modified constructor following the discussion about STDIN typeglob

    At the same time I have added some extra, more thorough tests. All the tests pass as expected here locally but now it has reached CPAN Testers, I have a failure. I can usually work out why something is failing from the diagnostic information...but I cannot see the problem in this case. Can you help please?

    This is the CPAN Tester Report and this is the test file:

    #!perl use 5.010; use strict; use warnings; use Test::More; use Business::Stripe::Webhook; #plan tests => 3; my $count = 0; print "\n"; my $payload; read(DATA, $payload, 10000); my $webhook_fail = Business::Stripe::Webhook->new( signing_secret => 'whsec_...', 'payload' => $payload, 'invoice-paid' => \&pay_invoice, ); $webhook_fail->process(); ok( !$webhook_fail->success, "Signature error" ); my $signing_secret = 'whsec_12345ABCDEFGHIJKLM'; $ENV{'HTTP_STRIPE_SIGNATURE'} = 't=ABCDEFGHIJ,v1=917fd62f6828ceb0509ae +bd9ee94e4c455887b6c174ef94037e089265c8c575c'; my $webhook_pass = Business::Stripe::Webhook->new( signing_secret => $signing_secret, 'payload' => $payload, 'invoice-paid' => \&pay_invoice, ); $webhook_pass->process(); ok( $webhook_pass->success, "Signature pass" ); sub pay_invoice { is( $_[0]->{'object'}, 'event', "pay.invoice handled - " . ++$coun +t ); } done_testing($count + 2); __DATA__ { "id": "evt_1NFK32EfkkexSbWLZb6LoEap", "object": "event", "api_version": "2020-08-27", "data": { ... bigger JSON object ... } }
    Any help (or general help with improving tests) would be very welcome...

    edited - to correct typo in module link

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (3)
As of 2023-09-29 13:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?