Get stacktrace classes, not just files, in Ruby - ruby

My goal is to find if the current stack has ActionJob::Base in it to see if it came from a background job.
I figure the way to do that is calling classes for my current location in ruby so I can search and find ActionJob::Base ancestor class in the call stack.
There are a few ways to get a stacktrace/backtrace from the current location in ruby. They involve Thread.current.backtrace. That results in an array of strings as filenames but not classes that were called. i.e.
/Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:537:in `eval_input'
/Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:472:in `block in run'
/Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:471:in `catch'
/Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:471:in `run'
/Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:400:in `start'
/Users/justin/dev/testarea/lamby_discovery/vendor/bundle-dev/ruby/2.7.0/gems/railties-6.1.3.2/lib/rails/commands/console/console_command.rb:70:in `start'
/Users/justin/dev/testarea/lamby_discovery/vendor/bundle-dev/ruby/2.7.0/gems/railties-6.1.3.2/lib/rails/commands/console/console_command.rb:19:in `start'
/Users/justin/dev/testarea/lamby_discovery/vendor/bundle-dev/ruby/2.7.0/gems/railties-6.1.3.2/lib/rails/commands/console/console_command.rb:102:in `perform'
/Users/justin/dev/testarea/lamby_discovery/vendor/bundle-dev/ruby/2.7.0/gems/thor-1.1.0/lib/thor/command.rb:27:in `run'
/Users/justin/dev/testarea/lamby_discovery/vendor/bundle-dev/ruby/2.7.0/gems/thor-1.1.0/lib/thor/invocation.rb:127:in `invoke_command'
/Users/justin/dev/testarea/lamby_discovery/vendor/bundle-dev/ruby/2.7.0/gems/thor-1.1.0/lib/thor.rb:392:in `dispatch'
/Users/justin/dev/testarea/lamby_discovery/vendor/bundle-dev/ruby/2.7.0/gems/railties-6.1.3.2/lib/rails/command/base.rb:69:in `perform'
byebug's backtrace has the information that I'm looking for (i.e. IRB::Context), but doesn't seem searchable and backtrace is a c method.
--> #0 IRB::Context.set_last_value(value#NilClass) at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb/context.rb:363
#1 IRB::Context.evaluate(line#String, line_no#Integer, exception#NilClass) at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb/context.rb:459
#2 block (2 levels) in IRB::Irb.block (2 levels) in eval_input at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:541
#3 IRB::Irb.signal_status(status#Symbol) at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:704
#4 block in IRB::Irb.block in eval_input at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:538
#5 block (2 levels) in RubyLex.block (2 levels) in each_top_level_statement at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb/ruby-lex.rb:166
ͱ-- #6 Kernel.loop at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb/ruby-lex.rb:151
#7 block in RubyLex.block in each_top_level_statement at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb/ruby-lex.rb:151
ͱ-- #8 Kernel.catch(*args) at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb/ruby-lex.rb:150
#9 RubyLex.each_top_level_statement at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb/ruby-lex.rb:150
#10 IRB::Irb.eval_input at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:537
#11 block in IRB::Irb.block in run(conf#Hash) at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:472
ͱ-- #12 Kernel.catch(*args) at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:471
#13 IRB::Irb.run(conf#Hash) at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:471
#14 #<Class:IRB>.start(ap_path#NilClass) at /Users/justin/.rbenv/versions/2.7.3/lib/ruby/2.7.0/irb.rb:400
Any recommendations?

My idea is loop through caller (you can limit, eg. caller.first(10)), and each of them, i'll load source code then check whether source string include? the target class or not (eg. ActionJob::Base).
Here is my solution, i use gem solargraph which help to parse source code (parse namspace, constants, methods, ...), in your case, we need to find any caller class has superclass is ActionJob::Base, right ? Solargraph support we do it:
gem 'solargraph', group: :development
bundle install
# debug helper
class Debug
def self.search_super(caller, super_clazz)
detect_paths = []
caller.each do |caller_path|
unless caller_path.nil?
filepath = caller_path.split(':').first
source = Solargraph::Source.load_string(File.read(filepath), filepath)
map = Solargraph::SourceMap.map(source)
detect = map.pins_by_class(Solargraph::Pin::Reference::Superclass)
.select { |clazz|
clazz.to_s == super_clazz.to_s
}
unless detect.blank?
detect_paths << filepath
end
end
end
detect_paths
end
end
then for example, you want to detect which job call the method Demo#search, you can set a break point on that method
class Demo
def search
binding.pry
end
end
and check in console
> Debug.search_super(caller, "ActionJob::Base")
note I tested on myside to detect superclass "ActionController::Base" (rails) and it worked, but i've not tested for ActionJobs yet.

