Методы имеют стандартное деление на public, protected и private.

Руби разрешает опускать скобки при обращении к методам. Естественно, в разумных пределах:


 >> 4.days.ago
 => Thu May 25 01:32:12 MSD 2006

(days является расширением к Integer, автоматически подключаемым в Rails).

Объявление метода происходит внутри класса:


class Fixnum
  def days
    self * 3600 * 24
  end
end

Метод можно объявить с параметрами:


class Fixnum
  def add(value)
    self + value
  end
end

Для вызовов методов существуют некоторые соглашения.
общим образом метод можно определить так:


class Myclass
  def my_method(value1, value2, *values)
  end
end

Тогда можно передавать любое количество параметров, лишние будут завернуты в виде массива в values

С такой передачей есть хитрость: пришел массив, как его засунуть в функцию в виде списка параметров?


Myclass.new.my_method("value1", "value2", *[1, 2, 3, 4, 5])

Т.е. массив разворачивается интерпретатором в список аргументов функции, что бы потом обратно свернуться в массив.

Еще одна хитрость с хешами:


Myclass.new.my_method("value1", :param1 => "value1", :param2 => "value2")

Если интерпретатор распознает в списке аргументов хеш, он и без скобок свернет его в хеш и подставит в переменную. С этим надо быть аккуратнее.

Метод так же можно определить, как блок (о блоках чуть-чуть попозже, поподробнее). Блок передается в define_method и становится полноправной функцией. Почему это плохо расскажу ниже.
Есть второй механизм создания методов: через eval.


module ActiveRecord
class Base
  def define_attr_method(name, value=nil, &block)
    sing = class << self; self; end
    sing.send :alias_method, "original_#{name}", name
    if block_given?
      sing.send :define_method, name, &block
    else
      # use eval instead of a block to work around a memory leak in dev
      # mode in fcgi
      sing.class_eval "def #{name}; #{value.to_s.inspect}; end"
    end
  end
 end
 end

Отсутствующие методы

Что будет если вызвать метод, которого нет на объекте?
Интерпретатор дернет метод method_missing(method_name, *args)

Именно таким образом происходит работа всех прокси объектов.

Duck-typing

“Если этот кирпич крякает, как утка и машет крыльями как утка и больше нам от утки ничего не нужно, то пускай этот кирпич сойдет за утку”

Интерфейсов в руби нет. Интерфейс подразумевает, что некоторый объект умеет какой-то набор действий, который необходим в других методах других объектов, причем этот набор фиксирован, равно как и фиксирована его семантика.

В руби объект может очень лихо менять свои методы, никого не спрашивая, поэтому интерфейс жестким не будет. И спрашивать у объекта kind_of? по меньшей мере некрасиво, потому что я вместо строки могу подставить прокси-объект к удаленному объекту.

Соответственно, в динамических языках интерфейсы заменяются проверкой respond_to?. В самом деле: неужели метод одного объекта будет запрашивать больше 2-3 методов на другом? Это уже greedy code называется. На этом и строится идея динамической типизации.

Для объекта есть несколько ручек, связанных с интерфейсами:
respond_to?, methods, method_missing, kind_of? и class. Соответственно, если прокси объект перекрывает все эти методы, то он становится попросту не отличим от того, кого он проксирует.

Sidebar