Is there a vim plugin that makes Moose attributes show up in Tag_List? - perl

I am editing packages that use Moose, and I was wondering if there were a plugin for making Moose attributes show up in the Tag List.
For example, in the following code, the attribute options does not show up in Tag_List, but print_out_site does:
use Moose;
use MooseX::AttributeHelpers;
...
has 'options' => (
metaclass => 'Collection::Hash',
isa => 'HashRef[Str]',
is => 'ro',
provides => {
exists => 'exists',
get => 'get',
set => 'set',
},
);
...
sub print_out_site {
my $self = shift;
my $key = shift;
$self->fasta_out_fh->print(">", $key, "\n");
$self->fasta_out_fh->print($self->sites->{$key}, "\n");
}

Add the line
--regex-perl=/has '(.*)' => \(/\1/a,attribute,moose attributes/
to ~/.ctags and it should show up. You may need to tweak the regular expression to avoid spurious matches in other files or to accommodate different formatting for the attribute declarations in other files.
This extends ctags so that it detects another type of tag based on the regular expression when parsing perl files.
Then you need to tell the taglist plugin about the new tag type by adding this to your vimrc file:
let tlist_perl_settings='perl;c:constant;l:label;p:package;s:subroutine;a:attribute'

Geoff, I tried your code but it didn't work for me with the syntax you use. Could this be a version problem? I'm using exuberant ctags version 5.8.
I also modified the regex a bit because the quotes are optional and you might want to allow spaces (but nothing else) preceeding the 'has' keyword.
Here is what worked for me.
I created a $HOME/.ctags file (didn't have one yet, otherwise just add to it) with the following line:
--regex-perl=/^\s*has\s+['"]?([0-9a-zA-Z_]+)/\1/a,attribute/
Then added the line in .vimrc as you suggested
let tlist_perl_settings='perl;c:constant;l:label;p:package;s:subroutine;a:attribute'
Now it lists my attributes in Moose modules.
In addition, I find it useful to also have information about the parent class, roles and used modules show up in the taglist, so here is my complete $HOME/.ctags file:
--regex-perl=/^\s*has\s+['"]?([0-9a-zA-Z_]+)/\1/a,attribute/
--regex-perl=/^\s*with\s+(['"])(.+)\1/\2/r,role/
--regex-perl=/^\s*extends\s+(['"])(.+)\1/\2/e,extends/
--regex-perl=/^\s*use\s+([^ ;]+)/\1/u,use/
and this is what I have in .vimrc (you can change the order of tags in the taglist simply by changing the order in the tlist_par_settings):
let tlist_perl_settings='perl;u:use;p:package;r:role;e:extends;c:constant;a:attribute;s:subroutine;l:label'
let Tlist_Show_One_File = 1
Because of the additional content I find it useful to use the Tlist_Show_One_File option, which forces the taglist to show only the tags of the currently selected file.
To temporarily hide some of the tags you can always move the cursor to the tag name and hit "zc" (and "zo" to reopen) the fold.

Related

Zend Translation and View Scripts

Form labels and error messages are translated automatically. But strings in the view scripts are not. I have to use $this->translate("text to transfer"); in each and every phtml files.I don't want to use this $this->translate("text to transfer"); method.How can I automatically translate view scripts as in the case of forms.My code is
protected function _initTranslation() {
$langNamespace = new Zend_Session_Namespace('language_sess');
$lang = $langNamespace->lang;
$registry = Zend_Registry::getInstance();
$tr = new Zend_Translate(
array(
'adapter' => 'array',
'content' => APPLICATION_PATH . "/languages/$lang/$lang.php",
'locale' => "ar",
'scan' => Zend_Translate::LOCALE_DIRECTORY
)
);
$registry->set('Zend_Translate', $tr);
return $registry;
}
OK, to make it clear, we need to understand few things:
Zend_Translate is supposed to translate only part of your site, not related to content. That is menu items, section names, titles, etc. You might have exceptions from that rule, especially if you use Zend_Translate_Adapter_Gettext.
For content, you should use something else to provide your translation. Usually, for example if it is a static article, you get that data from DB, not the language file.
In your case, if you are ok with a little bit "machine" translation, you should use google translate engine for sites
https://translate.google.com/manager/website/
As for dropping $this->translate("text to transfer"); part, you can try to translate all data in controller, but that is rather bad advice, I would advice you to do something else. When you pass your data to view, you can loop through it and make translation for each and everystring inside:
foreach($data as $key => $string) {
$data[$key] = $tr->translate($string);
}
or something like that. This is bad approach because of few reasons. But most important is that you are not dividing your presentation from your logic, and that is why the best place for this is View.
So my summary:
Try to keep using $this->translate()
If that really does not work for you, try to use google translate engine
If that is also not good for you, try Zend_Translate_Adapter_Gettext.
Please, do not use language files for your content.

how to include pl files in batch pod conversion?

I use the module Pod::Simple::HTMLBatch to create the documentation of the software which i write.
The script used is taken from the documentation:
use Pod::Simple::HTMLBatch;
my $batchconv = Pod::Simple::HTMLBatch->new;
$batchconv->some_option( some_value );
$batchconv->some_other_option( some_other_value );
$batchconv->batch_convert( \#search_dirs, $output_dir );
The module just considers pm files. How is it possible to tell the module to create the documentation also for pl files?
I did not find an option in the documentation.
Pod::Simple::Search looks for files matching this regular expression:
m/^[-_a-zA-Z0-9]+\.(?:pod|pm|plx?)\z/is
Which should include any *.pl files. If it's not working for you, try turning on its laborious flag, which is somewhat more forgiving about file names, testing like so:
m/\.(pod|pm|plx?)\z/i || -x _ and -T _
The only way to enable the laborious search with Pod::Simple::HTMLBatch is to create a search subclass, like I did for Pod::Site:
package My::Pod::Search;
use parent 'Pod::Simple::Search';
sub new {
my $self = shift->SUPER::new(#_);
$self->laborious(1);
return $self;
}
Then tell HTMLBatch to use your subclass:
$batchconv->search_class('My::Pod::Search');
$batchconv->batch_convert( \#search_dirs, $output_dir );
Might be nice to update HTMLBatch to accept a search object in its constructor to eliminate this silly workaround, though.

perl Template::Alloy with Catalyst not displaying properly

From my understanding, Template::Alloy::TT should be interchangable with Template Toolkit, however I am having some issues trying to swap one out with the other. Here is the config for my view file:
package maypp::View::HTML;
use strict;
use base 'Catalyst::View::TT';
__PACKAGE__->config({
INCLUDE_PATH => [
myapp->path_to( 'root', 'src' ),
myapp->path_to( 'root', 'lib' ),
],
PRE_PROCESS => 'config/main',
WRAPPER => 'site/wrapper',
ERROR => 'error.html',
TIMER => 0,
render_die => 1,
COMPILE_DIR => '/tmp/compiled_templates', #caches compiled templates
STAT_TTL => 1, #how long to cache templates before seeing if there are any changes
TEMPLATE_EXTENSION => '.html',
});
I thought that changing Catalyst::View::TT to Catalyst::View::TT::Alloy would be all I had to do to begin using Template::Alloy (this has been the procedure for me before). However, whenever I change this I do not get the correct output. Below is my wrapper file:
[% IF template.name.match('\.(css|js|txt)');
debug("Passing page through as text: $template.name");
content;
ELSE;
debug("Applying HTML page layout wrappers to $template.name\n");
content WRAPPER "$host/site/html" + "$host/site/layout";
END;
-%]
site/html will be processed, however site/layout does not go into site/html like it does when I just use regular Template Toolkit (typically site/layout goes into [% content %] in site/html). Is there something I'm doing wrong here? I'd like to use Template::Alloy for the speed increase, but that's only if I can get it working :) Thanks for the help!
Just taking a stab in the dark, I'd say TT::Alloy might not support the multiple WRAPPER + directive. In quite a few years of TT development, I've never used it, but that's not to say it isn't popular somewhere. My experience is an app might switch between wrapper A and wrapper B based on context, but wrapping B within A? Not so much.
If you're always going to need to do that though, why not put the second WRAPPER directive inside $host/site/html.tt ?

Perl Moose - Loading values from configuration file etc

I'm new to using Moose, but I was wondering how I can load values from a configuration file and then exposing those values as properties of my 'config' object where the attributes are the configuration names in the configuration file.
For example,
The configuration file might contain:
server:mozilla.org
protocol:HTTP
So I'd like my config object to have a 'server' attribute with a value of 'mozilla.org' and a protocol attribute with a value of 'HTTP'.
Right now my understanding is that I have to explicitly name the attributes with a
has 'server' => ( is => 'ro', isa => 'Str', default => 'mozilla.org' );
type of entry in my Config.pm file.
How do I dynamically create these so that the configuration file can change without having me rewrite the Config.pm each time that it does?
TIA!
That's such an obvious idea, it has been implemented already several times.
MooseX::ConfigFromFile
MooseX::Configuration
MooseX::SimpleConfig
Also see
MooseX::App
MooseX::App::Cmd
MooseX::Runnable
which map command-line options to attributes, which you most likely also want.
This isn't quite what you asked for, but you can get a config attribute that's a hash reference by using BUILDARGS to populate the config info at the time of creation. Assuming that the lines of your config file consist of key-value pairs separated by :, something like this should work:
package My::Module;
use Moose;
has 'config'=>(isa=>'HashRef[Str]',is=>'rw',required=>1);
around BUILDARGS=>sub
{
my $orig=shift;
my $class=shift;
my $args=shift; #other arguments passed in (if any).
my %config_hash=();
open(my $read,"<","config_file") or confess $!;
while(<$read>)
{
chomp;
my #array=split /:/;
$config_hash{$array[0]}=$array[1];
}
close($read);
$args->{config}=\%config_hash;
return $class->$orig($args);
};
no Moose;
1;
With minimal effort, it's also easy to have additional attributes to specify the name and path of the config file along with the delimiter. These could be accessed inside of BUILDARGS as, eg, $args->{config_file} and $args->{config_delimiter}.

Is there a tool for extracting all variable, module, and function names from a Perl module file?

My apologies if this is a duplicate; I may not know the proper terms to search for.
I am tasked with analyzing a Perl module file (.pm) that is a fragment of a larger application. Is there a tool, app, or script that will simply go through the code and pull out all the variable names, module names, and function calls? Even better would be something that would identify whether it was declared within this file or is something external.
Does such a tool exist? I only get the one file, so this isn't something I can execute -- just some basic static analysis I guess.
Check out the new, but well recommended Class::Sniff.
From the docs:
use Class::Sniff;
my $sniff = Class::Sniff->new({class => 'Some::class'});
my $num_methods = $sniff->methods;
my $num_classes = $sniff->classes;
my #methods = $sniff->methods;
my #classes = $sniff->classes;
{
my $graph = $sniff->graph; # Graph::Easy
my $graphviz = $graph->as_graphviz();
open my $DOT, '|dot -Tpng -o graph.png' or die("Cannot open pipe to dot: $!");
print $DOT $graphviz;
}
print $sniff->to_string;
my #unreachable = $sniff->unreachable;
foreach my $method (#unreachable) {
print "$method\n";
}
This will get you most of the way there. Some variables, depending on scope, may not be available.
If I understand correctly, you are looking for a tool to go through Perl source code. I am going to suggest PPI.
Here is an example cobbled up from the docs:
#!/usr/bin/perl
use strict;
use warnings;
use PPI::Document;
use HTML::Template;
my $Module = PPI::Document->new( $INC{'HTML/Template.pm'} );
my $sub_nodes = $Module->find(
sub { $_[1]->isa('PPI::Statement::Sub') and $_[1]->name }
);
my #sub_names = map { $_->name } #$sub_nodes;
use Data::Dumper;
print Dumper \#sub_names;
Note that, this will output:
...
'new',
'new',
'new',
'output',
'new',
'new',
'new',
'new',
'new',
...
because multiple classes are defined in HTML/Template.pm. Clearly, a less naive approach would work with the PDOM tree in a hierarchical way.
Another CPAN tools available is Class::Inspector
use Class::Inspector;
# Is a class installed and/or loaded
Class::Inspector->installed( 'Foo::Class' );
Class::Inspector->loaded( 'Foo::Class' );
# Filename related information
Class::Inspector->filename( 'Foo::Class' );
Class::Inspector->resolved_filename( 'Foo::Class' );
# Get subroutine related information
Class::Inspector->functions( 'Foo::Class' );
Class::Inspector->function_refs( 'Foo::Class' );
Class::Inspector->function_exists( 'Foo::Class', 'bar' );
Class::Inspector->methods( 'Foo::Class', 'full', 'public' );
# Find all loaded subclasses or something
Class::Inspector->subclasses( 'Foo::Class' );
This will give you similar results to Class::Sniff; you may still have to do some processing on your own.
There are better answers to this question, but they aren't getting posted, so I'll claim the fastest gun in the West and go ahead and post a 'quick-fix'.
Such a tool exists, in fact, and is built into Perl. You can access the symbol table for any namespace by using a special hash variable. To access the main namespace (the default one):
for(keys %main::) { # alternatively %::
print "$_\n";
}
If your package is named My/Package.pm, and is thus in the namespace My::Package, you would change %main:: to %My::Package:: to achieve the same effect. See the perldoc perlmod entry on symbol tables - they explain it, and they list a few alternatives that may be better, or at least get you started on finding the right module for the job (that's the Perl motto - There's More Than One Module To Do It).
If you want to do it without executing any code that you are analyzing, it's fairly easy to do this with PPI. Check out my Module::Use::Extract; it's a short bit of code shows you how to extract any sort of element you want from PPI's PerlDOM.
If you want to do it with code that you have already compiled, the other suggestions in the answers are better.
I found a pretty good answer to what I was looking for in this column by Randal Schwartz. He demonstrated using the B::Xref module to extract exactly the information I was looking for. Just replacing the evaluated one-liner he used with the module's filename worked like a champ, and apparently B::Xref comes with ActiveState Perl, so I didn't need any additional modules.
perl -MO=Xref module.pm