Related

Celluloid 0.17.3 giving unexpected "undefined method" error

I have started using Celluloid gem this morning for that first time. I am following this Railscasts tutorial and trying to figure things out.
I have a class called "SomeClass" and it has only one method. Here is the code:
require 'celluloid'
class SomeClass
include Celluloid
def initialize(name)
#name = name
end
def assholify()
puts "#{#name} has become an ASSHOLE."
end
end
When I create new instances of the class and call its method (with a bang i.e. "assholify!"), I am getting the undefined method 'assholify!', error. But Celluloid is supposed to trigger the method asynchronously when it is called with a bang. So here is how I am calling the method:
names = ['John', 'Tom', 'Harry']
names.each do |name|
n = SomeClass.new name
n.assholify!
end
Here is the full backtrace of the error:
I, [2016-09-09T11:28:02.488618 #3682] INFO -- : Celluloid 0.17.3 is running in BACKPORTED mode. [ http://git.io/vJf3J ]
/home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/calls.rb:42:in `rescue in check': undefined method `assholify!' for #<SomeClass:0x10897dc> (NoMethodError)
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/calls.rb:39:in `check'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/calls.rb:26:in `dispatch'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/call/sync.rb:16:in `dispatch'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/cell.rb:50:in `block in dispatch'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/cell.rb:76:in `block in task'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/actor.rb:339:in `block in task'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/task.rb:44:in `block in initialize'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/task/fibered.rb:14:in `block in create'
from (celluloid):0:in `remote procedure call'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/call/sync.rb:45:in `value'
from /home/railsdev/.rvm/gems/ruby-2.3.1/gems/celluloid-0.17.3/lib/celluloid/proxy/sync.rb:22:in `method_missing'
from some_class.rb:18:in `block in <main>'
from some_class.rb:16:in `each'
from some_class.rb:16:in `<main>'
Why am I getting this error? Is it the right way to call the function? Also how do I get rid of Celluloid 0.17.3 is running in BACKPORTED mode. warning?
The undefined method error occurred because actor methods are not called with a bang in the recent versions of celluloid gem. Instead you call the method like this: n.async.assholify. So here is what the code should look like:
names = ['John', 'Tom', 'Harry']
names.each do |name|
n = SomeClass.new name
n.async.assholify # Instead of "n.assholify!"
end
For "Celluloid 0.17.0 is running in BACKPORTED mode" warning, take a look at this wiki. Backported Mode is the default, for a limited time. If you use require 'celluloid/current' instead of require 'celluloid', you should not see this warning.

TypeError: wrong argument type class (expected module) in rspec

i'm developing a simple net application (packed as a gem) to learn Ruby and TDD.
I have this class (receiver.rb):
require 'eventmachine'
class Receiver < EM::Connection
def initialize(port)
EM.run do
EM.open_datagram_socket('0.0.0.0', port, self)
end
end
end
And this test (receiver_spec.rb):
require "spec_helper"
require "net/receiver"
describe "Receiver" do
it "can istantiate" do
#rec = Receiver.new(500)
end
end
Anyway, when i run rspec it prints out this:
1) Receiver can istantiate
Failure/Error: #rec = Receiver.new(500)
TypeError:
wrong argument type Receiver (expected Module)
# /var/lib/gems/1.9.1/gems/eventmachine- 1.0.7/lib/eventmachine.rb:1535:in `include'
# /var/lib/gems/1.9.1/gems/eventmachine-1.0.7/lib/eventmachine.rb:1535:in `block in klass_from_handler'
# /var/lib/gems/1.9.1/gems/eventmachine-1.0.7/lib/eventmachine.rb:1535:in `initialize'
# /var/lib/gems/1.9.1/gems/eventmachine-1.0.7/lib/eventmachine.rb:1535:in `new'
# /var/lib/gems/1.9.1/gems/eventmachine-1.0.7/lib/eventmachine.rb:1535:in `klass_from_handler'
# /var/lib/gems/1.9.1/gems/eventmachine- 1.0.7/lib/eventmachine.rb:867:in `open_datagram_socket'
# ./lib/rppc/net/receiver.rb:9:in `block in initialize'
# /var/lib/gems/1.9.1/gems/eventmachine-1.0.7/lib/eventmachine.rb:187:in `call'
# /var/lib/gems/1.9.1/gems/eventmachine-1.0.7/lib/eventmachine.rb:187:in `run_machine'
# /var/lib/gems/1.9.1/gems/eventmachine-1.0.7/lib/eventmachine.rb:187:in `run'
# ./lib/rppc/net/receiver.rb:8:in `initialize'
# ./spec/net/receiver_spec.rb:6:in `new'
# ./spec/net/receiver_spec.rb:6:in `block (2 levels) in <top (required)>'
I'm quite new to the ruby environment, so if i missed something let me know.
I'm not sure what documentation you're working from, but it appears the open_datagram_socket requires a Module and cannot accept a Class as the third (handler) argument.
Per the comment in http://www.rubydoc.info/github/eventmachine/eventmachine/EventMachine.open_datagram_socket, it appears this restriction may have been loosened in a later version of EventMachine

