Loading a faulty ruby file - forcing this

Hi.

Consider you have two ruby files.

file1.rb:

require ‘pp’
RUBY_FILE = ‘./file2.rb’

begin
load RUBY_FILE
rescue NameError => error

pp error # Do not report the error here. Be silent.

end

Now we call the two methods defined in file2.rb

foo()
bar()

file2.rb:

def foo
puts ‘This is from foo()’
end

Create an error on purpose here.

joe_doe()

def bar # The second method.
puts ‘This is from bar()’
end

Note - I use the parens () at bar() to make it more
explicit and illustrate my question.

If you run file1.rb, an error occurs:

undefined method `bar’ for main:Object (NoMethodError)

The method call to foo() works.

If you look at the content of file2.rb, you can see that
the method definition first has foo(), then a method
call to a method that does not exist (on purpose), and
then the method definition to bar()

Ruby apparently stops processing file2.rb when it
encounters a NameError exception.

My question is:

  • Is there a way to force or otherwise cause Ruby to continue
    reading the second file? I am in control of the ruby files so
    I can use eval without a problem.

What I would like to achieve is to let ruby read a file
and treat it as a ruby file, but if it encounters errors,
it would disregard these errors, and continue processing
that file.

In a way, I’d need a faulty ruby loader that ignores errors
when instructed (instructed by me, that is).

Right now, in the code above, I can not achieve this, as
ruby stops the very moment it encounters an invalid method
call. How could I continue to process that faulty file?

2011/11/29 Marc H. [email protected]:

load RUBY_FILE

end
The method call to foo() works.

when instructed.

Right now, in the code above, I can not achieve this, as
ruby stops the very moment it encounters an invalid method
call. How could I continue to process that faulty file?

You could hook into Object#method_missing and
Object.const_missing to handle NameErrors before
they happen, although I’d try to redesign my code
in any possible way before resorting to such methods.

On Tue, Nov 29, 2011 at 11:38 AM, Marc H. [email protected]
wrote:

load RUBY_FILE

end
The method call to foo() works.

If you look at the content of file2.rb, you can see that
the method definition first has foo(), then a method
call to a method that does not exist (on purpose), and
then the method definition to bar()

Ruby apparently stops processing file2.rb when it
encounters a NameError exception.

Of course. An exception always immediately stops execution at the
point where it is thrown and unwinds the stack until it finds a
handler (or the process terminates).

My question is:

  • Is there a way to force or otherwise cause Ruby to continue
    reading the second file? I am in control of the ruby files so
    I can use eval without a problem.

Basically you could wrap every individual section with “begin rescue
end”. Then such a section would be the smallest part which could
fail. Alternatively you could split the file in multiple parts and
have a specific implementation of “load” which ignores errors:

def load_ignorant(s)
load(s)
rescue Exception
# eat it
end

call. How could I continue to process that faulty file?
Why do you want to do that? That sounds like a bad plan to me since
you won’t notice any issues and your application’s state is unclear.

Kind regards

robert

unsubscribe


From: Robert K. [email protected]
To: ruby-talk ML [email protected]
Sent: Tuesday, November 29, 2011 8:56 AM
Subject: Re: Loading a faulty ruby file - forcing this

On Tue, Nov 29, 2011 at 11:38 AM, Marc H. [email protected]
wrote:

load RUBY_FILE

end
The method call to foo() works.

If you look at the content of file2.rb, you can see that
the method definition first has foo(), then a method
call to a method that does not exist (on purpose), and
then the method definition to bar()

Ruby apparently stops processing file2.rb when it
encounters a NameError exception.

Of course. An exception always immediately stops execution at the
point where it is thrown and unwinds the stack until it finds a
handler (or the process terminates).

My question is:

  • Is there a way to force or otherwise cause Ruby to continue
    reading the second file? I am in control of the ruby files so
    I can use eval without a problem.

Basically you could wrap every individual section with “begin rescue
end”. Then such a section would be the smallest part which could
fail. Alternatively you could split the file in multiple parts and
have a specific implementation of “load” which ignores errors:

def load_ignorant(s)
load(s)
rescue Exception

eat it

end

call. How could I continue to process that faulty file?
Why do you want to do that? That sounds like a bad plan to me since
you won’t notice any issues and your application’s state is unclear.

Kind regards

robert

IMO the “proper” way to do this would be to use ruby_parser and
ruby2ruby. (These are both gems, look them up.)

You would first parse the Ruby code, then somehow split it into
individual runnable chunks, convert each back into Ruby code with
ruby2ruby and eval every single one.

Of course, this will only work if at least the syntax of the file in
question is correct.

– Matma R.

You could hook into Object#method_missing and
Object.const_missing to handle NameErrors before
they happen, although I’d try to redesign my code
in any possible way before resorting to such methods.

Hmmm. My approach would only work easily if I’d
be able to continue loading the whole ruby file
in question. I am not sure I understood this solution
well though - I have to handle NameErrors before
they happen?

An exception always immediately stops execution at the
point where it is thrown and unwinds the stack until it
finds a handler (or the process terminates).

Oh I see! Would be neat to be able to suppress that
when one wants to, with the rest of the code continued
to be read and interpreted.

Basically you could wrap every individual section with
“begin rescue end”. Then such a section would be the
smallest part which could fail. Alternatively you could
split the file in multiple parts and have a specific
implementation of “load” which ignores errors:

def load_ignorant(s)
load(s)
rescue Exception

eat it

end

Hmm you mean wrap the file into different smaller files
and load these? Probably feasible. I’d however like to
keep a constraint as in having a large ruby file available
already. It also sounds like too much work to split the
file in question up.

Why do you want to do that? That sounds like a bad plan
to me since you won’t notice any issues and your
application’s state is unclear.

The demo code in question just shows that the ruby file
only has invalid calls to non-existent methods. But
otherwise, it is fine. I would argue that by definition
there can not be any issues with it (from that faulty
ruby file) because after all it is faulty anyway and
there are only two states for it - either it contains
valid ruby code or it is invalid (in which case it should
be ignored).

Consider it a crazy wish for purposely sloppy programming
where perfection can stop at 40% rather than go for the
usual 100%.

As for the reason why I want to do that - I want to run
invalid code which could become partially valid, rather
than stopped when encountering an Exception.

Consider it as something that will never find its way
into any program.

If it is too cumbersome to achieve though then this idea
already falls short.

On Nov 29, 2011, at 08:45 , Marc H. wrote:

My approach would only work easily if I’d
be able to continue loading the whole ruby file
in question.

Your approach TO WHAT?

I once made a feature request for a resume method that could be used
in a
rescue clause to continue execution after the line of error. I think at
the
time I wanted to use if for some type of hook system. Not sure as it was
so
long ago.

Matz rejected the idea though. Maybe you can offer him a better use
case.

On Tue, Nov 29, 2011 at 5:45 PM, Marc H. [email protected]
wrote:

An exception always immediately stops execution at the
point where it is thrown and unwinds the stack until it
finds a handler (or the process terminates).

Oh I see! Would be neat to be able to suppress that
when one wants to, with the rest of the code continued
to be read and interpreted.

You cannot do that because exception throwing code is written with the
knowledge that execution does not continue after the exception. In
other words if the exception does not throw it is ensured code is in
proper state. By suppressing exceptions code cannot rely on proper
state and might want to throw another exception later.

end

where perfection can stop at 40% rather than go for the
usual 100%.

As for the reason why I want to do that - I want to run
invalid code which could become partially valid, rather
than stopped when encountering an Exception.

Why?

Consider it as something that will never find its way
into any program.

If it exists, it will. :slight_smile:

If it is too cumbersome to achieve though then this idea
already falls short.

I do not think this is a good idea. There was an article of a famous
author (might have been von Neumann) who said that the difference
between machines and natural systems is that we build machines so
errors show up as quickly as possible whereas nature tries to reduce
errors so systems can continue to work.

The semantic of a half valid piece of code is unknown. Hence you
cannot rely on it doing what you intended it to do.

Kind regards

robert

Da: Intransition [mailto:[email protected]]
Inviato: venerd 2 dicembre 2011 03:41
A: ruby-talk ML; [email protected]
Cc: ruby-talk ML; [email protected]
Oggetto: Re: Loading a faulty ruby file - forcing this

I once made a feature request for a resume method that could be used
in a
rescue clause to continue execution after the line of error. I think at
the
time I wanted to use if for some type of hook system. Not sure as it was
so
long ago.

Matz rejected the idea though. Maybe you can offer him a better use
case.

Caselle da 1GB, trasmetti allegati fino a 3GB e in piu’ IMAP, POP3 e
SMTP autenticato? GRATIS solo con Email.it http://www.email.it/f

Sponsor:

Conto Arancio al 4,20%. Zero spese e massima liberta’, aprilo in due
minuti!

Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid=11922&d=29-12