Ruby - how to reload a file with changes in IRB or PRY?
Asked Answered
H

3

6

I want to reload a file in irb. The file, prime.rb, contains the following code:

def is_prime? num
  (2..num-1).each do |div_by|
    if num % div_by == 0
      return false
    end 
  end 
  true
end

I can use require_relative to require the file:

irb(main):001> require_relative 'prime'
=> true
irb(main):002> is_prime? 10
=> false
irb(main):003> is_prime? 11
=> true

If I make a change to prime.rb, how can I reload the file? I have tried:

irb(main):004> require_relative 'prime'
=> false

The same behavior occurs in pry.

Hookah answered 13/5, 2019 at 12:48 Comment(0)
I
12

Try Kernel#load with relative path to rb file:

irb> load './path/to/prime.rb'

Kernel#require loads a source file only once, while Kernel#load loads it every time you call it.

Ref https://mcmap.net/q/273496/-how-can-i-reload-a-script-in-irb

Insincerity answered 13/5, 2019 at 12:52 Comment(8)
load 'prime.rb` returns true but does not seem to pick up changesHookah
wait it works with relative only, e.g. load "./prime.rb" even though using no filepath worked it didn't really reload but using relative it doesHookah
sweet, yeah. It's odd that the load says it works (if the file doesn't exist it gives an error) but then not reloaded (the absolute, i.e. just the filename). But with the relative is says true and it really does reloadHookah
@MichaelDurrant From docs If the filename does not resolve to an absolute path, the file is searched for in the library directories listed in $:. Maybe you have file with same name in library directories?Insincerity
@MichaelDurrant the reason load 'prime.rb' did not seem to have an effect is that ruby has a standard lib class by that name Prime so you were actually loading this file and not your prime.rb file.Interstratify
@Interstratify omg nice one. I thought something really odd was going on, you nailed it!Hookah
Nothing gets by @engineersmnky.Hallowmas
I had the same problem with another file name, called config/application.rb (in a lambda, to emulate rails like files), load returned true but it still didn't pick the code change and I don't thing there's a collision with standard libSouthing
L
3

require just says that you literally "require" some other .rb file to be loaded. Once it is loaded, that requirement is satisfied, and further require calls with the same target file are ignored. This makes it save to have the same require call sprinkled liberately across many source files - they won't actually do anything after the first one has been executed.

You can use load to force it to actually load the file - this should do exactly what you expect (require calls load after checking whether the file has already been required).

Note that all of this is straightforward if you are in a plain-old-ruby context (i.e., calling methods or instatiating objects yourself) but can become a bit hairy if one of the "big guns" a.k.a. Rails is involved. Rails does a lot of magic behind the scenes to automatically require missing stuff (hence why you see so few explicit require calls in Rails code) - which leads to explicit loads in the irb sometimes seemingly having no effect.

Logbook answered 13/5, 2019 at 12:55 Comment(1)
Ruby on Rails has an autoloader that can do this but it also does a lot of strange things to avoid defining the constants you think you're defining, instead replacing them with similarly named anonymous classes. This means they can be thrown aside and replaced seamlessly. Doing this yourself is probably asking too much, so using ActiveSupport may be the way to go for a canned solution.Close
N
1

Using PRY:

In my case, load was returning true and with $ MyClass.method I could see the new source code, yet the method was still performing old code.

I solved by using reset command (pry only) as suggested here

Northway answered 5/8, 2021 at 3:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.