First, I'm not attempting to test a module. I'm testing classes within a single module. This SO question/answer doesn't describe the code I'm looking at, so it's tough to draw parallels to my curiosity.
I'm following along with this tutorial, which is outdated; However, it's a suggested resource.
My specific question is:
Why is the RSpec language in the spec file placed within the module TicTacToe, like so:
require 'some_file'
module TicTacToe
#RSpec examples here
end
I'm very new to RSpec and coding in general, so I'm not familiar with the conventions of writing tests in RSpec; Is this organization necessary? Out-dated? My tests are passing and things are working as expected; I'm just attempting to learn how to write tests, and most specs begin with RSpec.describe Foo do or describe Bar do
I have not seen module used like that within spec files. I suspect that's a very old tutorial. (Wordpress helpfully shows it's from Oct 25, but neglects to mention which year. But the oldest comment is from 2014)
I recommend you find a more recent tutorial.
The describe keyword would be more appropriate here. Most of the specs I work with looked like this a few years ago:
RSpec.describe TicTacToe::SomeClass, type: :model do
#RSpec examples here
end
Or even more modern, rspec discerns the type (model, controller, etc.) from the path to the spec file:
# spec/model/tic_tac_toe/cell.rb
describe Cell do
let(:first_cell) { described_class.new }
#RSpec examples here
end
Related
My app runs on Shoes 3 and consists of the following code
require 'somefile'
Shoes.app do
stack do
flow do
#my_editbox = edit_line
end
flow do
button "Get Name" do
#my_editbox.text = "#{#name}"
end
end
end
end
With my external file somefile.rb holding
#name = "my name"
Clicking the button does nothing, and my edit box stays empty. Any help is appreciated!
That's not how Shoes works. Shoes is not Ruby, it only looks like Ruby. Many things that you know to work in Ruby simply will not work in Shoes, because Shoes is a toolkit written in C that will work in Ruby-ish ways by directly calling the Ruby APIs.
require calls are one of the things that will not work the way you expect. There is a nicely confusing explanation about some of these rules available on the Shoes website.
Personally, I found Shoes to be so frustrating and poorly documented that it wasn't worth using even in the extremely limited ways it can be used. Good luck.
Update
You asked below about the "how". I assume you mean, how do you properly use require in a Shoes app to load code from a separate file.
Take a look at this repo for an example. You can build a normal Ruby class and then require that class in your app. You can use that class within your Shoes.app do block in a normal Ruby way. But (as far as I can tell) because of the way self changes within the block, you cannot pull in a standalone instance variable that exists outside of a class/module.
You can do something like this, though, and it does work in the way you expect:
# foo.rb
module Foo
##name = 'foobar'
end
and
# test.rb
require './foo.rb'
Shoes.app do
stack do
flow do
#my_editbox = edit_line
end
flow do
button "Get Name" do
#my_editbox.text = Foo.class_variable_get(:##name)
end
end
end
end
Here I've created a module with a class variable because it doesn't make sense to use an instance variable in something that doesn't get instantiated.
There are certainly other ways of doing this as well, and you can probably find other examples on GitHub (though you may have to tweak that query to get more results), but this is a functional example to accomplish the task you've outlined.
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.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
In Java, every instruction executed is defined inside a method. In Ruby, you can do something like this:
class A
puts "Inside of A class" # [1]
end
and [1] will be executed when A is loaded. An example of this is the following code in Rails:
class Product < ActiveRecord::Base
validates :title, :presence => true, length: 1..19, :uniqueness => true
end
What sense does it have to write code outside of a method? How can it be used (how can it be invoked)?
I assume you want to know why you'd place code to execute "inside a class," when there's no way to have it execute more than once (when the class is first loaded.)
In Ruby, all classes are themselves objects - they are instance of the class Class. So what's happening under the hood when Ruby "reads" a class definition, is that Ruby is actually running methods on that instance of the class Class.
So a def inside the class definition of the class A is actually the same as A.send(:define_method, ...) - to understand what that means, you have to understand what senders and receivers are, and how they are implemented in Ruby. That SO post I linked to does a pretty good job of referring you to more material. The def syntax is just a convention to make the sending/receiving look like the syntax of other languages so that it's easier to "transition" to Ruby from other languages.
Ruby doesn't require that you should only call methods on the class itself when defining the class - so you can run any code you want. One use case is when you define a variable prefixed with an # inside the class definition:
class A
#class_var=123
def self.class_var
#class_var
end
def self.class_var=(inp)
#class_var=inp
end
end
a=A.new
b=A.new
b.class.class_var=5
puts a.class.class_var
# 5
Note the def self. notation that defines "class methods" - they can then access the "class variable" that you created by writing the code "inside the class."
This question comes up a lot for me, so I've written a more extensive blog post about it, to try and go into more detail about how Ruby implements these concepts. I have written them here in scare quotes, because they mean slightly different things in Java and C++, so don't apply their meanings very directly to try and understand what they mean in Ruby.
What sense has write code out of methods?
You've already seen it. Instead of changing the language itself (and the compiler) to add annotations to Ruby, the makers of Rails could make model validations easily (and lots of DSL for different things). Another example is att_accessor, a method that called in the context of a class will add accessor methods. And there are many many more.
Basically, you are adding that way lots of flexibility to the language.
How it can be used (how can it be invoked)?
You already did in your example. Just put the code there... and it is executed.
You can use and invoke it like such:
def putString
puts "Inside method outside of class"
end
class A
puts "Inside of A class" #[1]
putString
end
It gets invoked when you require the file.
Uses?
Meta-programming is one
['foo','bar'].each |m| do
def m
[m]
end
end
There's an even sneakier scenario where you can put code outside of the class, never mind the method, confused the heck out me when I first saw it.
Most of the answers here refer to code inside a class and outside its methods. I think the OP asked about code outside everything - forbidden in Java!
Java mimics the C languages' compilation cycle. In C, only certain kinds of lines can happen during compilation. Then, only the remaining kinds of lines can run during execution.
In Ruby, code evaluates from top to bottom. The commands class and def essentially mean "capture all these tokens, and evaluate them later." So, because the entire file evaluates at runtime, things outside classes can happen very early.
The most notorious example is:
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require is (prepare for a shock) just a method, and File is (prepare for another one) always available. So a Ruby programmer can exchange zillions of boring, fragile lines of configuration files (in Java ANT or C MAKE) for just a few ugly - but bullet-proof - lines of raw Ruby, at the top of each file.
I've been using for Rails apps I've been maintaining the hpricot_matchers and most recently rspec_tag_matchers as matcher implementations to test strings with nested tags inside (like, let's say, HTML or XML). Specially the last one is really good, since it uses Nokogiri.
Recently I started developing in Sinatra, and of course, I bundled rspec in it. All is nice and neat, til I found out I don't have certain matchers available like the have_tag (which check tags and attributes values). Well, this would be really great to have in Sinatra, and the above mentioned gems are not usable, since they have a rspec-rails dependency, which has a rails dependency.
So the question would be: is there any tool available for Sinatra which accomplishes the same task? Any Sinatra matchers out in the open? Couldn't find any, though.
Actually found out an extension that does the job...
https://github.com/kucaahbe/rspec-html-matchers
Should have looked a little bit more. I haven't checked whether it covers everything that the rails rspec matcher helpers do, but most of the important ones are there, including the very valuable have_tag. One thing, though: the specification for both is a bit different when it comes to nested conditions in sub-tags:
rspec_tag_matchers(rails3):
text.should have_tag("p") do |paragraph|
paragraph.should have_tag("strong")
end
rspec_html_matchers(sinatra/...):
text.should have_tag("p") do
with_tag("strong")
end
I think you are looking for this...
Code Example for Rspec Matchers
Code looks like this there...
# File lib/sinatra/tests/rspec/matchers.rb, line 52
def have_a_page_header(expected, tag = 'h2')
simple_matcher("have an '#{tag}' page header with [#{expected.inspect}]") do |given, matcher|
given.should have_tag(tag, expected, :count => 1)
end
end
The point is: You can always create your own matchers.
Hope that helps.
You can use Capybara when testing a sinatra app (or any rack app, for that matter). Capybara includes several matchers that would probably meet your needs:
have_selector('table tr')
have_xpath('//table/tr')
have_css('table tr.foo')
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.