I need to validate that a given string is valid Ruby syntax, programmatically, using Ruby. I imagine one way I can do this is by running the code in an EVAL statement, and detecting syntax errors that way.
What's a more proper, safer way I can accomplish this?
Let the code string be code. The standard way is to do something like this:
begin
RubyVM::InstructionSequence.compile(code)
nil
rescue Exception => e
... # Put code here to return `e` itself, print its message, or whatever you like
end
If an error is raised and is rescued, that error will display the syntax error. If not (and nil is returned), then code is syntactically valid Ruby code (which does not guarantee that it is free of other types of errors).
The comments saying it is dangerous to do, etc, does not seem to make sense.
I'd consider checking this in the browser with Opal - https://github.com/opal/opal
i manage to do "something"(like deleting files,etc) when exit or exit! is called from Object.
by changing the method exit and exit! inside Object class. (at_exit is too unreliable)
but then the "something" never execute if there's error such as NameError, etc.
is there way so i can make "something" that still execute if there's error.
(any error possible if necessary).
something like at_exit but works with all errors
thanks in advance for assistance. and forgive me if there's already question ask for this.
i do search a lot before asking here. and found nothing.
edit: i don't know where the original author of the code place the method. since the original author load it from dll files in the exe program the author used for launcher. (i can only edit After the original code take place...). so i think i need another approach for this... but i manage to make a workaround for my problem... by putting begin rescue in other places that send data to the original object. i filter the data send and throw my own error before it reach the main program... so i guess this works too.
Borrowing from an answer on a different thread, and definitely along the lines of what Marek commented, this is how you should handle errors in Ruby:
begin
# something which might raise an exception
rescue SomeExceptionClass => some_variable
# code that deals with some exception
rescue SomeOtherException => some_other_variable
# code that deals with some other exception
else
# code that runs only if *no* exception was raised
ensure
# ensure that this code always runs, no matter what
end
Original credit: Begin, Rescue and Ensure in Ruby?
I had a test that did this:
expect(#parser.parse('adsadasdas')).to raise_error(Errno::ENOENT)
and it didn't work. I changed to:
expect { #parser.parse('adsadasdas') }.to raise_error(Errno::ENOENT)
And it worked.
When do we use curly braces and when do we use parentheses with expect?
In response to OP's comment, I've edited and completely rewritten my answer. I realize that my original answer was oversimplified, so much so that it could be considered incorrect.
Your question was actually addressed somewhat by this other StackOverflow question.
One poster, Peter Alfvin, makes a good point when he says:
As for rules, you pass a block or a Proc if you're trying to test
behavior (e.g. raising errors, changing some value). Otherwise, you
pass a "conventional" argument, in which case the value of that
argument is what is tested.
The reason you're encountering the phenomenon you're seeing has to do with the raising of errors. When you pass #parser.parse('adsadasdas') as an argument (use parentheses) to expect, you are essentially telling ruby:
Evaluate #parser.parse('adsadasdas') first.
Take the result and pass this to expect.
expect should see if this result matches my expectation (that is, that Errno:ENOENT will be raised).
But, what happens is: when ruby evaluates #parser.parse('adsadasdas'), an error is raised right then and there. Ruby doesn't even get a chance to pass the result on to expect. (For all we care, you could have passed #parser.parse('adsadasdas') as an argument to any function... like multiply() or capitalize()) The error is raised, and expect never even gets a chance to do its work.
But when you pass #parser.parse('adsadasdas') as a proc (a code block) to expect using curly braces, what you are telling ruby is this:
expect, get ready to do some work.
expect, I would like you to keep track of what happens as we evaluate #parser.parse('adsadasdas').
Ok, expect, did the code block that was just evaluated raise a Errno:ENOENT error? I was expecting that it would.
When you pass a code block to expect, you are telling expect that you want it to examine the resulting behavior, the changes, made by your code block's execution, and then to let you know if it meets up to the expectations that you provide it.
When you pass an argument to expect, you are telling ruby to evaluate that argument to come to some value before expect even gets involved, and then you are passing that value to expect to see if it meets up to some expectation.
TL;DR: use expect(exp) to specify something about the value of exp and use expect { exp } to specify a side effect that occurs when exp is executed.
Let's unpack this a bit. Most of RSpec's matchers are value matchers. They match (or not) against any ruby object. In contrast, a handful of RSpec's matchers can only be matched against a block, because they have to observe the block while it's running in order to operate properly. These matchers concern side effects that take place (or not) while the block executes. The matcher would have no way to tell if the named side effect had occurred unless it is passed a block to execute. Let's consider the built-in block matchers (as of RSpec 3.1) one-by-one:
raise_error
Consider that one can return an exception from a method, and that is different than raising the exception. Raising an exception is a side effect, and can only be observed by the matcher by it executing the block with an appropriate rescue clause. Thus, this matcher must receive a block to work properly.
throw_symbol
Throwing symbols is similar to raising errors -- it causes a stack jump and is a side effect that can only be observed by running a block inside an appropriate catch block.
change
Mutation to state is a side effect. The matcher can only tell if there was a change to some state by checking the state before hand, running the block, then checking the state after.
output
I/O is a side effect. For the output matcher to work, it has to replace the appropriate stream ($stdout or $stderr) with a new StringIO, execute the block, restore the stream to its original value, and then check the contents of theStringIO`.
yield_control/yield_with_args/yield_with_no_args/yield_with_successive_args
These matchers are a bit different. Yielding isn't really a side effect (it's really just syntactic sugar for calling another function provided by the caller), but yielding can't be observed by looking at the return value of the expression. For the yield matchers to work, they provide a probe object that you pass on to the method-under-test as a block using the &probe syntax:
expect { |probe| [1, 2, 3].each(&probe) }.to yield_with_successive_args(1, 2, 3)
What do all these matchers have in common? None of them can work on simple ruby values. Instead, they all have to wrap a block in an appropriate context (i.e. rescuing, catching or checking before/after values).
Note that in RSpec 3, we added some logic to provide users clear errors when they use the wrong expect form with a given matcher. However, in the specific case of expect(do_something).to raise_error, there's nothing we can do to provide you a clear explanation there -- if do_something raises an error (as you expect it to...), then the error is raised before ruby evaluates the to argument (the raise_error matcher) so RSpec has no way to check with the matcher to see if supports value or block expectations.
in short:
use curly-brace (a block): when you want to test the behavior
use parenthesis when you want to test the returned value
worth reading: As for rules, you pass a block or a Proc if you're trying to test behavior (e.g. raising errors, changing some value). Otherwise, you pass a "conventional" argument, in which case the value of that argument is what is tested. - from this answer
In the test written with parentheses, the code is executed normally, including all normal error handling. The curly-brace syntax defines a block object upon which you can place the expectation. It encapsulates the code you expect to be broken and allows rspec to catch the error and provide its own handling (in this case, a successful test).
You can think of it this way as well: with the parentheses, the code is executed before being passed to the expect method, but with the block, expect will run the code itself.
I'm trying to write code like this:
assert_throws(:ExtractionFailed) { unit.extract_from('5 x 2005')}
ExtractionFailed is a trivial subclass of Exception, and under test/unit, I'm trying to assert that it is thrown when I call unit.extract_from(... bad data...)
I've moved ExtractionFailed into the SemanticText module, so now test/unit says:
<:ExtractionFailed> expected to be thrown but
<:"SemanticText::ExtractionFailed"> was thrown.
I tried writing assert_throws(:SemanticText::ExtractionFailed) {...} but I got the rather confusing message: TypeError: SemanticText is not a class/module
I can make it work by doing the following (although it seems like a hack):
assert_throws(SemanticText::ExtractionFailed.to_s.to_sym) { unit.extract_from('5 x 2005')}
So what's the right way to say this assertion in ruby?
Put quotes around the symbol name after the colon e.g.
assert_throws(:"SemanticText::ExtractionFailed") { unit.extract_from('5 x 2005')}
The quotes are necessary for a symbol that contains colons or other special characters.
If you try :"SemanticText::ExtractionFailed".class in irb you will see that it is a Symbol, removing the need to use to_s and/or to_sym.
I try to use rescue, but the error that i get is unclear,
and is same error in different cases (e.g in illegal port and already used port.)
require 'socket'
begin
server = TCPServer.open(33)
rescue => ex
puts "An error of type #{ex.class} happened, message is #{ex.message}"
end
and I get
=> An error of type TypeError happened, message is no implicit conversion of nil into String
The printed message is correct as "no implicit conversion of nil into String" is a type error.
Though the reason behind this error being raised could be this bug: https://bugs.ruby-lang.org/issues/10203
As far as I can tell, in the first 2 attempts it would work without any errors opening the socket port, and binding it to the IPv4 / IPv6 address automatically. In the third attempt, it trips and expects an explicit IP to be provided as the first param (like TCPServer.open(<string_IP>, <int_port>)). This is probably where it fails for you as it doesn't find an IP string, and raises a TypeError.
Though this error is essentially in ruby v2.1.x, so later / prior versions don't seem to have this problem (or at least I couldn't repro it locally except for this version)