Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

equivalent of Python's "with" in Ruby

In Python, the with statement is used to make sure that clean-up code always gets called, regardless of exceptions being thrown or function calls returning. For example:

with open("temp.txt", "w") as f:
    f.write("hi")
    raise ValueError("spitespite")

Here, the file is closed, even though an exception was raised. A better explanation is here.

Is there an equivalent for this construct in Ruby? Or can you code one up, since Ruby has continuations?

like image 858
Claudiu Avatar asked Oct 06 '10 18:10

Claudiu


People also ask

Does Ruby use Python?

The Ruby on Rails web framework is built using the Ruby programming language while the Django web framework is built using the Python programming language. This is where many of the differences lay. The two languages are visually similar but are worlds apart in their approaches to solving problems.

How Does Ruby Compare to Python?

Python is generally better for educational use or for people who want to build quick programs rather than work as developers, while Ruby is better for commercial web applications. There are more specific differences when comparing Ruby versus Python, and they have in common that there are many ways to learn both.

Can Python replace Ruby?

Programmers working on machine learning must have proficiency fluency in Python as it is used to create most AI algorithms. On the other end, there is Ruby. While there is potential, Ruby must tweak its machine learning and AI libraries to do as well as Python in this field. Ruby won't replace Python anytime soon.

Which is faster Ruby or Python?

Python is faster than Ruby, but they're both in a category of interpreted languages. Your fastest language is always going to be one that's compiled down to byte code or object code right on the computer.


2 Answers

Ruby has syntactically lightweight support for literal anonymous procedures (called blocks in Ruby). Therefore, it doesn't need a new language feature for this.

So, what you normally do, is to write a method which takes a block of code, allocates the resource, executes the block of code in the context of that resource and then closes the resource.

Something like this:

def with(klass, *args)
  yield r = klass.open(*args)
ensure
  r.close
end

You could use it like this:

with File, 'temp.txt', 'w' do |f|
  f.write 'hi'
  raise 'spitespite'
end

However, this is a very procedural way to do this. Ruby is an object-oriented language, which means that the responsibility of properly executing a block of code in the context of a File should belong to the File class:

File.open 'temp.txt', 'w' do |f|
  f.write 'hi'
  raise 'spitespite'
end

This could be implemented something like this:

def File.open(*args)
  f = new(*args)
  return f unless block_given?
  yield f
ensure
  f.close if block_given?
end

This is a general pattern that is implemented by lots of classes in the Ruby core library, standard libraries and third-party libraries.


A more close correspondence to the generic Python context manager protocol would be:

def with(ctx)
  yield ctx.setup
ensure
  ctx.teardown
end

class File
  def setup; self end
  alias_method :teardown, :close
end

with File.open('temp.txt', 'w') do |f|
  f.write 'hi'
  raise 'spitespite'
end

Note that this is virtually indistinguishable from the Python example, but it didn't require the addition of new syntax to the language.

like image 196
Jörg W Mittag Avatar answered Sep 21 '22 02:09

Jörg W Mittag


The equivalent in Ruby would be to pass a block to the File.open method.

File.open(...) do |file|
  #do stuff with file
end  #file is closed

This is the idiom that Ruby uses and one that you should get comfortable with.

like image 23
Ed S. Avatar answered Sep 21 '22 02:09

Ed S.