Reputation: 51229
I have a gem project with the following structure:
foo-bar
├── lib
│ └── foo
│ ├── bar
│ │ └── qux.rb
│ └── bar.rb
└── spec
├── spec_helper.rb
└── unit
├── baz_spec.rb
└── qux_spec.rb
In lib/foo
, bar.rb
defines a module Foo::Bar
, and inside that, a class Foo::Bar::Baz
. Inside lib/foo/bar
, qux.rb
defines a class Foo::Bar::Qux
.
spec_helper.rb
sets up RSpec and Simplecov, and finishes with require 'foo/bar'
. Both baz_spec.rb
and qux_spec.rb
start with require 'spec_helper'
.
baz_spec.rb
has the specs for Foo::Bar::Baz
, and it works fine. qux_spec.rb
, however, which has the specs for Foo::Bar::Qux
, fails with:
/Users/me/foo-bar/spec/unit/qux_spec.rb:6:in `<module:Bar>': uninitialized constant Foo::Bar::Qux (NameError)
from /Users/me/foo-bar/spec/unit/qux_spec.rb:4:in `<module:Foo>'
from /Users/me/foo-bar/spec/unit/qux_spec.rb:3:in `<top (required)>'
from /Users/me/.rvm/gems/ruby-2.2.0/gems/rspec-core-3.2.2/lib/rspec/core/configuration.rb:1226:in `load'
...
(etc.)
I've verified that it's not just a typo by moving the code for Foo::Bar::Baz
out of lib/foo/bar.rb
and into its own file, lib/foo/bar/baz.rb
, after which baz_spec.rb
also stops working.
It also doesn't seem to make a difference whether I declare the class as
class Foo::Bar::Qux
...
or as
module Foo
module Bar
class Qux
...
I'm using Ruby 2.2.0 with RSpec 3.2.2 on Mac OS X Yosemite.
Clearly there's something wrong with my requires
, but as a Ruby novice I'm not seeing it. Any ideas?
Upvotes: 1
Views: 263
Reputation: 51229
Solved: after taking a closer look at the other projects I was cargo-culting from, I realized I'd misunderstood require
.
Unlike (apparently) its Rails equivalent, the out-of-the-box Kernel.require
just loads .rb
files (and extension libraries). So in the example above, require 'foo/bar'
doesn't load files from the foo/bar
directory, it just loads foo/bar.rb
.
In order to load the files under foo/bar
, including qux.rb
, I had to go into bar.rb
and explicitly load those files at the top of the module declaration:
module Foo
module Bar
Dir.glob(File.expand_path('../bar/*.rb', __FILE__), &method(:require))
# ...module declaration continues...
Just one of the many scripting-language-heritage pitfalls waiting for those who come to Ruby from other more heavyweight languages, I suppose.
Upvotes: 1
Reputation: 10630
you need to add foo.rb
file under ./lib
and add require statements for each file in order you want them to get loaded. You can look at sample gem for reference: dogeify and an article that walks you through gem creation build your first gem.
Upvotes: 2
Reputation: 2528
If you're using ActiveSupport
a single line like this will help you:
ActiveSupport::Dependencies.autoload_paths << "./lib"
If you're now trying to use Foo::Bar::Qux
, ActiveSupport will look for a file named foo/bar/qux.rb
inside of the lib
folder.
Upvotes: 1