Background - in a Rails app, I'm seeing a bug in production where a file cannot find a class from the standard library; but in development, everything works fine. Presumably, some gem that I have in the development group but not the production group is requiring the necessary library, so the symbol is define for development but not for production.
Is there any way I can get Ruby to tell me where require was called for a given file?
(I'm deliberately not naming the offending library, because I don't want suggestions as to what might be requiring it; I want to know how I can find out myself)
To answer your direct question: patch/override the require method and get access to all the info you need.
app/config/environment.rb
# set up intrumentation
module RequireSpy
def require(*args)
puts "requiring #{args.join(', ')} from #{caller.first}"
super
end
end
Object.include(RequireSpy)
# init your rails app as usual
require File.expand_path('../application', __FILE__)
Rails.application.initialize!
Upon booting the rails app, it'll print a LOT of output:
requiring tilt from /Users/sergio/.gem/ruby/2.4.2/gems/sinatra-1.4.8/lib/sinatra/base.rb:3:in `<top (required)>'
requiring rack/protection from /Users/sergio/.gem/ruby/2.4.2/gems/sinatra-1.4.8/lib/sinatra/base.rb:4:in `<top (required)>'
requiring thread from /Users/sergio/.gem/ruby/2.4.2/gems/sinatra-1.4.8/lib/sinatra/base.rb:7:in `<top (required)>'
requiring time from /Users/sergio/.gem/ruby/2.4.2/gems/sinatra-1.4.8/lib/sinatra/base.rb:8:in `<top (required)>'
requiring uri from /Users/sergio/.gem/ruby/2.4.2/gems/sinatra-1.4.8/lib/sinatra/base.rb:9:in `<top (required)>'
You probably want to filter that.
Related
Ubuntu 18.04, ruby 2.5.1p57
I have a ruby program that I use on a number of different linux system. On one it produces a screed of warning from require 'savon'
elasticsearch#secesprd02:~$ ruby /usr/local/tools/dev/es-cluster/bin/send-json.rb -v --cluster test -c /usr/local/tools/dev/conf/conf.json -r name=ES-api-winlogbeat json/winlogbeat-api-key
/var/lib/gems/2.5.0/gems/akami-1.3.1/lib/akami/wsse.rb:99: warning: shadowing outer local variable - key
/var/lib/gems/2.5.0/gems/akami-1.3.1/lib/akami/wsse.rb:99: warning: shadowing outer local variable - v1
/var/lib/gems/2.5.0/gems/akami-1.3.1/lib/akami/wsse.rb:99: warning: shadowing outer local variable - v2
/usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59: warning: loading in progress, circular require considered harmful - /var/lib/gems/2.5.0/gems/gyoku-1.3.1/lib/gyoku/hash.rb
from /usr/local/tools/dev/es-cluster/bin/send-json.rb:8:in `<main>'
from /usr/local/tools/dev/es-cluster/bin/send-json.rb:8:in `require_relative'
from /usr/local/tools/dev/common-library/lib/app-configure.rb:3:in `<top (required)>'
from /usr/local/tools/dev/common-library/lib/app-configure.rb:3:in `require_relative'
from /usr/local/tools/common-library/lib/SecretServer.rb:1:in `<top (required)>'
from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:39:in `require'
from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:135:in `rescue in require'
from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:135:in `require'
from /var/lib/gems/2.5.0/gems/savon-2.12.1/lib/savon.rb:26:in `<top (required)>'
from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'
...
The program runs without any obvious problems apart from the warings.
I have updated savon and akami gems but this made no difference.
The warning is caused due to
loading in progress, circular require considered harmful - /var/lib/gems/2.5.0/gems/gyoku-1.3.1/lib/gyoku/hash.rb
That should not cause you any harm, given that the require keeps track of files already loaded, so the behaviour of your application should not be affected in any way.
A good overview on that can be found on this answer.
Under normal circumstances it's fine to require the same file twice, because require keeps a record of the libraries it has loaded and ignores a second call.
It looks as if you get this error if the library you are requiring
requires itself somehow, which is not something that require can cope
with -- the require operation presumably needs to complete before the
library is added to the list.
So if in a.rb you require b.rb and in b.rb you require a.rb. then when you write require "a" Ruby will
* start to require a.rb
* start to require b.rb
* start to require a.rb again and realise there is something terribly wrong.
I installed gem 'ssh-net'. From the console I tried to require the gem like this:
irb(main):009:0* require 'ssh-net'
LoadError: cannot load such file -- ssh-net
from /var/lib/gems/2.3.0/gems/activesupport-4.2.10/lib/active_support/dependencies.rb:274:in `require'
from /var/lib/gems/2.3.0/gems/activesupport-4.2.10/lib/active_support/dependencies.rb:274:in `block in require'
from /var/lib/gems/2.3.0/gems/activesupport-4.2.10/lib/active_support/dependencies.rb:240:in `load_dependency'
from /var/lib/gems/2.3.0/gems/activesupport-4.2.10/lib/active_support/dependencies.rb:274:in `require'
from (irb):9
from /home/csrhub/git/csrhub-api/bin/console:150:in `<top (required)>'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/lib/bundler/cli/exec.rb:63:in `load'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/lib/bundler/cli/exec.rb:63:in `kernel_load'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/lib/bundler/cli/exec.rb:28:in `run'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/lib/bundler/cli.rb:476:in `exec'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/lib/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/lib/bundler/cli.rb:30:in `dispatch'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/lib/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/lib/bundler/cli.rb:24:in `start'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/exe/bundle:46:in `block in <top (required)>'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/lib/bundler/friendly_errors.rb:123:in `with_friendly_errors'
from /var/lib/gems/2.3.0/gems/bundler-2.1.1/exe/bundle:34:in `<top (required)>'
from /usr/local/bin/bundle:23:in `load'
from /usr/local/bin/bundle:23:in `<main>'
Then I tried with a gem that works:
irb(main):023:0* require 'memcache'
=> false
I printed the gems locations:
csrhub#csrhub:~/git/csrhub-api$ bundle info 'net-ssh'
* net-ssh (5.2.0)
Summary: Net::SSH: a pure-Ruby implementation of the SSH2 client protocol.
Homepage: https://github.com/net-ssh/net-ssh
Path: /var/lib/gems/2.3.0/gems/net-ssh-5.2.0
csrhub#csrhub:~/git/csrhub-api$ bundle info 'memcache'
* memcache-client (1.8.5)
Summary: A Ruby library for accessing memcached.
Homepage: http://github.com/mperham/memcache-client
Path: /var/lib/gems/2.3.0/gems/memcache-client-1.8.5
csrhub#csrhub:~/git/csrhub-api$
I see that both gems are placed in the same directory. Why memcache is invokable and the ssh-net is not? What am I missing?
May be it has something to do with this ?
I installed gem 'ssh-net'.
No, you didn't. You installed the gem net-ssh, as you can clearly see in the output of bundle info that you posted:
csrhub#csrhub:~/git/csrhub-api$ bundle info 'net-ssh'
* net-ssh (5.2.0)
Summary: Net::SSH: a pure-Ruby implementation of the SSH2 client
Here you can see that the name of the gem is net-ssh and not ssh-net and that the name of the primary class is Net::SSH.
From the console I tried to require the gem like this:
irb(main):009:0* require 'ssh-net'
LoadError: cannot load such file -- ssh-net
The primary class in this gem is called Net::SSH. (It integrates in the Net namespace of the Ruby standard library, which has libraries like Net::FTP, Net::HTTP, Net::IMAP, Net::POP, Net::SMTP, and Net::Telnet.)
According to standard Ruby naming conventions, a class named Net::SSH should be located in a file named lib/ssh.rb. This is the file you need to require.
This is also shown in the very first line of the very first code sample of the very first page of the documentation:
require 'net/ssh'
I see that both gems are placed in the same directory. Why memcache is invokable and the ssh-net is not? What am I missing?
In 99.9% of all cases where a computer tells you it cannot find something, it is because that thing you told it to find is indeed not there. Computers are very, very good at finding things.
The same thing is the case here: you told Ruby
require 'ssh-net'
which means "go through each directory in the $LOAD_PATH and look for a file named ssh-net.rb". Such a file simply does not exist, ergo, you get a LoadError exception.
I want to use ActiveModel::Validations in a small Roda app, and I really want to keep it small and I would like to avoid loading the entirety of ActiveModel in it. Is there a way to require only ActiveModel::Validations ?
At least with activemodel-4.2.6. an attempt to require 'active_model/validations' results with
/home/bbozo/.rvm/gems/ruby-2.2.4/gems/activemodel-4.2.6/lib/active_model/validations/format.rb:4:in `<module:Validations>': uninitialized constant ActiveModel::Validations::EachValidator (NameError)
from /home/bbozo/.rvm/gems/ruby-2.2.4/gems/activemodel-4.2.6/lib/active_model/validations/format.rb:3:in `<module:ActiveModel>'
from /home/bbozo/.rvm/gems/ruby-2.2.4/gems/activemodel-4.2.6/lib/active_model/validations/format.rb:1:in `<top (required)>'
from /home/bbozo/.rvm/gems/ruby-2.2.4/gems/activemodel-4.2.6/lib/active_model/validations.rb:405:in `require'
from /home/bbozo/.rvm/gems/ruby-2.2.4/gems/activemodel-4.2.6/lib/active_model/validations.rb:405:in `block in <top (required)>'
from /home/bbozo/.rvm/gems/ruby-2.2.4/gems/activemodel-4.2.6/lib/active_model/validations.rb:405:in `each'
from /home/bbozo/.rvm/gems/ruby-2.2.4/gems/activemodel-4.2.6/lib/active_model/validations.rb:405:in `<top (required)>'
Hmff, OK, writing this question I found the solution ^_^
I managed to load "only" ActiveModel validations and it's dependencies, I ended up requiring
require 'active_support/concern'
require 'active_model/validator'
require 'active_model/validations'
require 'active_model/naming'
require 'active_model/callbacks'
require 'active_support/callbacks'
require 'active_model/translation
just to make this pass:
class Foo
include ActiveModel::Validations
end
so it seems I'll be requiring the entire active model or find an alternative validations framework.
require 'active_model'
class Account
include ActiveModel::Validations
end
I am learning custom matchers for rspec from this old, 2008 tutorial - http://www.reactive.io/tips/2008/12/10/up-and-running-with-custom-rspec-matchers/
Project Structure
.
├── one_plus.rb
└── one_plus_spec.rb
I followed all the instructions, but I am not able to understand why I am getting the following error:
rspec one_plus_spec.rb
/home/john/.rvm/rubies/ruby-2.0.0-p598/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- one_plus (LoadError)
from /home/john/.rvm/rubies/ruby-2.0.0-p598/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:54:in `require'
from /home/john/Code/Rspec/Misc/CustomRspecMatchers/one_plus_spec.rb:3:in `<top (required)>'
from /home/john/.rvm/gems/ruby-2.0.0-p598/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `load'
from /home/john/.rvm/gems/ruby-2.0.0-p598/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `block in load_spec_files'
from /home/john/.rvm/gems/ruby-2.0.0-p598/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `each'
from /home/john/.rvm/gems/ruby-2.0.0-p598/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `load_spec_files'
from /home/john/.rvm/gems/ruby-2.0.0-p598/gems/rspec-core-2.14.8/lib/rspec/core/command_line.rb:22:in `run'
from /home/john/.rvm/gems/ruby-2.0.0-p598/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:80:in `run'
from /home/john/.rvm/gems/ruby-2.0.0-p598/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:17:in `block in autorun'
john#ubuntu:~/Code/Rspec/Misc/CustomRspecMatchers$
There is no clear answer in other stack overflow questions for this. I don't just want a solution, but I also want to know why this error happens and the concepts that I need to learn to prevent it from happening again.
Try using require_relative instead:
require_relative 'one_plus'
./ (current directory) was removed from the load path in Ruby 1.9.
your load path doesn't include ./ by default, that's why.
Understanding Ruby's load paths includes details as well as solutions.
I personally use require_relative pretty often in specs myself, but you can also modify the load path.
When I run cucumber, I get the following messages:
*** WARNING: You must use ANSICON 1.31 or higher (http://adoxa.110mb.com/ansicon) to get coloured output on Windows
Warning: you should require 'minitest/autorun' instead.
Warning: or add 'gem "minitest"' before 'require "minitest/autorun"'
From:
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/lib/cucumber/core_ext/disable_mini_and_test_unit_autorun.rb:3:in `<top (required)>'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/lib/cucumber/runtime.rb:21:in `initialize'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/lib/cucumber/cli/main.rb:40:in `new'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/lib/cucumber/cli/main.rb:40:in `execute!'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/lib/cucumber/cli/main.rb:20:in `execute'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/bin/cucumber:14:in `<top (required)>'
C:/RailsInstaller/Ruby2.1.0/bin/cucumber:23:in `load'
C:/RailsInstaller/Ruby2.1.0/bin/cucumber:23:in `<main>'
MiniTest::Unit::TestCase is now Minitest::Test. From C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/test/unit/testcase.rb:8:in `<module:Unit>'
undefined method `_run_suite' for class `Test::Unit::Runner' (NameError)
C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/test/unit.rb:676:in `<class:Runner>'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/test/unit.rb:261:in `<module:Unit>'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/test/unit.rb:15:in `<module:Test>'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/test/unit.rb:7:in `<top (required)>'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/lib/cucumber/core_ext/disable_mini_and_test_unit_autorun.rb:25:in `<top (required)>'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/lib/cucumber/runtime.rb:21:in `initialize'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/lib/cucumber/cli/main.rb:40:in `new'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/lib/cucumber/cli/main.rb:40:in `execute!'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/lib/cucumber/cli/main.rb:20:in `execute'
C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/cucumber-1.2.1/bin/cucumber:14:in `<top (required)>'
C:/RailsInstaller/Ruby2.1.0/bin/cucumber:23:in `load'
C:/RailsInstaller/Ruby2.1.0/bin/cucumber:23:in `<main>'
bundle list gives me:
DL is deprecated, please use Fiddle
Gems included by the bundle:
* builder (3.2.2)
* bundler (1.7.7)
* cucumber (1.2.1)
* diff-lcs (1.1.3)
* gherkin (2.11.8)
* json (1.8.1)
* minitest (4.7.5)
* multi_json (1.10.1)
* rspec-expectations (2.11.2)
Based on a similar question on stack exchange, I have the following in `features\support\env.rb':
require 'minitest'
module MiniTestAssertions
def self.extended(base)
base.extend(MiniTest::Assertions)
base.assertions = 0
end
attr_accessor :assertions
end
World(MiniTestAssertions)
What's my next step to getting cucumber working?
Edit:
I've tried running cucumber in a completely empty directory (expecting to get a warning that no features are defined), but get exactly the same message: the warning about minitest, then the error about undefined method '_run_suite'. Evertyhing I can find on the web about this either relates to Rails (which I'm not using) or says it's an old problem that has been fixed, so I'm completely stuck. :(
Any reason why you can't use ruby 1.9 for going through this exercise?
The latest version of the The Cucumber Book - version 3.0 - was released in Mar 2014 when ruby 1.9.3 was the most prevalently used ruby version.
The code for the book was tested with ruby 1.9.3-p194 (as mentioned in Appendix 2 - Installing Cucumber section).
The authors/pragprog may come up with a new edition of the book, and at that time they will ensure the code in the book work with ruby 2.2 or the then most commonly used version of ruby.
It is quite possible to figure out how to make these examples work for ruby 2.0 or higher version, but that is a headache I would recommend you not concern yourself at this time. Given that you are just now starting to learn about cucumber, it would be best to follow the text in the book based on the version it recommends.
After getting familiar with cucumber, and other components of the ruby world, you will appreciate why I find "How do I persuade it to use RSpec?" to be very funny. :-)
As you know, the configuration of your development environment is a tedious and error-prone task. I prefer to work in a *nix-type environment, which you could achieve on your Windows box using, say, VirtualBox or some Docker-for-Windows arrangement.
If you can get such a Docker configuration for Windows up and running, then this may be your best bet to solve the issue quickly, since Docker is all about sharing/reusing pre-configured environments/deployments, which can be a real time-saver! There are already some fine Dockerfile configurations that should help you see which components to install. See: this and that.
BTW, if you prefer to use rspec over minitest (and who wouldn't?), you'll want to use some sample code that doesn't "require 'minitest'". If you only are interested to get the current example working, you might entertain the idea that is given by the error message to "require 'minitest/autorun'". I hope it helps you--good luck!