I want to know a good way to run code in my ruby gem (and not just through tests).
That means I want to run ruby lib/{gemname}.rb on the terminal and be able to see some output
So I have this line in my base file:
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
and then I load a file called debugger.rb by requiring it at the bottom of the base file. This file then gives me the output I need.
This works but this kind of clutters my code and I don't want to accidentally commit it and watch it break in production.
So what's a good way of doing this?
My approach for developing and debugging gems has two parts:
1) Always use require_relative to include needed "internal" gem related files. This allows the gem to be loaded up normally when installed as a gem and also in my development environment (ignoring any versions of the gem that may already be installed.)
2) Then use the following snippet of code (usually) at the bottom of the main file, to activate debugging features when the base my_gem.rb file is run explicitly on the command line.
if __FILE__ == $0
#debugging code goes here!
end
With this strategy there's no need to worry about yanking debug code before releasing the gem.
Related
Try creating a gem based on bundler's official guide on developing a Ruby gem.
Running bundle gem foodie will create a structure and generate files in the lib directory:
foodie
version.rb
foodie.rb
foodie.rb reads
require "foodie/version"
module Foodie
# Your code goes here...
end
Running ruby lib/foodie.rb (or also from different directories) will result in
C:/Ruby23-x64/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- foodie/versio
n (LoadError)
from C:/Ruby23-x64/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from foodie.rb:1:in `<main>'
On the other hand installing the gem via rake install and then requiring the gem works just fine.
It works from source if require "foodie/version" is changed to require_relative "foodie/version" in foodie.rb. As I understand
require works based on modules
require_relative works based on directory structure
To me the latter looks like a hack. It'd no longer make sense to structure your code via modules as it wouldn't be enforced (maybe it'd still make sense but you could make mistakes and never notice).
My questions are:
Is it possible to test a gem from source without installing it while following the bundler convention (using require instead of require_relative)?
Why does the gem work after installed?
Is there any best practice for the usage of require, require_relative, modules, files and general structure?
Thank you.
You need to add your lib dir to Ruby’s load path. The load path is a list of directories that Ruby searches for files in when you call require. Rubygems also manages the load path when you are using gems, which is why your code works when installed as a gem.
You say “as I understand ... require works based on modules”, this is not correct. require works with files, it’s just convention that a class or module is defined in a file with a matching name, e.g. MyModule might be in my_module.rb.
There are a few ways to add a dir to the load path. From the command line you can use the -I option:
$ ruby -I lib lib/foodie.rb
If you wanted to avoid typing -I lib you could use the RUBYLIB environment variable. Ruby adds the contents of this to the load path:
$ export RUBYLIB=lib
$ ruby lib/foodie.rb
(On Windows I think you will need to use set rather than export.)
You can also manipulate the load path from withing the program itself. It is stored in the global variable $LOAD_PATH, aliased as :$. This is how Rubygems and Bundler manage your gems.
I'm working on making my first gem, which is not a Rails app, is a tic-tac-toe library with some AI in it, so I can play a computer opponent that will never lose and force a win if possible.
Right now I am trying to debug the attack strategy in the AI, but I can't seem to figure out how to get pry-byebug working in my test script, specfically, have the debugging commands like step, next, etc. work upon hitting a binding.pry.
The gem, named smart-tac-toe, has the following directory structure:
$ ls smart-tac-toe
example Gemfile Gemfile.lock Guardfile lib LICENSE.txt Rakefile README.md smart_tac_toe.gemspec spec tmp
As you can see above, there is an 'example' directory in my gem which contains "example.rb", where I use the classes I've made.
However, when I use binding.pry and try to use step and next, the Pry session just exits and the script keeps running.
In my smart_tac_toe.gemspec file, I clearly have pry-byebug:
spec.add_development_dependency "pry-byebug", '~>2.0.0'
and at the top of my example.rb file, I have tried requiring the proper gems:
require 'pry'
require 'pry-byebug'
require "../lib/smart_tac_toe.rb"
I am using Ruby 2.1.1p76 , the repo for this gem is located at https://github.com/discotroll65/smart_tac_toe
Also, though putting binding.pry into my example script does throw me into a debugging session, initially it is in a reading mode, and I have to press q to exit that before I can start doing repl stuff. Any thoughts as to why this may be?
Ok, looking into this more I realized (I think...still kind of new to the game) a couple things --
1.) If you want to if have
require 'pry'
at the top of your ruby file and have it work in general, it would help to install it in your development environment using your terminal:
user#machine/currentdirectory/$ gem install pry
likewise with pry-byebug:
user#machine/currentdirectory/$ gem install pry-byebug
2.) The real answer to my initial question is to use
byebug
in my script as the debugging hook, instead of
binding.pry
(thanks #mtm for the suggestion!)
when I do use byebug though, while step and next work properly, the REPL it throws me into doesn't have any color, and isn't as nice in general...anyway to fix that?
I think you're overdoing it. This works for me:
require 'pry-byebug'
puts 'foo'
binding.pry
puts 'bar'
What is the difference between
require 'blahblahlblah.rb'
vs
require './blahblah.rb'
vs
require File.expand_path('../blahblah', __FILE__)
I see both of them being used. Wondering what's better, and under what circumstance is one better than the other.
Thanks!
require blaba.rb is searching to your default gem path to load the file, which depends on the ruby version you are using. For example RVM will search in $HOME/.rvm/rubies/... while a system wide ruby will search in the distribution's default path. Note that this is where gems are located, but you could manually add a library say mylibrary.rb in the same path and use it in any of your programs. However, that's an awful thing to do, it's a much cleaner procedure to create gems and install them in your system.
require ./blabla.rb loads a file that is sitting in your working directory. You could add the full path like require /home/username/library/myproject/models/sample.rb. It will work just about the same. In the UNIX-like world the ./ sign means current directory. This solution is often used in irb to load say a rails Model i.e. users.rb into irb or pry and work with it. To give you an example in a shell environment (if you are familiar with UNIX shells, you'll figure it out):
GreyJewel ~ » ls myports.txt
myports.txt
GreyJewel ~ » ls ./myports.txt
./myports.txt
The third solution require File.expand_path('../sample.rb', __FILE__) is used in programs, because it explicitly creates a full path using as an anchor the directory which the file holding the line sits, which is a much more secure approach compared to require ./sample.rb. Note that when you load a ruby file, you can omit the file extension .rb.
Hope this clarifies a bit the situation.
I have git cloned a repo from Github, now I want to experiment with it, as in I want to poke around the code and mess with it. I've created a file test.rb that should load this gem, but I want to load my locally checked out version, what's the right way to do this?
Right now I'm just using a bunch of "require_relative 'the_gem_name/lib/file'", which feels wrong.
When you require 'foo' Ruby checks all the directories in the load path for a file foo.rb and loads the first one it finds. If no file named foo.rb is found, and you’re not using Rubygems, a LoadError is raised.
If you are using Rubygems (which is likely given that it is included in Ruby 1.9+), then instead of immediately raising a LoadError all the installed Gems are searched to see if one contains a file foo.rb. If such a Gem is found, then it is added to the load path and the file is loaded.
You can manipulate the load path yourself if you want to ensure a particular version of a library is used. Normally this isn’t something that’s recommended, but this is the kind of situation that you’d want to do it.
There are two ways of adding directories to the load path. First you can do it in the actual code, using the $LOAD_PATH (or $:) global variable:
$LOAD_PATH.unshift '/path/to/the/gems/lib/'
require 'the_gem'
Note that you normally want to add the lib dir of the gem, not the top level dir of the gem (actually this can vary depending on the actual Gem, and it’s possible to need to add more than one dir, but lib is the norm).
The other way is to use the -I command line switch to the ruby executable:
$ ruby -I/path/to/the/gems/lib/ test.rb
This way might be a bit cleaner, as normally you don’t want to be messing with the load path from inside your code, but if you’re just testing the library it probably doesn’t matter much.
Following apneadiving's suggestion in the comments, I created a Gemfile and added this line
source "http://rubygems.org"
gem 'gem_name', path: '~/path/to/gem/source/folder'
Then bundle install, and bundle exec ruby test.rb and it worked.
I'm trying to create a gem with Bundler, following this guide: http://rakeroutes.com/blog/lets-write-a-gem-part-one/. In it, it says:
I incorrectly thought after taking my first look through the gemspec
that I would need to add more require statements as I developed my
gem. That isn’t the case: the files just need to be in git.
I am trying to clean up some of my old gems to use this convention, but when I install my gem, the classes from the other files are not available. I have a couple directories nested under my /lib dir, but I wouldnt think that would be an issue. Is there anything simple to overlook that would prevent my other files from being required? Any help would be appreciated.
In the link, when he says he doesn't need to add a lot of "require" statements, he must mean adding files to the s.files, s.executables, and s.test_files arrays--these determine what files get packaged up into the gem and what files get ignored. As you can see from the gem spec, whatever's tracked by git in certain directories is going to be included in the packaged gem.
Ruby's require is a different story. Standard require rules still apply.
Ruby's gem system works by adding a bunch of different places for Ruby to look for "foo.rb" when you run require "foo". If "lib" is your only require path for your gem, when you require "my_gem" Ruby is only going to run the code in lib/my_gem.rb. If lib/my_gem.rb doesn't require any other files in your gem, then Ruby hasn't seen them and so you'll get undefined constant errors when you try to use the classes from those files.
For examples, you might take a look at two simple gems I've written; both were started with bundle gem: HashToHiddenFields and SimpleStats. In both gems, main Ruby file in lib/ requires everything that needs to be loaded for the gem to work correctly. For example, hash_to_hidden_fields.rb requires action_view/helpers/hash_to_hidden_fields so that the ActionView::Helpers::HashToHiddenFields constant+module exists so we can include it into ActionView::Base.
Hope that answers the question. I know Ruby requiring was pretty fuzzy to me for a while.