How to Detect if Ruby is Running a Cucumber Test - ruby

Very similar to this question: Easy way to detect whether rspec or cucumber is running?
How can I detect in Ruby that I am running under cucumber?
I have some path variables in a common code project that will need to be changed if the code being used is a cucumber project or a standard script. I'm trying to cover a relative pathing issue. require_relative '../../{filename}' will fail when the file structure is different when under the cucumber structure. It would need to traverse back two more levels like: '../../../../{filename}'.
Common Project: C:\RubyProjects\common-project\common
build_properties.rb
def build_properties_from_yaml('', '')
params = YAML.load_file(File.absolute_path << '/utils/parameters.yml')
end
Cucumber Project: C:\RubyProjects\programs\2017\features\step_definitions
test_rest.rb
require_relative './../../../RubyProjects/common-project/common'
class Verify
include Common
build_properties_from_yaml('', '')
end
Some Other Project: C:\RubyProjects\programs\2017\
File.rb
require_relative './../../RubyProjects/common-project/common'
class RunCode
include Common
build_properties_from_yaml('', '')
end
With the case of the "utils" folder, it sits under the features folder in cucumber but there is no such folder in other projects without cucumber. That is what throws off the code and i'd like to check for cucumber in the yaml load process.

If just if Rails.env.test? does not work for you, you may add to the features/support/env.rb:
ENV['CUCUMBER'] = "true"
Then examine it where you want:
if ENV['CUCUMBER']
...
end
You can wrap this in a method somewhere and use it.
EDIT: #spikermann's comments are absolutely right. For sure, you're doing something wrong if your code depends from an env. But in some cases (one-time code or kind of) it could be easier to make a hack.

Related

Ruby: reading files in turn

I have 2 files which should be run in order. I create run.rb file:
files =[
'./file-name-1.rb',
'./file-name-2.rb',
]
files.each do |file|
require file
end
And run it. Are there more correct methods of solving this problem?
Since it is file-name-2.rb that depends on file-name-1.rb, then it should be the one to require "file-name-1.rb". It should not be run.rb's job to know what another file's dependencies are. The correct way to solve this, then, is:
file-name-2.rb
require "file-name-1.rb"
# ...
run.rb
require "file-name-2.rb
# ....
And, as Frederick suggests in the comments above, it's unorthodox for a file to do work other than declaring constants (classes, modules) and/or methods at the time it's required. Instead, it should define methods to do that work, and then other files that require it can invoke those methods. This way you always know exactly when the work will be done, even if your application has a complex dependency structure.

Ruby, including module in current directory

I am currently working through the Well Grounded Rubyist. Great book so far. I am stuck on something I don't quite get with ruby. I have two files
In ModuleTester.rb
class ModuleTester
include MyFirstModule
end
mt = ModuleTester.new
mt.say_hello
In MyFirstModule.rb
module MyFirstModule
def say_hello
puts "hello"
end
end
When I run 'ruby ModuleTester.rb', I get the following message:
ModuleTester.rb:2:in <class:ModuleTester>': uninitialized constant ModuleTester::MyFirstModule (NameError)
from ModuleTester.rb:1:in'
From what I have found online, the current directory isn't in the the namespace, so it can't see the file. But, the include statement doesn't take a string to let me give the path. Since the include statement and require statements do different things, I am absolutely lost
as to how to get the include statement to recognize the module. I looked through other questions, but they all seem to be using the require statement. Any hints are greatly appreciated.
You use require to load a file, not include. :-)
First, you have to require the file containing the module you want to include. Then you can include the module.
If you're using Rails, it has some magic to automagically require the right file first. But otherwise, you have to do it yourself.
You need to require the file before you can use types defined in it. *
# my_first_module.rb
module MyFirstModule
def say_hello
puts 'hello'
end
end
Note the require at the beginning of the following:
# module_tester.rb
require 'my_first_module'
class ModuleTester
include MyFirstModule
end
mt = ModuleTester.new
mt.say_hello
The require method actually loads and executes the script specified, using the Ruby VM's load path ($: or $LOAD_PATH) to find it when the argument is not an absolute path.
The include method, on the other hand actually mixes in a Module's methods into the current class. It's closely related to extend. The Well Grounded Rubyist does a great job of covering all this, though, so I encourage you to continue plugging through it.
See the #require, #include and #extend docs for more information.
* Things work a bit differently when using Rubygems and/or Bundler, but getting into those details is likely to confuse you more than it's worth at this point.

how to run a spec file with ruby without spec

