Why is my method not found? (NoMethodError)


#1

Hi,
I have written a small tcp scanner procedural and wanted to change it to
OOP but something went wrong. Until this line everything works fine:

        my_scanner.scanning(hosts,ports)

but here I always get:
test.rb:95: private method `scanning’ called for
#Scanner:0xb7c9c428 (NoMethodError)

but why? my_scanner is from the Scanner class which owns the method
scanning?!? Do I get something wrong?

here’s my code:

#!/usr/bin/ruby -w

require ‘socket’
require ‘timeout’

class Scanner

 def initialize
    @hosts,@ports = Array($*)
 end



 def portarrange
    case @ports
      when /^.+[..]/                                        # for

ranges (75…123)
@ports = @ports.split("…")
@ports = @ports[0].to_i…@ports[1].to_i
when /^.+[,]/ # for
multiple ports (34,345,213)
@ports = @ports.split(",")
else
@ports = Array(@ports) # for
one single port (21)
end
end

 def hostarrange
    case @hosts
      when /^.+[,]/                                        # for

multiple IP’s/hosts (81.95.1.40,64.111.124.251,www.cnn.com)
@hosts = @hosts.split(",")
else
@hosts = Array(@hosts) # for
one single port (81.95.1.40)
end
end

def output(state,port)
   printed = false
   portsfile = File.new("ports", "r")
   scanpat = "^.+ #{port}/tcp"
   portsfile.each_line do |line|
                if line =~ Regexp.new(scanpat)
                  puts "#{state}    : #{line}"
                  printed = true
                end
                puts "#{state}    : #{port}" if printed == false 

end
ensure
portsfile.close
end
end

def scanning(hosts,ports)
       hosts.each do |host|
        begin
          puts "scanning #{host}:"
          ports.each do |port|
            begin
                Timeout::timeout(10){TCPSocket.new(host, port)}    #

set timeout here
rescue Timeout::Error
output(“filtered”,port)
rescue
output(“closed”,port)
else
output(“open”,port)
end end
end
end
end

##################### code start #####################

puts “no arguments past,correct usage:\nruby #{$0} [hosts] [ports]\n” if
!ARGV[1]

my_scanner = Scanner.new

hosts = my_scanner.hostarrange
ports = my_scanner.portarrange
=begin
puts "debugging: "
puts hosts
puts ports

everything alright until here

=end
my_scanner.scanning(hosts,ports)

##################### eof #####################


greets

                        (
                        )
                     (
              /\  .-"""-.  /\
             //\\/  ,,,  \//\\
             |/\| ,;;;;;, |/\|
             //\\\;-"""-;///\\
            //  \/   .   \/  \\
           (| ,-_| \ | / |_-, |)
             //`__\.-.-./__`\\
            // /.-(() ())-.\ \\
           (\ |)   '---'   (| /)
            ` (|           |) `
      jgs     \)           (/

one must still have chaos in oneself to be able to give birth to a
dancing star


#2

Your problem is that there is way too much nesting within your
methods. You lost track of which “end” maps to which “do” and “begin”
in numerous places. As a general rule, if you’re nesting more than
two levels deep within a method, you just made your method a lot more
difficult to maintain. The below version fixes your nesting issues
(but does not correct them for maintainability).

require ‘socket’
require ‘timeout’

class Scanner

 def initialize
    @hosts,@ports = Array($*)
 end

 def portarrange
    case @ports
      when /^.+[..]/
         @ports = @ports.split("..")
         @ports = @ports[0].to_i..@ports[1].to_i
      when /^.+[,]/
         @ports = @ports.split(",")
      else
         @ports = Array(@ports)
      end
 end

 def hostarrange
    case @hosts
      when /^.+[,]/
         @hosts = @hosts.split(",")
      else
         @hosts = Array(@hosts)
      end
 end

def output(state,port)
   printed = false
   portsfile = File.new("ports", "r")
   scanpat = "^.+ #{port}/tcp"
   begin
     portsfile.each_line do |line|
       if line =~ Regexp.new(scanpat)
         puts "#{state}    : #{line}"
         printed = true
       end
       puts "#{state}    : #{port}" if printed == false
     end
   ensure
   portsfile.close
   end
end

def scanning(hosts,ports)
  hosts.each do |host|
    begin
      puts "scanning #{host}:"
      ports.each do |port|
        begin
          Timeout::timeout(10){TCPSocket.new(host, port)}
        rescue Timeout::Error
          output("filtered",port)
        rescue
          output("closed",port)
        else
          output("open",port)
        end
      end
    end
  end
end

end

##################### code start #####################

puts “no arguments past,correct usage:\nruby #{$0} [hosts] [ports]\n”
if
!ARGV[1]

my_scanner = Scanner.new

hosts = my_scanner.hostarrange
ports = my_scanner.portarrange
=begin
puts "debugging: "
puts hosts
puts ports

everything alright until here

=end
my_scanner.scanning(hosts,ports)

##################### eof #####################


#3

Sorry. Neglected to provide the literal answer to your question.
Because of the incorrect placement of "end"s, your definition of
“scanning” actually occurred within another one of your method
definitions. I hadn’t tried that before but, unsurprisingly, it has
the net effect of making your “method within a method” private.


#4

You are using an editor with proper syntax highlighting right?

With vim, my method, module, and class begin/do/end keywords are purple,
while all other block keywords are yellow. Makes it very easy to see if
I
missed a method end or a block end.

Jason


#5

hi,
many thanks !! now I could fix it with your help (there was a
further “end”-mistake in the output routine…) but do you know any
tricks or meassures to avoid these deep nestings while coding or
keep track of the begins and ends of ones code?

Code folding is one way. In TextMate for example, it is easy to see
if you put end in enough times.
One other thing is to put a comment after an ‘end’ to tell you what
it is ending.

C-like languages can be just as much trouble with closing braces.


#6

Evan Light wrote:

Sorry. Neglected to provide the literal answer to your question.
Because of the incorrect placement of "end"s, your definition of
“scanning” actually occurred within another one of your method
definitions. I hadn’t tried that before but, unsurprisingly, it has
the net effect of making your “method within a method” private.

hi,
many thanks !! now I could fix it with your help (there was a further
“end”-mistake in the output routine…) but do you know any tricks or
meassures to avoid these deep nestings while coding or keep track of the
begins and ends of ones code?


greets

                        (
                        )
                     (
              /\  .-"""-.  /\
             //\\/  ,,,  \//\\
             |/\| ,;;;;;, |/\|
             //\\\;-"""-;///\\
            //  \/   .   \/  \\
           (| ,-_| \ | / |_-, |)
             //`__\.-.-./__`\\
            // /.-(() ())-.\ \\
           (\ |)   '---'   (| /)
            ` (|           |) `
      jgs     \)           (/

one must still have chaos in oneself to be able to give birth to a
dancing star


#7

On May 7, 2007, at 7:56 PM, zswu wrote:

It’s a good habit that just writed end after you had writen “class,
def, if, do, e.t.c” before code the segment.

I feel it’s a much better idea to use an editor that handles that
busy work for you. It just drops the error count too much not to be
worth it.

James Edward G. II


#8

It’s a good habit that just writed end after you had writen “class,
def, if, do, e.t.c” before code the segment.


#9

Certainly, this is a good idea, though i dont use this kind of
editor.Because i want more controlling to my code, and this method
make me feelling better.It is just a personal habit, not anything
else.Everyone has own good play.


#10

On May 7, 11:31 am, anansi removed_email_address@domain.invalid wrote:

meassures to avoid these deep nestings while coding or keep track of the
begins and ends of ones code?

The first question that I ask myself when I start to nest deeploy is
“should I be factoring some of this nested code into additional
methods”. If even for the sake of my own sanity, the answer is
usually “yes”. :wink: