I am kinda of new to Rspec and I am writing some test examples when a question came up.
First, I was using global variables to define three constant values I was going to use in a lot of tests. For example:
$message = 'this is a test'
However, I notice that this global was being carried over to other test files and causing issues. Ok... decided then to avoid the globals as this can cause a lot of pain in the future in case my test file number grows.
I then went for the let() block. Example:
let(:message) { 'this is a test' }
Now the problem was that this variable could not be used inside before and after hooks. Ok...
My last try was using constants inside the contexts/describes, like this:
self::MESSAGE = 'this is a test'
However, just like let's this cannot be used inside the hooks as they are not either classes or modules.
So, I am stuck ...
How do you guys deal with that? Will I need to create instance variables for that? Is that any other alternative I can use?
Thank you very much.
You have one other option for defining data -- instance variables.
before do
#data = [ {one: 1, two: 2},
{one: 2, two: 3} ]
end
You can use #data in all the tests within the scope of the before. This is pretty much the same as let for the purposes of just setting up static data, but it might be a better fit for you -- without seeing your code it's hard to say.
Related
This is a bit of a weird question, but I'm not quite sure how to look it up. In our project, we already have an existing concept of a "shift". There's a section of code that reads:
foo.shift
In this scenario, it's easy to read this as trying to access the shift variable of object foo. But it could also be Array#shift. Is there a way to specify which class we expect the method to belong to? I've tried variations such as:
foo.send(Array.shift)
Array.shift(foo)
to make it more obvious which method was being called, but I can't get it to work. Is there a way to be more explicit about which class the method you're trying to call belongs to to help in code readability?
On a fundamental level you shouldn't be concerned about this sort of thing and you absolutely can't tell the Array shift method to operate on anything but an Array object. Many of the core Ruby classes are implemented in C and have optimizations that often depend on specific internals being present. There's safety measures in place to prevent you from trying to do something too crazy, like rebinding and applying methods of that sort arbitrarily.
Here's an example of two "shifty" objects to help illustrate a real-world situation and how that applies:
class CharacterArray < Array
def initialize(*args)
super(args.flat_map(&:chars))
end
def inspect
join('').inspect
end
end
class CharacterList < String
def shift
slice!(0, 1)
end
end
You can smash Array#shift on to the first and it will work by pure chance because you're dealing with an Array. It won't work with the second one because that's not an Array, it's missing significant methods that the shift method likely depends on.
In practice it doesn't matter what you're using, they're both the same:
list_a = CharacterArray.new("test")
list_a.shift
# => "t"
list_a.shift
# => "e"
list_a << "y"
# => "sty"
list_b = CharacterList.new("test")
list_b.shift
# => "t"
list_b.shift
# => "e"
list_b << "y"
# => "sty"
These both implement the same interfaces, they both produce the same results, and as far as you're concerned, as the caller, that's good enough. This is the foundation of Duck Typing which is the philosophy Ruby has deeply embraced.
If you try the rebind trick on the CharacterList you're going to end up in trouble, it won't work, yet that class delivers on all your expectations as far as interface goes.
Edit: As Sergio points out, you can't use the rebind technique, Ruby abruptly explodes:
Array.instance_method(:shift).bind(list_b).call
# => Error: bind argument must be an instance of Array (TypeError)
If readability is the goal then that has 35 more characters than list_b.shift which is usually going dramatically in the wrong direction.
After some discussion in the comments, one solution is:
Array.instance_method(:shift).bind(foo).call
Super ugly, but gets across the idea that I wanted which was to completely specify which instance method was actually being called. Alternatives would be to rename the variable to something like foo_array or to call it as foo.to_a.shift.
The reason this is difficult is that Ruby is not strongly-typed, and this question is all about trying to bring stronger typing to it. That's why the solution is gross! Thanks to everybody for their input!
I'm confused on this one. I have a couple of viable solutions, but I don't like either of them. The problem at hand is that I am trying to generate a CSV in a Rails application. In my application specifically, I have a lot of values, around 30. Many of the values I would like displayed are also on associations, thus making the lines even longer... They look something like this (don't bother to read, just wanted you to have an idea of what i was talking about):
[piece.client.organization, piece.client.category, piece.client.name , piece.campaign.name, piece.name, piece_url(piece.id), piece.campaign.election_date, piece.campaign.win_loss, piece.final_date, piece.local_photos, piece.killed, piece.format_list, piece.artist_list, piece.partner_list, piece.account_executive_list, piece.out_of_stock, piece.total_intake, piece.campaign.candidate_tags, piece.client.spec_list, piece.campaign.mail_poll]
Except that they're even longer and more unwieldy. They work, but they make me feel bad inside. This is when I had the idea that I would just put them in a two-dimensional array, it instantly made the data look much more readable:
[["Client", piece.client.organization],
["Category", piece.client.category],
["Client Name", piece.client.name] ,
...
["Campaign Name", piece.campaign.name],
["Piece Name", piece.name]]
That's great, now I can just loop over it to create my CSV rows... However, it will blow up based on where I need to define it as my "piece" is undefined. So then, I thought... what if I just wrap the second arguments in quotes and call eval on them later on when I need them? Then I looked it up, and people seem to say to use eval only to save lives...
Can anyone think of a simpler way to keep all of my data paired with column names, but maybe not use eval? Or maybe suggest that this would be a good use case for eval?
You can usually avoid eval by using blocks instead. For example, re-define your structure in terms of method calls:
columns = [
[ "Client", lambda { |piece| piece.client.organization } ],
[ "Category", lambda { |piece| piece.client.category } ],
# ...
]
Then when iterating over your block, do something like this:
pieces.each do |piece|
spec.each do |label, proc|
value = proc.call(piece)
# ... Do whatever you need here
end
end
Defining blocks (Proc internally) can help define methods for doing things while deferring variable binding to some point in the future.
eval has a reputation for being dangerous because it can execute anything. It's best to avoid it unless there really is no other way.
I recently asked how to test in RSpec if a block was called and the answers to that question seem to work in a simple case. The problem is when the initialization with the block is more complex. Then it is done in before and reused by a number of different tests in the context, among them the one testing if the block was evaluated. See the example:
context "the node definition using block of code" do
before do
#n=node do
# this block should be called
end
# some more complex setup concerning #n
end
it "should call the block" do
# how to test it?
end
# here a bunch of other tests using #n
end
In this case the solution with side effect changing value of a local variable does not work. Raising an exception from the block is useless since the whole statement must be properly evaluated to be used by the other tests.
Obviously I could do the tests separately, but it seems to stink, since I must copy-paste the initialization part and since the was-the-block-called test inherently belongs to this very context.
How to test if the block was evaluated in such a case?
Explanation for question asked by #zetetic below.
The context is that I'm implementing a kind of DSL, with nodes defined by their parameters and blocks of code (that can define something else in the scope of node). Since the things defined by the node's block can be pretty generic, at least for the first attempt I just need to be sure the block is evaluated and that what a user provides there will be considered. For now does not matter what it is.
Probably I should refactor my tests now and using mocks make them test behaviors rather then implementation. However it will be a little bit tricky, for the sake of some mixins and dynamic handling of messages sent to objects. For now the cincept of such tests is a little bit fuzzy in my head ;-)
Anyway your answers and comments helped me to better understand how RSpec works and explained why what I'm trying to do looks as if it did not fit to the RSpec.
Try something like this (untested by me):
context "the node definition using block of code" do
let(:node){
node = Node.new "arg1", "arg2", node_block
# more complex stuff here
node
}
context "checking the block is called" do
let(:node_block) {
double = double("node_block")
double.should_receive("some kind of arg").and_return("something")
# this will now cause a fail if it isn't called
double
}
it "should call the block" do
node.blah()
end
end
let(:node_block) {
# some real code
}
subject { node.blah() }
it { should == 2 }
# ...
end
So that's a very shaky piece of code (you'll have to fill in the gaps as you didn't give very much to go on, and let is obviously a lambda too, which could mean you've got to play around with it a bit) that uses let and a double to check it's called, and avoids using before, which is really for side effects not setting up variables for use in the specs.
#zetetic makes a very insightful comment that you're not testing behaviour here. I'm not against using rspec for doing more unit test style stuff (guidelines are made to be broken), but you might ask how later tests will pass when using a real block of code if that block isn't being called? In a way, I'm not even sure you need to check the block is called, but only you know.
I just spent ages trying to figure out why my specs were passing in isolation, but when running the controller and lib tests together, some specs were mysteriously failing. The culprit was this:
In one spec:
describe SomeThing do
CONSTANT_VALUE = "a value"
# ... examples etc ...
end
And in another:
describe AnotherThing do
CONSTANT_VALUE = "a different value"
# ... the rest is history
end
The values I'd assigned to these constants was leaking between my specs and causing unexpected behaviour. Am I supposed to use a let block for defining constants etc? Or something else?
Yes, let is the answer here.
"Is 'eval' supposed to be nasty?" inspired this one:
Mostly everybody agrees that eval is bad, and in most cases there is more elegant/safer replacement.
So I wanted to ask: if eval is misused that often, is it really needed as a language feature? Is it doing more evil than good?
Personally, the only place I find it useful is to interpolate strings provided in config file.
Edit: The intention of this question is to get as many real-life cases as possible when eval is the only or the best solution. So please, don't go into "should a language limit a programmer's creativity" direction.
Edit2: And when I say eval, of course I refer to evaling string, not passing ruby block to instance_eval or class_eval.
The only case I know of (other than "I have this string and I want to execute it") is dynamically dealing with local and global variables. Ruby has methods to get the names of local and global variables, but it lacks methods to get or set their values based on these names. The only way to do AFAIK is with eval.
Any other use is almost certainly wrong. I'm no guru and can't state categorically that there are no others, but every other use case I've ever seen where somebody said "You need eval for this," I've found a solution that didn't.
Note that I'm talking about string eval here, by the way. Ruby also has instance_eval, which can take either a string or a block to execute in the context of the receiver. The block form of this method is fast, safe and very useful.
When is it justified? I'd say when there's no reasonable alternative. I was able to think of one use where I can't think of an alternative: irb, which, if you dig deep enough (to workspace.rb, around line 80 in my copy if you're interested) uses eval to execute your input:
def evaluate(context, statements, file = __FILE__, line = __LINE__)
eval(statements, #binding, file, line)
end
That seems pretty reasonable to me - a situation where you specifically don't know what code you're going to have to execute until the very moment that you're asked to do so. Something dynamic and interactive seems to fit the bill.
The reason eval is there is because when you need it, when you really need it, there are no substitutes. There's only so much you can do with creative method dispatching, after all, and at some point you need to execute arbitrary code.
Just because a language has a feature that might be dangerous doesn't mean it's inherently a bad thing. When a language presumes to know more than its user, that's when there's trouble.
I'd argue that when you find a programming language devoid of danger, you've found one that's not very useful.
When is eval justified? In pragmatic terms, when you say it is. If it's your program and you're the programmer, you set the parameters.
There is one very important use-case for eval() which cannot (AFAIK) be achieved using anything else, and that is to find the corresponding object reference for a binding.
Say you have been passed a block but (for some reason) you need access to object context of the binding, you would do the following:
obj = eval('self', block.binding)
It is also useful to define the following:
class Proc
def __context__
eval('self', self.binding)
end
end
IMO mostly for Domain Specific Languages.
"Evaluation Options in Ruby" is an article by Jay Fields about it on InfoQ.
eval is a tool, it is neither inherently good nor evil. It is justified whenever you are certain it is the right tool for what you are trying to accomplish.
A tool like eval is about evaluating code at runtime vs. "compile" time. Do you know what the code is when you launch Ruby? Then you probably don't need eval. Is your code generating code during runtime? then you probably need to eval it.
For example, the methods/functions needed in a recursive decent parser depend on the language being parsed. If your application builds such a parser on-the-fly, then it might make sense to use eval. You could write a generalized parser, but it might not be as elegant a solution.
"Programatically filling in a letrec in Scheme. Macros or eval?" is a question I posted about eval in Scheme, where its use is mostly unavoidable.
In general eval is a useful language feature when you want to run arbitrary code. This should be a rare thing but maybe you are making your own REPL or you want to expose the ruby run-time to the end user for some reason. It could happen and that is why the feature exists. If you are using it to work around some part of the language (e.g. global variables) then either the language is flawed or your understanding of the language is flawed. The solution is typically not to use eval but to either better understand the language or pick a different language.
It's worth noting that in ruby particulary instance_eval and class_eval have other uses.
You very likely use eval on a regular basis without even realizing it; it's how rubygems loads the contents of a Gemspec. Via rubygems/lib/specification.rb:
# Note: I've removed some lines from that listing to illustrate the core concept
def self.load(file)
code = File.read(file)
begin
_spec = eval code, binding, file # <-------- EVAL HAPPENS HERE
if Gem::Specification === _spec
return _spec
end
warn "[#{file}] isn't a Gem::Specification (#{_spec.class} instead)."
rescue SignalException, SystemExit
raise
rescue SyntaxError, Exception => e
warn "Invalid gemspec in [#{file}]: #{e}"
end
nil
end
Typically, a gem specification would look like this:
Gem::Specification.new do |s|
s.name = 'example'
s.version = '0.1.0'
s.licenses = ['MIT']
s.summary = "This is an example!"
s.description = "Much longer explanation of the example!"
s.authors = ["Ruby Coder"]
s.email = 'rubycoder#example.com'
s.files = ["lib/example.rb"]
s.homepage = 'https://rubygems.org/gems/example'
s.metadata = { "source_code_uri" => "https://github.com/example/example" }
end
Note that the gemspec file simply creates a new object but does not assign it nor send it anywhere.
Trying to load or require this file (or even executing it with Ruby) will not return the Gem::Specification value. eval is the only way to extract the value defined by an external ruby file.
One use of eval is compiling another language to ruby:
ruby_code = "(def foo (f a b) (mapv f (cons a b)))".compile_to_ruby
# "foo_proc = ->(f a b) { mapv_proc.call(f, (cons_proc.call(a, b)) }"
eval ruby_code
I use a 3D modeling software that implemented Ruby for writing custom text macros. In that software we are given access to model data in the form of name:value pairs accessed using the following format:
owner.name
#=> value
So for a 36 inch tall cabinet, I could access the height and convert its value to feet like so:
owner.height.to_f / 12
The main problem is that objects in that software have no unique identifiers aside from something called their schedule_number. If I want to name a variable using the schedule_number in the variable name so that I can call and use that value elsewhere, the only possible way I know to do that is by using eval:
eval "#{owner.schedule_number} = owner.height"