Robert Klemme
5/29/2008 8:29:00 PM
On 29.05.2008 19:04, Rick DeNatale wrote:
> On Thu, May 29, 2008 at 11:30 AM, Jacob Rubynovice <l33tb0y@gmail.com> wrote:
>> Dear Rubyists,
>>
>> I am a novice Ruby developer who is interested in figuring out a way to
>> design something like what is demonstrated below. The reason why
>> each_line would not work in this example is because when you pass a
>> block of code to the FileReader object, the memory (members of
>> FileReader) is not shared with the block of code that is sent to
>> FileReader.
>>
>> Maybe I have the wrong idea for how this would be designed. I just
>> think it would be very convenient to do this sort of thing because I
>> could re-use the code to open a file and read lines and only pass it
>> code blocks pertainant to what I want to do with those lines of code.
>>
>> Please note that I do not only want to do this for an open file/read
>> line script. It would also be useful if you were expanding an IP range
>> that exceeds what you could store into an array object because you could
>> write an each_host method that takes in a block of code that relates to
>> what you want to do to each host.
>>
>> class FileReader
>>
>> def initialize(fname, &block)
>> @filename = fname
>> end
>> def each_line(&block)
>> begin
>> source = File.new(@filename, "r")
>> rescue => err
>> exit
>> end
>> begin
>> while(line = source.readline)
>>
>> line.strip!
>> if((line == "") || (line =~ /[\t+\s+]/))
>> next
>> end
>> block.call
>> end
>> rescue EOFError
>> source.close
>> rescue => err
>> puts "[!] #{err}"
>> exit
>> end
>> end
>
>
> This can be made much shorter using Ruby conventions:
>
> class FileReader
>
> def initialize(fname, &block)
> @filename = fname
> end
>
> def each_line
> source = File.open(@filename, "r") do |f| # this will
> automatically close the file
> f.each do | line | # This avoids having to check for
> end-of-file explicitly.
> line.strip!
> yield line unless ((line == "") || (line =~ /[\t+\s+]/))
> end
> end
> rescue => err # Note that a method definition itself acts like begin/end
> puts "[!] #{err}"
> exit
> end
> end
>
> The two inner lines:
> line.strip!
> yield line unless ((line == "") || (line =~ /[\t+\s+]/))
>
> could be combined as:
>
> yield line unless ((line.strip! == "") || (line =~ /[\t+\s+]/))
>
> But I think that the two line form might be a little clearer.
>
> I'm not sure just what you expect the regex to be doing, as you've
> coded it it's going to skip any line which
> has at least one tab followed immediately by at least one whitespace
> character regardless of anything else in the line.
No, the complete expression will skip empty lines as well we lines that
contain either a tab, a space (which includes tab IIRC) or a plus sign.
irb(main):004:0> /[\t+\s+]/ =~ " "
=> 0
irb(main):005:0> /[\t+\s+]/ =~ "+"
=> 0
irb(main):007:0> /\s/ =~ "\t"
=> 0
Even shorter
File.foreach file do |line|
next if /^\s*$/ =~ line
line.chomp!
# whatever
end
You can even stick this into a method, e.g.
def File.each_non_empty file
foreach file do |line|
next if /^\s*$/ =~ line
line.strip!
yield line
end
end
Note that the regular expression that was posted originally is most
likely wrong.
Kind regards
robert