Which libraries are loaded by default in pry? - ruby

When I use Tempfile class in pry, I don't use require it.
% pry -f
pry(main)> Tempfile
Tempfile < #<Class:0x00007fb5121149b8>
But when in irb I must to require tempfile first.
% irb
irb(main):001:0> Tempfile
NameError: uninitialized constant Tempfile
from (irb):1
from /Users/ironsand/.rbenv/versions/2.4.3/bin/irb:11:in `<main>'
irb(main):002:0> require 'tempfile'
=> true
So it seems pry load some libraries by default.
Which libraries are actually loaded?
This is my environment
% ruby -v
ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin17]
% irb --version
pirb 0.9.6(09/06/30)
% pry --version
Pry version 0.11.3 on Ruby 2.4.3

You can compare $LOADED_FEATURES to see everything that's loaded in a default pry session vs an irb session (or a plain ruby script).
The short answer is that Pry loads whichever libraries it needs to provide its own behaviour. The long answer is too long (and too likely to get out of date, or differ between versions) to list here -- better to ask your current environment.
It's good practice not to rely on other libraries to load their dependencies for you, because those dependencies can change. (Though in cases like this, it can be hard to notice you're missing a require, because everything still works.)

As an alternative to $LOADED_FEATURES, which can be a bit excessive, consider:
Gem.loaded_specs.values.each {|s| puts s.name}
which only lists gems with specs
[20] pry(main)> Gem.loaded_specs.values.each {|s| puts s.name};nil
did_you_mean
coderay
method_source
pry
io-console
vls
=> nil
BTW, in this example, I had loaded the vls gem manually.

Related

Where is SimpleDelegator in Ruby 2.7?

I have been using the SimpleDelegator class for various things. But I noticed, Ruby 2.7 (ArchLinux x86_64) doesn't come with the SimpleDelegator class (no Delegator either).
My program:
#!/usr/bin/ruby -w
class OutputDecorator < SimpleDelegator
def puts(*args)
STDOUT.write "Hello #{args.join}... It's Ruby #{RUBY_VERSION} #{RUBY_PLATFORM}\n"
end
end
$stdout = OutputDecorator.new($stdout)
$stdout.puts('Sourav')
$stdout = $stdout.__getobj__
$stdout.puts('Sourav')
Running with:
Ruby 2.4.6:
> ~/.rvm/rubies/ruby-2.4.6/bin/ruby p.rb
Hello Sourav... It's Ruby 2.4.6 x86_64-linux
Sourav
Ruby 2.5.5:
> ~/.rvm/rubies/ruby-2.5.5/bin/ruby p.rb
Hello Sourav... It's Ruby 2.5.5 x86_64-linux
Sourav
Ruby 2.6.3:
> ~/.rvm/rubies/ruby-2.6.3/bin/ruby p.rb
Hello Sourav... It's Ruby 2.6.3 x86_64-linux
Sourav
Ruby 2.7.0:
> ruby p.rb
Traceback (most recent call last):
p.rb:2:in `<main>': uninitialized constant SimpleDelegator (NameError)
Is there any new alternatives to SimpleDelegator in Ruby 2.7?
The Delegator and SimpleDelegator classes aren't core classes like Array or Mutex. They're part of the delegate standard library which needs to be loaded first: require 'delegate'.
It happened to work in older Ruby versions as they came with an older RubyGems version by default. RubyGems is automatically loaded since Ruby 1.9 and until 3.1.0 that meant delegate was loaded indirectly. Updating RubyGems or running ruby with --disable=gems should cause the exact same issue with Ruby <= 2.6 too. irb also loads several standard libraries: delegate but also timeout and many more.
Programming languages with a similar mechanism like C++ also have this issue: instead of load/require there's #include, including a standard library header might include another one, then a newer version might not include the other header anymore and user code relying on the old behavior fails to compile.

Why does require choose the latest version of a gem?

If I load a gem, let's say activerecord, in IRB require chooses the latest version of activerecord. Programmatically, what is influencing this decision to choose the latest gem version? Is require doing this, or is there something in the loaded IRB that forces requires to choose the latest version?
Here are my activerecord gems installed by bundler:
➜ ~ ls -al /Users/robskrob/.rvm/gems/ruby-2.4.1/gems/activere
activerecord-4.2.10/ activerecord-5.0.0.1/ activerecord-5.1.2/ activerecord-5.1.3/ activerecord-5.1.4/ activerecord-5.1.5/ activerecord-5.1.6/ activeresource-5.0.0/
And here is an example IRB session:
➜ ~ irb
2.4.1 :001 > require 'active_record'
=> true
2.4.1 :002 > Gem.loaded_specs['activerecord'].version
=> #<Gem::Version "5.1.6">
2.4.1 :003 >
If I load a gem, let's say activerecord, in IRB require chooses the latest version of activerecord.
Actually, it chooses the latest version that doesn't conflict with any already activated gem.
Programmatically, what is influencing this decision to choose the latest gem version? Is require doing this, or is there something in the loaded IRB that forces requires to choose the latest version?
This is requires job. More specifically, it is the job of the monkey-patched require from the RubyGems library, not the original require from the Ruby core library.
This is just simple separation of concerns: IRb is a REPL, not a package management system, it shouldn't know anything about packages.

How to require pry during development of a ruby gem?

