How do you print a ruby hash using the new ruby syntax? - ruby-1.9.3

I want to print my ruby hashes using the new syntax (i.e. {hello: 1, world: 2} vs. {:hello => 1, :world => 2}.
I've tried pretty print pp:
irb(main):001:0> {hello: 1, hi: 2}
=> {:hello=>1, :hi=>2}
but to no avail. Is there a way to do this?

Related

MongoDB/Perl: find_one doesn't return data after unrelated code

mongodb is v4.0.5
Perl is 5.26.3
MongoDB Perl driver is 2.0.3
This Data::Dumper output shows what's driving me crazy
INFO - $VAR1 = [
'275369249826930689 1',
{
'conf' => {
'param' => 'argument'
},
'id' => '275369249826930689',
'lastmsg' => '604195211232139552',
'_id' => bless( {
'oid' => ']:\',&�h�GeR'
}, 'BSON::OID' )
}
];
352832438449209345 275369249826930689
INFO - $VAR1 = [
'275369249826930689 2'
];
The second INFO - $VAR1 should show the same content as the first one. This is the original code, which I have (see below) broken down to find the culprit.
ddump(["$userid 1",
$c_identities->find_one({
channel => 'chan1',
id => $userid,
})
]);
my #filtered = reverse
grep { $_->{author}->{id} == $userid } #{$answers};
ddump(["$userid 2",
$c_identities->find_one({
channel => 'chan1',
id => $userid,
})
]);
ddump is just a wrapper for Data::Dumper. If I remove the "my #filtered" line, the second find one again returns the expected result (a MongoDB document). $answers is just a listref of hashes - no objects - from some API, completely unrelated to MongoDB.
So I broke the "reverse grep" code down to see where the culprit is. The say are the two numbers you see between the dumpers above. This is what I can do, to get answer from the second find_one:
for my $answer (#{$answers}) {
say $answer->{author}->{id}, ' ', $userid;
push #filtered, $answer;
}
As long as I do just this, the second find_one delivers a result. If, however, I do this:
for my $answer (#{$answers}) {
say $answer->{author}->{id}, ' ', $userid;
if ($answer->{author}->{id} == $userid) {
}
push #filtered, $answer;
}
I get the output from above (where the second dumper yields no return from the find_one. It's insane - the if-clause containing the numeric eq causes the second find_one to fail! This is also the grep body in the intended code.
What's going on here? How can this have possibly any effect on the MongoDB methods?
Using the numeric comparison operator == numifies the value, but it's probably too large to fit into an integer and becomes a float. It can also just become an integer and lose double quotes when serialized to JSON or similar format. Using eq instead of == keeps the value unchanged.

perl mongDB to_json howto convert an ISODate, What is the right way to serialize Datetime object

I have
a mongoDB with :
my $data = $newspapers->find_one({_id => 2000});
last_mdb_update is a datetime in $data and is a ISODate in mongoDB
$result = to_json( $data, { ascii => 1, utf8 => 1, pretty => 1 } );
I got an error:
encountered object '2013-11-06T06:45:16', but neither allow_blessed nor convert_blessed settings are enabled
Note:
I can do, to fix and serialize, but is an ugly workaround and just works for that field:
$data->{last_mdb_update} = ''.$data->{last_mdb_update};
$result = to_json( $data, {ascii => 1, utf8 => 1, pretty => 1, convert_blessed => 1 } );
says (...) nor TO_JSON method available
what is TO_JSON method for ISODate ?
By default, MongoDB ISODate objects are returned as DateTime objects in the Perl MongoDB driver. The error you are getting sounds like it is coming from the JSON serialization library, which is unrelated to MongoDB.
JSON has no native datetime type, so if you want to serialize it you'll need to convert the DateTime object to some kind of number or string first.
sub DateTime::TO_JSON {
{ "".shift }
}
my $result = to_json( $data, { utf8 => 1, pretty => 1, convert_blessed => 1 } );
works !

Perl/Curses event handling and I/O

So, I just started trying to use the perl curses module for a project I'm working on. The documentation seems to be extremely lacking, what little I can find on cpan seems to be half-finished and assumes previous curses library experience, which I don't have. I have two issues I am trying to solve, my code so far:
#!/usr/bin/perl
use strict;
use Curses::UI;
use Term::ReadKey;
my ($cols, $rows, $wp, $hp) = GetTerminalSize();
my $cui = new Curses::UI( -color_support => 1);
sub eDialog {
my $return = $cui->dialog(
-message => "Are you sure?",
-title => "Really quit?",
-buttons => ['yes', 'no']
);
exit(0) if $return;
}
sub entryUpdate {
my $mainentry = shift;
if($mainEntry->get() =~ m/.*\n$/)
{
print STDERR $mainEntry->get();
}
}
$cui->set_binding( \&eDialog , "\cQ");
my $mainWin = $cui->add(
'viewWin', 'Window',
-border => 1,
-height => ($rows - 3),
-bfg => 'green'
);
my $mainView = $mainWin->add(
"viewWid", "TextViewer",
-wrapping => 1
);
my $entryWin = $cui->add(
'entryWin', 'Window',
-border => 1,
-y => ($rows - 3),
-height => 1,
-bfg => 1
);
my $mainEntry = $entryWin->add(
"entryWid", "TextEntry",
-onchange => \&entryUpdate()
);
$mainEntry->focus();
$cui->mainloop();
I managed to get the UI set up how I want it, but actually making it work is proving problematic.
1). I want to be able to, when text is typed into the $mainEntry widget, detect when enter/return is pressed, and execute a subroutine to do stuff with the text typed into the widget, then clear it out. (I tried accomplishing this with the entryUpdate subroutine, but that isn't working at all, no matter how I've tried to do it.)
2). I want to be able to periodically (Say, every 1 second or 500ms), execute another subroutine, and have the string it returns added to the $mainView widget.
Getting either or both of these to work has proven to be a huge issue thus far, I just dont know enough about how curses works and I haven't been able to find the information I need anywhere. Any help would be much appreciated.
1) You can simply bind the return key to a subrouting using set_binding:
use Curses qw(KEY_ENTER);
$mainEntry->set_binding(sub {
$mainView->text($mainView->text . $mainEntry->get . "\n");
$mainView->draw;
$mainEntry->text("");
}, KEY_ENTER);
2) It seems that there are timer methods (found them by grepping the Curses-UI source code), but they are not documented, which is probably an issue. Here's how it's used:
$cui->set_timer('timer_name', sub {
$mainView->text($mainView->text . scalar(localtime)."\n");
$mainView->draw;
}, 1);

What is wrong with my declaration of a hash inside a hash in Perl?

I am struggling with the following declaration of a hash in Perl:
my %xmlStructure = {
hostname => $dbHost,
username => $dbUsername,
password => $dbPassword,
dev_table => $dbTable,
octopus => {
alert_dir => $alert_dir,
broadcast_id => $broadcast_id,
system_id => $system_id,
subkey => $subkey
}
};
I've been googling, but I haven't been able to come up with a solution, and every modification I make ends up in another warning or in results that I do not want.
Perl complaints with the following text:
Reference found where even-sized list expected at ./configurator.pl line X.
I am doing it that way, since I want to use the module:
XML::Simple
In order to generate a XML file with the following structure:
<settings>
<username></username>
<password></password>
<database></database>
<hostname></hostname>
<dev_table></dev_table>
<octopus>
<alert_dir></alert_dir>
<broadcast_id></broadcast_id>
<subkey></subkey>
</octopus>
</settings>
so sometthing like:
my $data = $xmlFile->XMLout(%xmlStructure);
warn Dumper($data);
would display the latter xml sample structure.
Update:
I forgot to mention that I also tried using parenthesis instead of curly braces for the hash reference, and eventhough it seems to work, the XML file is not written properly:
I end up with the following structure:
<settings>
<dev_table>5L3IQWmNOw==</dev_table>
<hostname>gQMgO3/hvMjc</hostname>
<octopus>
<alert_dir>l</alert_dir>
<broadcast_id>l</broadcast_id>
<subkey>l</subkey>
<system_id>l</system_id>
</octopus>
<password>dZJomteHXg==</password>
<username>sjfPIQ==</username>
</settings>
Which is not exactly wrong, but I'm not sure if I'm going to have problems latter on as the XML file grows bigger. The credentials are encrypted using RC4 algorith, but I am encoding in base 64 to avoid any misbehavior with special characters.
Thanks
{} are used for hash references. To declare a hash use normal parentheses ():
my %xmlStructure = (
hostname => $dbHost,
username => $dbUsername,
password => $dbPassword,
dev_table => $dbTable,
octopus => {
alert_dir => $alert_dir,
broadcast_id => $broadcast_id,
system_id => $system_id,
subkey => $subkey
}
);
See also perldoc perldsc - Perl Data Structures Cookbook.
For your second issue, you should keep in mind that XML::Simple is indeed too simple for most applications. If you need a specific layout, you're better off with a different way of producing the XML, say, using HTML::Template. For example (I quoted variable names for illustrative purposes):
#!/usr/bin/env perl
use strict; use warnings;
use HTML::Template;
my $tmpl = HTML::Template->new(filehandle => \*DATA);
$tmpl->param(
hostname => '$dbHost',
username => '$dbUsername',
password => '$dbPassword',
dev_table => '$dbTable',
octopus => [
{
alert_dir => '$alert_dir',
broadcast_id => '$broadcast_id',
system_id => '$system_id',
subkey => '$subkey',
}
]
);
print $tmpl->output;
__DATA__
<settings>
<username><TMPL_VAR username></username>
<password><TMPL_VAR password></password>
<database><TMPL_VAR database></database>
<hostname><TMPL_VAR hostname></hostname>
<dev_table><TMPL_VAR dev_table></dev_table>
<octopus><TMPL_LOOP octopus>
<alert_dir><TMPL_VAR alert_dir></alert_dir>
<broadcast_id><TMPL_VAR broadcast_id></broadcast_id>
<subkey><TMPL_VAR subkey></subkey>
<system_id><TMPL_VAR system_id></system_id>
</TMPL_LOOP></octopus>
</settings>
Output:
<settings>
<username>$dbUsername</username>
<password>$dbPassword</password>
<database></database>
<hostname>$dbHost</hostname>
<dev_table>$dbTable</dev_table>
<octopus>
<alert_dir>$alert_dir</alert_dir>
<broadcast_id>$broadcast_id</broadcast_id>
<subkey>$subkey</subkey>
<system_id>$system_id</system_id>
</octopus>
</settings>
You're using the curly braces { ... } to construct a reference to an anonymous hash. You should either assign that to a scalar, or change the { ... } to standard parentheses ( ... ).

