Perl is shiny

Have fun with perl!

API with Mojolicious and Tie::File storage

use Mojolicious::Lite -signatures;
use Tie::File;

tie my @todos, 'Tie::File', 'todos'
    or die 'could not open storage';

# curl localhost:3000/list
get '/list' => sub ($c) {
    $c->render(json => \@todos);
};

# curl --request POST localhost:3000/add --data 'walk my dog'
post '/add' => sub ($c) {
    push @todos, $c->req->body;
    $c->rendered(204); # no content
};

app->start;

Automate Windows GUI - Win32::GuiTest

use File::Basename;
use Win32::GuiTest qw( WaitWindow FindWindowLike SetForegroundWindow SendKeys MenuSelect GetSystemMenu );

my $input_dir        = "C:\\Program Files\\Notepad++";
my $filename_to_open = "readme.txt";

# Open the given dir in windows explorer and wait for it to open (timeout - 5sec)
my $status_code = system("C:\\Windows\\explorer.exe", $input_dir);
WaitWindow(basename($input_dir), 5);

# Search for that file explorer window and bring it to front
my ($exp_window) = FindWindowLike(0, basename($input_dir));
SetForegroundWindow($exp_window);

# Keys to be pressed on keyboard in sequential order
foreach my $key ($filename_to_open, "{APP}", "N", "{ENTER}") {
    SendKeys($key);
}
WaitWindow(basename($filename_to_open), 5);

# Search for Notepad++ app window
my ($notepad_win) = FindWindowLike(0, $filename_to_open);
SetForegroundWindow($notepad_win);

# Close the Notepad++ window
MenuSelect("&Close", 0, GetSystemMenu($notepad_win, 0));
WaitWindow(basename($input_dir), 5);

# Close the file explorer window
SendKeys("^w");

Automate the web browser (e.g. Firefox)

use Firefox::Marionette();

my $firefox = Firefox::Marionette->new(visible => 1);
my $window  = $firefox->new_window(type => 'tab', focus => 1);
$firefox->switch_to_window($window);

# Return first element matching a class (search textbox)
my $e = $firefox->go('https://metacpan.org/')
                ->find_class('form-control home-search-input')

# Remove if there is something already filled there
$firefox->clear($e);

# Fill it with search element e.g. Mojolicious
$firefox->type($e, "Mojolicious");

# Find search button by the given id and click it
$firefox->find_class('btn search-btn')->click();

# Take screenshot of entire document
my $fh = $firefox->selfie()->filename;
print $fh->filename;
# /tmp/full_screenshot.png

# This will only take screenshot of the element specified
my $fh = $firefox->selfie($firefox->find_class('content search-results'));
print $fh->filename;
# /tmp/partial_screenshot.png

Clamping a value

use v5.36;

my ($min, $max) = (1,100);
my @inputs = (-10,10,200);

for my $i (@inputs) {
  my $value = clamp($i,$min,$max);
  say "$i set to $value to be within ($min,$max)";
}

sub clamp ($i,$min,$max) {
  return (sort { $a <=> $b } ($i,$min,$max))[1];
}

# -10 set to 1 to be within (1,100)
# 10 set to 10 to be within (1,100)
# 200 set to 100 to be within (1,100)

Data Visualization using Chart::Plotly - Line chart

use strict;
use warnings;

use Chart::Plotly 'show_plot';
use Chart::Plotly::Image 'save_image';
use Chart::Plotly::Plot;
use Chart::Plotly::Trace::Scatter;

my @domainAxis = ("2021-04-15", "2021-04-16", "2021-04-17", "2021-04-18");
my @rangeAxis  = (10, 3, 5, 9);

my $plot    = Chart::Plotly::Plot->new();
my $scatter = Chart::Plotly::Trace::Scatter->new(x => \@domainAxis, y => \@rangeAxis);
$plot->add_trace($scatter);

# Opens the plot in a browser locally
show_plot($plot);

# Save the generated image locally
save_image(
    file   => "lineChart.png",    # Referring to a local filesystem path
    plot   => $plot,
    width  => 1024,               # Sets the image width
    height => 768,                # Sets the image height
    engine => 'auto'
);

Easy interaction with CSV

use Text::CSV_XS qw( csv );

# Read whole file in memory
my $aoa = csv (in => "data.csv");  # as array of array
my $aoh = csv (in => "data.csv",
               headers => "auto"); # as array of hash

# Write array of arrays as csv file
csv (in => $aoa, out => "file.csv", sep_char=> ";");

# Only show lines where "code" is odd
csv (in => "data.csv", filter => { code => sub { $_ % 2 }});

Scrape a random quote

use Mojo::UserAgent;

my $agent = Mojo::UserAgent->new;

my $tx = $agent->get("http://www.quotationspage.com/random.php");

my $quote  = $tx->res->dom->at("dt");
my $author = $quote->next->at("b");

print join " &mdash; ", ($quote->all_text, $author->all_text);
# Perl is shiny &mdash; Perl Hacker

Objects with Moo

package Point;

use Moo;

has 'x' => is => 'rw';
has 'y' => is => 'rw';

sub describe {
  my ($self) = @_;

  printf "A point at (%d,%d)", $self->x, $self->y;
}

Point->new( x => 4, y => 2 )->describe;
# A point at (4,2)

Objects with Object::Pad

use Object::Pad 0.41;

class Point {
   has $x :param = 0;
   has $y :param = 0;
   has $z = 0;

   method move ($dX=0, $dY=0, $dZ=0) {
      $x += $dX;
      $y += $dY;
      $z += $dZ;
      return $self;
   }

   method describe {
      print "A point at ($x, $y, $z)\n";
   }
}

Point->new(x => 5, y => 10)->move(1,1)->describe;
# A point at (6, 11, 0)

Proper Try/Catch

use Feature::Compat::Try;
 
sub foo {
   try {
      attempt_a_thing();
      return "success";
   }
   catch ($e) {
      warn "It failed - $e";
      return "failure";
   }
}