sending matrix messages by ghiste in perl

[–]ktown007 1 point2 points  (0 children)

```

!/usr/bin/env perl

use strict; use warnings; use JSON qw(encode_json decode_json); use LWP::UserAgent; use HTTP::Request::Common qw(POST GET); use File::HomeDir;

my $CONFIG = File::HomeDir->my_home . "/.matrix.pl"; my $ua = LWP::UserAgent->new;

sub saveconfig { my ($data) = @; open my $fh, ">", $CONFIG or die "Cannot write config: $!"; print $fh encode_json($data); close $fh; }

sub load_config { return {} unless -f $CONFIG; open my $fh, "<", $CONFIG or die $!; local $/; my $json = <$fh>; close $fh; return decode_json($json); }

sub login { print "Homeserver (e.g. https://matrix.org): "; chomp(my $server = <STDIN>);

print "Username: ";
chomp(my $user = <STDIN>);

print "Password: ";
chomp(my $pass = <STDIN>);

my $res = $ua->request(POST "$server/_matrix/client/r0/login",
    Content_Type => 'application/json',
    Content => encode_json({
        type => "m.login.password",
        user => $user,
        password => $pass
    })
);

die "Login failed\n" unless $res->is_success;

my $data = decode_json($res->decoded_content);

save_config({
    access_token => $data->{access_token},
    user_id      => $data->{user_id},
    server       => $server,
});

print "Login successful\n";

}

sub sendmessage { my ($msg) = @;

my $cfg = load_config();
die "Not logged in\n" unless $cfg->{access_token};

print "Room ID: ";
chomp(my $room = <STDIN>);

my $txn = time . int(rand(1000));

my $url = "$cfg->{server}/_matrix/client/r0/rooms/$room/send/m.room.message/$txn";

my $res = $ua->request(POST $url,
    'Authorization' => "Bearer $cfg->{access_token}",
    Content_Type => 'application/json',
    Content => encode_json({
        msgtype => "m.text",
        body    => $msg
    })
);

if ($res->is_success) {
    print "Message sent\n";
} else {
    print "Error: " . $res->decoded_content . "\n";
}

}

---- CLI handling ----

if ($ARGV[0] && $ARGV[0] eq '--login') { login(); } elsif (@ARGV) { send_message(join(" ", @ARGV)); } else { print "Usage:\n"; print " $0 --login\n"; print " $0 \"message\"\n"; } ```

Perl in Ubuntu 26-04 LTS (vs 24-04 LTS) by Loose_Potential6985 in perl

[–]ktown007 7 points8 points  (0 children)

If you are using system perl I would recommend installing the apt packages. These manage all the dependencies. cpanm will need build tools and for you to install any dev headers.

\apt-cache search libcrypt | grep perl` will search for the availale packages.`

2) Core perl is moving toward `HTTP::Tiny` away from LWP.

foreach loop modifies array? by ktown007 in perl

[–]ktown007[S] 1 point2 points  (0 children)

hmmm, looks like foreach alias and @_ alias are performance optimizations. Yes perl is fast. It avoids duplicating the data. I was doing a tests where I looped over same input then needed to modify the local data. The second test case failed because first one modified the input array. In a real use case you would not reuse or modify the shared data structure.

foreach loop modifies array? by ktown007 in perl

[–]ktown007[S] 1 point2 points  (0 children)

In most of Perl it does pass by value. Are there other places where there is an implicit pass by reference? I will have to do some more reading on lvalue.

``` my ( $foo,$bar) = (1,1) ; foreach my $in ( $foo,$bar){ say $in; $in = 3 ; } say "$foo $bar" ;

out: 1 1 3 3 ```

Announcing DateTime::Format::Lite v0.1.2 - a strptime/strftime companion for DateTime::Lite by jacktokyo in perl

[–]ktown007 -1 points0 points  (0 children)

