Automatically run RSPec when plain-old Ruby (not Rails) files change - ruby

I am writing a Ruby script designed to run from the command line. The script has a corresponding RSpec file that verifies its functionality. The folder structure is:
./main_script.rb
./spec/main_script_spec.rb
Running rspec spec in the top level directory works as expected. Test results from the ./spec/main_script_spec.rb file are shown. I'd like to avoid running this manually every time I change either the main script file or the spec file. All my search results turn up things like guard which (as far as I can tell) are all designed for Rails apps.
How do I setup RSpec to watch for script or spec changes and run automatically with non-Rails Ruby code?

Like David said, Guard can be used to watch a wide variety of files and perform actions when those files are modified. It does not have to be used with a Rails app. I have set up something similar in the past using guard. Here is what I did:
Place the following in your Gemfile:
source 'https://rubygems.org'
gem 'guard'
gem 'guard-shell'
gem 'rspec'
gem 'rb-fsevent', '~> 0.9'
Then run:
$ bundle install
Create a Guardfile in your home directory with:
$ guard init
In the Guardfile, comment out the examples and add this:
guard :shell do
watch(%r{^*\.rb}) { `bundle exec rspec spec/` }
end
This tells guard to watch for modifications to any ruby files in the directory and execute the command bundle exec rspec spec/ when they change (the backticks are used to execute the command in the shell).
Then open up a new terminal window in your current directory and start a guard server to start watching the files:
$ bundle exec guard
Now your Rspec test suite should automatically run when you modify ruby files in the directory.

I used guard at the past, but now I'm using a combination of rspec focus feature and watch command.
It's very simple, just add an f before a describe of it block you want to run the test. So it would becomes fdescribe or fit block. This is the same as adding a tag :focus => true to your block.
We can then filter specs with the focus tag: rspec -t focus
Now, to keeping running theses specs (every 0.5 seconds) with focus tag we call it with watch command:
watch -n 0.5 rspec -t focus
But with that the output won't show colors. So, we need to use with unbuffer.
sudo apt-get install expect
With a little customization:
watch -n 0.5 --color 'unbuffer bundle exec rspec -t focus'
Since it's annoying to type this all, I made two alias at my ~/.bash_aliases file (your can use .bashrc as well):
alias focus="watch -n 0.5 --color 'unbuffer bundle exec rspec -t focus'"
alias focuss="bundle exec rspec -t focus"
Now I can type focus to keep running it, or for a single focus execution I type focuss

Guard can be used for plain old ruby. I generally have trouble with guard so I like to use watchr, another gem. With a few lines of code you can tell watchr to watch for changes to your files and run a command when they change.
For an example of guard with plain ruby, see the shuhari gem.
update on watchr gem: There appears to be an issue with this gem, perhaps with versions of ruby >= 2.0. The observr gem addresses this issue and works as expected in ruby 2.3.

I have used guard and the guard-rspec addition with great results, and I don't believe it to be Rails-specific. Other Ruby/RSpec projects should work equally well.
The guard documentation recommends the use of Bundler and to "always run Guard through Bundler to avoid errors". I.e. you install it through your Gemfile and always run it with bundle exec guard (or use rubygems-bundler to avoid the bundle exec part).

Related

How do I run Rails/Rake from another directory?

Without cd-ing into the root directory of my Rails application, how can I execute a Rails or Rake command for that application.
I tried:
bundle exec rake my_tasks:do_stuff BUNDLE_GEMFILE=/PATH/TO/RAILS_APP/Gemfile
among other combinations, to no avail.
[Update]
The issue is actually two-fold, bundle doesn't know where the gemfile is and rake doesn't know what to run.
To use Bundler:
BUNDLE_GEMFILE=/PATH/TO/RAILS_APP/Gemfile bundle exec ...
Note that BUNDLE_GEMFILE has to go before 'bundle exec'.
To use Rake:
rake -f /PATH/TO/RAILS_APP/Rakefile my_task:do_stuff
To use Rails console:
????
Have yet to figure out how to enter the Rails console from another directory. Looking at the source, I think it may not be possible, because it eventually does File.join('script','rails') to kick off the rails process.
Without you showing the error message you are getting, I'm assuming it has less to do with Bundler than it does Rake. When the rake command is run, it searches for a Rakefile starting in the current directory and traversing up the tree until it finds one. You can override this behavior by explicitly specifying a Rakefile in the options to the rake command. This is done using the -f <RAKEFILE> option.
eg.
bundle exec rake -f /PATH/TO/RAILS_APP/Rakefile my_task:do_stuff
Bear in mind that your Rake tasks have to be "CWD agnostic". Most tasks and scripts are as they tend to get the project directory based on a path relative to a known file in the directory tree. You probably already understand that, but it's worth mentioning in case the tasks are expecting the current working directory to actually be the rails root. That would be a case where running them from outside the project could potentially be dangerous.

How do you get LiveReload to work with Octopress using Guard

I am using this guide to add liveReload to Octopress.
http://www.erikzaadi.com/2012/09/16/using-live-reload-with-octopress/
Once I get to 'rake generate && rake watch',
The command line spits out I am missing a specific gem; i.e.'rake-0.9.6', which is strange because I thought by installing the bundle took care of that.
I suspect that bundle is being saved elsewhere; but shouldn't that bundle be saved in the directory of my choosing (i.e. Sites/myproject?)
Add these two entries to your Gemfile, in the :development group:
gem 'guard'
gem 'guard-livereload'
Create a file called Guardfile containing something like:
guard 'livereload' do
watch(%r{public/generated})
watch(%r{public/.+\.(css|js|html)})
end
Start 2 shell tabs running these commands: rake generate && rake watch and guard
`
rake generate && rake watch
`
start guard LiveReload
`
guard
`
It’s neat to get LiveReload working with Octopress. However, the generation can finish after your page does a reload, so you won’t see your latest changes. I’ll update this blog post when I figure out a solution to that one. Until then, you may find it more convenient to manually refresh the blog page yourself.
It’s worth noting that if you’re running any other instance of guard- LiveReload, then one of these two copies will win and one won’t work. If you run a rails server this way, then this can bite you. It took me a bit of time to figure out why guard wasn’t working.
source
http://www.railsonmaui.com/blog/2013/04/27/octopress-setup-with-github-and-org-mode/#sec-4

