Почему я не могу определить свои методы там, где хочу?

Методы определяются во время выполнения программы. Поэтому, в отличие от Perl, метод не может быть использован до того, как определен. Следующий пример работать не будет:

  greeting("Daniel")
  def greeting(name)
    puts "Hello #{name}"
  end

а вот такой будет:

  def greeting(name)
    puts "Hello #{name}"
  end
  greeting("Daniel")

Это trade-off. Эта особенность дает больше свободы изменять методы во время работы программы. Например:

  def greeting(name)
    puts "Hello #{name}"
  end
  greeting("Daniel")

  def greeting(name)
    puts "Hi #{name}"
  end
  greeting("Daniel")

Результаты работы этого кода:

  Hello Daniel
  Hi Daniel

В то время как эквивалент на Perl:

  sub greeting {
    print "Hello $_[0]
";
  }
  greeting("Daniel")

  sub greeting {
    print "Hi $_[0]
";
  }
  greeting("Daniel")

выдаст

  Hi Daniel
  Hi Daniel

так как процедуры в Perl определяются во время компилирования программы.

Правило, гласящее, что методы должны быть определены до того, как использованы, действует только тогда, когда они определены и вызываются на одном уровне. Это значит, например, что методы объекта и класса могут быть определены после их вызова, так как на самом деле метод исполняется после того, как он определен:

  class Greeting
    def initialize
      hello
    end

    def hello
      puts "Hi!"
    end
  end

  Greeting.new             # -> Hi!

Вход для пользователей