Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Can I conditionally skip loading "further" ruby code in the same file,
if a library (loaded via require) is not found ?

begin
  require 'aws-sdk'
rescue LoadError
  puts "aws-sdk gem not found"
  return #does not work. nor does next
end

# code after here should not be executed as `aws-sdk` gem was not found
puts "=== should not get executed"

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

In the above code, can I ask Ruby not to load the file further after hitting a rescue LoadError.

Like an early return but for loading a file and not for a function.

Need it because i have i have a rake task which needs aws-sdk rubygem but i use it only on my local machine. If aws-sdk is not found it does not make sense for me to load code afterwards in the same file. I guess i can split the code into smaller files and warp it in a require call

if Rails.env.development?
  require 'import_to_heroku'
end

But do not want to warp or modify my existing code

Also, i can wrap the whole code in an conditional but that is inelegant. A begin-rescue block is also a form of explicit control flow. I do not want to wrap or touch the original code is any manner

Maybe an api such as

require_or_skip_further_loading 'aws-ruby`

So i want my code to be functionally equivalent to

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

Or via an if conditional

library_found = false
begin
  require 'aws-sdk'
  library_found = true
rescue LoadError
  puts "aws-sdk gem not found"
  return #does not work
end

if library_found      
  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
end

Want program execution to continue after LoadError is raised. ie. gracefully handle LoadError and do not load code written after LoadError in the same file. cannot raise exit or abort on LoadError And particularly the code after LoadError should not be executed (or loaded) by the ruby interpreter

Had originally asked How to skip require in ruby? but i did not ask the question properly. hope this is better worded

like image 479
deepak Avatar asked Oct 06 '22 05:10

deepak


1 Answers

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

like image 95
BernardK Avatar answered Oct 10 '22 01:10

BernardK