I've just upgraded an old project to Rails 4 and I've just realized that it has upgrade the schema.rb using the new-style hash syntax. I suppose Rails is gonna use this syntax for all its generators.
How can I, friendly, say to Rails that I prefer the old-style syntax for hashes?
schema.rb is created by rake db:migrate command. As per my knowledge, it will be hard to suggest the old-style syntax for hashes to Rails. BUT nothing is impossible, you can play around with rails/activerecord/lib/active_record/schema_dumper.rb file. The only problem is when you upgrade the rails gem next time it will override.
This old-style syntax to new-style syntax for hashes was done in Dump schema using new style hash commit.
I know this is not exactly an answer to your question, but it might help nevertheless.
If you use vim, this will allow you to toggle between the old & new syntax (source):
function! s:RubyHashSyntaxToggle() range
if join(getline(a:firstline, a:lastline)) =~# '=>'
silent! execute a:firstline . ',' . a:lastline . 's/[^{,]*[{,]\?\zs:\([^: ]\+\)\s*=>/\1:/g'
else
silent! execute a:firstline . ',' . a:lastline . 's/[^{,]*[{,]\?\zs\([^: ]\+\):/:\1 =>/g'
endif
endfunction
command! -bar -range RubyHashSyntaxToggle <line1>,<line2>call s:RubyHashSyntaxToggle()
noremap <Leader>rh :RubyHashSyntaxToggle<CR>
At max it will take you 3 keystrokes to get the schema the way you want. It is not automatic, but as a counterpart it will work on any file, not just on the schema.
You could invoke the substitution every time you save a file (I do that to remove extra spaces at the ends of lines).
And if you don't use vim, these regexes probably be adapted to other editors.
Related
Hello I would like to master VIM as my primary IDE. I know there are many plugins etc. but I have one question: Is possible for VIM to understand the particular language (in case I wont plugin for my language) in which code is written? I mean some rules that I can define and then use e.g. for auto-completion, refactoring, folding etc. For example consider following two perl codes in which I want refactor variables. In first example there are variables with same names but one is scalar and another are array and hash, in second example same name of variable as was defined before was used in another scope (loop etc.). Thus refactoring using simple text matching is not elegant way I thing:
1st example:
my #same_name;
my $same_name; # How to refactor this variable without affecting all other variables?
my %same_name;
$same_name[0] = 5;
$same_name{"key"} = 5;
$same_name = 5;
2nd example:
my #array;
my $already_existing_variable; # How to refactor this variable
foreach my $already_existing_variable (#array){
print $already_existing_variable; # Without affecting this variable
}
print $already_existing_variable; # Variable that should be also refactorized
Or how can I achieve that when I type $arr {and hit TAB here} it will automatically extend to $array[ ? For this VIM must to know that when I prepend $ before variable which was declared with # I want to access array elements.
Another example would be: how to fold code using e.g. BEGIN and END keywords? Those was jut trivial examples but I think you get the point. I think it is similar task to write own compiler or something. Thank you.
I'm using vim with my perl scripts almost all days:
Rename variables
App::EditorTools gives you the function to rename variables like Padre.
install App::EditorTool $ cpanm App::EditorTools
install vim plugin $ editortools install-vim
move cursor on the variable name in vim.
type \pL
I'm not sure why it parses wrong scope in the 2nd example, but you can temporarily wrap the foreach brock with lambda and rename variables inside the code block first.
sub {
foreach my $already_existing_variable (#array){
print $already_existing_variable; # Without affecting this variable
}
}->();
Reformat script indent
Perl::Tidy has perltidy command line tool to format your script.
install Perl::Tidy $ cpanm Perl::Tidy
create ~/.perltidyrc according to your taste. like folowing:
-pbp
-pt=2
-sbt=2
-bt=2
-bbt=2
-ce
-nbbc
set equalprg to perltidy in your ~/.vimrc
au FileType perl setl ep=perltidy
type gg=G in your script.
Syntax Check
vim's built-in compiler plugin for perl does very well.
set :compilerto perl in your ~/.vimrc
au FileType perl :compiler perl
type :make in normal mode
type :copen to open up quickfix window
if you don't want warnings in your quickfix list, you can unset the flag for it.
let g:perl_compiler_force_warnings = 0
$PERL5LIB is also important while invoking :make, you can give specific directories in it.
let &l:path = './lib,./blib/lib,./blib/arch,' . &l:path
let $PERL5LIB = substitute(&l:path, ',', ':', 'g')
Completions
vim has nice completion tool out of the box. see :help comple-generic
type $ar in insert mode and press CTRL-N
You might be interested in ctags too.
I can already tell something is wrong when the first sentence is "Hello I would like to master VIM as my primary IDE."
Vim is not an IDE. Vim is a text editor. (You can use google to find out more)
If you feel that the features an IDE provides (refactoring, smarter auto-completion...) are more important than the features that vim provides (fast movement, never take your hands off the home row, programmable editor...) then you should use an IDE, or an IDE with a vim plugin. Usually, if you want to mix IDE features with vim features, you do it with a plugin to the IDE, not the other way around (there are some exceptions such as eclim).
As a Perl beginner I am sometimes getting compilation errors and have to search a lot to find it. In the end it is just a missing semicolon at the end of a line. Some syntax errors with missing semicolon are checked by Perl but not in general. Is there a way to get this check?
edit:
I know about Perl::Critic but can't use it atm. And I don't know if it checks for missing semicolon in general.
Because semicolons actually mean something in Perl and aren't just there for decoration, it's not possible for any tool (even the Perl interpreter itself) to know in every case whether you actually meant to leave off the semi-colon or not. Thus, there's no general-case answer to your question; you'll just need to go through your code and make sure it's correct.
As mentioned in my comments, there are various tricks you can try with your editor to expedite the process of finding potentially-incorrect lines; you must, however, either examine and fix these by hand or risk introducing new problems.
The syntax check is perl -c, but that's no different than attempting to run the program outright. Due to its flexible/undecidable syntax, one cannot generally do what you want. That's the downside of comfort and expressiveness.
Upgrade to the latest stable Perl, the parser's error messages got better/more exact over the last years and will correctly recognise many circumstances of a missing semicolon.
Rule of thumb that works for many parsers/other languages: if the error makes no sense, look a couple of lines before.
use diagnostics; usually gives you a nice hint, same as use warnings;. Try to keep a consistent coding style, check perlstyle.
Also you can use Perl::Critic online.
Also as general advice learn how to use packages and modules, try to group code into subs and study the syntax of arrays, lists and hashes. A common mistake is forgetting the ; after an anonymous hashref assignment:
my $hashref = { a => 5, b => 10};
In Perl, you call modules using :: as path separator. So, if you have a module on site/lib/GD/Image.pm, you call use GD::Image.
However, long time ago I found out that you can also call use GD'Image and things like my $img = new GD'Image;, and there are also modules on CPAN using that syntax on ther names/documentation.
What is the purpose or logic behind that? Is it maybe, as many things in Perl, just a feature intended to humanize sentences and allow you to create and use modules like Acme::Don't?
Does it have any other intention different to ::?
See perlmod for explanation:
The old package delimiter was a single quote, but double colon is now the preferred delimiter
So, the reason is history.
The single quote is an old ADA separator. However, it didn't play well with Emacs, so the double colon became used.
Good God! ADA? Emacs? I am old.
Something I keep doing is removing comments from a file as I process it. I was was wondering if there a module to do this.
Sort of code I keep writing time and again is
while(<>) {
s/#.*// ;
next if /^ \s+ $/x ;
**** do something useful here ****
}
Edit Just to clarify, the input is not Perl. It is a text file of my own making that might have data I want to process in some way or other. I want to beable to place comments that are ignored by my programs
Unless this is a learning experience I suggest you use Regexp::Common::comment instead of writing your own regular expressions.
It supports quite a few languages.
The question does not make clear what type of file it is. Are we dealing with perl source files? If so, your approach is not entirely correct - see gbacon's comment. Perl source files are notoriously difficult (impossible?) to parse with regex. In that case, or if you need to deal with several types of files, use Regexp::Common::comment as suggested by Niffle. Otherwise, if you think your regex logic is correct for your scenario, then I personally prefer to write it explicitly, it's just a pair of strighforward lines, there is little to be gained by using a module (and you introduce a dependency).
It is generally advised not to use additional linux tools in a Perl code;
e.g if someone intends to print the last line of a text file he can:
$last_line = `tail -1 $file` ;
or otherwise, open the file and read it line by line
open(INFO,$file);
while(<INFO>) {
$last_line = $_ if eof;
}
What are the pitfalls of using the previous and why should I avoid using shell tools in my code?
thanx,
Efficiency - you don't have to spawn a new process
Portability - you don't have to worry about an executable not existing, accepting different switches, or having different output
Ease of use - you don't have to parse the output, the results are already in a usable form
Error handling - you have finer-grained control over errors and what to do about them in Perl.
It's better to keep all the action in Perl because it's faster and because it's more secure. It's faster because you're not spawning a new process, and it's more secure because you don't have to worry about shell meta character trickery.
For example, in your first case if $file contained "afilename ; rm -rf ~" you would be a very unhappy camper.
P.S. The best all-Perlway to do the tail is to use File::ReadBackwards
One of the primary reasons (besides portability) for not executing shell commands is that it introduces overhead by spawning another process. That's why much of the same functionality is available via CPAN in Perl modules.
One reason is that your Perl code might be running in an environment where there is no shell tool called 'tail'.
It's a personal call depending on the project:
Is it going to be always used in shell environments with tail?
Do you care about only using pure Perl code?
Using tail? Fine. But that's really a special case, since it's so easy to use and since it is so trivial.
The problem in general is not really efficiency or portability, that is largely irrelevant; the issue is ease of use. To run an external utility, you have to find out what arguments it accepts, write code to transform your program's data structures to that format, quote them properly, build the command line, and run the application. Then, you might have to feed it data and read data from it (involving complexity like an event loop, worrying about deadlocking, etc.), and finally interpret the return value. (UNIX processes consider "0" true and anything else false, but Perl assumes the opposite. foo() and die is hard to read.) This is a lot of work to do, and that's why people avoid it. It's much easier to create an instance of a class and call methods on it to get the data you need.
(You can abstract away processes this way; see Crypt::GpgME for example. It handles the complexity associated with invoking gpg, which would normally involve creating multiple filehandles other than STDOUT, STDIN, and STDERR, among other things.)
The main reason I see for doing it all in Perl would be for robustness. Your use of tail will fail if the filename has shell metacharacters or spaces or doesn't exist or isn't accessible. From Perl, characters in the filename aren't an issue, and you can distinguish between errors in accessing the file. Sometimes being robust is more important than speedy coding and sometimes it's not.