[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

mimic File.open pattern

Daniel Schüle

7/30/2006 1:15:00 PM

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(r)
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
5 Answers

Daniel Schierbeck

7/30/2006 2:12:00 PM

0

Schüle Daniel wrote:
> 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(r)
> 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>

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

Robert Klemme

7/30/2006 2:14:00 PM

0

Schüle Daniel wrote:
> 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(r)
> 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?

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

Tim Hunter

7/30/2006 8:19:00 PM

0

Daniel Schierbeck wrote:
> Schüle Daniel wrote:
>> 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(r)
>> 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>
>
> 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
>
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/.... 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.


Daniel Schierbeck

7/30/2006 9:04:00 PM

0

Timothy Hunter wrote:
> Daniel Schierbeck wrote:
>> Schüle Daniel wrote:
>>> 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(r)
>>> 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>
>>
>> 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
>>
> 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/.... 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.

I don't think the original post mentioned that the resource needed to be
closed :) 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

Daniel Schüle

7/30/2006 10:53:00 PM

0


thanks, I will adapt the pattern