How can I prettify Perl code generated by Perl?

I have a test generator written in Perl. It generates tests that connect to a simulator. These tests are themselves written in Perl and connect to the simulator via its API. I would like the generated code to be human-readable, which means I'd like it to be properly indented and formatted. Is there a good way to do it?
Details follow, or you can skip to the actual question below.
This is an example:
my $basic = ABC
TRIGGER => DELAY(
NUM => 500,
),
)
BASIC
my $additional = STATE_IS(
STATE => DEF,
INDEX => 0,
),
ADDITIONAL
I'd like the command ABC to be executed with a delay of 500 (units aren't relevant just now) after I call &event, and the state of index 0 is DEF. Sometimes I'll also want to wait for indeces 1, 2, 3 etc...
For only one index I'd like to see this in my test:
&event(
CMD => ABC
TRIGGER => DELAY(
NUM => 500,
TRIGGER => STATE_IS(
STATE => DEF,
INDEX => 0,
),
),
)
For two indeces I'd like to see:
&event(
CMD => ABC
TRIGGER => DELAY(
NUM => 500,
TRIGGER => STATE_IS(
STATE => DEF,
INDEX => 0,
TRIGGER => STATE_IS(
STATE => DEF,
INDEX => 1,
),
),
),
)
So basically I'm adding a block of:
TRIGGER => STATE_IS(
STATE => DEF,
INDEX => 0,
),
for each index, and the index number changes.
Here's how I'm doing it:
for $i (0..$num_indeces) {
# update the index number
$additional =~ s/(INDEX\s*=>\s*)\d+,/$1 $i,/;
$basic =~ s/(
(\),\s*) # capture sequences of ),
+ # as many as possible
\)\s* # end with ) without a ,
} )/$additional $1/sx; # replace with the additional data
Here's the actual question
The problem here is that the code comes out poorly indented. I'd like to run the resulting $basic through a prettifier like this:
&prettify($basic, "perl");
Which would format it nicely according to Perl's best practices. Is there any good way to do this?
PerlTidy makes your code not only tidy, but really beautiful. You can easily tweak it according to your local coding standards.
I have used this:
use Perl::Tidy;
sub Format {
my $source = shift;
my $result;
Perl::Tidy::perltidy(
source => \$source,
destination => \$result,
argv => [qw(-pbp -nst)]
);
return $result;
}