perl - File::Basename->fileparse returns "File::Basename" - perl

For some reason my code is doing this wierd thing where fileparse only prints (literally) File::Basename
use strict;
use warnings 'all';
use File::Basename;
...
my $fileName = File::Basename->fileparse($filePath);
print("$filePath\n");
print("$fileName\n");
And output is:
a/b/c/d.bin
File::Basename
What did I do wrong?

The fileparse is not a method; it is a function. This function is exported by default, so you actually want to do
use File::Basename;
my $fileName = fileparse($filePath);
You have used is as a method call. Here File::Basename->fileparse($filePath) is equivalent to
fileparse("File::Basename", $filePath)
because in a method invocation, the invocant (usually an object; here the package name) becomes the first argument. This is wrong, as it treats "File::Basename" as the path to parse, and the following arguments as a list of valid suffixes.
If you want to use the fileparse function without exporting it to your namespace, you could
use File::Basename (); # note empty parens that supress the import
File::Basename::fileparse(...); # use fully qualified name

Related

Can't find exported subroutine in Perl

I have a module called Utilities.pm. It exports a subroutine called dummy_method.
package Foo::Utilities;
use strict;
use vars qw($VERSION #ISA #EXPORT #EXPORT_OK);
require Exporter;
#ISA = qw(Exporter);
#EXPORT = qw(dummy_method);
sub dummy_method {
# do things
}
I have a Perl script that uses the dummy_method subroutine:
use strict;
use warnings;
use Foo::Utilities qw('dummy_method');
my $foo = Foo::Utilities::dummy_method("foo");
print("$foo\n");
Executing that script throws an export error:
"dummy_method" is not exported by the Foo::Utilities module
Can't continue after import errors at /home/me/foo.pl line 3
BEGIN failed--compilation aborted at /home/me/foo.pl line 3.
I'm confused because I am explicitly exporting that subroutine with #EXPORT = qw(dummy_method);. How do I use dummy_method in another script?
Some people are obsessed with using qw for import lists, even if there is only one element. I think this makes others think this is a requirement, when it is just one way of making a list.
use Foo::Utilities qw('dummy_method');
says to import a method called 'dummy_method', not dummy_method, just like print qw('dummy_method') prints 'dummy_method', not dummy_method.
Try instead:
use Foo::Utilities 'dummy_method';
or, if you must:
use Foo::Utilities qw(dummy_method);
Though since you are exporting it by default, you could just do:
use Foo::Utilities;
Or, since you are calling it as Foo::Utilities::dummy_method, not even export it by default:
use Foo::Utilities ();
The code you have written, with the modification suggested by ysth, works correctly. The only remaining possibility that I can think of is that you have named or located your module incorrectly
use Foo::Utilities 'dummy_method'
will load a file called Foo/Utilities.pm where the Foo directory is in one of the paths in your #INC. It is a common error to omit the initial directories that must be in the path to the module, and you do say that your module is called just Utilities.pm
There must also be a Foo/Utilities.pm that behaves differently, otherwise the use statement would fail even to find the file
I have written your code in more modern Perl. This also works
Foo/Utilities.pm
package Foo::Utilities;
use strict;
use warnings 'all';
use Exporter 'import';
our #EXPORT = qw(dummy_method);
sub dummy_method {
print "dummy_method()\n";
'do things';
}
main.pl
use strict;
use warnings;
use Foo::Utilities 'dummy_method';
my $foo = dummy_method('foo');
print("$foo\n");
There is no need for using vars any more, and it has been better to import the import method from Exporter (instead of inheriting it) since Perl v5.8.7

Perl variable that takes different values

I need to upload files with different names in the same format like this:
file_name_yyyy-mm-dd_code.txt
How can I write it in Perl?
Right now I can do this:
#!/usr/bin/perl
use warnings;
use strict;
use Config::Simple;
use File::Basename;
use Getopt::Long;
use Pod::Usage;
use Net::Google::Drive::Simple;
use POSIX 'strftime';
use Storable;
# my $date = strftime '%m-%d-%Y', localtime;
# for testing purpose, use specific date
my $date = '2018-07-16';
my $code;
# $code will change
my $gd = Net::Google::Drive::Simple->new();
my ($p1, $folder) = $gd->children("Test");
$folder = <folder id>;
$gd->file_upload("testfile_${date}_${code}.txt", $folder);
and it uploads files with this format in the same folder as the perl file:
file_name_yyyy-mm-dd.txt
but it doesn't upload files with this format (which I need to do): file_name_yyyy-mm-dd_somecode.txt
For example:
file_name_2018-07-16_code1.txt or file_name_2018-07-16_code2.txt
I have absolutely no experience with Perl so I don't even know where to look.
The problem is that, in
"file_name_$date_$code.txt"
$date_ is a valid variable name, but not the one you want. Delineate the identifiers with braces, like this
"file_name_${date}_${code}.txt"
Or you can use sprintf, like this
sprintf 'file_name_%s_%s.txt', $date, $code
which produces the same result
You still haven't been very clear in describing what you want, but I wonder if you're looking for glob().
for my $file (glob("file_name_${date}_*.txt")) {
$gd->file_upload($file, $folder);
}
You can adjust the string you pass to glob() so it gives you whatever files your really want.

Program unexpectedly reports "Use of uninitialized value"

This is with regard to my previous question
Hold Subroutine response and set to variable in Perl
The statement Module::thesub("hello")
worked in Module.pm but fails if I move it to main.pl
main.pl
#!/usr/bin/perl
use strict;
use warnings;
use Module;
Module::thesub("hello");
Module.pm
#!/usr/bin/perl
use strict;
use warnings;
package Module;
sub thesub {
state $stored;
$stored = shift if #_;
return $stored;
}
my $testvar = thesub();
print $testvar;
1;
I get this error
Use of uninitialized value $testvar
which means the variable $testvar has no value.
How can I fix this?
Statements in a module run when the module is loaded, at use Module;. At that time thesub() still wasn't called with an argument and $stored in it is undefined. So that is what $testvar gets when it's assigned and the warning is emitted when it's printed.
The $testvar can be used in main
use strict;
use warnings;
use Module;
Module::thesub("hello");
my $testvar = Module::thesub();
even though I am not sure from the question what the purpose of this is.
Remove the assignment and print of $testvar from the module. Note that you'll also need use feature 'state'; at the beginning of the module, to enable the feature pragma.
A few comments on the module you show
No need for #!/usr/bin/perl, as a module is generally not meant to be run
The package Module; is commonly the first line
While what you have works, consider making symbols from the module available to the calling code, so that it can import them and simply say thesub(). A common way is
package Module;
use warnings;
use strict;
use Exporter qw(import);
our #EXPORT_OK = qw(thesub);
sub thesub { ... }
1;
and in the main
use Module qw(thesub);
thesub("hello");
See Exporter for starters and search SO, where there are great many posts on this.

what does perl use Cwd qw(); mean?

What does
use Cwd qw();
mean in perl?
I know qw gives quotes to each elements inside ()
But what about this case?
The qw() is a fancy way of writing an empty list. Doing () would be two characters shorter.
Passing an empty list to use is important to avoid importing. From the use documentation:
If you do not want to call the package's import method (for instance, to stop your namespace from being altered), explicitly supply the empty list
E.g. by default, the Cwd module exports getcwd. This doesn't happen if we give it the empty list:
use strict;
use Cwd;
print "I am here: ", getcwd, "\n";
works, but
use strict;
use Cwd ();
print "I am here: ", getcwd, "\n";
aborts compilation with Bareword "getcwd" not allowed while "strict subs" in use.
I believe that since qw() after use Module is for importing subroutines, when left empty it simply loads the module but doesn't import any subroutines into the namespace.
For example this throws an error since getcwd is not imported:
#!/usr/bin/perl
use warnings;
use strict;
use Cwd qw();
my $dir=getcwd;
But I'm not sure if this is the answer you was looking for..!
Usually it "imports" commands so you don't have to create an object and call the function on them.
Example (from perlmonks):
#without qw
use CGI;
my $q = CGI->new();
my $x = $q->param('x');
#with qw
use CGI qw/:standard/;
my $x = param("x")
Source: http://www.perlmonks.org/?node_id=1701
Most modules have import groups like :all or :standard also.

Why does strict complain about variables from a required other script?

This is usex.pl:
#use strict;
require 'x.pl';
print $x;
Here is x.pl:
#use strict;
our $x = 99;
1;
It runs fine as shown. If I uncomment the line to use strict in usesx.pl, I get
Global symbol "$x" requires explicit package name
The use or not of strict in x.pl seems not to matter (unless I drop the 'our' keyword, but I'm not interested in that.)
I'm fairly new to Perl. Why does strict make $x not visible in the main script, and what is the normal solution to this?
Two reasons.
The error happens at compile-time, before require is ever executed. That's easy to fix using BEGIN.
our is lexically-scoped, and it's in a different lexical scope (file or block) than the print, so it's no longer in effect.
The whole approach is fundamentally bad. Here's one better way:
package MyConfig;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT = qw( $x );
our $x = 123;
1;
use strict;
use warnings;
use MyConfig;
print "$x\n";
Hehe, our is not easy to grok as it mixes the concepts of global and lexical scope. What it does is exempting a global variable from the strict 'vars' pragma and allowing unqualified access to it within its scope, which is the enclosing block, or the end of the current file, whatever comes first. Read the full (but brief) story in the manual, which is also accessible by saying perldoc -f our on the command line.
As for your script, you can verify the truthfulness of the words in the manual by modifying the variable accessor to use a package-qualified name:
use strict;
require 'x.pl';
print $main::x;