How to Cancel Evaluating a Required Ruby File? (A.K.A. Top-Level Return)

How to cancel evaluating a required Ruby file? (a.k.a. top-level return)

UPDATE:

A "top-level return" feature has been added.

ORIGINAL:

Commenter matt pointed out that Feature 4840, which would do exactly what I'm asking about, has been in discussion since June 2011. Further, the feature was still being discussed as late as November 2015 in core team meetings regarding new Ruby features.

There are a lot of difficulties involved in designing a feature like this; for a list of the pros and cons, I highly suggest checking out the discussions.

The proposed feature would allow exiting the required file while using any of the the following top-level statements:

if condition
return
end

while condition
# ...
return
end

begin
# ...
return
rescue
# ...
return
ensure
# ...
return
end

And it would not exit the required file in the following statements:

class Foo
return # LocalJumpError
end

def foo
return # returns from method, not from required file
end

proc do
return # LocalJumpError
end

x = -> { return } # returns as from lambda, not from required file

Since the feature remains unimplemented, I have awarded the bounty to steenslag for successfully solving the problem (as originally written) to the letter, if not the spirit.

How to skip require in ruby?

i have rescued LoadError but i want that if LoadError is executed., further code should not be executed. In the example given, the rake task db:import_to_heroku should not be called

Then do:

begin
require 'aws-sdk'

namespace :db do
desc "import local postgres database to heroku. user and database name is hardcoded"
task :import_to_heroku => [:environment, "db:dump_for_heroku"] do
# code using aws-sdk gem
end
end
rescue LoadError
puts "aws-sdk gem not found"
end

Can I conditionally skip loading further ruby code in the same file?

I haven't checked the source, but I suppose that, when you run ruby my_file.rb at the console, or require/load it from Ruby code, the file is read entirely into memory before being evaluated. I'm afraid there is no such thing as skipping a part of a file.

I had an idea with catch/throw.

requiring file (for example a Rake task ?) treq1.rb :

catch :aws_sdk do
require_relative 'original'
end

puts '... continued'

The original file that you don't want to modify, original.rb :

puts 'in original, not to be modified'
begin
require 'aws-sdk'
rescue LoadError
puts "aws-sdk gem not found"
throw :aws_sdk
end

puts ">>> to execute only if 'aws-sdk' is found"

# namespace :db do ... etc
#end

Execution :

$ ruby -w treq1.rb 
in original, not to be modified
aws-sdk gem not found
treq1.rb:2:in `require_relative': method `backtrace' called on unexpected T_NODE object (0x007fd32b88e900 flags=0x381c klass=0x0) (NotImplementedError)
from treq1.rb:2:in `block in <main>'
from treq1.rb:1:in `catch'
from treq1.rb:1:in `<main>'

Googling with the error : http://www.ruby-forum.com/topic/4406870

Recent post, no answer. It works in a single file, if you want to wrap your code.

Let's try another solution. Supposing that you can change the Rake task, treq2.rb :

begin
require_relative 'original'
rescue LocalJumpError
puts 'rescued LocalJumpError'
end

puts '... continued'

In original.rb, replace throw :aws_sdk by return :

$ ruby -w treq2.rb 
in original, not to be modified
aws-sdk gem not found
rescued LocalJumpError
... continued

This way it works.

HTH

Does ruby stop evaluating if statements when first condition is false?

Ruby, and most other programming languages use short circuiting boolean expressions. Meaning any expression of the form false && puts("hi") will not run the right side of the expression puts("hi"). This goes for if conditions as well, anything with && really.

This is specially important to know because you always want to put faster or cheaper expressions/functions on the left side and more expensive expressions on the right side of a && operator.

Consider this

puts "hi" if expensive_method() && some_value

In the above example expensive_method will always run. But what if some_value is sometimes false? This would be more efficient:

puts "hi" if some_value && expensive_method()

Taking advantage of the possibility that some_value might sometimes be false, we spare ourselves from having to evaluate expensive_method in those cases.

In short, take advantage of boolean expression short circuiting.

https://en.wikipedia.org/wiki/Short-circuit_evaluation

How to Evaluate code of another ruby file?

You can use Kernel#eval in order to achieve what you want.

but in code1.rb you will need to remove puts, or place it before, as puts returns nil.

So use this changes

code1.rb

a = 10
b = 15
c = a+b
puts "c = #{c}"
c

code2.rb

code1 = File.open('code1.rb', 'r').read
c = eval(code1)

a = 10
e = c*5+a
puts "e = #{e}"

c = eval(code1) This magic line will use return value of your code1.rb file and then we can use it in code2.rb

Or another alternative you can allow your local variables to be overwritten by eval method, but in that case you need to define them in your code2.rb. Consider this

code2.rb

a,b,c = [0, 0, 0]

code1 = File.open('code1.rb', 'r').read
eval(code1)

a = 10
e = c*5+a
puts "e = #{e}"

That works due to local variables scope and evaluation. Both variants are working solutions

Does the || operator evaluate the second argument even if the first argument is true?

This happens because the ruby interpreter defines a variable when it sees an assignment to it (but before it executes the actual line of code). You can read more about it in this answer.

Boolean OR (||) expression will evaluate to the value of left hand expression if it is not nil and not false, else || will evaluate to the value of right hand expression.

In your example the ruby interpreter sees an assignment to a and rr (but it doesn't execute this line yet), and initializes (defines, creates) a and rr with nil. Then it executes the || expression. In this || expression, a is assigned to 10 and 10 is returned. r=20 is not evaluated, and rr is not changed (it is still nil). This is why in the next line rr is nil.

FILE__ returns different value when using binding.pry

Use _file_ instead of __FILE__. For example, given two files:

# foo.rb
require 'pry'
require './bar'
binding.pry
b = Bar.new

and:

# bar.rb
require 'pry'
class Bar
def initialize
binding.pry
end
end

Run them with ruby foo.rb:

ruby foo.rb

From: /Users/username/foo.rb @ line 3 :

1: require 'pry'
2: require './bar'
=> 3: binding.pry
4: b = Bar.new

(main):1 ⇒ _file_
=> "/Users/username/foo.rb"
(main):2 ⇒ exit

From: /Users/username/bar.rb @ line 4 Bar#initialize:

3: def initialize
=> 4: binding.pry
5: end

(#<Bar:0x00007fbb6caaff08>):1 ⇒ _file_
=> "/Users/username/bar.rb"

_file_ and any other local variable names can be found in binding.local_variables.

How to stop the Rails debugger for the current request

Just put conditions on the debugger statement so that it stops only when you want it to, e.g.:

debugger if animal == 'tiger'

or if, say, you want to examine the code only on loop 384:

animals.each_with_index do |animal, i|
debugger if i == 384
# do something
end

or put in a variable that will let you continue ad hoc:

continue_debugger = false
animals.each do |animal|
debugger unless continue_debugger
# in the debugger type `p continue_debugger = true` then `c` when done
end


Related Topics



Leave a reply



Submit