binding.pry being skipped in Ruby - ruby

binding.pry is not catching for me in some situations.
For instance, when I run this code using ruby programtorun.rb in the terminal, it doesn't open up a Pry session.
require 'pry'
class Foo
def bar
boo = true
binding.pry
end
end
f = Foo.new
f.bar
I tried reinstalling Pry but the problem persisted.

The problem is that binding.pry stops on the next line to be executed in your program. Your next line is non-existent. binding.pry is literally the last thing you call before your script ends.
Changing
class Foo
def bar
boo = true
binding.pry
end
end
to
class Foo
def bar
binding.pry
boo = true
end
end
caused it to stop for me at boo=true.

Related

Unable to reach binding.pry

Trying to use binding.pry works until the emoticons_hash.each
Trying to use it inside of .each or after it will not trigger it. It also doesn't work within other methods of this program, even with a puts "hello" after it.
require 'pry'
require 'yaml'
def load_library(filepath)
emoticons_hash = YAML.load_file (filepath)
puts emoticons_hash.inspect
language_hash = {}
emoticons_hash.each do |emoticon|
language_hash[emoticon] = emoticons_hash[emoticon].value
binding.pry
end
binding.pry
puts "hello"
end
def english
binding.pry
puts "hello"
end
There's something in your emoticons_hash variable? If yes, it responds to .each method?
I think your binding.pry are not reaching this way because one of these two problems.

Ruby messages to self

If I run the following Ruby code:
class Foo
def foo=(something)
puts "It's a #{something}"
end
def foo_assign
self.foo = "bar"
end
end
f = Foo.new
f.foo_assign
The output is: It's a bar.
On the other hand, if I run the code:
class Foo
def foo=(something)
puts "It's a #{something}"
end
def foo_assign
foo = "bar"
end
end
f = Foo.new
f.foo_assign
There is no output. How can that be given that foo and self.foo are equivalent?
foo = "bar" is ambiguous in the foo_assign method. Ruby thinks you are trying to assign a local variable and not call the method, so that's what it does for you. (imagine setting bar = "foo" on the next line, it would still work, even though there is no bar= method). In cases where it's ambiguous what you are trying to do or call, you have to use self.. Someone better than I might be able to explain this all better or more clearly, but that's what is happening here.

respond_to?() from top level of script

I can use respond_to?() from the main object in irb:
irb(main):001:0> def foo
irb(main):002:1> "hi"
irb(main):003:1> end
=> nil
irb(main):004:0> respond_to?(:foo)
=> true
irb(main):005:0> self
=> main
But when I put this into a script, it doesn't seem work as I'd expect:
$ cat test.rb
#! /usr/local/bin/ruby
def foo
"hi"
end
puts respond_to?(:foo)
puts self
$ ./test.rb
false
main
What's going on here?
EDIT:
The irb behavior works for me in 1.9.3, but not in 2.2.0. But regardless, is it possible to use respond_to?() as such from a script?
As an alternative, I can catch a NoMethodError from a call to send(), but that would also catch such exceptions from inside a valid method as well, which makes error handling a little convoluted.
Methods defined at the top level are made private methods of Object and by default respond_to? only returns true for public methods. To check for private and protected methods, set the include_all argument to true:
def foo
"hi"
end
puts respond_to?(:foo, true)
puts self
Now when the script is run, respond_to?(:foo, true) should return true:
$ ./test.rb
true
main

I can not understand "uninitialized constant" in ruby

I have two files in folder pc under my home directory.
First file:
class A
class << self
protected
def foo
puts "In foo"
end
end
end
Second file:
class B < A
def bar
self.class.class_eval { foo }
end
end
B.new.bar
My problem is when I run the second file I get the following error:
second.rb:1:in `<main>': uninitialized constant A (NameError)
Why is that?
B.new.bar
# => In foo
just works fine in my console. I guess you probably forgot to require the file containing A from the file B.
In file B use
require 'a'
(assuming the file containing A is called a.rb).
I read the various comments, and just to avoid confusion, here's the full content of the two files.
class_a.rb
class A
class << self
protected
def foo
puts "In foo"
end
end
end
class_b.rb
require_relative 'class_a'
class B < A
def bar
self.class.class_eval { foo }
end
end
puts B.new.bar
And here's how to execute them from the console
$ ruby class_b.rb
In foo
Of course, you should execute the file class_b.rb, not class_a.rb or you will not see any result.
Try require_relative 'class_a' or require class_a.
Note that the file's extension is not included.
This should work, assuming it's all in the same file. If not, you'll need to require the first file into the next:
# class_b.rb
require 'class_a.rb'
class B < A
def bar
self.class.class_eval { foo }
end
end
B.new.bar
#=> "In foo"
UPDATE:
In order to require the file, you may need to cite the path of the file relative to your current directory. For instance, if class_a.rb is located in ~/home and you're running irb (or class_b.rb is in ~/home), then you'd include class_a.rb by citing its relative path as follows:
require './class_a'

Preventing methods from being re-defined

So, I need to make a method within a class protected from re-definition. I am not really sure how else to explain it so here's the code:
module Foo
def bar
p "lol"
end
end
Now, that's the original Foo#bar method and I need it to be like a constant. So, I did come up with a solution. That was to save the method in a Constant and detect when someone tried changing it it would simply re-load it from that constant (it was a Proc object):
module Foo
Original_bar = Proc.new { p "lol" }
def bar
Original_bar.call
end
def self.method_added(method_name)
if method_name == :bar
def Foo::bar
Original_bar.call
end
end
end
end
But this isn't completely safe since once could use the same "trick" I did to bypass method_added and I am not really fond of this, since it's not very ruby-like.
Tests
A normal test:
module Foo
def bar
p "lmao"
end
end
Foo::bar # => "lol"
And another test using the trick:
def Foo::bar
p "rofl"
end
Foo::bar # => "rofl"
tl;dr
How to make a method in Ruby "unredefinable" (if that's even a word)?
If you freeze the module that should prevent method being added to it.
Note that a c extension can unfreeze variables (see evil.rb for example.
You can make your code warn you that a method has been over-ridden by turning on warnings:
$VERBOSE = true
module Foo
def self.bar
p "lmao"
end
end
def Foo::bar
p "rofl"
end
(irb):9: warning: method redefined; discarding old bar
It may be possible, but not practical, to raise an exception when warnings are issued.
This won't warn you if you first undefine Foo.bar, however.

Resources