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").
Around a year ago, we were treated to a gripping duel,
in which the redoubtable talexb pipped PM veteran jdporter by just three
Experience Points, and so scale the highly coveted Chancellor plateau first.
With the delightful planetscape still inactive, I'm pleased to report that
this original 100 metre sprint to Chancellor has transmogrified
into an exciting three-way 1500 metre race to join the
Top Fifty Perl Monks of All Time:
after so many years I still lack the understanding of basics.
I always thought of sort as if it should check every element of a list against any other element: this is not true. Infact rereading the sort docs, the very bottom line, I read: is implemented via the mergesort algorithm
Mergesort is based on old Latin motto divide et impera and because of this not every combination is take in count while sorting. It is optimized to compute only the lowest number of checks.
Let clean the field: sort is not like map infact:
perl -we "sort @ARGV" 1 2 gives Useless use of sort in void context at -e line 1
perl -we "$x = sort @ARGV" 1 2 gives Useless use of sort in scalar context at -e line 1
So must to be used only in list context, it seems wise unless if you want to hack it: in my Re: Perl Weekly Challenge 206 -- oneliner I used sort to push results in @r but, with my usual try&error, I found I need to use as return value for sort the subtraction $a-$b infact returning 0 failed the test with 10:10 09:30 09:00 09:55 as arguments. Using 1 as return value failed with 01:01 00:50 00:57 and returning -1 failed the test with 10:10 09:30 09:00 09:55
Why?
In the docs I read also subroutine that returns an integer less than, equal to, or greater than 0 so I tried to see what happens forcing the returned value:
Hello fellow Perlers, I'm looking to take over the MIDI module maintainership on CPAN. Issues on the tracker haven't been responded to in almost a decade, even some simple patches that have been provided, I've sent an email to the maintainer suggesting some modifications, and nothing has gained a response. I'm not sure if Darrell Conklin, the maintainer, is still active at all. If anybody knows Darrell or, better yet, is Darrell, I'd be happy to get in touch with him, so I'm posting publicly here for exposure.
While i agree that Perl would benefit from a modern OO system, i think this new system shouldn't give up any of the flexibilities ye olde 'bless' provides.
Before i go into details, i must admit that i'm not a huge fan of the "attributes" stuff that most OO system use. Or at least not to the extend they are used anyway. I've seen code that uses like 4-5 attributes for a single class and just as much for a variable. I call this C++ line noise. Yes, it makes the code more concise(1), but when you have to spend a minute per line of code just to understand just the implication of these flags, they are not what i call helpful. Going forward, the new 'class' system will have to be very carefully design to avoid making a mess with attribute feature creep.
I also understand that 'class' is still in the early stages, so i can only look on what has been designed so far. My main questionmarks are:
Abort object creation?
Constructor not proper functions?
Deciding when to call parent constructor?
Let's look at those in detail:
Abort object creation?
One of the nice things about 'bless' is that constructors are just functions with return values. This allows the constructor a lot of flexibility.
One of those is to not construct an object under some circumstances. Something like this:
package Foo::Bar::UrlHandler;
sub new($proto, %config) {
my $class = ref($proto) || $proto;
if(!defined($config{url})) {
# No URL given, don't know what to do next
return;
}
my $self = bless \%config, $class;
return $self;
}
From what i understand, a 'class' is pretty much required to be created, no matter if that makes sense with the given parameters. This will probably make error handling/detection in the caller more complicated. And no, eval() is seldomly the solution to such problems but many times the cause of them.
Constructor not proper functions?
From the design, it seems you don't write the constructor as a proper function, you can only 'ADJUST()' what it does. This has a few implications that make it much less flexible than bless():
No "named" constructor
Modules like DBI (among others) make use of the fact that bless() can run in arbitrarily names constructors. For DBI, this is connect(). In my opinion, this makes it much clearer to the user of this module that constructing an new instance is not only an in-memory operation, it also connects to the server.
No option for multiple constructors
In my projects, i have a few modules that provide multiple constructor. For example, there might be a classic new(list-of-parameters), but also a newFromConfig(filename) that takes a filename to a configuration file. This makes especially sense when using sub signatures. Another example would be, say, a file parser that has a newFromFile() and newFromUrl() method.
Yes, you can achieve this by subclassing with the new 'class' OO, but that can make the code harder to maintain, especially if only the initialization differs.
No simple "factories"
I sometimes use the concept of "factories", e.g. modules that decide on given parameters which object to return. In keeping with the example of the UrlHandler above, something like this isn't too uncommon:
package Foo::Bar::UrlHandler;
sub new($proto, %config) {
my $class = ref($proto) || $proto;
if(!defined($config{url})) {
# No URL given, don't know what to do next
return;
}
if($config{url} =~ /^http\:/) {
return Foo::Bar::UrlHandler::HTTP->new();
} elsif($config{url} =~ /^file\:/) {
return Foo::Bar::UrlHandler::FILE->new();
}
# Invalid URL?
return;
}
The new 'class' OO is a long overdue project and i thank the developers for their hard work. But at this early stage, it seems to be only a copy of other programming languages, without the flexibility Perl can (and currently does) provide when it comes to object orientation.
I'm using Perl (and ignore the Moo* stuff(3)) because i can shape the language to fit the problem. If we go the way in which we have to shape the problem to fit the language, we all might as well switch to there-is-only-one-way-to-do-it languages like C++, Java or TypesScript.
Yes, 'class' has the potential to make object oriented code easier to read and write, and i'm certainly all for that. We just need to make sure that it turns out TIMTOWTDI enough not to feature the same headaches as Java or C++. I can only talk about this from one own, small personal viewpoint, but because of (not "despite of"!) the flexibility of the old bless() OO and the typelessnes of Perl variables, in the last two decades i was able to single-handedly write a big web framework and implement multiple commercial systems in Perl.
Footnotes:
(1) just as $_ does. Which makes following code flow (and debugging it) a huge pain. Use $_ is banned in my projects.
(2) Sometime you override, sometime you enhance, sometimes the parameters to new() tell you what to do
(3) Combining the rigidity of C++ with the speed of Windows Vista somehow never appealed to me.
I was too lazy to act though until further provoked by
a new version of the get_properties function
that updated a non-const global variable.
After changing its interface to avoid the need to modify the dreaded global,
I felt obliged to write some unit tests for my new interface,
in both Perl and C++, as a fun learning exercise.
This meditation describes that endeavour.
Create the Test Files
I started by writing a helper script create-test-files.pl to create two simple LLiL-format
(each line must match: ^[a-z]+\t\d+$) test files to be read by the unit tests:
# create-test-files.pl
use strict;
use warnings;
sub build_file {
my ( $file, $data ) = @_;
open( my $fh, '>', $file ) or die "open '$file': $!";
print {$fh} $data or die "write '$file': $!";
}
my $tt_1_data = <<"LLiL";
camel\t50
dromedary\t70
pearl\t42
LLiL
my $tt_2_data = <<"LLiL";
dromedary\t3
kibitzer\t1000
dromedary\t2
camel\t19
dromedary\t1
LLiL
my %test_files = (
'llil-1.txt' => $tt_1_data,
'llil-2.txt' => $tt_2_data
);
for my $fname (sort keys %test_files) {
print STDERR "Create test file '$fname'...";
unlink($fname);
build_file( $fname, $test_files{$fname} );
print STDERR "done.\n";
}
After running this script, you should have two short LLiL-format text files: llil-1.txt and llil-2.txt.
These files will be used by the unit tests.
If you reply with unit tests written in another language, please use these two files in your unit tests.
LLiL.pm
package LLiL;
use strict;
use warnings;
# Read a LLiL-format file.
# Return the number of lines in the file or -1 if the file could not b
+e opened
# Update $hash_ret, a reference to a hash of properties
sub get_properties {
my $fname = shift; # in: a LLiL-format filename
my $hash_ret = shift; # inout: a reference to a hash of properti
+es
my $cnt = 0;
open( my $fh, '<', $fname ) or return -1;
while (<$fh>) {
++$cnt;
chomp;
my ($word, $count) = split /\t/;
$hash_ret->{$word} += $count;
}
close($fh);
return $cnt;
}
# Note: Some extra validation that could be done in get_properties() a
+bove
# ( not done because, to allow the code to run as fast as possib
+le,
# get_properties assumes the input data adheres to the LLiL sp
+ec,
# that is, each line matches ^[a-z]+\t\d+$ ):
# s/^\s+//; s/\s+$//; # remove leading and trailing whitesp
+ace
# next unless length; # ignore empty lines
# $word =~ /^[a-z]+$/ or die "error: invalid word '$_' (must contai
+n [a-z] only)";
# $count =~ /^\d+$/ or die "error: invalid count '$_' (must contai
+n [0-9] only)";
1;
# llil.t
# Simple unit test of get_properties() function in LLiL.pm.
# Normal run of this test : prove -v -I . llil.t
# Can also run with : perl -I . llil.t
# Note: before running this test, create the test files
# llil-1.txt and llil-2.txt by running: perl create-test-files.pl
use strict;
use warnings;
use LLiL;
use Test::More;
my $ntests = 5;
plan tests => $ntests;
my $expected_href = {
'camel' => 69,
'dromedary' => 76,
'kibitzer' => 1000,
'pearl' => 42
};
my %hash_ret;
my $href = \%hash_ret;
# Error tests
{
my $n = LLiL::get_properties( 'non-existent-file', $href );
cmp_ok( $n, '==', -1, "get_properties non existent file return valu
+e" );
}
# Normal tests
{
my $n = LLiL::get_properties( 'llil-1.txt', $href );
cmp_ok( $n, '==', 3, "get_properties file 1 return value" );
$n = LLiL::get_properties( 'llil-2.txt', $href );
cmp_ok( $n, '==', 5, "get_properties file 2 return value" );
cmp_ok( scalar(%{$href}), '==', 4, "number of items in hash" );
is_deeply( $href, $expected_href, "hash content" );
}
The output from running the prove command above is:
> prove -v -I . llil.t
llil.t ..
1..5
ok 1 - get_properties non existent file return value
ok 2 - get_properties file 1 return value
ok 3 - get_properties file 2 return value
ok 4 - number of items in hash
ok 5 - hash content
ok
All tests successful.
Files=1, Tests=5, 0 wallclock secs ( 0.00 usr + 0.00 sys = 0.00 CPU
+)
Result: PASS
Note that this only unit tests that the hash contains the correct keys and values.
The sorting/ordering of the values in the hash is performed in a separate later step.
Please feel free to respond with improved Perl versions of llil.t or
with a version of this simple unit test in another language.
I am keen of collecting the computing polyglots. Honestly, they are bilingual - the main script with the small portion of the windows batch script as the second supporting language. And I like to call them hybrids.
I do it just for fun. And I know that some languages are hybridizing very well. Some of them are resistant to hybridization. And some of them that can be hybridized result to awful stuff. Such kind of polyglots I call chimeras.
Couple days ago I began thinking about how to embed a raku script within a batch file in the same way how it was done for perl with pl2bat.bat. I am not so familiar with raku and my first attempt doesn't look quite elegant. But it's working version and seems following the raku syntax and strictness.
I kindly ask fellows to help to improve it and make it better if it's possible.
@rem = q:to/use strict;/;
@echo off
raku -e "('no strict;' ~ (slurp q<%~f0>)).EVAL" %*
goto :EOF
use strict;
say "Hello! I am Raku.";
say @*ARGS;
Below are more suggestions from another people. The main problem with their versions that they are not pure hybrids and I classify them standing closer to chimeras because they use the raku syntax that is considered as the non existent external command and throws warnings by default. And it's a bit risky because it has non-zero probability to have such commands and execute them.
Both use the strange construction @@. What does it mean? I tried to google the answer but with no any success. In terms of the raku syntax I guess it looks like a nameless array of array. But I am not 100% sure.
The version using heredoc
@@; $_ = q:to/@@; goto :EOF/; # 2>nul
@@; raku "%~f0" %*
@@; goto :EOF
say "Hello! I am Raku.";
say @*ARGS;
Welcome to the first (?) Sunday Perl Challenge Trip! The challenge will last one week and then points will be calculated. I dont hope someone is mad enough to accept the challange, but I think is more fun this way, instead of posting my code alone. But who knows..
Assignement
We need to implement nested autocompletion while reading user input: the command A lead to options 1 2 3 and command B to 4 5 etc..
Simple? No: a dread :) Let specify it better. Given the following data:
# dummy items to play with
my @animals = (qw( cow camel dog cat ));
my @foods = (qw( fish pasture meat ));
my @places = (qw( wood sea desert ));
# commands
my $commands = {
select => {
completion_list => \@animals,
commands => {
give => {
completion_list => \@foods,
},
take_to => {
completion_list => \@places,
},
},
},
kill => {
completion_list => \@animals,
}
};
the first choices are only select and kill and if you choose select (entering it or using selTAB to autocomplete it) then autocomplete should permit only one item from @animals Once you entered (directly or autocompleting it) an animal then only the two commands give and take_to should be available. And so on.
I used hardcoded keywords commands and completion_list to drive my solution: feel free to use them or not or to change them.
An example session:
Press TAB for autocompletion or available options
autocompletion nested>("kill", "select")
+ # 'TAB' on empty input shows available commands
autocompletion nested>select c("camel", "cat", "cow")
+ # 'cTAB' shows animals but not 'dog'
autocompletion nested>select ca("camel", "cat")
+ # 'caTAB' shows two animals starting with 'ca'
autocompletion nested>select camel ("give", "take_to")
+ # I press 'mTAB' thae autocomplete in 'camel'
+ # 'TAB' again for next level commands: give and take_to
autocompletion nested>select camel take_to ("desert", "sea", "wood")
+ # 'tTAB' and 'TAB' again
autocompletion nested>select camel take_to desert
+ # 'desTAB' leads to 'desert'
+ # ENTER 1
autocompletion nested>
+ # ENTER 2 exits the user input cycle
CHOOSEN: select camel take_to desert
+ # finally we print the resulting path
-20 for reading my solution (declare it in the answer: it includes Hint1 and Hint2) and use it as starting point :)
Extra points
+40 points for not using Term::ReadLine family modules :)
+20 points for a correct use of BACKSPACE to have editable lines: you change your mind and you go back through the line
+10 points if you are able to avoid the double ENTER I need to end the line building when we reached the end of the datastructure
+100 points if you publish it as CPAN module in this week
my ethernal gratidute if I understand your code :)
My solution
My code is ugly enough, but it works. It is full of comments to help you understing what's going on. Some unused code is commented to show possible improvemnts. It has some debug options: 0 (default), 1, 2 that ruins a bit the output but are useful to see the flow.
Avoid to comment my code before the challange ends. Here we are:
This code locates the variable on the heap, and replaces it's value.
it's curious that print uses syscall SYS_write but write is not triggering that syscall.
I'm asking this as a meditation, because I don't expect any Perl (or other) code for that.
Questions:
Is it possible to filter speech frequencies in a video with significant accuracy to identify the passages were people talk?
Can the resulting pattern be used to synchronize a subtitle file, to match the gaps?
I'm looking for a low tech solution offering a handful of plausible adjustments to chose, not a speech recognition bazooka (like YT's auto-subtitles)
Background:
I'm often downloading foreign language movies and like to see them with original voice and subtitles to practice and learn vocabulary, but am often obliged to download and adjust the subtitles timing, because
they are shifted, because of trailers or of "what happened last time" intros
they are stretched, because of different frame rates
they need readjustment in the middle because scenes were cut out
there are already Perl modules to fix the first two cases for .srt files.
That is, if the parameters are known. But finding them can be tricky.
FWIW: VLC offers an option for such synchros, but tends to freeze for a minute if the shift is in the area of 20 secs. No fun when trying out the best settings.
ChatGPT:
This regular expression is used to match a pattern that contains multiple lines of text. The regular expression is designed to match one or more occurrences of a sequence of characters that can include any characters except a newline (represented by \n) or an at sign (@), or an at sign that is immediately followed by one or more other characters (also represented by @) and then another at sign.
The outermost parentheses ( ) define a capturing group that captures the matched text, this group will be repeated one or more times + .
The first non-capturing group (?: ) is used to match any characters except a newline or an at sign. The second non-capturing group (?:@[^@]*@) matches an at sign, followed by zero or more characters that are not an at sign, followed by another at sign.
The ? after the first non-capturing group means that the preceding element is optional and can match zero or one time.
The ? after the second non-capturing group means that the preceding element can match zero or one time, and the \n means that it will match a new line.
This regular expression should be used in conjunction with other tests or validation to ensure that it only matches valid input. It is not a complete solution to validate emails or other texts, just a pattern matching.
Dmitri: Can you optimize it?
ChatGPT:
Yes, it can be optimized for performance. Here's one possible way:
The first change I made is that instead of using \n? after the second non-capturing group, I added [^\n]*\n? which means that the pattern matches zero or more characters that are not a newline, followed by an optional newline. This change allows the regular expression engine to stop looking for a newline as soon as it encounters a character that is not a newline.
The second change I made is that I used [^\n@] instead of [^\n] before the @ . This change allows the regular expression engine to stop looking for an at sign as soon as it encounters a character that is not an at sign.
These changes should improve the performance of the regular expression by reducing the number of characters that the regular expression engine needs to examine for each match.
However, it's worth noting that regular expressions can be very complex and it's hard to give a definitive answer without knowing more about the specific use case and the input data. You can also try different variations and test them on your specific input to see which one performs better.
I think this is pretty good! (The regular expression I picked at random from this old node.)
Every few years I try to update this post so that people are aware.
Question is how to send email through GMail, or otherwise a Google Account.
It's still easy, but different. The instructions can be found in the above link through your own research. It can be done.
I want to keep this knowledge alive. When I have difficulty and find a solution, I want others to know how I overcame it. We should all be able to send mail or text messages through our Google accounts.
use warnings;
use strict;
use Net::SMTP;
my $smtp = Net::SMTP->new(
'smtp.gmail.com',
Hello => 'local.example.com',
Timeout => 30,
Debug => 1,
SSL => 1,
Port => 465
);
# Password here is an app password. Need to enable 2FA on Google
# account to generate one
$smtp->auth('steve.bertrand@gmail.com', '*app_password*') or die;
$smtp->mail('steve.bertrand@gmail.com');
$smtp->to('steve.bertrand@gmail.com');
$smtp->data();
$smtp->datasend("hey!\n");
$smtp->quit();
After updating git-portable I do have a Perl 5.36 operating on Windows.
Which is a bit surprising given all the struggle Strawberry is going thru.
I remember there might be "restrictions" with this since it's optimized to work inside bash and expects *nix path conventions. But I'm wondering - well meditating - if this might not be a viable substitution for Strawberry.
I also suppose that the c-compiler/make combo might cause problems when installing further modules ... (?)
But portable means one could keep an unaltered git version in one directory and adjust another in a second directory...
Snippets of code should be wrapped in
<code> tags not<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).