Undoing auto-indentation - ruby

Wnen you use irb with auto indent mode, the end statements get indented one level extra
def foo
...
end
instead of showing the ordinary indenting convention:
def foo
...
end
because you cannot tell irb in advance that you are going to escape one level in the next line. This question has been addressed elsewhere like here or here, but neither gives a satisfactory answer. They just suggest giving up.
However, if we can minimally overwrite some irb methods so that auto indent will insert white spaces not in the prompt area but at the beginning of the line you type in, then by default, irb will still be inserting spaces, but we will be able to erase some spaces with backspace. Is this possible?
Or, if that is not realistic, then is it possible to make irb erase the last line from the screen and redisplay it with proper indentation right after you press Enter on a line including end?

Rewriting the last line is possible. Doing it in irb is difficult due to its lack of documentation and consistent api across versions. An irb alternative, ripl, has already solved this issue for itself with an auto-indent plugin. If you want to give ripl and its auto-indenting a try:
$ gem install ripl-auto_indent
$ echo "require 'ripl/auto_indent'" >> ~/.riplrc
# Auto-indent away
$ ripl
>> def foo
>> puts "it's auto-magic!"
>> end

Related

binding.pry appears to be debouncing and then re-displaying text input

I'm following along with a tutorial book, and in order to step through my code I've required pry and added a binding.pry reference in a method which gets executed:
require 'pry'
module Rulers
module Model
class FileModel
def initialize(filename)
#filename = filename
binding.pry
basename = File.split(filename)[-1]
...
When I load the code which executes this constructor method, I successfully hit my binding.pry debugger point as expected. However, when I start typing commands at the prompt, the characters I enter are printed out in the same prompt:
[7] pry(#<Rulers::Model::FileModel>)> .whic.whichh
In the above example, I typed .which. I had gotten all the way to .whic when the REPL added the characters I had typed thus far (i.e. it added .whic to .whic, resulting in .whic.whic). The last character I typed was h, which registers after .whic.whic. Finally, the last h I typed was also appended to the chars on the prompt.
Interestingly, the duplicated chars do not appear to affect the REPL's ability to understand the commands I type in. For example, the following:
[8] pry(#<Rulers::Model::FileModel>)> .which .which vim
[8] pry(#<Rulers::Model::FileModel>)> .which vim
/usr/bin/vim
In the above example, I was successful in typing .which quickly enough to not result in a muddled version of the which command, and I also pressed Enter before vim could be duplicated erroneously. If the redundant 2nd .which command were to affect my ability to return the expected output, I would expect to see an error returned. Instead, I see /usr/bin/vim as I would expect when typing which vim in my regular, non-pry command line prompt.
I have no theories on where to begin debugging this. Any ideas?

Thread ignoring first input when using getch

require 'rubygems'
require 'mechanize'
require 'io/console'
flag = 0
t2 =Thread.new do
puts flag
loop do
temp = STDIN.getch
if temp=="\n"
flag = (flag+1)%2
puts flag
end
end
end
# => Some foreground code
t2.join
When i run the code i get the value of flag printed 0 as it should. But the thread does not change the value of flag on the first Enter I hit. Hitting Enter the second time changes flag to 1 although. The thread works normally toggling the value of flag on further Enter hits. Why is this happening? What have I done wrong?
Problem seems to be only with getch
as when I use gets in place of getch the problem disappears. But I cant use gets because I want the user to hit a single key without needing to press Enter after the key to give input.
For example flag should not change when the user inputs a instead of Enter and so I have used getch to make sure the input is given after a single keyboard hit.
A similar problem was described here but it isn't a duplicate.
Edit 1:
The problem seems to be with getch and not the check what do ever.
flag = 0
t2 =Thread.new do
puts flag
loop do
temp = STDIN.getch
flag = (flag+1)%2
puts flag
end
end
t2.join
Even after removing the if statement, the first Enter is ignored no matter what but other characters seem to respond to the first time. The problem is coming only when I hit Enter. It doesn't count the first Enter I hit.
ruby 2.3.3p222 (2016-11-21 revision 56859) [x64-mingw32]
I tried your code on a Windows machine and was able to re-create the problem. As you correctly guessed it has nothing to do with threading and everything with how getch works (on Windows).
If you add a p temp.inspect to your loop you will see that it is not so much that the first '\n' is swallowed, rather it is that it is somehow "held back". The best way to see this if you press Enter and another key alternatively. You will see that the inspect is "off-by-one".
A good explanation about the problem is discussed here:
https://www.rubytapas.com/2016/12/14/ruby-code-on-windows/
With that information, a simple solution (that has the added benefit to run also on Linux, not sure about Mac) is:
require 'rubygems'
require 'mechanize'
require 'io/console'
STDIN.binmode #this line added to prevent line-end translation
flag = 0
t2 =Thread.new do
puts flag
loop do
temp = STDIN.getch
if temp=="\r" # note: changed from LF to CR
flag = (flag+1)%2
puts flag
end
end
end
# => Some foreground code
t2.join
Notes:
Admittedly I don't fully get the way it works. I was expecting that Enter would cause a "\r\n" sequence in binmode, but I only see "\r". Not sure what happens to the "\n", but it seems to work reliably this way.
Also note that in the current version the program can not be terminated with Ctrl+C. You'll have to add a check for that.

Ruby: Why do I get warning "regex literal in condition" here?

A simple Ruby program, which works well (using Ruby 2.0.0):
#!/usr/bin/ruby
while gets
print if /foo/../bar/
end
However, Ruby also outputs the warning warning: regex literal in condition. It seems that Ruby considers my flip-flop-expression /foo/../bar/ as dangerous.
My question: Where lies the danger in this program? And: Can I turn off this warning (ideally only for this statement, keeping other warnings active)?
BTW, I found on the net several discussions of this kind of code, also mentioning the warning, but never found a good explanation why we get warned.
You can avoid the warning by using an explicit match:
while gets
print if ~/foo/..~/bar/
end
Regexp#~ matches against $_.
I don't know why the warning is shown (to be honest, I wasn't even aware that Ruby matches regexp literals against $_ implicitly), but according to the parser's source code, it is shown unless you provide the -e option when invoking Ruby, i.e. passing the script as an argument:
$ ruby -e "while gets; print if /foo/../bar/ end"
I would avoid using $_ as an implicit parameter and instead use something like:
while line = gets
print line if line=~/foo/..line=~/bar/
end
I think Neil Slater is right: It looks like a bug in a parser. If I change the code to
#!/usr/bin/ruby
while gets
print if $_=~/foo/..$_=~/bar/
end
the warning disappears.
I'll file a bug report.

How can I comment out my Ruby return values with something like "# =>"?

Having just started with Ruby and while following a tutorial, the result was shown as:
a + b # => 3
I have never seen such a possibility; that seems so handy! Could you please tell me what it is? is it proprietary or is it for everyone?
Josh Cheek's seeing is believing. Apparently you can run it over your code, or it can be integrated in several editors.
Reconfigure Your REPL
The # symbol is a comment in Ruby. By default, most Ruby REPLs (e.g. irb or pry) will use => to prefix the return value of your last expression.
In IRB, you can modify this prefix so that each return value is prefixed by a different string. You can do this through the IRB::Context#return_format method on your conf instance. For example:
$ irb
irb(main):001:0> conf.return_format = "#=> %s\n"
#=> "#=> %s\n"
irb(main):002:0> 1 + 2
#=> 3
More permanent changes would have to be made in your IRB configuration file by customizing the prompt through the IRB.conf[:PROMPT] Hash and then setting IRB.conf[:PROMPT_MODE] to your custom prompt, but in my opinion the solution above is simpler even though you have to run it within the current REPL session rather than saving it as a default.

Jumping to a Ruby bang method using Ctags in Vim

I'm having a problem with jumping to a Ruby bang method using Exhuberant Ctags. I have searched for others having a similar problem and am unable to find anything. An example of the problem can be shown using the following small Ruby class:
class Hello
def start
method!
end
def method
# Blah
end
def method!
# Blah
end
end
When ctags -R . is run on this file the resulting tags file contains the following 2 lines demonstrating that both methods are discovered at generation:
method test.rb /^ def method$/;" f class:Hello
method! test.rb /^ def method!$/;" f class:Hello
However, if I place my cursor on the call to method! on line 3 and press ^] then the cursor jumps to the method definition rather than to the correct bang version. It seems as if the exclamation mark is not being included in the identifier that is searched for.
Is there a way to fix this so the correct method is jumped to?
I realize this is super-old, but I ran into the same thing in both Vim 8.0 and Neovim. If I enter :tag mymethod! from vim's command-line, it finds the relevant tag, but if I try <C-]> with my cursor on the method name, it errors E426: tag not found: mymethod (note the lack of ! in the name it searched for).
You can fix this by adding ! to the list of characters recognized as keyword characters in Ruby syntax:
:set iskeyword+=!
You could add this to ~/.vim/after/syntax/ruby.vim to apply it in any Ruby file you open. I haven't tested this though, so can't say whether it will adversely affect anything else. I know it will change word jumping behavior. w will, for instance, treat the ! as part of the "small" word.
On second thought, it will definitely mishandle things like !some_test. If you were to hit <C-]> with the cursor anywhere in there, it would search for a method named !some_test, which is definitely not what you want. A better solution would be to write a wrapper function around the tag lookup for Ruby files. I'm actually working on something for that, so I'll post when I have something that presentable.
Update: I found a surprisingly simple workaround:
nnoremap <buffer><silent> <C-]> :tag <C-R><C-W><CR>
For some reason, the behavior of <C-R><C-W> in command-line mode differs from that of expand('<cword>'), and arguably from the documentation. Even though ! is not an 'iskeyword' character, and expand('<cword>') results in mymethod, <C-R><C-W> results in mymethod!. The same applies to is_this_your_method?. You could apply this workaround by putting the following in ~/.vim/ftplugin/ruby.vim:
nnoremap <buffer><silent> <C-]> :tag <C-R><C-W><CR>
nnoremap <buffer><silent> g] :tselect <C-R><C-W><CR>
nnoremap <buffer><silent> g<C-]> :tjump <C-R><C-W><CR>
Update 2
It turns out the special behavior of <C-R><C-W> was provided by vim-ruby (and included in Vim's runtime files by default). That script customizes <C-R><C-W> and also adds a <Plug><cword> mapping to correctly identify the Ruby cursor identifier. I only ran into the mishandling of ! because I had inadvertently clobbered the mappings already provided by vim-ruby when adding what I find to be more a comfortable keybinding:
nnoremap <C-.> <C-]>
If I'd done nmap instead, vim-ruby's mapping could have done its job. Alternatively, you could leverage what vim-ruby provides by doing (in a ruby ftplugin file):
nnoremap <buffer><silent> <C-]> :<C-U>exe v:count1."tag <Plug><cword>"<CR>
nnoremap <buffer><silent> g] :<C-U>tselect <Plug><cword><CR>
nnoremap <buffer><silent> g<C-]> :<C-U>tjump <Plug><cword><CR>
You can always use :tag:
:tag method!
Or visual mode - if you highlight any text (with v + movement) before you hit ^], it will use the highlighted text as the tag instead of trying to find an 'identifier' under the cursor. So if your cursor is on the m in method!, then
vE^]
should do the trick. If your cursor is elsewhere in the word, then hit b first.
I was using MacVim snapshot 63 at the time I posted this question. I'm now using snapshot 72 and the problem has gone. The only advice I can give here is to upgrade the version of Vim that you are using.

Resources