How to run a spec file with ruby without spec?
How do I inherit the spec base class to the current ruby spec file?
I think all you need are the files required in the spec_helper.rb you should be able to call the specs with
ruby -Ispec my_spec.rb #=> assuming you have a spec folder and there is a spec helper inside.
That's two questions.
1) "how to run a spec file with ruby without spec?"
either put
require "rubygems"
require "spec"
require "spec/autorun"
in the file, or run
ruby -rrubygems -rspec -rspec/autorun whatever_spec.rb
from the command line. But spec is easier.
2) "How do i inherit the spec base class to the current ruby spec file?"
Basically, you don't. RSpec is an internal DSL which means that it generates objects for you based on your describe and it blocks. These objects are instances of real classes (e.g. Spec::Example::ExampleGroup), but they're very complicated and magical and you shouldn't try to extend them unless you really know what you're doing. What are you trying to accomplish?

Adding a directory to $LOAD_PATH (Ruby)

I have seen two commonly used techniques for adding the directory of the file currently being executed to the $LOAD_PATH (or $:). I see the advantages of doing this in case you're not working with a gem. One seems more verbose than the other, obviously, but is there a reason to go with one over the other?
The first, verbose method (could be overkill):
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
and the more straightforward, quick-and-dirty:
$:.unshift File.dirname(__FILE__)
Any reason to go with one over the other?
The Ruby load path is very commonly seen written as $: , but just because it is short, does not make it better. If you prefer clarity to cleverness, or if brevity for its own sake makes you itchy, you needn't do it just because everyone else is.
Say hello to ...
$LOAD_PATH
... and say goodbye to ...
# I don't quite understand what this is doing...
$:
I would say go with $:.unshift File.dirname(__FILE__) over the other one, simply because I've seen much more usage of it in code than the $LOAD_PATH one, and it's shorter too!
I'm not too fond on the 'quick-and-dirty' way.
Anyone new to Ruby will be pondering what $:. is.
I find this more obvious.
libdir = File.dirname(__FILE__)
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
Or if I care about having the full path...
libdir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
UPDATE 2009/09/10
As of late I've been doing the following:
$:.unshift(File.expand_path(File.dirname(__FILE__))) unless
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
I've seen it in a whole bunch of different ruby projects while browsing GitHub.
Seems to be the convention?
If you type script/console in your Rails project and enter $:, you'll get an array that includes all the directories needed to load Ruby. The take-away from this little exercise is that $: is an array. That being so, you can perform functions on it like prepending other directories with the unshift method or the << operator. As you implied in your statement $: and $LOAD_PATH are the same.
The disadvantage with doing it the quick and dirty way as you mentioned is this: if you already have the directory in your boot path, it will repeat itself.
Example:
I have a plugin I created called todo. My directory is structured like so:
/---vendor
|
|---/plugins
|
|---/todo
|
|---/lib
|
|---/app
|
|---/models
|---/controllers
|
|---/rails
|
|---init.rb
In the init.rb file I entered the following code:
## In vendor/plugins/todo/rails/init.rb
%w{ models controllers models }.each do |dir|
path = File.expand_path(File.join(File.dirname(__FILE__), '../lib', 'app', dir))
$LOAD_PATH << path
ActiveSupport::Dependencies.load_paths << path
ActiveSupport::Dependencies.load_once_paths.delete(path)
end
Note how I tell the code block to perform the actions inside the block to the strings 'models', 'controllers', and 'models', where I repeat 'models'. (FYI, %w{ ... } is just another way to tell Ruby to hold an array of strings). When I run script/console, I type the following:
>> puts $:
And I type this so that it is easier to read the contents in the string. The output I get is:
...
...
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/controllers
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models
As you can see, though this is as simple an example I could create while using a project I'm currently working on, if you're not careful the quick and dirty way will lead to repeated paths. The longer way will check for repeated paths and make sure they don't occur.
If you're an experienced Rails programmer, you probably have a very good idea of what you're doing and likely not make the mistake of repeating paths. If you're a newbie, I would go with the longer way until you understand really what you're doing.
Best I have come across for adding a dir via relative path when using Rspec. I find it verbose enough but also still a nice one liner.
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
There is a gem which will let you setup your load path with nicer and cleaner code. Check this out: https://github.com/nayyara-samuel/load-path.
It also has good documentation
My 2ยข: I like $LOAD_PATH rather than $:. I'm getting old... I've studied 92,000 languages. I find it hard to keep track of all the customs and idioms.
I've come to abhor namespace pollution.
Last, when I deal with paths, I always delete and then either append or prepend -- depending upon how I want the search to proceed. Thus, I do:
1.times do
models_dir = "#{File.expand_path(File.dirname(__FILE__))}/models"
$LOAD_PATH.delete(models_dir)
$LOAD_PATH.unshift(models_dir)
end
I know it's been a long time since this question was first asked, but I have an additional answer that I want to share.
I have several Ruby applications that were developed by another programmer over several years, and they re-use the same classes in the different applications although they might access the same database. Since this violates the DRY rule, I decided to create a class library to be shared by all of the Ruby applications. I could have put it in the main Ruby library, but that would hide custom code in the common codebase which I didn't want to do.
I had a problem where I had a name conflict between an already defined name "profile.rb", and a class I was using. This conflict wasn't a problem until I tried to create the common code library. Normally, Ruby searches application locations first, then goes to the $LOAD_PATH locations.
The application_controller.rb could not find the class I created, and threw an error on the original definition because it is not a class. Since I removed the class definition from the app/models section of the application, Ruby could not find it there and went looking for it in the Ruby paths.
So, I modified the $LOAD_PATH variable to include a path to the library directory I was using. This can be done in the environment.rb file at initialization time.
Even with the new directory added to the search path, Ruby was throwing an error because it was preferentially taking the system-defined file first. The search path in the $LOAD_PATH variable preferentially searches the Ruby paths first.
So, I needed to change the search order so that Ruby found the class in my common library before it searched the built-in libraries.
This code did it in the environment.rb file:
Rails::Initializer.run do |config|
* * * * *
path = []
path.concat($LOAD_PATH)
$LOAD_PATH.clear
$LOAD_PATH << 'C:\web\common\lib'
$LOAD_PATH << 'C:\web\common'
$LOAD_PATH.concat(path)
* * * * *
end
I don't think you can use any of the advanced coding constructs given before at this level, but it works just fine if you want to setup something at initialization time in your app. You must maintain the original order of the original $LOAD_PATH variable when it is added back to the new variable otherwise some of the main Ruby classes get lost.
In the application_controller.rb file, I simply use a
require 'profile'
require 'etc' #etc
and this loads the custom library files for the entire application, i.e., I don't have to use require commands in every controller.
For me, this was the solution I was looking for, and I thought I would add it to this answer to pass the information along.

