Mimic File.open pattern

Hello all,

open is singleton method of File and can be used in two ways

1 way

f = File.open(“data”)
f.readline until f.lineno == 10
puts f.readline
f.close

2 way

File.open(“data”) do |f|
f.readline until f.lineno == 10
puts f.readline
end

I am trying to mimic this with my own classes

irb(main):001:0> class Resource
irb(main):002:1> @@cnt=0
irb(main):003:1> def initialize
irb(main):004:2> @id = @@cnt
irb(main):005:2> @@cnt += 1
irb(main):006:2> end
irb(main):007:1> def id;@id;end
irb(main):008:1> end
=> nil
irb(main):009:0> class Q
irb(main):010:1> def Q.get &block
irb(main):011:2> r = Resource.new
irb(main):012:2> if Kernel::block_given?
irb(main):013:3> block.call®
irb(main):014:3> else
irb(main):015:3* return r
irb(main):016:3> end
irb(main):017:2> end
irb(main):018:1> end
=> nil
irb(main):019:0> Q.get
=> #<Resource:0x40206fe0 @id=0>
irb(main):020:0> Q.get {|r| puts r.id}
1
=> nil
irb(main):021:0>

I am interested in further suggestions
is my implementation close to that of File.open?

Regards, Daniel

Schüle Daniel wrote:

2 way

irb(main):004:2> @id = @@cnt
irb(main):014:3> else
irb(main):021:0>

I am interested in further suggestions
is my implementation close to that of File.open?

You’re missing the cleanup part when called with a block. The crucial
bit is that the block form allows proper cleanup under all circumstances
by using begin - ensure.

Kind regards

robert

Schüle Daniel wrote:

2 way

irb(main):004:2> @id = @@cnt
irb(main):014:3> else
irb(main):021:0>
First off, you can make it more efficient if your use `yield’ instead of
calling the block explicitly:

class Q
def self.get
if block_given?
yield Resource.new
else
Resource.new
end
end
end

The above is what I’d go with, but there a lots of ways to accomplish
what you want. Take this for example:

class Q
def self.get
yield resource = Resource.new
rescue LocalJumpError
resource
end
end

or even shorter (though it’ll catch other exceptions as well, so you
have to be careful)

class Q
def self.get
yield(resource = Resource.new) rescue resource
end
end

Cheers,
Daniel

Daniel S. wrote:

irb(main):003:1> def initialize
irb(main):013:3> block.call®
=> nil
Resource.new
rescue LocalJumpError
end
end

Cheers,
Daniel

There’s no need to golf this. There’s a well-known idiom for coding
block-scoped resources. See the section entitled “Destroy this object
when it goes out of scope” at
http://wiki.rubygarden.org/Ruby/page/show/RubyIdioms. Here’s the example
from that page:

def Resource.open( identifier ) # :yield: resource
resource = Resource.new( identifier )
if block_given?
begin
yield resource
ensure
resource.close
end
else
return resource
end
end

The benefit of using the standard idiom is that any Ruby programmer that
reads your code will instantly understand what it’s doing. Coding it any
other way will likely cause a bit of confusion. And, of course, if you
don’t use the idiom you might forget the “ensure” part.

Timothy H. wrote:

f.close
irb(main):002:1> @@cnt=0
irb(main):012:2> if Kernel::block_given?
1
else
yield resource = Resource.new
yield(resource = Resource.new) rescue resource
http://wiki.rubygarden.org/Ruby/page/show/RubyIdioms. Here’s the example
else
return resource
end
end

The benefit of using the standard idiom is that any Ruby programmer that
reads your code will instantly understand what it’s doing. Coding it any
other way will likely cause a bit of confusion. And, of course, if you
don’t use the idiom you might forget the “ensure” part.

I don’t think the original post mentioned that the resource needed to be
closed :slight_smile: I thought he wanted an easy way to either yield or return. But
yes, for that wider problem, your code is superior. We were just
answering different questions.

Cheers,
Daniel

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs