__FILE__ returns different value when using binding.pry - ruby

__FILE__ returns the path of the current Ruby script file.
One potentially significant problem is that, if using binding.pry, __FILE__ evaluates to (pry). It is potentially problematic to have __FILE__ evaluate to different values depending on whether it is evaluated in the context of binding.pry. For example,
$stdout.print "****************************************\n\n"
$stdout.print "FILE: #{__FILE__}\n\n"
$stdout.print "****************************************\n\n"
binding.pry
When the script pauses at binding.pry, I get:
__FILE__
# >> (pry)
Does anyone know any mechanism to get the path of the current file even in the context of binding.pry?

Use _file_ instead of __FILE__. For example, given two files:
# foo.rb
require 'pry'
require './bar'
binding.pry
b = Bar.new
and:
# bar.rb
require 'pry'
class Bar
def initialize
binding.pry
end
end
Run them with ruby foo.rb:
ruby foo.rb
From: /Users/username/foo.rb # line 3 :
1: require 'pry'
2: require './bar'
=> 3: binding.pry
4: b = Bar.new
(main):1 ⇒ _file_
=> "/Users/username/foo.rb"
(main):2 ⇒ exit
From: /Users/username/bar.rb # line 4 Bar#initialize:
3: def initialize
=> 4: binding.pry
5: end
(#<Bar:0x00007fbb6caaff08>):1 ⇒ _file_
=> "/Users/username/bar.rb"
_file_ and any other local variable names can be found in binding.local_variables.

Sergio Tulentsev made a simple suggestion, assign __FILE__ to a variable before invoking binding.pry.
anothermh, mentioned _file_ which is available in binding pry.
In the end, I combined the two answers:
# When in the context of binding.pry, __FILE__ resolves to '(pry)',
# binding contains the local variable _file_ which always resolves to
# the current file, even when being evaluated in the context of binding.pry .
# _file_ is only available, in binding. This does the trick:
current_file = __FILE__.downcase == '(pry)' ? _file_ : __FILE__

Related

Ruby with RSpec NoMethodError: undefined method length for nil:NilClass

I'm new to Ruby and RSpec trying to write a unit case for string length. I have 3 rb files as follows
1. Calling file
require_relative 'ruby_final_operations'
require_relative 'ruby_helper'
require 'uri'
require 'open-uri'
require 'prime'
module RubyOperations
# Public: Various commands for the user to interact with RubyCommand.
class Command
res = RubyOperations::Operations.new
res.letter_count(res.inputstr)
2nd File - Method Implementation
require_relative 'ruby_helper'
require 'logger'
$FILE_LOG = RubyOperations.create_log(File.expand_path('~/RubyOperations_LOG.log'), Logger::DEBUG)
$STD_LOG = RubyOperations.create_log(nil, Logger::INFO)
module RubyOperations
class Operations
def inputstr
RubyOperations.log('Enter the String:[Length 20]',:BOTH)
#str = gets.chomp
raise StandardError if #str =~ /\d/ || #str.empty? || #str.length > 20
rescue StandardError,ArgumentError => e
RubyOperations.log(e,:ERROR)
end
def letter_count(str)
result = #str.length
RubyOperations.log("The number of letters in the string: #{result}",:BOTH)
end
3rd file - RSpec
require 'ruby_final_operations'
describe 'RubyOperations' do
describe 'Operations' do
subject = RubyOperations::Operations.new
describe '.letter_count' do
context 'when operation is provided' do
it 'returns letter count' do
allow(subject.letter_count("hello").to receive(:result).and_return(5)
end
end
end
The problem is that in the 2nd File he argument is 'str' but the typed string is stored is '#str'.
How can I pass the string 'hello' from the rspec file to test this.
There are a few issues:
Calling a instance_method with an argument that is not used
def letter_count #get rid of argument, the argument does nothing,
#basically it looks you added the argument,
# just, so you can call the other method there.
Make your main simple, with a clear sequence
res.inputstr
res.letter_count
But about your actual question, in your test you change the wrong thing the wrong method
allow(subject.letter_count("hello").to receive(:result).and_return(5)
# letter count should do the log entry, not return five, at least that what your method say
So you probably want to set the #str before you test the letter_count method.
subject.instance_variable_set("hello")
# then test for what you expect the method to return
expect(subject.letter_count).to eq(5)
# this specific test will fail, because you are doing a log entry, and not return the length on letter_count.

Pry doesn't work when launched from method invoked by RSpec test

I'm trying to use Pry with RSpec.
Goal is to be able to drop binding in method and debug it.
Here is what I have.
lib/play.rb
class Play
def self.hello
print 'Hello world!'
require 'pry'; binding.pry
end
end
spec/play_spec.rb
require_relative '../lib/play'
describe Play do
it 'Play#hello should print message' do
expect {Play.hello}.to output('Hello world!').to_stdout
#require 'pry'; binding.pry
end
end
If I uncomment binding in spec file and run
rspec
I'm getting into Pry which behaves as expected
Frame number: 0/23
From: /Users/iiezhachenko/Documents/Repos/bdd-ruby- playground/spec/play_spec.rb # line 6 :
1: require_relative '../lib/play'
2:
3: describe Play do
4: it 'Play#hello should print message' do
5: expect {Play.hello}.to output('Hello world!').to_stdout
=> 6: require 'pry'; binding.pry
7: end
8: end
[1] pry(#<RSpec::ExampleGroups::Play>)> ls
RSpec::Core::MemoizedHelpers#methods: is_expected should should_not subject
RSpec::Core::Pending#methods: pending skip
RSpec::Mocks::ArgumentMatchers#methods:
If I comment out binding.pry in spec fill, put it in method which is tested and invoke "rspec" again. I'm getting into completely messed Pry.
[1] pry(Play)> ls
[2] pry(Play)> fghjk
[3] pry(Play)> kweutyalfh
[4] pry(Play)> exit
F
Failures:
1) Play Play#hello should print message
Failure/Error: expect {Play.hello}.to output('Hello world!').to_stdout
expected block to output "Hello world!" to stdout, but output "Hello world!\n\e[1mFrame number:\e[0m 0/32\n\n\e[1mFrom:\e[0m /Users/iiezhachenko/Documents/Repos/bdd-ruby-playground/lib/play.rb # line 4 Play.hello:\n\n \e[1;34m2\e[0m: \e[32mdef\e[0m \e[1;36mself\e[0m.\e[1;34mhello\e[0m\n \e[1;34m3\e[0m: print \e[31m\e[1;31m'\e[0m\e[31mHello world!\e[1;31m'\e[0m\e[31m\e[0m\n => \e[1;34m4\e[0m: require \e[31m\e[1;31m'\e[0m\e[31mpry\e[1;31m'\e[0m\e[31m\e[0m; binding.pry\n \e[1;34m5\e[0m: \e[32mend\e[0m\n\n\e[0G\e[1m\e[1;34mPlay.methods\e[0m\e[0m: hello\n\e[1m\e[1;34mlocals\e[0m\e[0m: _ __ _dir_ _ex_ _file_ _in_ _out_ _pry_\nNameError: undefined local variable or method `fghjk' for Play:Class\nfrom (pry):1:in `hello'\nNameError: undefined local variable or method `kweutyalfh' for Play:Class\nfrom (pry):2:in `hello'\n"
Diff:
## -1,2 +1,17 ##
Hello world!
+Frame number: 0/32
+
+From: /Users/iiezhachenko/Documents/Repos/bdd-ruby-playground/lib/play.rb # line 4 Play.hello:
+
+ 2: def self.hello
+ 3: print 'Hello world!'
+ => 4: require 'pry'; binding.pry
+ 5: end
+
Play.methods: hello
+locals: _ __ _dir_ _ex_ _file_ _in_ _out_ _pry_
+NameError: undefined local variable or method `fghjk' for Play:Class
+from (pry):1:in `hello'
+NameError: undefined local variable or method `kweutyalfh' for Play:Class
+from (pry):2:in `hello'
# ./spec/play_spec.rb:5:in `block (2 levels) in <top (required)>'
Anyone faced such issue?
As the answer by OP indicates, the problem involves console output suppression, which can inadvertently break Pry.
If you check your spec/spec_helper.rb file, there is likely some code inside the RSpec configuration block that is referring to $stderr and/or $stdout. Removing those lines of code should fix the problem.
For other examples of how this output might be getting suppressed, see the answers to this question: Suppress console output during RSpec tests
Issue resolved by removing stdout capturing from test. Thanks everyone.

pry inspect method not working

I have the following code from understanding computation book. The intention is to change the inspect behavior.
class Number < Struct.new(:value)
def inspect
"<<#{self}>>"
end
def to_s
value.to_s
end
end
It works as expected when I use irb:
irb(main):014:0> Number.new(1)
=> <<1>>
but it does not when I use pry:
[8] pry(main)> n = Number.new(1)
=> #<struct Number value=1>
The Pry is version 0.10.3 on Ruby 2.0.0. Why does it not work?
Pry doesn't just use inspect to display the return value. It calls a proc called print object that is defined in configuration. In lib/pry.rb, you can find that it is set to:
class Pry
# The default print
DEFAULT_PRINT = proc do |output, value, _pry_|
_pry_.pager.open do |pager|
pager.print _pry_.config.output_prefix
Pry::ColorPrinter.pp(value, pager, Pry::Terminal.width! - 1)
end
end
end
In order to use inspect as in irb, set it like this as instructed here:
Pry.config.print = proc {|output, value| output.puts "=> #{value.inspect}"}
Then you will get:
pry(main)> n = Number.new(1)
=> <<1>>
I use Pry version 0.10.4.
I've just added the following lines in my .pryrc file (I think, that is a good
place for such code):
if defined?(BigDecimal)
BigDecimal.class_eval do
def inspect
"<#{to_s('+3F')}>"
end
end
end
And result:
balance: <+100.0>,
commission_amount: <+0.15>
Sawa is right in that Pry uses its own printer, but if you look closer at the source you can see that it actually uses Ruby's PP behind the scenes, and PP defines its own behaviour for pretty printing Structs:
class Struct # :nodoc:
def pretty_print(q) # :nodoc:
q.group(1, sprintf("#<struct %s", PP.mcall(self, Kernel, :class).name), '>') {
q.seplist(PP.mcall(self, Struct, :members), lambda { q.text "," }) {|member|
q.breakable
q.text member.to_s
q.text '='
q.group(1) {
q.breakable ''
q.pp self[member]
}
}
}
end
def pretty_print_cycle(q) # :nodoc:
q.text sprintf("#<struct %s:...>", PP.mcall(self, Kernel, :class).name)
end
end
It's worth checking out the documentation (though it is only brief) if you are interested in learning more about this.
So in your struct you could also define your own pretty_print and pretty_print_cycle methods, which would mean Pry could print these how you want, without having to override their DEFAULT_PRINT proc.

Get path of parent requiring file, Ruby

Is it possible to get the location of the file which requires another file in Ruby?
I have a project where I spawn some processes and I would love to be able, in the code, to determine which file is the parent of the required file. This is nice when debugging.
Example:
#initial.rb:
require "./my_file.rb"
fork do
require "./my_file2.rb"
end
-
#my_file.rb:
puts "Required from file: #{?????}"
-
#my_file2.rb:
require "./my_file.rb"
I would expect to get something like:
#=> Required from file: /path/to/initial.rb
#=> Required from file: /path/to/my_file2.rb
Based on Jacobs answer I ended with this redefinition of require_relative and require:
alias :old_require_relative :require_relative
def require_relative(arg)
#~ puts caller.map{|x| "\t#{x}"}
puts "%s requires %s" % [ caller.first.split(/:\d+/,2).first, arg]
old_require_relative arg
end
alias :old_require :require
def require(arg)
#~ puts caller.map{|x| "\t#{x}"}
puts "%s requires %s" % [ caller.first.split(/:\d+/,2).first, arg]
old_require arg
end
In a test test scenario with the following load sequence:
test.rb
+- test1.rb
+- test1_a.rb
+ test2.rb
The following calls
require './test1'
require './test2'
or
require_relative 'test1'
require_relative 'test2'
result in:
test.rb requires ./test1
C:/Temp/test1.rb requires test1_a
test.rb requires ./test2
You could also include the line of the requirement in the output.
You should never need to do this, but you can examine the call stack from Kernel#caller. You'll have to filter out require methods (especially if you use any libraries that override require).

cattr_accessor outside of rails

I'm trying to use the google_search ruby library (code follows) but it complains that 'cattr_accessor is an undefined method' - any ideas why this might be or how I could fix it?
require 'rubygems'
require 'google_search'
GoogleSearch.web :q => "pink floyd"
cattr_accessor seems to be a Rails extension that acts like attr_accessor, but is accessible on both the class and its instances.
If you want to copy the source of the cattr_accessor method, check out this documentation:
# File vendor/rails/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb, line 46
def cattr_accessor(*syms)
cattr_reader(*syms)
cattr_writer(*syms)
end
# File vendor/rails/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb, line 4
def cattr_reader(*syms)
syms.flatten.each do |sym|
next if sym.is_a?(Hash)
class_eval("unless defined? ##\#{sym}\n##\#{sym} = nil\nend\n\ndef self.\#{sym}\n##\#{sym}\nend\n\ndef \#{sym}\n##\#{sym}\nend\n", __FILE__, __LINE__)
end
end
# File vendor/rails/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb, line 24
def cattr_writer(*syms)
options = syms.extract_options!
syms.flatten.each do |sym|
class_eval("unless defined? ##\#{sym}\n##\#{sym} = nil\nend\n\ndef self.\#{sym}=(obj)\n##\#{sym} = obj\nend\n\n\#{\"\ndef \#{sym}=(obj)\n##\#{sym} = obj\nend\n\" unless options[:instance_writer] == false }\n", __FILE__, __LINE__)
end
end
You can get this functionality by including the Ruby Facets gem. Reference the source here:
https://github.com/rubyworks/facets/blob/master/lib/core/facets/cattr.rb
You generally don't need to require all code from the gem. You can selectively require what you want. There are quite a few useful extensions in the gem though.

Resources