I have a gem called private_lib.
The file lib/private_lib.rb contains the following:
require 'private_lib/version'
require 'private_lib/handicap'
require 'private_lib/traversal_cap'
module PrivateLib
end
The lib/private_lib/handicap.rb file contains the following
# module for handicap functions
class Handicap
include TraversalCap
-- other code
end
and the file lib/private_lib/traversal_cap.rb contains the following
module TraversalCap
def some_method
end
-- other code
end
I also have a test file spec/handicap_spec.rb which contains the following
require "spec_helper"
describe Handicap do
include TraversalCap
-- some tests that access the ```Handicap``` class
-- some tests that access directly the traversal_cap some_method.
end
When I run rspec spec/handicap_spec, I get the following error
private_lib/lib/private_lib/handicap.rb:3:in `<class:Handicap>': uninitialized constant Handicap::TraversalCap (NameError)
from private_lib/lib/private_lib/handicap.rb:2:in `<top (required)>'
Why isn't the handicap class seeing the traversal_cap module?
It is because of the order you require the files.
At the time the line require 'private_lib/handicap' is run it reads the handicap.rb file and hits the line where you include TraversalCap. But you haven't yet run require 'private_lib/traversal_cap' at this point so the module is undefined.
Quick fix is to change the order of the require calls, or alternatively put require 'private_lib/traversal_cap' at the top of the handicap file.
Related
I have a gem project with rspec configured. My folder structure looks like this -
lib/
- foo/
- foo.rb
- alpha.rb
spec/
- spec_helper.rb
integration/
- alpha_spec.rb
The files foo.rb and alpha.rb have the following structures in terms of class definitions.
# lib/foo/foo.rb
class Foo
# do stuff
end
and
# lib/foo/alpha.rb
require_relative 'foo'
class Foo
class Alpha
# do stuff
end
end
The main takeaway here is that Alpha is a nested class that requires 'foo.rb' directly. (Someone using it would require foo/alpha from their script)
My spec_helper.rb file simply requires my library by loading foo/alpha -
# spec/spec_helper.rb
# Check if `Foo` class is already defined
Object.const_defined?('Foo') ? puts "IS DEFINED" : "IS NOT DEFINED"
require 'foo/alpha'
To my surprise, the constant Foo was already loaded even before requiring alpha/foo, as the output returned IS DEFINED.
Because of this, my require statement tries to load alpha.rb which in turn requires foo.rb and that errors out with
foo.rb:1:in `<top (required)>': Foo is not a class (TypeError)
According to this thread, that type of error is raised by RSpec when a class (Foo) is already defined.
How is this happening? Does RSpec attempt to do some magic behind the scenes and load my library? How do I get around this?
EDIT: I also removed the --require spec_helper line from my .rspec file so it's only getting loaded manually when I run the test.
I'm pretty new to Ruby and facing a pretty basic problem i guess. I'm probably missing out on some basic concepts and constructs. So this is what i'm trying to do,
I'm writing a sinatra project, and i have a classes which are written in different files. The structure looks something of this sort,
project_name
- api.rb
- base.rb
- settings.rb
In my api.rb file i have defined a class and some methods, it also calls some methods form base.rb and base.rb calls some methods from settings.rb
In api.rb
require 'sinatra'
require 'json'
require 'uri'
require 'base' --> This is the base.rb which is resulting in error
module XX
class Api
def some_method
base = Base.new
base.setup
# some more code
end
end
end
In base.rb, it has the following code
require 'settings'
module XX
class Base
def setup
# some code
end
def some_method
#some code
end
end
end
When i just run ruby api.rb, i'm getting an error in the require statement, unable to load such file-- base (LoadError).
What is it that i'm missing here? Also, how is it that ruby know whether it a gem or a file required..does it check to see if the require is a file in the project and then goes on to check for a gem ? How is this process done in ruby?
Any help is much appreciated!
I am trying to run Minitest with Spec syntax with rake test and get this error:
/path/to/gem/spec/script_spec.rb:3:in `<top (required)>': uninitialized constant MyGem (NameError)
My Rakefile:
require 'rake/testtask'
Rake::TestTask.new do |t|
t.test_files = FileList['spec/*_spec.rb']
end
My file structure:
gem/
--lib/
----script.rb
--spec/
----script_spec.rb
--Rakefile
My script.rb:
module MyGem
class OptionParser
def self.option?(arg)
arg =~ /^-{1,2}\w+$/
end
end
end
Using Minitest::Spec syntax in script_spec.rb:
require "minitest/autorun"
describe MyGem::OptionParser do
describe "option?" do
it "must be true for option name" do
OptionParser.option?('--nocolor').assert true
end
end
end
How do I fix it? Maybe lib folder isn't loaded? Do I miss something related to Spec syntax?
MyGem::OptionParser is not loaded in your tests. You either need to require it in your spec file or create a spec_helper where you require all files that you need in all your tests so you only need to require 'spec_helper' in your specs.
Also, since you're using the spec syntax, you will have to `require 'minitest/spec'. Your spec_helper would look something like:
# spec/spec_helper.rb
require 'minitest/spec'
require 'minitest/autorun'
require 'script'
And do this to your Rakefile so you can do require 'script' like above in your specs instead of doing require_relative '../lib/script'.
require 'rake/testtask'
Rake::TestTask.new do |t|
t.test_files = FileList['spec/*_spec.rb']
end
Lastly, for your spec to work, add require 'spec_helper' at the top of your script_spec file. You'll have to do this for all your spec files and make sure to add require for all the files you need to load in your specs to your spec_helper file.
Since you're also doing spec-style testing, you might want to change your test to this:
MyGem::OptionParser.option?('--nocolor').must_equal true
You could also have code like this in your 'spec_helper' file to automatically load all files in your lib folder:
Dir["../lib/**/*.rb"].each do |rb_file|
require rb_file
end
Hope this helps!
I have a custom gem and am encountering a really weird LoadError when I install it as a gem and attempt to require it in irb.
Everything works fine with my rspec tests inside the project folder. This only occurs when using it as an actual gem in irb.
The file it throws a LoadError exception at (/lib/mws/api/order_response.rb) does in fact exist. I've tried renaming the file and updating the file that requires it (/lib/mws.rb). I've tried recreating the file thinking maybe there was a permissions issue. Nothing works.
If I comment out the require line for that specific file, everything works. There's nothing special about the file. There's 4 other files nearly identical to it (*_response.rb).
I feel like I'm taking crazy pills. I must being overlooking something but I sure don't see it.
Trace:
chris#Samus:~$ irb
1.9.3p194 :001 > require 'mws'
LoadError: cannot load such file -- mws/api/order_response
from /Users/chris/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/chris/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/chris/.rvm/gems/ruby-1.9.3-p194/gems/mws-0.1.18/lib/mws.rb:14:in `<top (required)>'
from /Users/chris/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:60:in `require'
from /Users/chris/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:60:in `rescue in require'
from /Users/chris/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:35:in `require'
from (irb):1
from /Users/chris/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'
File with the requires (/lib/mws.rb)
require 'mws/base'
require 'mws/connection'
require 'mws/utility'
require 'mws/api/seller'
require 'mws/api/product'
require 'mws/api/order'
require 'mws/api/report'
require 'mws/api/general_response'
require 'mws/api/product_response'
require 'mws/api/report_response'
require 'mws/api/seller_response'
require 'mws/api/order_response' # <--- the offending line
module MWS
# #see Base#initialize MWS::Base for instantiation details.
# #return [Base] returns MWS::Base object.
def self.new(merchant_id, access_key, secret_key)
MWS::Base.new(merchant_id, access_key, secret_key)
end
end
# The below is for documentation generation purposes.
# MWS is a wrapper for the Amazon Marketplace Web Service (MWS) API.
module MWS
# API handles all the Amazon MWS API specific stuff.
module API
end
# Utilities contains various functions needed throughout MWS. Utilities is a mixin to multiple classes.
module Utilities
end
end
File I'm requiring (/lib/mws/api/order_response.rb):
module MWS
module API
# Class for parsing Amazon's XML responses into managable objects.
class OrderResponse
# Include GeneralResponse instance methods as class methods
extend GeneralResponse
end
end
end
And my file structure
For anyone interested, I was using Jeweler to handle building this gem. As it turns out, Jeweler uses your Git repository when building a gemspec.
If you haven't added all required files to your git repository, Jeweler's gemspec rake task will not include them when generating a new gemspec file.
Can should check in /Users/chris/.rvm/gems/ruby-1.9.3-p194/gems/mws-0.1.18/lib/mws/api if the file lies there (and doesn't have obscure permissions).
If that's not the case, you probably forgot to add it in your gemspec.
If it is there, please try requiring/loading it with the absolute path (for debugging purpose).
You can see everything in the file structure at github.com/ddd1600/simple_angel
I'm getting alot of errors while trying to create a ruby application (soon to be a gem) "the correct way", viz. by thoroughly dividing the logic into classes and "loader files" and all of that. Point is, I know how to do this code the simpler way, without obeying OO principles, but I want to do it "correctly".
So, first of all, the file structure is as follows---
root folder = ~/Develop/simple_angel
inside /simple_angel
- /lib
- Gemfile
- Rakefile
- simple_angel.gemspec
inside /lib
- simple_angel.rb
- /simple_angel
inside /lib/simple_angel
- company.rb
- search.rb
- version.rb
But, here are some basics.
Here is what I'm calling to run this program from the terminal (PATH when running is ~/Develop/simple_angel)
ruby -Ilib lib/simple_angel/search.rb
Here is search.rb
#these 'requires' are supposed to be loaded in lib/simple_angel.rb, so here I show
#them commented out
#
#require 'rubygems'
#require 'httparty'
#require 'json'
#require 'company'
module SimpleAngel
class Search
SEARCH_URL = "http://api.angel.co/1/startups"
def search(user_input)
response = HTTParty.get("#{SEARCH_URL}/#{user_input}")
parsed_response = JSON.parse(response.body)
Company.new(parsed_response)
end
end
s = SimpleAngel::Search.new
s = Search.new
x = s.search(6702)
p x
end
Here is the "loader" file, lib/simple_angel.rb (PS: what is a more formal title for this sort of file?)
require 'httparty'
require 'json'
require 'simple_angel/search'
require 'simple_angel/version'
require 'simple_angel/company'
module SimpleAngel
end
Lastly, when I (again), run "ruby -Ilib lib/simple_angel/search.rb" (with all of search.rb's 'requires' commented out (^&^), this is my error message:
[ddouglas#coders:~/Develop/simple_angel on master]
% ruby -Ilib lib/simple_angel/search.rb
lib/simple_angel/search.rb:15:in `search': uninitialized constant SimpleAngel::Search::HTTParty (NameError)
from lib/simple_angel/search.rb:24:in `<module:SimpleAngel>'
from lib/simple_angel/search.rb:8:in `<main>'
^&^ - now that we're all up to speed here, I might as well include the error that happened when I left search.rb's "requires" in place
% ruby -Ilib lib/simple_angel/search.rb ✹
/usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- company (LoadError)
from /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from lib/simple_angel/search.rb:6:in `<main>'
I can't say I understand the point the class is trying to make regarding splitting up your files.
The first error (uninitialized constant SimpleAngel::Search::HTTParty) is because from within SimpleAngel::Search, you call HTTParty. Try changing that to ::HTTParty to specify the root namespace.
The big picture issue, looking back on this issue, was that I probably just needed to activate my /lib folder within rails via this addition to config/application.rb
config.autoload_paths += Dir["#{config.root}/lib/**/"]
from there, code can be directly loaded via the file_name.rb => FileName class system from anywhere within rails