How can a code block access an object's variables?

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

end
my_reader = FileReader.new(ARGV[0])
my_reader.each_line { puts line
    # do more parsing stuff here
}

···

--
Posted via http://www.ruby-forum.com/.

You can pass arguments to block.call which can then be accessed by the block.

  block.call(line)

And then when when calling your method, use

    my_reader.each_line do |myline|
      # myline holds the value of "line"
      puts myline
    end

There's a decent introduction to blocks in the Pickaxe book. (http://whytheluckystiff.net/ruby/pickaxe/html/tut_containers.html\)

Jacob Rubynovice 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

end
my_reader = FileReader.new(ARGV[0])
my_reader.each_line { puts line
    # do more parsing stuff here
}

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.

···

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

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

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

···

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.

Robert Klemme wrote:

Maybe I have the wrong idea for how this would be designed. I just
class FileReader
    begin
    rescue => err

  def initialize(fname, &block)
      end

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

You are correct. I was wrong with that regular expression. I was
trying to make a regular expression that ignores lines that only contain
white space- tabs, spaces, newlines (although newlines/returns are
automatically removed with the strip method).

Additionally, I just want to thank all of you for your suggestions.
They have been tremendously helpful. I think that the code block
feature of Ruby can be used to save tons of re-coding that would
otherwise need to be done in most of the modern conventional programming
languages.

···

On 29.05.2008 19:04, Rick DeNatale wrote:

--
Posted via http://www.ruby-forum.com/\.

Right you are, for some reason I failed to see the square brackets.
Maybe I DO need new glasses. <G>

···

On Thu, May 29, 2008 at 4:29 PM, Robert Klemme <shortcutter@googlemail.com> wrote:

On 29.05.2008 19:04, Rick DeNatale wrote:

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.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/