So some ruby libraries double as executables, using the trick:
if __FILE__ == $0
# act as executable...
end
I'm writing a mini-library, and was wondering if there were a similar trick I could use to embed my rspec tests in the file. Some sort of constant or something I could check, like:
if RSPEC_TARGET == $0
describe 'Foo' do
it "should foo" #...
end
end
ARGV contains the name of the script. I use the following in my modules:
if ARGV.include? File.basename(__FILE__)
# unit tests here
end
Related
If I want to run a bunch of ruby scripts (super similar, with maybe a number changed as a commandline argument) and still have them output to stdout, is there a way to do this?
i.e a script to run these:
ruby program1.rb input_1.txt
ruby program1.rb input_2.txt
ruby program1.rb input_3.txt
like
(1..3).each do |i|
ruby program1.rb input_#{i}'
end
in another script, so I can just run that script and see the output in a terminal from all 3 runs?
EDIT:
I'm struggling to implement the second highest voted suggested answer.
I don't have a main function within my program1.rb, whereas the suggested answer has one.
I've tried this, for script.rb:
require "program1.rb"
(1..6).each do |i|
driver("cmd_line_arg_#{i}","cmd_line_arg2")
end
but no luck. Is that right?
You can use load to run the script you need (the difference between load and require is that require will not run the script again if it has already been loaded).
To make each run have different arguments (given that they are read from the ARGV variable), you need to override the ARGV variable:
(1..6).each do |i|
ARGV = ["cmd_line_arg_#{i}","cmd_line_arg2"]
load 'program1.rb'
end
# script_runner.rb
require_relative 'program_1'
module ScriptRunner
class << self
def run
ARGV.each do | file |
SomeClass.new(file).process
end
end
end
end
ScriptRunner.run
.
# programe_1.rb
class SomeClass
attr_reader :file_path
def initialize(file_path)
#file_path = file_path
end
def process
puts File.open(file_path).read
end
end
Doing something like the code shown above would allow you to run:
ruby script_runner.rb input_1.txt input_2.txt input_3.txt
from the command line - useful if your input files change. Or even:
ruby script_runner.rb *.txt
if you want to run it on all text files. Or:
ruby script_runner.rb inputs/*
if you want to run it on all files in a specific dir (in this case called 'inputs').
This assumes whatever is in program_1.rb is not just a block of procedural code and instead provides some object (class) that encapsulates the logic you want to use on each file,meaning you can require program_1.rb once and then use the object it provides as many times as you like, otherwise you'll need to use #load:
# script_runner.rb
module ScriptRunner
class << self
def run
ARGV.each do | file |
load('program_1.rb', file)
end
end
end
end
ScriptRunner.run
.
# program_1.rb
puts File.open(ARGV[0]).read
If I have some test, e.g.
require_relative "Line"
require_relative "LineParser"
describe Line do
it "Can be created" do
load "spec_helper.rb"
#line.class.should == Line
end
it "Can be parsed" do
...
How can I print out the test group name - "Line" in this case.
I tried adding:
before :all do
puts "In #{self.class}"
end
but that gives: In RSpec::Core::ExampleGroup::Nested_3, not Line
You may have specific reasons for wanting access to the test name while you're in the test...however, just in case it fits your needs to just have the line output in the test report, I like this configuration:
RSpec.configure do |config|
# Use color in STDOUT
config.color_enabled = true
# Use color not only in STDOUT but also in pagers and files
config.tty = true
# Use the specified formatter
config.formatter = :documentation
end
This gives me output like:
MyClassName
The initialization process
should accept two optional arguments
RSpec will read command line arguments from a file, so you could add the following to a .rspec file in the root of your project:
--format documentation
--color
(This file may already exist depending on the gem you're using for RSpec and how you've installed it.)
The answer turned out to be:
before :all do
puts "In #{self.class.description}"
end
$ rspec line_spec.rb
In Line
say we have a ruby file.rb like:
if __FILE__ == $0 then
if ARGV[0] == 'foo'
puts "working"
# Dir.chdir(../)
v = Someclass.new
v.do_something
end
end
it suppose to print working only if the file was triggered like ruby file.rb foo.
My question: how can that kind of stuf be tested within rspec?
My try is below. The file ran but not in the scope of rspec test:
Dir expected :chdir with (any args) once, but received it 0 times
it 'should work' do
FILE = File.expand_path('file.rb')
RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
#v = Someclass.new
Someclass.should_receive(:new).and_return #v
#v.should_receive(:do_something)
`#{RUBY} #{FILE} foo`
end
Backticks runs new shell, executes command, and returns result as a string. Thats why it runs outside your scope. Backticks does not care about contents of your script: ruby, bash, or something else.
chdir, of course, applied only to this new shell, so there seems no way to check you sample script for directory changing (except of tracing system calls). Maybe some 'real' script will do something, output more, thus providing more possibilities to check it.
I have three RSpec2 test files, each of which passes individually. But running the suite with rspec spec (or jruby -S rspec spec) fails.
The problem: ARGV is being set to ["spec"] and running my program with a spec argument changes its behavior. I try to handle this in my tests with:
before(:each) do
ARGV.clear # also tried: ARGV.delete_if { |val| true }
end
but the puts ARGV statement in my code indicates ARGV is still being set to ["spec"].
I've also created a spec/spec_helper.rb file with:
RSpec.configure do |config|
config.before(:suite) do
ARGV.clear
end
end
with the same result. When I run tests individually, ARGV is empty. But when I run rspec spec, ARGV is ["spec"].
Possibly relevant background: I'm running under rbenv.
Rewrite your code such that ARGV isn't mentioned in the methods you're testing.
For example, if you need to test that you can parse "play_jukebox", then do
def test_play_jukebox
parse_options(["play_jukebox"])
end
and in your bin file, have
if $0 == __FILE__
parse_options(ARGV)
end
I want to write a Ruby script something like this:
class Foo
# instance methods here
def self.run
foo = Foo.new
# do stuff here
end
end
# This code should only be executed when run as a script, but not when required into another file
unless required_in? # <-- not a real Kernel method
Foo.run
end
# ------------------------------------------------------------------------------------------
I want to be able to unit test it, which is why I don't want the code outside of the class to run unless I execute the script directly, i.e. ruby foo_it_up.rb.
I know I can simply put the Foo class in another file and require 'foo' in my script. In fact, that is probably a better way to do it, just in case Foo's functionality is needed somewhere else. So my question is more academic than anything, but I'd still be interested in knowing how to do this in Ruby.
This is usually done with
if __FILE__ == $0
Foo.run
end
but I prefer
if File.identical?(__FILE__, $0)
Foo.run
end
because programs like ruby-prof can make $0 not equal __FILE__ even when you use --replace-progname.
$0 refers to the name of the program ($PROGRAM_NAME), while __FILE__ is the name of the current source file.