2

Try creating a gem based on bundler's official guide on developing a Ruby gem.

Running bundle gem foodie will create a structure and generate files in the lib directory:

  • foodie
    • version.rb
  • foodie.rb

foodie.rb reads

require "foodie/version"

module Foodie
  # Your code goes here...
end

Running ruby lib/foodie.rb (or also from different directories) will result in

C:/Ruby23-x64/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- foodie/versio
n (LoadError)
        from C:/Ruby23-x64/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from foodie.rb:1:in `<main>'

On the other hand installing the gem via rake install and then requiring the gem works just fine.

It works from source if require "foodie/version" is changed to require_relative "foodie/version" in foodie.rb. As I understand

  • require works based on modules
  • require_relative works based on directory structure

To me the latter looks like a hack. It'd no longer make sense to structure your code via modules as it wouldn't be enforced (maybe it'd still make sense but you could make mistakes and never notice).

My questions are:

  • Is it possible to test a gem from source without installing it while following the bundler convention (using require instead of require_relative)?
  • Why does the gem work after installed?
  • Is there any best practice for the usage of require, require_relative, modules, files and general structure?

Thank you.

thisismydesign
  • 21,553
  • 9
  • 123
  • 126
  • Please break this up into separate questions, because: 1. the three questions you have asked are quite different, and 2. they will be more useful to future readers that way. Thanks! – Jared Beck Apr 20 '17 at 16:44
  • Thanks for the feedback. I asked it this way because these questions emerged from the same issue/context - I'd imagine others to have similar questions in a similar situation. I think the same context is required for each question. Is it good practice to repeat the same context for several questions? – thisismydesign Apr 21 '17 at 09:11

1 Answers1

1

You need to add your lib dir to Ruby’s load path. The load path is a list of directories that Ruby searches for files in when you call require. Rubygems also manages the load path when you are using gems, which is why your code works when installed as a gem.

You say “as I understand ... require works based on modules”, this is not correct. require works with files, it’s just convention that a class or module is defined in a file with a matching name, e.g. MyModule might be in my_module.rb.

There are a few ways to add a dir to the load path. From the command line you can use the -I option:

$ ruby -I lib lib/foodie.rb

If you wanted to avoid typing -I lib you could use the RUBYLIB environment variable. Ruby adds the contents of this to the load path:

$ export RUBYLIB=lib
$ ruby lib/foodie.rb

(On Windows I think you will need to use set rather than export.)

You can also manipulate the load path from withing the program itself. It is stored in the global variable $LOAD_PATH, aliased as :$. This is how Rubygems and Bundler manage your gems.

matt
  • 78,533
  • 8
  • 163
  • 197
  • Thanks! Two remarks / questions: 1, My assumption was that even if you define several modules and classes within a single file you can choose to require only a certain class (e.g. `require A/B/C` with the following structure in a single file: `module A module B class C ... end end end`). Is there no way to achieve this? 2, The takeaway for me is that `require_relative` is the same as `require` except the former has an extended functionality and should therefore be prefered. Do you agree with this or are there any drawback for generally using `require_relative` instead of `require`? – thisismydesign Apr 21 '17 at 13:02