Методы имеют стандартное деление на 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)
Именно таким образом происходит работа всех прокси объектов.
“Если этот кирпич крякает, как утка и машет крыльями как утка и больше нам от утки ничего не нужно, то пускай этот кирпич сойдет за утку”
Интерфейсов в руби нет. Интерфейс подразумевает, что некоторый объект умеет какой-то набор действий, который необходим в других методах других объектов, причем этот набор фиксирован, равно как и фиксирована его семантика.
В руби объект может очень лихо менять свои методы, никого не спрашивая, поэтому интерфейс жестким не будет. И спрашивать у объекта kind_of? по меньшей мере некрасиво, потому что я вместо строки могу подставить прокси-объект к удаленному объекту.
Соответственно, в динамических языках интерфейсы заменяются проверкой respond_to?. В самом деле: неужели метод одного объекта будет запрашивать больше 2-3 методов на другом? Это уже greedy code называется. На этом и строится идея динамической типизации.
Для объекта есть несколько ручек, связанных с интерфейсами:
respond_to?, methods, method_missing, kind_of? и class. Соответственно, если прокси объект перекрывает все эти методы, то он становится попросту не отличим от того, кого он проксирует.