Require paths for rspec tests in a Ruby Gem - ruby

I am creating a simple Ruby Gem which is currently laid out as per the example in the Making your own gem documentation.
My directory structure:
.
├── Gemfile
├── Gemfile.lock
├── lib
│   ├── go_run
│   │   ├── parser.rb
│   │   └── runner.rb
│   └── go_run.rb
└── spec
├── go_run_spec.rb
├── parser_spec.rb
└── runner_spec.rb
I originally called the Runner class in lib/go_run/runner.rb just Runner, but now, as per the documented example I have namespaced it under GoRun::Runner. The code works. The problem is that now running bundle exec rspec spec/parser_spec.rb does not. It fails with:
/home/smurf/dev/ruby/go_run/lib/go_run/parser.rb:3:in `<top (required)>': uninitialized constant GoRun (NameError)
The 3rd line of that file is:
class GoRun::Parser
I am requireing the library code in spec/parser_spec.rb using require 'go_run/parser'.
I tried including it with require_relative '../lib/go_run/parser', but that produced the same error.
Does anybody know what I am doing wrong?
Update: I have uploaded the complete code on this branch: https://github.com/henrytk/go_run/tree/stackoverflow-43155117

The problem is originating in lib/go_run/parser.rb rather than from the test itself. Whenever Ruby finds the GoRun::Parser definition, it goes looking for GoRun in the constant lookup table, but it won't be there, and so the program exits with an error.
Note that using lib/go_run.rb as an entry point also will not work, because go_run/parser.rb is required before GoRun is defined.
Part of the problem is using GoRun as both the project level namespace, and an entry point class.
There are a couple of idioms you should consider to fix this situation:
Make GoRun a top level module, used purely for namespacing. Move the logic that lives in the current logic into its own class, for example go_run/cli.rb. The go_run.rb file is then kept as a sort of manifest file, that requires the classes of your project.
Use the nested module- and class syntax. This will define the outer module if it isn't already.
Use a spec_helper.rb file that bootstraps your project using require 'go_run', to make sure everything is properly loaded before running your tests.

Related

Where to place go.mod file

I have a repository structure as follows :-
xyz/src
1. abc
- p
- q
- r
2. def
- t
- u
- v
3. etc
- o
- m
- n
I have created a .mod file in src and run go build ./...
Except for local packages everything is fine. So if abc/p is being used in def then it throws the following exception :- cannot find module providing package abc/p. The idea behind keeping the .mod file in src package was to make sure the path is being found from where the mod file is located. Can anyone suggest where should the mod file ideally should be? also i tried placing it one directory above in xyz but still same issue as well as i created one for each sub directory. I am bit confused on this. Will I have to create separate repository for abc and etc. But considering gopath which earlier used to work for the same I think module should also be able to do the same. Any suggestions?
The most common and easiest approach is a single go.mod file in your repository, where that single go.mod file is placed in the root of your repository.
Russ Cox commented in #26664:
For all but power users, you probably want to adopt the usual convention that one repo = one module. It's important for long-term evolution of code storage options that a repo can contain multiple modules, but it's almost certainly not something you want to do by default.
The Modules wiki says:
For example, if you are creating a module for a repository
github.com/my/repo that will contain two packages with import paths
github.com/my/repo/foo and github.com/my/repo/bar, then the first
line in your go.mod file typically would declare your module path as
module github.com/my/repo, and the corresponding on-disk structure
could be:
repo/
├── go.mod <<<<< Note go.mod is located in repo root
├── bar
│   └── bar.go
└── foo
└── foo.go
In Go source code, packages are imported using the full path including
the module path. For example, if a module declared its identity in its
go.mod as module github.com/my/repo, a consumer could do:
import "example.com/my/repo/bar"
That imports package bar from the module github.com/my/repo.
I have a single go.mod in the root of my go application. I am using the following structure inspired by Kat Zien - How Do You Structure Your Go Apps
At the minute one of my applications looks like this
.
├── bin
├── cmd
│   ├── cli
│   └── server
│ └── main.go
├── pkg
│   ├── http
│   │   └── rest
| │ # app-specific directories excluded
│   └── storage
│   └── sqlite
All packages are imported via their full path, i.e. import "github.com/myusername/myapp/pkg/http/rest" otherwise it causes problems all over the place and this was the one change I had to make going from $GOPATH to go mod.
go mod then handles all the dependencies it discovers properly as far as I've discovered so far.

Easier way to require spec files in Sinatra

I have a spec_helper that looks like this:
require 'pry'
require 'helpers/data_helper.rb'
require 'distributer.rb'
require 'house_distributer.rb'
require 'accounting_service.rb'
require 'mixer_worker.rb'
require 'mixer.rb'
require 'transaction_service.rb'
ENV['RACK_ENV'] = 'test'
RSpec.configure do |config|
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.warnings = true
config.order = :random
end
and a folder structure that looks like this:
.
├── Gemfile
├── Gemfile.lock
├── README.md
├── app.rb
├── config.ru
├── lib
│   ├── accounting_service.rb
│   ├── distributer.rb
│   ├── house_distributer.rb
│   ├── mixer.rb
│   ├── mixer_worker.rb
│   └── transaction_service.rb
├── public
│   ├── css
│   │   └── add_coins.css
│   ├── images
│   │   └── bitcoin_dawg.jpg
│   └── javascripts
│   └── add_coins.js
├── spec
│   ├── helpers
│   │   └── data_helper.rb
│   ├── lib
│   │   ├── accounting_service_spec.rb
│   │   └── transaction_service_spec.rb
│   └── spec_helper.rb
└── views
└── add_coins.erb
This does not work:
Dir["lib/*.rb"].each {|file| require file }
[1] pry(main)> Dir["lib/*.rb"]
=> ["lib/house_distributer.rb", "lib/distributer.rb", "lib/mixer.rb", "lib/accounting_service.rb", "lib/mixer_worker.rb", "lib/transaction_service.rb"]
I get this error message:
/Users/jwan/.rbenv/versions/2.1.2/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- lib/house_distributer.rb (LoadError)
from /Users/jwan/.rbenv/versions/2.1.2/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
What can I do to make this easier?
Also side note, distributer.rb has to be loaded before house_distributer.rb because of this:
class HouseDistributer < Distributer
end
Some explanation of max pleaner's answer...
When you write:
require 'lib/house_distributer.rb'
ruby looks for the file in the directories assigned to the $LOAD_PATH environment variable. $LOAD_PATH is an array of Strings, where each String is a path to a directory. The directories in the $LOAD_PATH array are searched in order, and the first match wins.
If $LOAD_PATH contains a directory called:
'/Users/7stud/ruby_programs'
Then the require statement above will look for a file with the absolute path:
'/Users/7stud/ruby_programs/lib/house_distributer.rb'
You can check which directories are in your $LOAD_PATH like this:
$ puts $LOAD_PATH
This is what I get:
/Users/7stud/.rvm/gems/ruby-2.4.0#global/gems/did_you_mean-1.1.0/lib
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/site_ruby/2.4.0
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/site_ruby/2.4.0/x86_64-darwin14
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/site_ruby
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/vendor_ruby/2.4.0
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/vendor_ruby/2.4.0/x86_64-darwin14
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/vendor_ruby
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0
/Users/7stud/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/x86_64-darwin14
Obviously, your app's files are not in directories like those.
On the other hand, if you require a file whose path starts with a / or a . -- for instance:
require './lib/house_distributer.rb'
then ruby skips $LOAD_PATH, and in this case ruby looks for the file relative to the current working directory. Note however, that the current working directory may not be the directory containing the file with the require statement. For instance, if you execute your sinatra program from a different directory, say two levels up from the file containing the require statement, then the two levels up directory will be the current working directory, and ruby will look for the required file relative to the two levels up directory.
Enter require_relative. require_relative will look for the file relative to the path of the current file--not the current working directory.
As a result, you should probably never use require with a relative path and instead use require_relative.
Note that you can also programmatically add paths to $LOAD_PATH any time you want:
$LOAD_PATH << '/Users/7stud/ruby_programs'
And if a file called dog.rb is in that directory, I can require it like so:
require 'dog' #extension is unnecessary
Response to comment:
The simplest thing to do would be:
$LOAD_PATH << "/Users/jwan/Desktop/programming/interview_questions/gemini/‌​jobcoin_mixer/"
But in sinatra, settings.root is the path to your app directory, so do:
$LOAD_PATH.unshift setttings.root
That way you can move your app to another directory without changing anything.
Or, you can remove lib/ from the front of every path that Dir[] returned:
require 'pathname'
paths = [
"lib/house_distributer.rb",
"lib/distributer.rb",
"lib/mixer.rb",
"lib/accounting_service.rb",
]
new_paths = paths.map do |path|
pn = Pathname.new path
pn.relative_path_from(pn.parent).to_s
end
p new_paths
--output:--
["house_distributer.rb", "distributer.rb", "mixer.rb", "accounting_service.rb"]
The file not found is because you use "lib/*.rb" and not ./"lib/*.rb".
To ensure the dependencies are loaded in the correct order, you can do this:
move HouseDistributor to lib/distributor/house_distributor.rb
Require files like so:
Dir['./lib/**/*.rb']
.sort_by { |path| path.count("/") }
.each { |path| require path }
this uses **/*.rb to do a recursive search and will sort the files by the count of "/" (their depth) before requiring
Just a note of caution, if you are doing a recursive require, keep in mind that you actually do want to require all those files. For example if you are are using ActiveRecord and have a schema.rb file, you probably don't want to require that.
The other 2 answers are technically correct and address the goal but not the aim. In other words - why are you doing that in the first place? For instance, why do this:
Also side note, distributer.rb has to be loaded before house_distributer.rb because of this:
class HouseDistributer < Distributer
end
And not this?
require_relative "distributer.rb"
class HouseDistributer < Distributer
end
And in the tests (cough) sorry, the specs:
# spec/house_distributer_spec.rb
require 'spec_helper'
require_relative "../lib/house_distributer.rb"
# spec/transaction_service_spec.rb
require 'spec_helper'
require_relative "../lib/transaction_service.rb"
And since transaction_service.rb appears to need HouseDistributer from lib/house_distributer.rb…
# lib/transaction_service.rb
require_relative "house_distributer.rb"
The rule of thumb
If a file needs another to run then require (or require_relative) it in the file that requires it. Then you get:
A kind of natural sandboxing by only running what is needed (maybe Distributer works perfectly and HouseDistributer has the error because of a monkey patch - how will you know if you require files that aren't actually needed?)
No need to handle requires elsewhere.
No need (or much less need) to know the order of requires.
No need to fiddle about with the load path (which has been a dubious need ever since require_relative was introduced).
Changing the load path and then using require can break sandboxing and make specs work that should fail by loading a gem you have installed on your system but isn't defined as a dependency in the gemspec.
I'd add, use bundler's sandboxing too, to avoid further errors and let it handle your load path, e.g.
bundle install --binstubs --path=vendor (or vendor.noindex on a Mac) then:
bin/rspec and whatever commandline args you need.

Hyperledger Fabric unit test cross-chaincode invocation without collapsing vendor folder

I have been running into compilation issues when I tried to perform unit testing in golang locally, when trying to instantiate and invoke another chaincode through the MockStub object. Below is my file hierarchy:
├── transaction-chaincode
│   ├── transaction.go
│   ├── transaction_test.go
│   └── vendor
└── user-chaincode
├── user.go
├── user_test.go
└── vendor
The scenario here basically involves one of the chaincode, for example user.go, calling the other chaincode transaction.go. The vendor folders in both directories contain the exact same content.
The problem occurs when I try to instantiate a new instance of the transaction chaincode thru shim.NewMockStub in user_test.go, as the transaction mock object looks for the init method from within transaction-chaincode/vendor/ instead of user-chaincode/vendor/, despite the vendor folders having the same packages (and thus the same method).
I was able to get rid of this error by having a single vendor folder at the parent directory of transaction-chaincode & user-chaincode, but I cannot do so for developmental purposes. How would you suggest I solve this unit testing problem while keeping the vendor folders in their respective locations?
If I understood correctly, you are putting shim and other dependencies in each vendor folder. user_test.go then does something like NewMockStub(..., &transaction_chaincode.transaction{}). You want transaction_chaincode.transaction to bind to user/vendor ?
I don't think that'll happen. The shim import in transaction_chaincode.transaction will bind to its transaction_chaincode/vendor.
If the above understanding is correct, why do you think its a "problem" ?

Project organization and cljsbuild config to require namespace

How do I organize my project structure and configure cljsbuild to require my own namespace? For example in my project/src-cljs folder I have:
└── project
├── file1
│   └── file1.cljs
├── file2
│   └── file2.cljs
└─── required
   └── required.cljs
I'd like file1.cljs(namespaced as file1.file1) and file2.cljs(namespaced as file2.file2) to require required.cljs(namespaced as required.required).
My :cljsbuild looks like:
:cljsbuild {:builds
[{:source-paths ["src-cljs/project/file1"]
:compiler {:output-to "resources/public/js/file1.js"}}
{:source-paths ["src-cljs/project/file2"]
:compiler {:output-to "resources/public/js/file2.js"}}]}
When I (:require [required.required :as required]) and compile I get the exception:
Caused by: clojure.lang.ExceptionInfo: No such namespace: required.required, could not locate required/required.cljs, required/required.cljc, or Closure namespace "required.required" at line 1 src-cljs/project/file1/file1.cljs
You don't usually want a separate js output file and cljsbuild profile for each namespace. You want one single cljsbuild profile including all of your namespaces. Something like:
:cljsbuild {:builds
[{:source-paths ["src-cljs/project"]
:compiler {:output-to "resources/public/js/project.js"}}]}
Not only that: you might want to have ["src-cljs"] as :source-paths and then name your namespaces like project.ns1.sub-ns1. But you can do it without the project ns prefix just fine.
You can find an example of this simple layout in the simple example project from lein-cljsbuild
Looking to the cljsbuild README, it seems like you were taking the path of "Multiple build configurations". In practice this is mostly used to have separate build profiles for your main code and the tests working against that code. That's shown in the advanced example.

Why is the structure of my ruby project like this and why use load path?

I am using an old, 2010 book called "the rspec book" to learn rspec and cucumber. PLEASE DON'T tell me how old this book is and that ruby 1.8.7 and 1.9.3 are outdated. I have not yet seen any beginner book like this which uses latest ruby.
The current structure of my project named "codebreaker":
.
├── features
│   ├── codebreaker_starts_game.feature
│   ├── codebreaker_submits_guess.feature
│   ├── step_definitions
│   │   └── codebreaker_steps.rb
│   └── support
│   └── env.rb
└── lib
├── codebreaker
│   └── game.rb
└── codebreaker.rb
Here is the code and notes from the book:
/features/step_definitions/codebreaker_steps.rb
Given /^I am not yet playing$/ do
end
When /^I start a new game$/ do
Codebreaker::Game.new.start
end
/lib/codebreaker/game.rb
module Codebreaker
class Game
def start
end
end
end
If you run cucumber now, you’ll see the error uninitialized constant Codebreaker (NameError) because Cucumber isn’t loading game.rb yet. The conventional approach to this is to have
a file in the lib directory named for the top-level module of the app. In our case, that’s codebreaker.rb . Create that file now, with the following:
/lib/codebreaker.rb
require 'codebreaker/game'
Now add the following to features/support/env.rb:
$LOAD_PATH << File.expand_path( '../../../lib' , __FILE__)
require 'codebreaker'
Cucumber will load features/support/env.rb , which now requires
lib/codebreaker.rb , which, in turn, requires lib/codebreaker/game.rb
, which is where we defined the Codebreaker module with the Game with
an empty start () method. If you now run cucumber
features/codebreaker_starts_game.feature , you should see some
different results.
My question: Why do we have this env.rb and why does it not point directly to lib/codebreaker/game.rb ? Why go through lib/codebreaker.rb. It makes no sense to me. Please help.
As your app currently stands it wouldn't make any difference.
With a real project there would be many more files though and you would require them through lib/codebreaker.rb so that users of your library just need to require the one file.
You wouldn't want to duplicate that list of requires in env.rb, so your specs load lib/codebreaker.rb, just like any other user of your library.

Resources