How to define Ruby Test::Unit testcase with `must`

I had a test case of the following form:
require 'test/unit'
class SomeTests < Test::Unit::TestCase
def test_should_do_action
assert true
end
end
and have re-written it using must as suggested in the book A Test::Unit Trick to Know About:
require 'test/unit'
class SomeTests < Test::Unit::TestCase
must "do action" do
assert true
end
end
And when I run it, I get an undefined method 'must' error shown as follows:
SomeTests.rb:3:in `<class:SomeTests>': undefined method `must' for SomeTests:Class (NoMethodError) from
SomeTests.rb:2:in `<top (required)>' from
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require' from
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require' from
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rake/rake_test_loader.rb:10:in `block (2 levels) in <main>' from
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rake/rake_test_loader.rb:9:in `each' from
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rake/rake_test_loader.rb:9:in `block in <main>' from
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rake/rake_test_loader.rb:4:in `select' from
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rake/rake_test_loader.rb:4:in `<main>' rake aborted! Command failed with status (1): [ruby -w -I"lib" -I"/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0" "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rake/rake_test_loader.rb" "test/**/*Tests.rb" ]
Tasks: TOP => default => test (See full trace by running task with --trace)
I thought that must might be a part of minitest, so I required 'minitest/unit' instead, but I still get an error. I also assume that must keyword isn't part of rspec, which I'm not using yet.
How do I get this to work properly?
It looks like that method is not provided out of the box, but was developed by a third party. You need to add code described here.

Cannot read span elements

Hi since I did gem install watir watir-classic my scripts are not reading anymore the span elements. Can you please help me to fix this problem
here my example
Source
Rented
<SPAN class="displayData" style="padding-left:2px; width: 15;"><span name="tab4RateInfoForm.vehicleGroup"/>F</span></SPAN>
My code
carGroup=browser.span(:name => 'tab4RateInfoForm.vehicleGroup').text
Error message
C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:79:in `rescue in match?': name is an unknown way of finding a <span> element (tab4RateInfoForm.vehicleGroup) (Watir::Exception::MissingWayOfFindingObjectException)
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:76:in `match?'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:62:in `block in match_with_specifiers?'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:59:in `each'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:59:in `all?'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:59:in `match_with_specifiers?'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:22:in `block (2 levels) in each'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:140:in `block in each_element'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:139:in `each'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:139:in `each_element'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:21:in `block in each'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:20:in `each'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:20:in `each'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/locator.rb:150:in `locate'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/element.rb:33:in `locate'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/element.rb:63:in `assert_exists'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/watir-classic-3.3.0/lib/watir-classic/element.rb:132:in `text'
Solution 1: Use css locator
You will have to use a css-locator (or xpath):
carGroup = browser.span(:css, 'span[name="tab4RateInfoForm.vehicleGroup"]').text
Solution 2: Monkey patch
Alternatively, if you have a lot of legacy scripts that use the name attribute, you can monkey patch Watir to have the name method for all elements (or specific element if desired).
Add the following to wherever you require watir:
Watir::IE.new(true)
module Watir
class Element
def name
return self.attribute_value('name')
end
end
end
Your original method should now work.
Looks like span elements can no longer be accessed via name attribute.
Try this (use generic element instead of span):
carGroup=browser.element(:name => 'tab4RateInfoForm.vehicleGroup').text

