Ruby 1.8.7: Can't load module from custom gem - ruby

After creating a custom gem I'd like to reference functions defined in a module it contains.
Custom gem is dsi_core and the module lib/cuke.rb contains simply:
module DsiCore
module Cuke
def self.Features(*args)
puts "Hello world!"
end
end
end
I've installed the gem and can see /var/lib/gems/1.8/gems/dsi_core-0.1.0/lib/cuke.rb exists as it should.
In another gem dsi_fabric there is the code dsi_fabric/lib/dsi_fabric:
require 'dsi_core'
# ...
DsiCore::Cuke.Features(*ARGV)
Trying to run this from the lib/ directory of dsi_fabric gem:
ruby -rubygems ./dsi_fabric.rb arg1 arg2
..results in:
./dsi_fabric.rb:7: uninitialized constant DsiCore::Cuke (NameError)
This refers to the Cuke.Features line in dsi_fabric.rb.
What am I doing wrong?

You're requiring 'dsi_core' instead of 'cuke'. Try changing require 'dsi_core' to require 'cuke'.

If you are testing in existing namespace problem can be namespace, so try with root namespace reference.
::DsiCore::Cuke.Features(*ARGS)
also like I mentioned in comment you need to put
def self.Features(*args)
# ...
end
Hehe I do not like that capital method name annotation but to each his own :)
EDIT
Also try
require 'rubygems'
require 'dsi_core'

I was miscomprehending how Gem imports work.
If you create a gem and add other gem dependencies to it in the gemspec, those dependencies are automagically imported already.
Therefore what I have above is wrong - to import the cuke.rb file from gem dsi_core in gem dsi_fabric you would use:
require 'cuke'
i.e. the require dsi_core is implicit by nature of the Gem specification and gemspec.
Then to reference in the code would be
DsiCore::Cuke
..as I originally posted.
I was confused because mny public gems indicate you should use require with the form:
require `gem-name/module-or-class`.
However this is misleading: the gem name isn't being used at all, but rather a directory named after the gem:
require 'dir-name/module-or-class'
In this example the gem gem-name has the following directory structure:
lib/gem-name/module-or-class.rb
i.e. they've made a folder in the gem's lib/ directory named after the gem itself.

Related

Ruby gem dependency loading

I'm putting some shared models for a rails app inside it's own gem. It's just models, so I'm not using an engine. Getting it set up seemed to work fine until I added the "acts_as_list" gem.
# gem - domain.gemspec
spec.add_dependency "acts_as_list"
# gem - lib/domain.rb
require "acts_as_list"
# gem - lib/domain/models/page.rb
acts_as_list scope: [:ancestry]
This works fine in the console for my gem, I can run methods specific to acts_as_list as usual. However, when I add my gem to another project, it gives me an error.
# project - Gemfile
gem "www_domain", path: "../www_domain"
Bundler::GemRequireError: There was an error while trying to load the gem 'domain'.
NoMethodError: undefined method `acts_as_list' for #<Class:0x0055da70121ab0>
/home/shaun/sites/demo/domain/lib/domain/models/page.rb:32:in `<class:Page>'
Is there something special I have to do in this case to access the acts_as_list method because my model is inside a gem?
Update: Here is my complete lib/domain.rb file for the gem:
require "yaml"
require "active_record"
require "acts_as_list"
require "ancestry"
# rbfiles = File.join(File.dirname(__FILE__), "lib", "**", "*.rb")
# Dir.glob(rbfiles).each do |file|
# require file.gsub("lib/", "")
# end
module Domain
# Your code goes here...
def self.root
File.dirname(__dir__)
end
def self.db_config
YAML.load_file("#{Domain.root}/db/config.yml")["development"]
end
end
require "domain/version"
require "domain/models/page"
require "domain/models/menu"
require "domain/models/article"
require "domain/models/page_part"
I can use acts_as_list and ancestry methods in the console of my gem (running bin/console from the gem directory). But the project console (running bundle exec rails console from the project directory) will not start because of the gem error I mentioned.
This might result from a load order issue if the model being required before the require :acts_as_list statement. Check to see if the gem specifies the load order. If not, you could try something like:
# gem - lib/domain.rb
require "acts_as_list"
require "models/page"
If the load order is unclear, I find it helpful to simply add a
puts __FILE__
at the top of the relevant source files.

When building a Ruby gem, how do you specify which files Bundler should require?

