5

I go into irb and require a file

irb> require_relative 'prime'
irb> true

This file 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

requiring the file in irb works and I can use the method, e.g.

irb> require_relative 'prime'
irb> is_prime? 10
irb> -> false

irb> is_prime? 11
irb> -> true

However if I modify the source file, say add puts 'HHH', that does not show up unless I exit the console and re-enter and then require the file

If I stay in the console and require the file again I get false as it is already loaded and I don't get the new changes

I have tried

irb> reload

and

irb> reload!

but they give me

NoMethodError (undefined method `reload!' for main:Object)

Also I tried

irb> load 'prime.rb'
irb> => true

but did not pick up the change

Using PRY gave similar results

Michael Durrant
  • 93,410
  • 97
  • 333
  • 497

3 Answers3

9

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://stackoverflow.com/a/4633535/4950680

Martin
  • 4,042
  • 2
  • 19
  • 29
  • load 'prime.rb` returns true but does not seem to pick up changes – Michael Durrant May 13 '19 at 12:54
  • 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 does – Michael Durrant May 13 '19 at 12:56
  • 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 reload – Michael Durrant May 13 '19 at 12:58
  • @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? – Martin May 13 '19 at 13:00
  • 3
    @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`](https://ruby-doc.org/stdlib-2.6.3/libdoc/prime/rdoc/Prime.html) so you were actually loading this file and not your `prime.rb` file. – engineersmnky May 13 '19 at 13:20
  • @engineersmnky omg nice one. I thought something really odd was going on, you nailed it! – Michael Durrant May 13 '19 at 13:41
  • 3
    Nothing gets by @engineersmnky. – Cary Swoveland May 13 '19 at 17:18
  • 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 lib – Juan José Ramírez Aug 05 '21 at 03:15
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.

AnoE
  • 8,048
  • 1
  • 21
  • 36
  • 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](https://rubygems.org/gems/activesupport/versions/5.0.0.1) may be the way to go for a canned solution. – tadman May 13 '19 at 16:19
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