How to develop a Ruby GEM without having to install it first?

I'm developing a GEM that I've forked and I'm trying to modify it slightly for my app.
I'm finding it difficult and time consuming because for every change I make I have to
uninstall
build
re-install
run the app
Is there an easier way of which doesn't require repeating all steps above?
To use it in some app using bundler
If what you mean is for using it in a app to test it / use it, you can just specify a path for your gem or even point to a git repo in the Gemfile http://gembundler.com/gemfile.html
Like
gem "mygem", :path => "~/code/gems/mygem"
To use it as a standalone gem. i.e: like rspec or rake that can run outside of an app.
Just specify the path to your gem binary when running the gem command, like:
$ ~/path_to_my_gem/bin/mygem some args
If you can execute inside your gem directory (i.e: the command does not create files in the current directory, or needs any specific files from the current directory), just do this:
$ ./bin/mygem some args
Note that this last one is just for future reference, I think it's not applicable in the OP context.
use require_relative to include your files:
require_relative 'yourgem/yourclass'
This is the documentation for the function.

Are bundle exec and require 'bundler/setup' equivalent?

Do these things accomplish exactly the same?
starting a ruby process with bundle exec ruby foo.rb
having require "bundler/setup" as the first line of foo.rb
In your specific example they can be considered the same, however in reality they are not the same.
bundle exec makes some changes to the environment that bundler/setup does not make. If your foo.rb never runs a subshell, or never tries to run other ruby executables in subshells, then both versions are equivalent (they will both load bundled gems correctly and work exactly the same).
The whole idea with bundle exec is to enable you to run executables that were not originally designed with bundler in mind. Like rspec, rails, rackup. If your own app (foo.rb) does not try to run such executables that might be dependent on your bundles, then it makes no difference either way. Since all you want to make sure with bundler is that you load the correct gems, and for that bundler/setup works exactly as expected in your case.
From the bundler docs when talking about running ruby system executables:
In some cases, running executables without bundle exec may work, if the executable happens to be installed in your system and does not pull in any gems that conflict with your bundle.
However, this is unreliable and is the source of considerable pain. Even if it looks like it works, it may not work in the future or on another machine.
Then from the manpage of bundle exec you can get some additional clues as to what bundle exec actually does:
ENVIRONMENT MODIFICATIONS
make sure that it's still possible to shell out to bundle from inside a command invoked by bundle exec (using $BUNDLE_BIN_PATH)
put the directory containing executables (like rails, rspec, rackup) for your bundle on $PATH
make sure that if bundler is invoked in the subshell, it uses the same Gemfile (by setting BUNDLE_GEMFILE)
add -rbundler/setup to $RUBYOPT, which makes sure that Ruby programs invoked in the subshell can see the gems in the bundle
So if you build your app with bundler support in mind, then you never need to bundle exec your app.
But if you need to use other tools that load your app code that might load gems before they load your app code (which then might pull in a wrong non-bundled gem), then you need to use bundle exec.

Execute tests for another app from a rake file

I'm trying to execute cucumber tests for a project within a rake file in another project.
Currently I am trying this:
system "cd /path/to/project;rvm use --create 1.9.2-p290#test; cucumber features/test.feature"
This works for the cd, and the rvm seems to work if I run which ruby after the rvm use... but the problem is that the cucumber gem seems to be called from the current folder (not the app to test folder).
The error I get is:
cucumber is not part of the bundle. Add it to Gemfile. (Gem::LoadError)
It seems to be using the local gemset version of cucumber rather than the #test gemset.
Any thoughts on this?
Or is there a better way to run cucumber tests for another project that relies on rvm & a different bundle?
I've also been trying to do exactly the same thing; run an application's tests (or any rake task) from inside another 'control' application.
Reason: (just so I don't get served with a "why on earth?")
I am trying to build an application (rather like cruisecontrol.rb ) which can monitor, schedule and review the specs for a set of apps.
After some digging around in cruisecontrol's source I found that Bundler provides a solution;
Bundler.with_clean_env do
system "rake spec"
end
see line56 of https://github.com/thoughtworks/cruisecontrol.rb/blob/master/lib/platform.rb
That steps out of the bundle and the command is run without the control app's gems.
BUT as is most likely, the command uses bundle exec then this stops working.
Bundler.with_clean_env { system "bundle exec rake spec" }
And you are right back to the exact same problem. This is caused by some bundler variables still existing and being inherited by the sub-shell. Full (very good) explanation here.
The solution is to change the with_clean_env method on bundler like this;
BUNDLER_VARS = %w(BUNDLE_GEMFILE RUBYOPT BUNDLE_BIN_PATH)
module Bundler
def self.with_clean_env &blk
bundled_env = ENV.to_hash
BUNDLER_VARS.each{ |var| ENV.delete(var) }
yield
ensure
ENV.replace(bundled_env.to_hash)
end
end
above code from here
I put that in the environment.rb of my control application (it should probably be in a initializer?) and now I can run the specs of another app from within the control app.
#in control app
result = nil
Dir.chdir(test_app_path) #move into test app
Bundler.with_clean_env { result = `bundle exec rake spec` } #run test apps specs
puts result #display result inside control app
Changing the ; in your script to && seems to work.

Resources