In the past, based on a stylistic decision, I've created gems that use use names containing dashes:
foo-bar
However, the folder structure under lib looks more like this:
lib
foo_bar.rb
If I use one of my own gems in the Gemfile of another project, Bundler doesn't require the library automatically. If I use one of my single word named gems (bundy for example) in another project's Gemfile, the auto-require works.
Based on the default structure of a gem project created with Bundler, I'm guessing that Bundler is trying to require the contents of lib/foo/bar.rb. Unknown to me, gems seem to expect a '-' in the gem name to relate to a '/' in the path name.
What if I want Bundler to require lib/foo_bar.rb? Can this be done without:
Changing the name of the gem? (Some gems are in use in projects owned by companies I no longer work for, so I don't want to do this.)
Adding extraneous files to manage includes? (Seems messy and unprofessional.)
Adding an explicit require to the 'gem' declaration in the Gemfile? (Seems unprofessional.)
Looking through the Bundler code, I found that the auto-require path comes from one of two places:
The 'require' setting in the Gemfile
The name of the gem itself.
#/lib/bundler/dependency.rb
...
if options.key?('require')
#autorequire = Array(options['require'] || [])
end
...
and:
#/lib/bundler/runtime.rb
...
if dep.autorequire.nil? && dep.name.include?('-')
begin
namespaced_file = dep.name.gsub('-', '/')
Kernel.require namespaced_file
rescue LoadError => e
REQUIRE_ERRORS.find { |r| r =~ e.message }
raise if $1 != namespaced_file
end
end
...
This replaces the - characters in the gem's name with '/', just as I found from my experiments. From the looks of it, it also swallows the exception if it encounters a require error trying to require the transformed gem name. (It re-throws for others, so presumably it will fail if a gem's internal dependencies are broken.)
I can't find any other mechanism for setting an autorequire file, so I'll grudgingly have to use my second option: add an extra file in the location that Bundler expects which requires the files I need.
If you are creating a gem, it is better to include gems you depend on in your .gemspec file
Gem::Specification.new do |spec|
...
spec.add_dependency "gem-name-whatev", "~> 1.5" # just like Gemfile
spec.add_development_dependency "other-gem"
...
end

Require local gem ruby

I have a gem that I created in Ruby on my local machine and I need to require this gem in a plain Ruby script that starts a service.
I have to require like this:
require_relative '../../../my-gem/lib/my/gem'
Is it possible to do this require without putting in the relative path?
require checks for files in $LOAD_PATH. You can put your gem in one of those directories in order to require it directly. If you don't like your load path, you can add a new directory to it in your script, or set the RUBYLIB environment variable which is added to the load path.
If you have a gem, you can install it and set the version you want (in my example 1.0.0.beta) with gem 'my-gem', '= 1.0.0.beta'.
But I think yu look for another solution:
You can extend the location where require looks:
$:.unshift('../../../my-gem/lib')
require('my/gem')
or
$LOAD_PATH.unshift('../../../my-gem/lib')
require('my/gem')
You could also use $: << '../../../my-gem/lib', but I prefer unshift. If your gem contains a file with similar names as in a gem (avoid it!), then unshift guarantees your script is loaded.

Pry is not a module

Ok, as #tim-moore asked, I will post it in new question.
Ok, so I wanted to make gem using bundle. Pry extension gem require that gem start with pry- as mentioned here.
I used:
bundle gem pry-name
but it messed up my file structure
create pry-name/pry-name.gemspec
create pry-name/lib/pry/name.rb
create pry-name/lib/pry/name/version.rb
As you can see it created lib/pry directory. I know it's gem's style to created such structure but now I pry cannot load this gem automatically
One solution from my question was:
create pry-name.rb that contain only require 'pry/name'
After I have done this, and build gem, I started pry:
This message appear:
require 'pry-name' # Failed, saying: Pry is not a module
As for my guesses:
I'm creating commands writing something like this:
Pry::Commands.create_command "name-of-command" do
# my code goes here
end
and, as ruby find Pry::Commands. it want require it from lib directory not from Pry gem.
What does this error mean. Why it doesn't work. How make it work keeping in mind gem and pry requirements(pry gem starts with pry- and gem will create another directory(ies) when someone use - for example: gem pry-name will make pry/name)
Everywhere in your newly-created gem where it has module Pry, change it to: class Pry. Since Pry is already defined (as a class), you cannot redefine/reopen it as a module.

Strange require statement errors in Ruby?

I've got a wrapper for my Gem, socks, inside socks.rb. The entire file is made up of require statements, and a module declaration:
# lib/socks.rb
require 'socks/version'
require 'socks/base_controller'
require 'socks/templates'
require 'socks/tasks'
require 'socks/rake_tasks'
module Socks
end
However, require 'socks/tasks' and socks/rake_tasks is giving me a LoadError: no such file to load -- socks/tasks / rake_tasks error.
Is this a problem with the alignment of the require statements, or just the code?
Code is on Github: https://github.com/Beakr/socks
EDIT: require './socks/tasks' is now working, however require './socks/rake_tasks' is not.
Ruby load files using its $LOAD_PATH. This global array is changed by e.g. rubygems and bundler to allow to find libraries in various locations. In your sock.gemspec you have defined
gem.require_paths = ["lib"]
which means that rubygems will add the lib directory of your gem to ruby's $LOAD_PATH. But it odes so only if you have installed the gem and the gemspec is thus evaluated. If you don't want to install your gem, you can test your gem using
bundle exec irb
in your gem directory, or alternatively by first adapting your $LOAD_PATH in your irb session like so:
$LOAD_PATH.push "/path/to/your/gem/lib"
require 'socks'

Resources