Rspec any_instance stub causing error undefined method __rspec_original_dup

I'm trying to stub out a Class method for any instance of the class (via any_instance). My tests run through successfully, but at the end of the test when rspec is trying to reset the any_instance stub, it throws an error (Unable to find matching line from backtrace). Here's the apparent culprit line of code (removing it removes the error):
Confetti::Config.any_instance.stub(:write_info)
The full error is below. Seems like stub should've (but fails to) created the __rspec_original_dup method, and when the reset happens, it can't find the expected method.
Failure/Error: Unable to find matching line from backtrace
NameError:
undefined method `__rspec_original_dup' for class `Confetti::Config'
# /Library/Ruby/Gems/1.8/gems/rspec-mocks-2.11.1/lib/rspec/mocks/any_instance.rb:73:in `alias_method'
# /Library/Ruby/Gems/1.8/gems/rspec-mocks-2.11.1/lib/rspec/mocks/any_instance.rb:73:in `restore_dup'
# /Library/Ruby/Gems/1.8/gems/rspec-mocks-2.11.1/lib/rspec/mocks/any_instance.rb:72:in `class_eval'
# /Library/Ruby/Gems/1.8/gems/rspec-mocks-2.11.1/lib/rspec/mocks/any_instance.rb:72:in `restore_dup'
# /Library/Ruby/Gems/1.8/gems/rspec-mocks-2.11.1/lib/rspec/mocks/any_instance.rb:46:in `rspec_reset'
# /Library/Ruby/Gems/1.8/gems/rspec-mocks-2.11.1/lib/rspec/mocks/space.rb:17:in `reset_all'
# /Library/Ruby/Gems/1.8/gems/rspec-mocks-2.11.1/lib/rspec/mocks/space.rb:16:in `each'
# /Library/Ruby/Gems/1.8/gems/rspec-mocks-2.11.1/lib/rspec/mocks/space.rb:16:in `reset_all'
# /Library/Ruby/Gems/1.8/gems/rspec-mocks-2.11.1/lib/rspec/mocks.rb:23:in `teardown'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/mocking/with_rspec.rb:18:in `teardown_mocks_for_rspec'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/example.rb:308:in `run_after_each'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/example.rb:119:in `run'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/example.rb:253:in `with_around_each_hooks'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/example.rb:110:in `run'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:378:in `run_examples'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:374:in `map'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:374:in `run_examples'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:360:in `run'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:361:in `run'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:361:in `map'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/example_group.rb:361:in `run'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/command_line.rb:28:in `run'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/command_line.rb:28:in `map'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/command_line.rb:28:in `run'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/reporter.rb:34:in `report'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/command_line.rb:25:in `run'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/runner.rb:69:in `run'
# /Library/Ruby/Gems/1.8/gems/rspec-core-2.11.1/lib/rspec/core/runner.rb:8:in `autorun'
# /usr/bin/rspec:19
I solved this by simply using Rspec v2.10.0 instead of v2.11.0:
gem 'rspec', '~> 2.10.0'
From the links that Henrik provided, it sounds like they may release a bugfix for Rspec. Watch this issue for more information. In the meantime, downgrading solved the issue for me.
(Thanks for your work in helping me figure this out, Henrik.)

Resources