Load Error in require statement when using classes in multiple files - ruby

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!

Related

Include module not working in gem

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.

Unable to override RSpec Sysntax module method

I wanted to override the expect in under Syntax module. So, i have placed the below code into the .config/initializers/syntax.rb file
module RSpec
module Expectations
module Syntax
def enable_expect(syntax_host=::RSpec::Matchers)
return if expect_enabled?(syntax_host)
syntax_host.module_exec do
def expect(value=::RSpec::Expectations::ExpectationTarget::UndefinedValue, &block)
::RSpec::Expectations::ExpectationTarget.for(value, block)
end
end
end
end
end
end
And required this inside the env.rb file.
require_relative '../../.config/initializers/syntax'
This is not overriding the existing method. I'm using RSpec gem 3.2.0
What went wrong with the configuration?
I suggest you to put this override codes in spec/support directory and require it in rails or spec helper instead of putting in initializers.

Ruby will not recognize Diet module, will recognize Diets module

I have a main file, simple_carbon_calculator.rb, that requires a number of different files, but namely diet.rb. Both files require a data file, constants_and_converesions.rb.
In simple_carbon_calculator.rb:
require_relative 'constanst_and_conversions.rb'
require_relative 'diet.rb'
# Other Code
Diet.get_diet_emissions
In diet.rb:
require_relative 'constants_and_conversions.rb'
module Diet
def self.get_diet_emissions
## function
end
end
When I run simple_carbon_calculator.rb, the TypeError is raised: "Diet is not a module" However, when I change the module to be named Diets (note the s), it works fine. I honestly have no idea why. Any thoughts?
Cheers and thanks,
Reid

Monkey Patching Mongoid models contained in a Ruby gem

I have a Ruby gem which gets used across multiple projects that contains some Mongoid models.
I'm currently trying to reuse them in a project and monkey patch some extra methods. However, when I require the project and run the tests. I get a NoMethodError. Any ideas where I'm going wrong?
Here's my main project file:
require 'bundler'
Bundler.require(:default)
require 'mongoid-elasticsearch'
Mongoid::Elasticsearch.prefix = ENV["MONGOID_ENVIRONMENT"]
require 'mongoid_address_models/require_all' # This is where I include my gem
Mongoid.load!(File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml"), ENV["MONGOID_ENVIRONMENT"] || :development)
# Here are my monkey patched models
require 'models/street'
require 'models/locality'
require 'models/town'
require 'models/postcode'
require 'sorting_office/address'
module SortingOffice
end
And this is an example of one of the monkey patched models
class Postcode
REGEX = /([A-PR-UWYZ01][A-Z01]?[0-9IO][0-9A-HJKMNPR-YIO]\s?[0-9IO][ABD-HJLNPQ-Z10]{2})/i
def self.calculate(address)
postcode = UKPostcode.new(address.match(REGEX)[0])
where(name: postcode.norm).first
end
end
When I call Postcode.calculate(address) (for example), I get a NoMethodError
I think I've nailed this now. Rather than putting the monkey patch inside lib/models, I moved them to lib/sorting_office/models and required them like so:
require 'sorting_office/models/street'
require 'sorting_office/models/locality'
require 'sorting_office/models/town'
require 'sorting_office/models/postcode'
I'd still be interested to know WHY this worked though

Sinatra Helper in External File gives LoadError

I'm trying to add a helper to connect to a mongo db to my modular Sinatra application
When I type foreman start in my console I get:
/home/sunny/Programs/landing_pages/app.rb:17:in `block in <class:LandingPages>': undefined local variable or method `connect' for LandingPages:Class (NameError)
My app.rb file looks like this:
require 'sinatra/base'
require 'sinatra/partial'
require 'sinatra/db_helper'
require 'bundler/setup'
require 'mongo'
class LandingPages < Sinatra::Base
helpers Sinatra::DbHelper
configure do
$collection = connect
end
end
My ./lib/sinatra/db_helper.rb looks like this:
require 'sinatra/base'
module Sinatra
module DbHelper
def connect
conn = Mongo::Connection.new("localhost")
db = conn.db("leads")
db.collection("laws")
end
end
helpers DbHelper
end
My config.ru looks like this:
require './app'
run LandingPages
I thought I was following the instructions correctly on:
http://www.sinatrarb.com/extensions.html
but I'm not totally sure. I'm not making a gem but just a sinatra app so maybe my directory hierarchy isn't correct. I don't have a rake file or a gem spec. Do I need them?
Some googling also found this:
sinatra helper in external file
Dave Sag answers my question perfectly but I can't get it work.
This comes about because of the scope of methods created through the helpers is on the sinatra application instance, since it calls ruby's include under the hood. So this would work:
get '/some/route' do
db = connect
# do something else ...
end
But the configure block has a class scope, so it can be used for configuring the application as a whole. So to make this work, you can define the method as:
module Sinatra
module DbHelper
def self.connect
conn = Mongo::Connection.new("localhost")
db = conn.db("leads")
db.collection("laws")
end
end
end
which could then be called via: $collection = Sinatra::DbHelper.connect or perhaps more favoured, you could call register instead of helpers. register calls extend under the hood, so you end up with class level methods (if you extend a class, anyway). You could then make the configure block as so:
configure do |app|
$collection = app.connect
end
You could also do all of this in an registered method on the DbHelpers module. See the example in the documentation for how this might work.

Resources