How to Require File from 'Gem' Which Are Not Under 'Lib' Directory

How to require file from `gem` which are not under `lib` directory?

I found a solution that I think is a little more syntactically elegant:

gem_dir = Gem::Specification.find_by_name("my_gem").gem_dir
require "#{gem_dir}/spec"

Cannot require ruby files from a directory other then the one with main files (LoadError)

require searches in your $LOAD_PATH. require should generally be used if you want to use a gem that is installed on your system. For your purposes you want to use require_relative:

require_relative 'riverbattle/version'

Note that at first glance

require './riverbattle/version'

might also seem to work. However, . here points to the current directory from where you run the process, not the directory where the file resides, obviously this is not what you want.

Where does require pull ruby files that don't exist on the system?

Rubygems overwrites Ruby's own Kernel#require method with its own method which loads gems on demand (i.e. adds the gem to the $LOAD_PATH and then requires the requested file).

Thus, when you execute require 'bundler/gem_tasks', what happens is that rubygems searches for a gem containing bundler/gem_tasks.rb in its require_paths path (which is specified in the respective gemspec of each gem). If a matching gem is found on your system, its require_paths are added to the $LOAD_PATH and Ruby's original require method is called which will load the requested file.

In any case, neither Ruby nor Rubygems dynamically loads gems from the internet. It will only use gems installed locally to the configured GEM_PATHS. You can find the configured paths which are searched for installed gems by running gem env on your command line.

If you start Ruby with the --disable-gems command line argument, it will not automatically load rubygems and thus will not add its custom implementation of Kernel#require. Here, only files in locations you specifically added to the $LOAD_PATH can be required.

Executable require can't find it's own library

Your gem should have a lib directory. During development, you will need to get that lib directory added to Ruby's load path one way or another.

You can add it in Ruby code. I wouldn't recommend doing that in your situation, but it is helpful to put something like this in your test helper or spec helper files to help your tests find the library:

$LOAD_PATH << 'lib'

You can add it with a Ruby command-line option or environment variable:

RUBYOPT="-Ilib" ruby bin/chklinks.rb
ruby -Ilib bin/checklinks.rb

I'm assuming the commands above would be run from the root directory of your gem, so the path you need to add is simply lib. If your setup is different, you would change lib in the commands above to be some other path.

How to require all files in a directory, in a gem?

Rubygems has a facility called find_files that will allow you to search based anything in the load path:

Gem.find_files("my_gem/files/**/*.rb").each { |path| require path }

How do you get a ruby gem into the include path for require

It's actually not to hard to do this manually. Let's say you have a library whatever.rb that you want to distribute as a gem.

  1. make a directory lib and put a copy of whatever.rb in lib/whatever.rb.
  2. make a file whatever.gemspec, and put the following in there, filling in the appropriate values:

    Gem::Specification.new do |spec|
    spec.name = 'the-name-of-your-gem'
    spec.version ='0.0.1'

    # this is important - it specifies which files to include in the gem.
    spec.files = ["lib/whatever.rb"]

    # optional, but useful to your users
    spec.summary = "A more longwinded description of your gem"
    spec.author = 'Your Name'
    spec.email = 'you@yourdomain.com'
    spec.homepage = 'http://www.yourpage.com'

    # you did document with RDoc, right?
    spec.has_rdoc = true

    # if you have a ruby forge project
    spec.rubyforge_project = 'your-project-name-on-rubyforge'

    # if you have any dependencies on other gems, list them thusly
    spec.add_dependency('hpricot')
    spec.add_dependency('log4r', '>= 1.0.5')
    end
  3. now, to build the gem, use the gem build command:

    % gem build whatever.gemspec
    Successfully built RubyGem
    Name: the-name-of-your-gem
    Version: 0.0.1
    File: the-name-of-your-gem-0.0.1.gem
    %
  4. You can test locally by using gem install the-name-of-your-gem-0.0.1.gem
    To use your library in a script then, simply do the following at the top:

    require 'rubygems' # puts gem libraries in the require path
    require 'whatever' # loads your library

For more on what the various settings in the gemspec file, check the GemSpec Reference.

Personally, I use rubygems a lot to package executable scripts as well, and find it very handy for that.

What is the difference between require_relative and require in Ruby?

Just look at the docs:

require_relative complements the builtin method require by allowing you to load a file that is relative to the file containing the require_relative statement.

For example, if you have unit test classes in the "test" directory, and data for them under the test "test/data" directory, then you might use a line like this in a test case:

require_relative "data/customer_data_1"

How to write a gem? Preparing with 'lib' directory

You can check out a gem I made if you like

--

Gems

Rails gems are basically just zip-files for your Rails app

When you "install" a rails gem, the gem files inside the gem will actually be put into your Rails application. Take our gem as an example:

Sample Image

The folders marked in Red will be inserted into your Rails application when you install the gem. You can't see them, but they'll be there


Engine

It's my opinion that the majority of Rails gems will be engines:

This means that whenever you create a gem, all you're doing is creating a specific piece of functionality which can be applied to your application as required

A gem will create a module, which will wrap all your gem's functionality. This module will be defined in the lib file you created, and therefore allow you to extend your gem's functionality by inheriting from this module


Views / Controllers

To create views / controllers in your application, you need to remember what I said - the files from your gem will be placed into your app

With that in mind, the way to do it is to create an /app folder, and then put the views or controllers directories in there:

Sample Image

You basically need to create directories which inherit from the module you define in the lib directory of your gem:

-app
|-controllers
|--exception_handler
|---exception_controller.rb

|- views
|-- exception_handler
|--- exception
|---- show.html.erb

-lib
|-exception_handler.rb #-> ExceptionHandler module

This is exactly the same as if you namespace your routes

--

As I've created a gem, you may be best talking to me directly about the process. You can post a comment if you'd like to talk about it further



Related Topics



Leave a reply



Submit