Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Re^5: a *working* JSON module (Perl's Debugger), related issues

by Aldebaran (Curate)
on Oct 30, 2021 at 07:24 UTC ( #11138252=note: print w/replies, xml ) Need Help??


in reply to Re^4: Can someone please write a *working* JSON module (Perl's Debugger)
in thread Can someone please write a *working* JSON module

As always definition matters. perl -de0 is more than just a debugger. ... it's also Perl's main REPL, it's pretty good for ad hoc testing and interactive demos. I use it regularly for that.

I've seen your posts from (what are we gonna call it?) output in perl -de0 mode for years now, and they've mostly been over my head. Only recently have I discovered that I have a REPL too. I could have replicated your REPL.

Others even use it as a Perl Shell, because it's very customizable.

Can you elaborate?

But it is very valuable when analyzing monolithic foreign code (e.g. B::Deparse)

I would extend that to foreign code in general. I can't understand and integrate others' code into mine without it, whilst working alone. The number of keystrokes I save using the debugger is immeasurable. With successive use of save/source, it's like a trail in the forest and can even tell a story, and it's one you keep telling until you get out of the forest. I worked a little harder on a modifed script from bliako, and I'm able to point out places in code as perl -de0 sees it, and I can get into the nitty-gritty of execution. I'll repost the 2020 perl -de0 demonstration by Ricardo Signes, for reference. I place sources and debugger output in readmore tags:

This script has grown to the low end of medium size, both with source and output, where it is difficult to traverse and understand without help. Many will be trapped between the Scylla of knowing perl, and the Charybdis of dealing with celestial mechanics. Imagine if you were in charge of steering a ship through the Straits of Messina on $date_str = "2021-10-14"; and $time_str = "03:22:31";. Furthermore, you had to do it with the naked eye using the planets because of a solar flare. (Isn't that a lot of movies nowadays?) Would you make it with precise calculations or dashed to the rocks or depths like so many others?

I use the word source in two different contexts. Both seem to be scripts, with one operating on the other. The source that will execute is:

#!/usr/bin/perl use v5.030; # strictness implied use warnings; use feature qw[ signatures ]; no warnings qw[ experimental::signatures ]; use Astro::Coord::ECI::Utils 'deg2rad'; use Astro::Coords; use Astro::MoonPhase; use Astro::Telescope; use DateTime; use DateTime::Format::ISO8601; use DateTime::TimeZone; use Data::Dumper; use Log::Log4perl; use Try::Tiny; ###### # Calculate the moon phase of an event in time. # Required is the date (time defaults to 00:00:01) of the event # The moon-phase calculator does not need a location # since moon phase is the same across the planet (more-or-less) # with the usual antipodean side-effects # However, by specifying a timezone or even coordinates of the # event conversion of event's time to UTC is more accurate # (else UTC time is assumed) # author: bliako, modified by aldebaran # date: 2021-10-10 ###### my $debug = 1; my $time_str = "03:22:31"; my $alt = 0; my $date_str = "2021-10-14"; my @events = ( # { # # example event specification # "name" => "a name for reference, required", # "date" => "date of the event in YYYY-MM-DD", # "time" => "optional time as hh:mm:ss, default is 00:00:01", # #specify optional location using one of these for calculating # #epoch which uses UTC time, # #otherwise, UTC timezone will be assumed for event's time: # "timezone" => "standard timezone name, e.g. America/Havana", # "location" => "cuba", # "location" => {lon=>-81.137633, lat=>22.17927}, # }, { "name" => "in the 'Ho", "date" => $date_str, "time" => $time_str, "location" => { lon => -116.2, lat => 43.61 }, }, { "name" => "on the Scylla", "date" => $date_str, "time" => $time_str, "location" => { lon => 38.245833, lat => 15.6325 }, }, { "name" => "in Antipo' 'Ho", "date" => $date_str, "time" => $time_str, "location" => { lon => 63.8, lat => -43.61 }, }, { "name" => "at Antipodlean Scylla", "date" => $date_str, "time" => $time_str, "location" => { lon => -141, lat => -15.6325 }, }, ); # Not wanting to divine the configuration file for Log::Log4perl, modu +le used in # the query. Better for SSCCE considerations. thx parv { package Log::Log4perl; sub get_logger ($pkg) { return bless [], $pkg; } sub show (@arg) { warn @arg, "\n"; } sub debug ( $ignore, @rest ) { show( 'DEBUG: ', @rest ); } sub info ( $ignore, @rest ) { show( 'INFO: ', @rest ); } sub warn ( $ignore, @rest ) { show( 'WARNING: ', @rest ); } sub error ( $ignore, @rest ) { die 'ERROR: ', @rest, "\n"; } } my $logger = Log::Log4perl->get_logger(); $logger->info("$0"); ## event loop for my $event (@events) { my $epoch = parse_event($event); my ( $MoonPhase, $MoonIllum, $MoonAge, $MoonDist, $MoonAng, $SunDist +, $SunAng ) = phase($epoch); $logger->info("Moon age: $MoonAge days"); $logger->info( "Moon phase: " . sprintf( "%.1f", 100.0 * $MoonPhase ) . " % of cycle (birth-to-death)" ); $logger->info( "Moon's illuminated fraction: ", sprintf( "%.1f", 100.0 * $MoonIllum ) . " % of full disc" ); ## determine altitude # usage: die unless exists $event->{location}; # restriction my $return = get_elevation_from_coordinates( $event->{location}->{la +t}, $event->{location}->{lon}, 0 ); $logger->info("return from the google is $return meters"); my $observer = $return + 2; #(most people stand) $logger->info( event2str($event) . " at height $observer meters" ); $logger->info("Object\tAzimuth\t\tElevation"); for my $name (qw/Venus Jupiter Moon Saturn/) { my $planet = Astro::Coords->new( planet => $name ); # use DateTime my $date = DateTime->from_epoch( epoch => $epoch, time_zone => 'UT +C' ); $planet->datetime($date); $planet->telescope( Astro::Telescope->new( Name => $event->{name}, Long => deg2rad( $event->{location}->{lon} ), Lat => deg2rad( $event->{location}->{lat} ), Alt => $observer, #meters above +sea level ) ); my $az = $planet->az( format => 'deg' ); my $el = $planet->el( format => 'deg' ); $logger->info("$name\t$az\t\t$el"); } ## end planets loop } ## end event loop sub event2str { my $event = shift; if ( !exists $event->{_is_parsed} ) { warn "event has not been parsed, just dumping it..."; print Dump($event); } my $str = $event->{name} . " on " . $event->{datetime} . " (" . $event->{datetime}->epoch . " seconds unix-epoch)" . " timezone: " . $event->{datetime}->time_zone->name; if ( exists $event->{location} ) { if ( ref( $event->{location} ) eq 'HASH' ) { $str .= " (lat: " . $event->{location}->{lat} . ", lon: " . $event->{location}->{lon} . ")"; } else { $str .= "(" . $event->{location} . ")" } } return $str; } sub parse_event { my $event = shift; if ( !exists $event->{date} ) { die "date field is missing from even +t." } my $datestr = $event->{date}; die "event does not have a 'name' field, please specify one, anythin +g really." unless exists $event->{name}; my $timestr = "00:00:01"; if ( exists $event->{time} ) { $timestr = $event->{time}; print "event2epoch(): setting time to '$timestr' ...\n" if $debug > 0; die "time '$timestr' is not valid, it must be in the form 'hh:mm:s +s'." unless $timestr =~ /^\d{2}:\d{2}:\d{2}$/; } else { $event->{time} = $timestr } my $isostr = $datestr . 'T' . $timestr; my $dt = DateTime::Format::ISO8601->parse_datetime($isostr); die "failed to parse date '$isostr', check date and time fields." unless defined $dt; $event->{datetime} = $dt; my $tzstr = 'UTC'; if ( exists $event->{timezone} ) { $tzstr = $event->{timezone}; print "event2epoch(): found a timezone via 'timezone' field as '$tzstr' (tha +t does not mean it is valid) ...\n" if $debug > 0; } elsif ( exists $event->{location} ) { my $loc = $event->{location}; if ( ( ref($loc) eq '' ) && ( $loc =~ /^[a-zA-Z]$/ ) ) { # we have a location string my @alltzs = DateTime::TimeZone->all_names; my $tzstr; for (@alltzs) { if ( $_ =~ /$loc/i ) { $tzstr = $_; last } } die "event's location can not be converted to a timezone, consider specify +ing the 'timezone' directly or setting 'location' coordinates with: \ +[lat,lon\]." unless $tzstr; print "event2epoch(): setting timezone via 'location' name to '$timestr' ... +\n" if $debug > 0; } elsif ( ( ref($loc) eq 'HASH' ) && ( exists $loc->{lat} ) && ( exists $loc->{lon} ) ) { # we have a [lat,lon] array for location require Geo::Location::TimeZone; my $gltzobj = Geo::Location::TimeZone->new(); $tzstr = $gltzobj->lookup( lat => $loc->{lat}, lon => $loc->{lon +} ); if ( !$tzstr ) { die "timezone lookup from location coordinates lat:" . $loc->{lat} . ", lon:" . $loc->{lon} . " has failed."; } print "event2epoch(): setting timezone via 'location' coordinate +s lat:" . $loc->{lat} . ", lon:" . $loc->{lon} . " ...\n" if $debug > 0; } } if ($tzstr) { print "event2epoch(): deduced timezone to '$tzstr' and setting it +...\n" if $debug > 0; try { $dt->set_time_zone($tzstr) } catch { die "$_\n failed to set the timezone '$tzstr', is it valid?" } } $event->{_is_parsed} = 1; $event->{epoch} = $dt->epoch; return $event->{epoch}; } sub get_elevation_from_coordinates { my ( $lat, $lon, $debug ) = @_; use LWP::UserAgent; use HTTP::Request; use Data::Roundtrip; $debug //= 0; my $ua = LWP::UserAgent->new( agent => 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox +/78.0', ); my $response; my $payload = 'latitude=' . $lat . '&longitude=' . $lon . '&application_max_assets_mtime=1559625591'; my $payloadlen = length($payload); # this request was translated from Curl command-line # by [Corion]'s https://corion.net/curl2lwp.psgi my $req = HTTP::Request->new( 'POST' => 'https://www.mapcoordinates.net/admin/component/edit/Vpc_MapCoordinate +s_Advanced_GoogleMapCoords_Component/Component/json-get-elevation', [ 'Connection' => 'keep-alive', 'Accept' => '*/*', 'Accept-Encoding' => 'gzip, x-gzip, deflate, x-bzip2, bzip2', 'Accept-Language' => 'en-US,en;q=0.5', # 'Host' => 'www.mapcoordinates.net:443', 'Referer' => 'https://www.mapcoordinates.net/en', 'User-Agent' => 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firef +ox/78.0', 'Content-Length' => $payloadlen, 'Content-Type' => 'application/x-www-form-urlencoded; charse +t=UTF-8', 'DNT' => '1', 'Origin' => 'https://www.mapcoordinates.net', 'X-Requested-With' => 'XMLHttpRequest' ], $payload ); die "call to HTTP::Request has failed" unless $req; if ( $debug > 0 ) { print "$0 : $payload\n$0 : sending above payload, of $payloadlen bytes +...\n"; } $response = $ua->request($req); die "Error fetching: " . $response->status_line unless $response->is_success; my $content = $response->decoded_content; my $data = Data::Roundtrip::json2perl($content); die "failed to parse received data:\n$content\n" unless exists $data->{'elevation'}; return $data->{'elevation'}; } __END__

I was concerned that some of my data were coming back as zero from the google as errors, so I created an amalgamated story to test it. This is 5.mp.monk.txt, which is the path I've tapped out to get into the nitty gritty.

#source 5.1.mp.txt #source 5.mp.txt b 262 c s v p @_ p $debug b 312 b 317 c v n n s v l 280-300 b 289 c n r s v n p $json_string l 198-215 r c c c c s v n p $json_string c c c c s n p $json_string B * c #save 5.mp.monk.txt

There follows abridged output in code tags. I'll comment on it occasionally in p tags.

$ perl -d 5.mp.pl Loading DB routines from perl5db.pl version 1.55 Editor support available. Enter h or 'h h' for help, or 'man perldebug' for more help. Subroutine get_logger redefined at 5.mp.pl line 83. at 5.mp.pl line 83. main::(5.mp.pl:32): my $debug = 1; DB<1> source 5.1.mp.txt + >> #source 5.mp.txt

The source command loads a previous sequence. If execution or values therein had run into trouble, I save the commands and shave off the last one. I clear out previous useless prints and tepid steps, that is repetive n, n, n. Also, any boondoggles from hitting s and going deep into stuff above my head or entirely irrelevant. In this case, source 5.mp.txt was the first 8 commands, where I set all breakpoints:

>> b 262 >> c INFO: 5.mp.pl at 5.mp.pl line 94. event2epoch(): setting time to '03:22:31' ... event2epoch(): setting timezone via 'location' coordinates lat:43.61, +lon:-116.2 ... event2epoch(): deduced timezone to 'Etc/GMT-7' and setting it ... INFO: Moon age: 8.12733852952393 days at 5.mp.pl line 103. INFO: Moon phase: 27.5 % of cycle (birth-to-death) at 5.mp.pl line 104. INFO: Moon's illuminated fraction: 57.9 % of full disc at 5.mp.pl line 107. main::get_elevation_from_coordinates(5.mp.pl:262): 262: my ( $lat, $lon, $debug ) = @_; >> s main::get_elevation_from_coordinates(5.mp.pl:268): 268: $debug //= 0; >> v 265: use HTTP::Request; 266: use Data::Roundtrip; 267 268==> $debug //= 0; 269 270: my $ua = LWP::UserAgent->new( agent => 271 'Moz<p>These values are not the zero values I was concer +ned about</p>illa/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Fir +efox/78.0', ); 272 273: my $response; 274: my $payload = >> p @_ 43.61-116.20 >> p $debug 0 >> b 312 >> b 317

I'll have questions about the above, but let's keep on moving. Hit c to get to continue to a breakpoint. v lets me see where I am with some surrounding code, and then s steps into it:

>> c main::get_elevation_from_coordinates(5.mp.pl:312): 312: $response = $ua->request($req); >> v 309 "$0 : $payload\n$0 : sending above payload, of $payloadl +en bytes...\n"; 310 } 311 312==>b $response = $ua->request($req); 313: die "Error fetching: " . $response->status_line 314 unless $response->is_success; 315 316: my $content = $response->decoded_content; 317:b my $data = Data::Roundtrip::json2perl($content); 318 die "failed to parse received data:\n$content\n" ... >> s HTTP::Message::decoded_content(/usr/share/perl5/HTTP/Message.pm:283): 283: my($self, %opt) = @_; >> v 280 281 sub decoded_content 282 { 283==> my($self, %opt) = @_; 284: my $content_ref; 285: my $content_ref_iscopy; 286 287: eval { 288: $content_ref = $self->content_ref; 289: die "Can't decode ref content" if ref($content_ref) ne "SC +ALAR"; >> l 280-300 280 281 sub decoded_content 282 { 283==> my($self, %opt) = @_; 284: my $content_ref; 285: my $content_ref_iscopy; 286 287: eval { 288: $content_ref = $self->content_ref; 289: die "Can't decode ref content" if ref($content_ref) ne "SC +ALAR"; 290 291: if (my $h = $self->header("Content-Encoding")) { 292: $h =~ s/^\s+//; 293: $h =~ s/\s+$//; 294: for my $ce (reverse split(/\s*,\s*/, lc($h))) { 295: next unless $ce; 296: next if $ce eq "identity" || $ce eq "none"; 297: if ($ce eq "gzip" || $ce eq "x-gzip") { 298: require IO::Uncompress::Gunzip; 299: my $output; 300: IO::Uncompress::Gunzip::gunzip($content_ref, \$out +put, Transparent => 0) >> b 289 >> c HTTP::Message::decoded_content(/usr/share/perl5/HTTP/Message.pm:289): 289: die "Can't decode ref content" if ref($content_ref) ne "SC +ALAR"; >> n HTTP::Message::decoded_content(/usr/share/perl5/HTTP/Message.pm:291): 291: if (my $h = $self->header("Content-Encoding")) { >> r scalar context return from HTTP::Message::decoded_content: '{"elevatio +n":821,"success":true,"requestNum":"163546920137"}'

I took a gander through HTTP::Message, looking at internals. It's typical for me to do s, v, l 280-300 to see where execution has led. It will usually be a place I haven't seen before. Look how informative the result of r is, which is obviously to connote returning from a subroutine.

main::get_elevation_from_coordinates(5.mp.pl:317): 317: my $data = Data::Roundtrip::json2perl($content); 318: die "failed to parse received data:\n$content\n" >> s Data::Roundtrip::json2perl(/usr/local/share/perl/5.30.0/Data/Roundtrip +.pm:192): 192: my $json_string = $_[0]; >> v 189: return $pv 190 } 191 sub json2perl { 192==> my $json_string = $_[0]; 193 #my $params = defined($_[1]) ? $_[1] : {}; 194: my $pv = JSON::decode_json(Encode::encode_utf8($json_strin +g)); 195: if( ! defined $pv ){ warn "json2perl() : error, call to j +son2perl() has failed"; return undef } 196: return $pv; 197 } 198 sub json2json { >> n Data::Roundtrip::json2perl(/usr/local/share/perl/5.30.0/Data/Roundtrip +.pm:194): 194: my $pv = JSON::decode_json(Encode::encode_utf8($json_strin +g)); >> p $json_string {"elevation":821,"success":true,"requestNum":"163546920137"} >> l 198-215 198 sub json2json { 199: my $json_string = $_[0]; 200: my $params = defined($_[1]) ? $_[1] : {}; 201 202: my $pv = json2perl($json_string, $params); 203: if( ! defined $pv ){ warn "json2perl() : error, call to j +son2perl() has failed"; return undef } 204: $json_string = perl2json($pv, $params); 205: if( ! defined $json_string ){ warn "json2perl() : error, +call to perl2json() has failed"; return undef } 206 207: return $json_string; 208 } 209 sub yaml2yaml { 210: my $yaml_string = $_[0]; 211: my $params = defined($_[1]) ? $_[1] : {}; 212 213: my $pv = yaml2perl($yaml_string, $params); 214: if( ! defined $pv ){ warn "yaml2perl() : error, call to y +aml2perl() has failed"; return undef } 215: $yaml_string = perl2yaml($pv, $params); >> r scalar context return from Data::Roundtrip::json2perl: 'elevation' => +821 'requestNum' => 163546920137 'success' => JSON::PP::Boolean=SCALAR(0x55e918df2b78) -> 1

In this part, we step into bliako's json software, which I find quite readable. Again, I take a look and return with r with that nice summary. However, these are not the zero values I was concerned about, so I'll continue with c:

... event2epoch(): setting time to '03:22:31' ... event2epoch(): setting timezone via 'location' coordinates lat:15.6325 +, lon:38.245833 ... event2epoch(): deduced timezone to 'Africa/Asmara' and setting it ... ... {"elevation":841,"success":true,"requestNum":"163546921268"} DB<13> c + INFO: return from the google is 841 meters at 5.mp.pl line 115. INFO: on the Scylla on 2021-10-14T03:22:31 (1634170951 seconds unix-ep +och) timezone: Africa/Nairobi (lat: 15.6325, lon: 38.245833) at heigh +t 843 meters

Apparently, this point is on the Scylla side of the pair. If Charybdis existed, it would have a negative value, which is, of course, a physical nonstarter in the 21st century. I only have this one script so far to probe the validity of these values, but it's certainly true that small changes in input will have huge changes in output in certain neighborhoods. No false zero here.

... event2epoch(): setting time to '03:22:31' ... event2epoch(): setting timezone via 'location' coordinates lat:-43.61, + lon:63.8 ... event2epoch(): deduced timezone to 'Etc/GMT+4' and setting it ... ... DB<13> c + main::get_elevation_from_coordinates(5.mp.pl:317): 317: my $data = Data::Roundtrip::json2perl($content); 318: die "failed to parse received data:\n$content\n" DB<13> s + Data::Roundtrip::json2perl(/usr/local/share/perl/5.30.0/Data/Roundtrip +.pm:192): 192: my $json_string = $_[0]; DB<13> n + Data::Roundtrip::json2perl(/usr/local/share/perl/5.30.0/Data/Roundtrip +.pm:194): 194: my $pv = JSON::decode_json(Encode::encode_utf8($json_strin +g)); DB<13> p $json_string + {"elevation":0,"success":true,"requestNum":"163546928850"}

Then I finally got ^^^^there to see that google thinks that zero is the right value as opposed to returning it to indicate failure. So I got the peek I needed, what now? Clear the breakpoints and see if it rolls to the finish without trouble:

DB<14> B * + Deleting all breakpoints... DB<15> c + INFO: return from the google is 0 meters at 5.mp.pl line 115. INFO: in Antipo' 'Ho on 2021-10-14T03:22:31 (1634196151 seconds unix-e +poch) timezone: -0400 (lat: -43.61, lon: 63.8) at height 2 meters at 5.mp.pl line 117. ... Debugged program terminated. Use q to quit or R to restart, use o inhibit_exit to avoid stopping after program termination, h q, h R or h o to get additional info. DB<15> save 5.mp.monk.txt + commands saved in 5.mp.monk.txt DB<16> q + $

I think I edited out the values from the Scylla with the telescope:

INFO: on the Scylla on 2021-10-14T03:22:31 (1634170951 seconds unix-ep +och) timezone: Africa/Nairobi (lat: 15.6325, lon: 38.245833) at heigh +t 843 meters INFO: Object Azimuth Elevation INFO: Venus 168.793996164728 -81.0110616258686 INFO: Jupiter 258.080321870357 -14.8575841846033 INFO: Moon 251.270738258432 -35.2685064885712 INFO: Saturn 256.410482564197 -30.2637811706649

So if your passage depended on seeing these objects at that place and time, well then, you were screwed. The Gods are cruel.

Q1) What makes my Log4perl section a signature? This version is from parv, and I like that it gives me line numbers, but I don't see code for that. (?)

Q2) How would I turn the above script into "monolithic" foreign code?

Q3) Does Data::Roundtrip cover the same ground that JSON::XS did? I can't disambiguate what XS means.

Q4) What operator is this? I believe it takes my global value of 1 for $debug and makes it zero:

268==>      $debug //= 0;

Q5) Finally, reading all around these issues, I found this one-liner and was wondering if this would fall under the umbrella of what "the debugger" might be. What is happening with this command?

$ perl -Mre=debug -e "/just|another|perl|hacker/" Compiling REx "just|another|perl|hacker" ~ tying lastbr BRANCH (11) to ender END (15) offset 4 Final program: 1: TRIEC-EXACT[ahjp] (15) <just> <another> <perl> <hacker> 15: END (0) stclass AHOCORASICKC-EXACT[ahjp] minlen 4 Freeing REx: "just|another|perl|hacker" $

Thx for your comment

Replies are listed 'Best First'.
Re^6: a *working* JSON module (Perl's Debugger), related issues
by hippo (Bishop) on Oct 30, 2021 at 10:15 UTC
    Q4) What operator is this? I believe it takes my global value of 1 for $debug and makes it zero

    It is the defined-or-equals operator. It assigns the RHS to the LHS only if the LHS is undefined. It is listed in perlop along with all the other operators.


    🦛

      It is the defined-or-equals operator. It assigns the RHS to the LHS only if the LHS is undefined. It is listed in perlop along with all the other operators.

      Thanks, I was reading it wrong. I wouldn't say the documentation is particularly thick about it:

      $ perldoc perlop | grep '//=' .= %= ^= ^.= //= $

      , but I see why bliako uses it, and think I'll borrow the scheme.

        Just to expand on previous answer with some example. An operator of the form $LHS <OPERATOR>= $RHS (I think the general name is "shorthand"?) is the shorthand for $LHS = $LHS <OPERATOR> $RHS. (Edit: s/LHW/LHS/) E.g., the long way is: my $x = undef; my $x = $x // 12;. The shorthand is $x //= 12;. Many other operators follow this style, for example $x = 12; $x += 3; # $x is 15. But also $x = 0; $x ||= 1; Also, $x = 10; $x /= 2; # 5

        my $debug = 1; sub get_elevation_from_coordinates { my ($lat, $lon, $debug) = @_; $debug //= 0; ... }

        Now, in the context of the above quoted code which I think you refer to. There are 2 $debug there! One belongs to the outer scope of the sub. It will be valid inside the sub unless the sub declares (my $debug) its own private one. In this case it's an optional sub parameter who is set to zero if left undef (by the caller of the sub, e.g. in this case: get_elevation_from_coordinates(1,2)). That code would have been better like this:

        our $debug = 1; # OUR! sub get_elevation_from_coordinates { my ($lat, $lon, $debug) = @_; $debug //= $main::debug; # if none specified, use "global" (main's +) ... }

        In which case there's a global debug which is used to set its sub's debug value only if the caller did not specify one.

        This document is helpful to me: https://perl.plover.com/FAQs/Namespaces.html

        bw, bliako

Re^6: a *working* JSON module (Perl's Debugger), related issues
by stevieb (Canon) on Oct 30, 2021 at 20:51 UTC
    Q3) Does Data::Roundtrip cover the same ground that JSON::XS did? I can't disambiguate what XS means.

    Data::Roundtrip requires the JSON distribution. When used, the JSON module will load JSON::XS if it is available to your interpreter, and the pure perl JSON::PP if not. JSON::PP has been in core since ~5.14, so this functionality is very handy instead of just having your script fall over if JSON::XS isn't installed.

    XS simply means that there are components to the software that are compiled, therefore in most cases making much of its functionality much, much faster.

    One of my distributions, Bit::Manip is an XS based module, but I also have a pure perl version (Bit::Manip::PP) for those who can't or don't want to compile software. Here's a benchmark script between the two, and the results. The C/XS version is ~394% faster than the pure perl version:

    use warnings; use strict; # performs a benchmark between this XS # version and the PP version use Benchmark qw(timethese cmpthese); use Bit::Manip; use Bit::Manip::PP; my $do = $ARGV[0]; timethese(1000000, { 'c' => 'c', 'p' => 'p', } ); cmpthese(1000000, { 'c' => 'c', 'p' => 'p', } ); sub c { Bit::Manip::bit_set(65535, 0, 8, 0xFF); } sub p { Bit::Manip::PP::bit_set(65535, 0, 8, 0xFF); } __END__ Benchmark: timing 1000000 iterations of c, p... c: 3 wallclock secs ( 3.35 usr + 0.00 sys = 3.35 CPU) @ 29 +8507.46/s (n=1000000) p: 17 wallclock secs (16.58 usr + 0.00 sys = 16.58 CPU) @ 60 +313.63/s (n=1000000) Rate p c p 60606/s -- -80% c 299401/s 394% --
      One of my distributions, Bit::Manip is an XS based module, but I also have a pure perl version (Bit::Manip::PP)

      I'm intrigued why you called one Bit::Manip::PP but didn't name the other Bit::Manip::XS. Intrigued because naming of modules seems a bit of a dark art to me despite all the advice on the matter.

        I'm intrigued why you called one Bit::Manip::PP but didn't name the other Bit::Manip::XS

        Because I had written the entirety of Bit::Manip in C and XS, then front-ended it in Perl and released it. It was only after a while later I decided to do a rewrite in pure Perl and release that separately. No reason other than it had already been released as Bit::Manip.

Re^6: a *working* JSON module (Perl's Debugger), related issues
by bliako (Monsignor) on Oct 30, 2021 at 22:17 UTC

    Aldebaran++ that's really cool addition you got there!

    Q2) How would I turn the above script into "monolithic" foreign code?

    Turn your additions into a sub (a subroutine aka function) which will be a complete black box. It will take some inputs, and return some outputs (print if you must but don't forget to return all you need to return to the caller so that your sub is useful). For example:

    sub func { my ($event, @planet_names) = @_; # read in parameters supplied by call +er as in func($xyz) # check that we have some names and that event contains the fields we +need # return undef on error. # caller must check if received undef! return undef unless @planet_names; return undef unless exists $event->{epoch}; ... my %returned_planets = (); for my $a_planet_name (@planet_names){ my $planet = Astro::Coords->new( planet => $name ); ... $returned_planets{$a_planet_name} = $planet; } # return to the caller results as a hashref # I always use refs for params and results. others may not. return \%returned_planets; } # end of my function # example use my $ret = func($anevent, "venus", "saturn"); die "func() failed" unless defined $ret; # and now do what you like with the results.

    I am referring to the code you presented above about here:

    for my $event (@events) { my $epoch = parse_event($event); my ( $MoonPhase, $MoonIllum, $MoonAge, $MoonDist, $MoonAng, $SunDist +, $SunAng ) = phase($epoch);

    Then build some test cases to test your sub. Edge cases (e.g. empty planet names, wrong names) and also cases you know the result. And you are good to go :)

    Todo: at this stage it is a prototype. When final, we can turn this into OO, with $event being a class. But that's much later.

    Let me know how you convert your additions into a sub.

    Q3) Does Data::Roundtrip cover the same ground that JSON::XS did? I can't disambiguate what XS means.

    It's just a wrapper around many great modules to implement things like json2perl, perl2yaml with (hopefully correct) unicode suppprt. Don't worry about it. But you can safely replace it with calls to JSON's decode() etc. (which, as stevieb said, switches between XS or PP depending what is installed on your system) so that you have one less dependency.

    BTW, I think you also provided me with an answer as to why I never use the debugger :)

    bw, bliako

      Let me know how you convert your additions into a sub.

      I'll work on that. I appreciate the concrete Anweisungen

      It's just a wrapper around many great modules to implement things like json2perl, perl2yaml with (hopefully correct) unicode suppprt. Don't worry about it. But you can safely replace it with calls to JSON's decode() etc. (which, as stevieb said, switches between XS or PP depending what is installed on your system) so that you have one less dependency.

      Ok, it helps to know that PP is the alternative, and PP stands for, wait for it, pure perl.

      BTW, I think you also provided me with an answer as to why I never use the debugger :)

      I'm happy to provide you with certainty, a rare commodity in this world. :) Like I say, for me it's usually when I'm hooking up parts that are new to me, and I have to figure out what is not happening with values. With hippo's help, I've figured out parts of your debugging scheme, and see how it's built. I wasn't calling it correctly.

      >> p @_ 43.61-116.20 >> p $debug 0

      I had been passing a bare zero (a hasty stubout) as the third argument to this routine. this was undefined on arrival. Now I have improved it to hook into your debugging scheme, as you define $debug in the caller:

      my $return = get_elevation_from_coordinates( $event->{location}->{la +t}, $event->{location}->{lon}, $debug );

      Then I get the internals of the exchange with google, and everything makes even more sense:

      ./6.mp.pl : latitude=-15.6325&longitude=-141&application_max_assets_mt +ime=1559625591 ./6.mp.pl : sending above payload, of 72 bytes... INFO: return from the google is 0 meters

      When I hit M in the debugger too see what version of JSON I was running, I was surprised to see that

      /usr/local/lib/x86_64-linux-gnu/perl/5.30.0/JSON/XS.pm

      was among the loaded modules. I take that to mean that perl is covering its bases for backwards compatibility. I wonder how I might determine whether execution ran through it(?) What's more, I found my PP.pm module, and read it mod 1:

      locate  *JSON/PP.pm

      , wherein is:

      # Note that JSON version 2.0 and above will automatically use # JSON::XS or JSON::PP, so you should be able to just: use JSON;

      Again, with the M command, I see that my version is way north of 2.0:

      'JSON.pm' => '4.03 from /usr/local/share/perl/5.30.0/JSON.pm' 'JSON/XS.pm' => '4.03 from /usr/local/lib/x86_64-linux-gnu/perl/5.30.0 +/JSON/XS.pm'

      So, after all this, I see that it is not of any practical concern for what I do with json. What's more, I would be hesitant to fire a cannon of requests in compiled c to the same server. It might exceed what many consider polite. Love them or hate them, I don't want to be on the wrong side of the google.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11138252]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (2)
As of 2022-05-22 04:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you prefer to work remotely?



    Results (79 votes). Check out past polls.

    Notices?