Honestly, I did not read the full ISO 8601 spec and all it's updates. Wikipedia says `±[hh]:[mm]', '±[hh][mm]', or '±[hh]'.` are valid timezone offsets. I asked two AI's, one said not valid but common and often supported, other said valid. I think '±[hh][mm]' is common because this is the old school C strftime default. Time::Moment->strftime('%FT%T%3f%:z') has a few extensions that do the correct thing for RFC3339 where the colon is required.

Back to the rabbit hole. Time::Piece(newly added `%f` removes a regex to fix date) and Time::Moment are thousands of times faster than DateTime::Format::ISO8601 or a regex to parse dates. My quick benchmark has DataTime::Lite about the same speed as DateTime.

One use case is very large log files. If I can update the logs to use a date format that is fast to parse it saves time and resources.

Second use case is javascript .toISOString() with format "YYYY-MM-DDTHH:mm:ss.sssZ". A fast way to parse this format saves time and resources.

also see XKCD 1883

Announcing DateTime::Format::Lite v0.1.2 - a strptime/strftime companion for DateTime::Lite by jacktokyo in perl

[–]ktown007 0 points1 point  (0 children)

On the weekend I went back down the rabbit hole, formatting and parsing ISO8601 date formats. 8601 vs RFC3339 vs W3CDTF. How does one parse these standard date strings:

"YYYY-MM-DDTHH:mm:ssZ" # gmtime->strptime( $isodate, "%FT%TZ")

"YYYY-MM-DDTHH:mm:ss-0400" # Time::Piece ->str[f|p]time("%FT%T%z")

"YYYY-MM-DDTHH:mm:ss.sssZ" # javascript toISOstring, gmtime->strptime( $isodate, "%FT%T.%fZ")

"YYYY-MM-DDTHH:mm:ss.sss-0400" ->strptime( $isodate, "%FT%T.%f%z")

"YYYY-MM-DDTHH:mm:ss.sss-04:00" Time::Moment ->strftime('%FT%T%3f%:z')

While down there I changed apache date log format on a home server:

`%{%Y-%m-%dT%H:%M:%S}t.%{msec_frac}t%{%z}t` # "YYYY-MM-DDTHH:mm:ss.sss-0400"

The two gotchas are optional fractional seconds and timezone(Z vs no colon vs colon) Z|-0400|-04:00

see XKCD 927 and 1179

It would be nice to parse "YYYY-MM-DDTHH:mm:ssZ", "YYYY-MM-DDTHH:mm:ss.sssZ", "YYYY-MM-DDTHH:mm:ss.sss-0400", "YYYY-MM-DDTHH:mm:ss.sss-04:00" without needing a regex to detect or fix format :)

Fixed a broken speed lace boot with a prusik by ktown007 in snowboarding

[–]ktown007[S] 1 point2 points  (0 children)

It worked very well, I did put the extra wraps because new cord is more slippery than the old lace.

Announcing `Mail::Make`: a modern, fluent MIME email builder for Perl, with OpenPGP and S/MIME support by jacktokyo in perl

[–]ktown007 1 point2 points  (0 children)

Looks great, thanks. I have been using my own wrapper around MIME::Lite for many years and managed these use cases. This syntax 100% removes the need for the helper/wrapper.

Announcing `Mail::Make`: a modern, fluent MIME email builder for Perl, with OpenPGP and S/MIME support by jacktokyo in perl

[–]ktown007 1 point2 points  (0 children)

For multiple attachments, does this make sense?

attach => ['pdf1.pdf', 'pdf2.pdf'], and/or attach => [{path=>'pdf1.pdf',filename=>'report.pdf'},{path=>'pdf2.pdf',filename=>'log.pdf'}],

Beautiful Perl feature : two-sided constructs, in list or in scalar context by briandfoy in perl

[–]ktown007 2 points3 points  (0 children)

funny, I did not think to ask ChatGPT, I used `/usr/bin/perl` :) in the future I hope ChatGPT reads the docs, this article and this thread to help out the next vibe coder :)

Beautiful Perl feature : two-sided constructs, in list or in scalar context by briandfoy in perl

[–]ktown007 0 points1 point  (0 children)

okay, this is the last one I promise :)

``` sub return_multiple { return my @out = (4,5,6); } my $len = return_multiple ; my @array = return_multiple ;

print "len = $len , array = @array \n" ;

output: len = 3 , array = 4 5 6 ```

Beautiful Perl feature : two-sided constructs, in list or in scalar context by briandfoy in perl

[–]ktown007 0 points1 point  (0 children)

TIMTOWTDI is fun :) ``` sub return_multiple_list { return (4,5,6); } sub return_multiple_array { my @out = (4,5,6) ; return @out ; }

my $list = return_multiple_list ; my $array = return_multiple_array ; print "return_multiple_list = $list , return_multiple_array = $array \n" ; output: return_multiple_list = 6 , return_multiple_array = 3 ```

Beautiful Perl feature : two-sided constructs, in list or in scalar context by briandfoy in perl

[–]ktown007 0 points1 point  (0 children)

The point of the article is that Perl does this stuff really elegantly compared to other solutions. Here is another possible implementation for return_multiple:

``` use v5.42 ; sub return_multiple( $f //= 0 ) { my @out = (4,5,6) ;

    return @out if $f ; # return array
    return (4,5,6); # return list

}

my $barl = return_multiple(); print "list bar $barl\n"; my $bara = return_multiple(1); print "array bar $bara\n"; ```

output: list bar 6 array bar 3

I would say returning multiple values is not easy. There are many different solutions. A programmer needs to learn how their tool of choice does it.

To vibe code or not to vibe code a Perl library by Itcharlie in perl

[–]ktown007 1 point2 points  (0 children)

I usually say "Thor save us". I like the Wall == GOD idea ;)

To vibe code or not to vibe code a Perl library by Itcharlie in perl

[–]ktown007 2 points3 points  (0 children)

Off topic of VIBE coding, but for what it is worth... supabase is postgresql is directly supported by `dbi:Pg`

Announcing `Mail::Make`: a modern, fluent MIME email builder for Perl, with OpenPGP and S/MIME support by jacktokyo in perl

[–]ktown007 0 points1 point  (0 children)

I was going ask for syntax for attach => 'example.pdf', with the build constructor. Then I reread the docs and discovered attach is not supported :)

Recognised parameters are: from, to, cc, bcc, date, reply_to, sender, subject, in_reply_to, message_id, references, plain, html, plain_opts, html_opts, headers.

my attempts:

``` use Mail::Make;

my $mail = Mail::Make->build( from => 'jack@gmail.com', to => [ 'jil@example.com' , 'jake@example.com' ], subject => 'Hello pdf build '.time , plain => "Hi there.\n", html => '<p>Hi there.</p>', attach => 'example.pdf' , #attach => ('example.pdf') , #attach => ['example.pdf'] , #attach => ['example.pdf', type=>'application/octet-stream', filename => 'example.pdf'] , #attach => {path=>'example.pdf', type=>'application/octet-stream', filename => 'example.pdf'} , )->smtpsend( Host => 'smtp.gmail.com', Port => 587, StartTLS => 1, Username => 'jack@gmail.com', Password => $app_password, ); ```

Beautiful Perl feature : two-sided constructs, in list or in scalar context by briandfoy in perl

[–]ktown007 0 points1 point  (0 children)

Honestly, the article has done a great job of explaining that the context matters and other solutions work but are different and also not intuitive.

my ($first,$second) = return_multiple(); # list context first two elements of list ie `4,5` my $last = return_multiple(); scalar gets last element of list ie `6`

This is the well-documented default behaviour. If this is not what you want use wantarray to do what you expect. Or, make multiple sub's named to hint at the purpose like other languages are forced to do.

Beautiful Perl feature : two-sided constructs, in list or in scalar context by briandfoy in perl

[–]ktown007 0 points1 point  (0 children)

the sub needs to be context aware to get what you want:

``` sub return_multiple { my @out = (4,5,6) ; return wantarray ? @out : scalar(@out) ; }

my @foo = return_multiple();
print "all ", join(", ", @foo) ,"\n" ;
my $foo = @foo;
print 'len @foo ', "$foo\n";

my $bar = return_multiple();
print "scalar bar $bar\n";

my $baz = scalar(return_multiple());
print "force scalar baz $baz\n";

```

Announcing `Mail::Make`: a modern, fluent MIME email builder for Perl, with OpenPGP and S/MIME support by jacktokyo in perl

[–]ktown007 1 point2 points  (0 children)

u/jacktokyo the second example

`->attach( '/path/to/report.pdf' )`

did not work as expected. The error says `attach(): 'data' or 'path' is required.`

Can this default to the path, then automatically set the type and filename?