Passing a parameter/object to a ruby unit/test before running it using TestRunner

I'm building a tool that automates a process then runs some tests on it's own results then goes to do some other stuff.
In trying to clean up my code I have created a separate file that just has the test cases class. Now before I can run these tests, I have to pass the class a couple of parameters/objects before they can be run. Now the problem is that I can't seem to find a way to pass a parameter/object to the test class.
Right now I am thinking to generate a Yaml file and read it in the test class but it feels "wrong" to use a temporary file for this. If anyone has a nicer solution that would be great!
**************Edit************
Example Code of what I am doing right now:
#!/usr/bin/ruby
require 'test/unit/ui/console/testrunner'
require 'yaml'
require 'TS_SampleTestSuite'
automatingSomething()
importantInfo = getImportantInfo()
File.open('filename.yml', 'w') do |f|
f.puts importantInfo.to_yaml
end
Test::Unit::UI::Console::TestRunner.run(TS_SampleTestSuite)
Now in the example above TS_SampleTestSuite needs importantInfo, so the first "test case" is a method that just reads in the information from the Yaml file filname.yml.
I hope that clears up some confusion.
Overall, it looks like you're not really using the unit tests in a very rubyish way, but I'll leave that aside for a minute.
Your basic problem is that you have some setup that needs to happen before the tests run. The normal way to do that is with a setup method within the test unit case itself.
class UserTest < TestUnit::TestCase
def setup
# do your important calculation
end
def test_success
#.. assert some things
end
end
I would give some thought to what code it is that you're actually testing here, and see if you can break it down and test it in a more granular way, with lots more tests.
First, I agree with Cameron, this code definitely does not adhere to the Ruby way, though I'll also sidestep that for now.
The fastest way to get up and running with this, especially if this data is pretty much immutable (that is to say, your tests won't be altering it in anyway), is to just assign the value to a constant. So instead of naming your variable importantInfo, you name it IMPORTANT_INFO. Then it will be available to you in your tests. It's definitely not a pretty solution, and I think it couuld even be considered a test smell that you need that sort of global setup, but it's there for you.
Alternatively, you could look at stubbing out the importantInfo, which I actually think would provide for much cleaner and more readable tests.

Resources