I'm trying to develop a ruby gem for practice and I'm wondering how do I require pry during development and test runs? Is there anyway to require the gem only during development? I'm on Ruby and not Rails and I don't think I have any environment variables setup to rely on. Is there a conventional way to do this?
and
Currently if I run code that hits the above line, I get this error:
NoMethodError: undefined method `pry' for #<Binding:0x007f8d3287c4d8>
from /Users/jwan/programming/interview_questions/gemini/jobcoin_client/lib/jobcoin_client/requests/connection.rb:18:in `post'
A few questions:
How do I properly require pry so this line doesn't throw an error when developing a gem?
I read Yahuda's post but I'm still unclear why adding dependencies in the gemspec vs adding dependencies in the Gemfile. What is the difference?
Currently, after I make changes to the ruby gem, I have to run these series of commands. Is there anything more efficient that I can do?
gem build jobcoin_client.gemspec
WARNING: no homepage specified
WARNING: open-ended dependency on pry (>= 0, development) is not recommended
if pry is semantically versioned, use:
add_development_dependency 'pry', '~> 0'
WARNING: See http://guides.rubygems.org/specification-reference/ for help
Successfully built RubyGem
Name: jobcoin_client
Version: 0.1.0
File: jobcoin_client-0.1.0.gem
$ gem install jobcoin_client
Successfully installed jobcoin_client-0.1.0
Parsing documentation for jobcoin_client-0.1.0
Done installing documentation for jobcoin_client after 0 seconds
1 gem installed
05:45 PM
$ irb
irb(main):001:0> require 'jobcoin_client'
=> true
irb(main):002:0> require 'pry'
=> false
You can install it to the system and use a boolean flag to conditionally require it and set breakpoints.
gem install pry
Then in code, something like this:
SET_BREAKPOINTS = ENV["SET_BREAKPOINTS"] == "true"
require 'pry' if SET_BREAKPOINTS
binding.pry if SET_BREAKPINTS
To turn breakpoints on, you can manipulate env through code:
ENV["SET_BREAKPOINTS"] = "true"
or when calling a script from bash:
env SET_BREAKPOINTS=true irb -r 'your_gem'

why can I require gems which are outside from $LOAD_PATH

I installed a gem coffee-cup in my rvm gem set,ruby-2.1.1#test whose path is /Users/dingxijin/.rvm/gems/ruby-2.1.1#test/gems/coffee-cup-0.0.4.
Then I open irb,just like this:
2.1.1 :001 > puts $:
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0/x86_64-darwin12.0
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby/2.1.0
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin12.0
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0
/Users/dingxijin/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/x86_64-darwin12.0
=> nil
2.1.1 :002 > require "coffee-cup"
NameError: uninitialized constant CoffeeCup::Rails
from /Users/dingxijin/.rvm/gems/ruby-2.1.1#test/gems/coffee-cup-0.0.4/lib/coffee-cup/engine.rb:2:in `<module:CoffeeCup>' ..........
Does ruby search gems from the $LOAD_PATH directories?
why can I require coffee-cup,it's obviously that $LOAD_PATH doesn't have its directory?
The original, “normal” behaviour of require is how you have described it: the LOAD_PATH is searched for the requested file and if it’s not found a LOAD_ERROR is raised. Rubygems modifies this behaviour by replacing the Kernel#require method. The comment to the new require method explains what happens:
When RubyGems is required, Kernel#require is replaced with our own which
is capable of loading gems on demand.
When you call require 'x', this is what happens:
If the file can be loaded from the existing Ruby loadpath, it
is.
Otherwise, installed gems are searched for a file that matches.
If it's found in gem 'y', that gem is activated (added to the
loadpath).
The normal require functionality of returning false if
that file has already been loaded is preserved.
With Rubygems included in Ruby by default, this new behaviour is now the norm.
In your example if you look at the load path again after you have required a file from a gem you should see the gems’ path has been added.

How do I require a specific version of a ruby gem?

Specifically, the ruby-oci8 gem. I have both 1.0.7 and 2.0.4 installed. I want 1.0.7.
I can just require oci8, but I don't get the version I want.
irb(main):001:0> require 'oci8'
=> true
irb(main):002:0> OCI8::VERSION
=> "2.0.4"
I can require using the full path to the file, which works, but is not going to be portable:
irb(main):001:0> require 'C:\Ruby\lib\ruby\gems\1.8\gems\ruby-oci8-1.0.7-x86-mswin32-60\lib\oci8'
=> true
irb(main):002:0> OCI8::VERSION
=> "1.0.7"
I can use the gem command to ask for the version I want, but it doesn't appear to actually load the library:
irb(main):001:0> gem 'ruby-oci8', :lib=>'oci8', :version=>'=1.0.7'
=> true
irb(main):002:0> OCI8::VERSION
NameError: uninitialized constant OCI8
from (irb):2
I would definitely favor this last approach if would load the library, rather than just confirming that it's present on my system. What am I missing?
My problem was twofold:
1) confusing gem command syntax with that used in config.gem lines in a rails environment.rb configuration file.
2) failing to issue a require command after the gem command.
Proper usage in a script is:
gem 'ruby-oci8', '=1.0.7'
require 'oci8' # example is confusing; file required (oci8.rb) is not
# same name as gem, as is frequently the case
Proper usage in a rails 2.3.x environment.rb file is:
config.gem "ruby-oci8", :version=>'1.0.7'
Thanks to the folks at http://www.ruby-forum.com/topic/109100
Try the following syntax (instead of require):
require_gem 'RMagick' , '=1.10'
require_gem 'RMagick' , '>=1.10'
require_gem 'rake', '>=0.7.0', '<0.9.0'

Resources