I am trying to pass aliases and fields in them to a pig macro:
define mymac (a1, f, a2) returns void {
foreach (join $a1 on $f, $a2 on field) generate
$a1::$f as $f, $a2::field as field;
};
I get an error
Unexpected character '$'
on the second $ in $a1::$f when I call the macro as
mymac(x,foo,y);
I also tried
define mymac (a1, f, af, a2) returns void {
foreach (join $a1 on $f, $a2 on field) generate
$af as $f, $a2::field as field;
};
mymac(x,foo,x::foo,y);
and got even more cryptic error
org.apache.pig.PigServer - exception during parsing: Error during parsing. Pig script failed to parse: at expanding macro
So, what do I do? How do I combine alias with a field in a macro?
You need to put field names in '' when calling the macro, for example mymac(x,'foo','x::foo',y);. I have tested the 2nd approach you mentioned and it works.
Related
I am not able to understand if I uncommented the return line then output will be "CODE" else "SCALAR".. why it is so?
use strict;
sub test {
my ($abc,$grab) = #_;
print 'i m here';
print $abc;
## return []; if uncommented then output will be "REF" else "SCALAR"
}
my $pass= "i m good";
my %my_hash = ();
$my_hash{'fun'} = \&test($pass);
print ref($my_hash{'fun'})
Without implicit return, a subroutine returns the value of the last expression evaluated. print returns 1 on success, i.e. a scalar.
\&test($pass) is the same as \ test($pass), i.e. it evaluates to the reference to the value returned by the sub test. If it returns 1 from print, you'll get SCALAR, if it returns [], you'll get REF, because you have a reference to a reference to an array. You can verify it by dereferencing it, too:
print ${ $my_hash{fun} }, ': ', ref $my_hash{fun}, "\n";
You are not taking a reference to a function.
When you write:
\&test($pass);
that is a function invocation (you have an argument list).
Therefore, the function test is invoked with the argument $pass and then you take a reference to the returned value (you should not prefix function invocations with & unless you know and specifically desire what it does).
If you want a reference to test, you should use
$my_hash{'fun'} = \&test; ### (1)
If you want a reference to a function that invokes test with the currently in scope argument $pass, you should use:
$my_hash{'fun'} = sub { test($pass) }; ### (2)
Note that the latter will create a closure over the currently in scope variable $pass. To invoke (1), you use $my_hash{fun}->($some_arg). To invoke (2), you use $my_hash{fun}->().
Probably a super simple problem, getting the super helpful error message when trying to loop over a nested associative array:
Global symbol "%t" requires explicit package name
Code is:
use strict;
use Data::Dumper;
my %test;
$test{"1"}{"stuff"} = "foo";
$test{"2"}{"stuff"} = "bar";
Then dumping the second level arrays is fine:
foreach my $t (values %test){
print Dumper($t);
}
Which gives:
$VAR1 = {
'stuff' => 'foo'
};
$VAR1 = {
'stuff' => 'bar'
};
But as soon as i try accessing the third level strings, i get the above error, no matter what combination of $'s, #'s, %'s, qoutes or brackets i use.
foreach my $t (values %test){
print Dumper($t{"stuff"});
}
You need to do $t->{"stuff"}. $t is a hash reference (not an actual hash) so you need to use the dereferencing operator.
What you get are hash references, and as such, you'll have to dereference them:
foreach my $t (values %test){
print Dumper($t->{'stuff'})
}
In perl %t, #t and $t (and &t, but that's special in most cases) are all different variable names. For element access you use the corresponding paren type to say which variable you mean:
$t{boo} # accesses %t
$t[800] # accesses #t
I have an object ($p), and in the initialization I have $this->{list} = [];
Later, I fill up the array with objects of another class (q), and can access them as #{$self{list}} in another subroutine in class [p]. I am trying to sort this array, as
my #slist = sort $self->point_sort, #{$self->{list}};
point_sort is defined as a subroutine in class p, and I am getting
Can't call method "getQval" on an undefined value at p.pm line 64
getQval is a subroutine defined in object q, instances of which populate the {list}. I am trying to do
my $v1 = $a->getQval;
my $v2 = $b->getQval;
in the subroutine point_sort. Any suggestions? TIA.
Edit:
Changed the call to
my #slist = sort { $self->point_sort ($a,$b) } #{$self->{list}};
In point_sort, I have now
my ($c, $d) = #_;
my $val1 = $c->getVarVal;
The error:
Can't locate object method "getVarVal" via package "packageP" at ...
I think it has something to do with packages, not sure what it is. It is looking in package p, whereas I want it to look at package q.
Edit:
I did a print on $c above - perl thinks it is an object of class p - a hashtable
You're not actually using $self->point_sort as a comparison function here. It's being called immediately (with no arguments and before $a and $b are set, hence the error), and its return value (if it got that far) would then be used as the comparator.
The easiest fix is to pass $a and $b explicitly:
my #slist = sort { $self->point_sort($a, $b) } #{$self->{list}};
Then receive them as regular arguments in point_sort.
The syntax of sort are:
sort SUBNAME LIST # Sort the list using named function as the comparison function
sort BLOCK LIST # Sort the list using the block as the comparison function
sort LIST # Sort the list using the default comparison function.
You want $self->point_sort to be used as the comparison function, but you used the third syntax rather than one of the two that allows you to specify a comparison function.
Perhaps you want
sort { $self->point_sort($a, $b) } #{ $self->{list} }
is clear n
I am trying to convert a line a, f_1(b, c, f_2(d, e)) to a line with lisp style function call
a (f_1 b c (f_2 d e)) using Text::Balanced subroutines:
A function call is in the form f(arglist), arglist can have one or many function calls within it with heirarchical calls too;
The way i tried -
my $text = q|a, f_1(a, b, f_2(c, d))|;
my ($match, $remainder) = extract_bracketed($text); # defaults to '()'
# $match is not containing the text i want which is : a, b, f_2(c,d) because "(" is preceded by a string;
my ($d_match, $d_remainder) = extract_delimited($remainder,",");
# $d_match doesnt contain the the first string
# planning to use remainder texts from the bracketed and delimited operations in a loop to translate.
Tried even the sub extract_tagged with start tag as /^[\w_0-9]+\(/ and end tag as /\)/, but doesn't work there too.
Parse::RecDescent is difficult to understand and put to use in a short time.
All that seems to be necessary to transform to the LISP style is to remove the commas and move each opening parenthesis to before the function names that precedes it.
This program works by tokenizing the string into identifiers /\w+/ or parentheses /[()]/ and storing the list in array #tokens. This array is then scanned, and wherever an identifier is followed by an opening parenthesis the two are switched over.
use strict;
use warnings;
my $str = 'a, f_1(b, c, f_2(d, e))';
my #tokens = $str =~ /\w+|[()]/g;
for my $i (0 .. $#tokens-1) {
#tokens[$i,$i+1] = #tokens[$i+1,$i] if "#tokens[$i,$i+1]" =~ /\w \(/;
}
print "#tokens\n";
output
a ( f_1 b c ( f_2 d e ) )
I'm using a config file (in YAML) to define types that are used later on to validate other config values required for my app:
---
action: >
use List::MoreUtils;
my $value = $_;
any { $value eq $_ } qw(fatal keep merge non-fatal replace);
dir : return defined $_ ? -d $_ : -1;
file : return defined $_ ? -f $_ : -1;
string: 1;
---
config-element:
value: foo
type : file
etc ...
The idea is to eval each type definition, throw them into a hash and then call to validate configuration data (the following is schematic for easy comprehensibility):
#throw sub refs into hash
my %type_sub;
foreach my $key (keys %$type_def_ref) {
my $sub_str = "sub {$type_def_ref->{$key}}";
$type_sub{$key} = eval $sub_str;
}
#validate (myfile is a real file in the cwd)
print $type_sub{file}->('myfile'),"\n";
print $type_sub{action}->('fatal'), "\n";
The problem is that the subroutines in %type_sub don't seem to accept parameters. In the above case, the first print statement outputs -1 while the second outputs:
Use of uninitialized value $value in string eq at (eval 15) line 1.
Use of uninitialized value $_ in string eq at (eval 15) line 1.
Can't call method "any" without a package or object reference at
(eval 15) line 1.
which is not at all what I expect, yet the subroutines are being called.
What am I doing wrong?
EDIT:
I was being sloppy and everything works fine now. Thanks to Friedo.
Don't write code in configuration. Create a library with the code and simply configure which subroutine name you want to use. That should save you an huge amount of work translating strings to code and managing the process. It also saves you a ton of time tracking down problems when someone adjusts the configuration and introduces a syntax error.
I talk about this extensively in the "Configuration" chapter in Mastering Perl, as well as the chapters on dynamic subroutines.
Code doesn't belong in configuration. Say that until you believe it.
Your subroutine parameters will be in the #_ array, not $_. To get the first parameter, look in $_[0] or do my $foo = shift;. (shift operates on #_ by default.)
As for any, I believe the problem is due to any not being able to load its prototype at runtime (subroutine prototypes can only be called at compile-time.) You may need to use explicit parens and an explicit subroutine reference:
any( sub { $value eq $_ }, qw(fatal keep merge non-fatal replace) );