def class A
def a
raise "hi" #can't be reached
end
class B
def b
a() #doesn't find method a.
end
end
end
Я хочу вызвать a из b и поднять исключение. Как я могу?
def class A
def a
raise "hi" #can't be reached
end
class B
def b
a() #doesn't find method a.
end
end
end
Я хочу вызвать a из b и поднять исключение. Как я могу?
Ruby не имеет вложенных классов.
Единственный способ унаследовать поведение - это, ну, через наследование.
Если вы хотите, чтобы ваш код работал, вам нужно использовать язык, который поддерживает вложенные классы. Хотя это невероятно опрятная и мощная функция, я, к сожалению, знаю только два языка с вложенными классами:
Я не знаю другого.
Java имеет конструкцию с именами вложенных классов, но у них есть некоторые неудачные конструктивные ограничения.
В приведенном выше примере не вложенный внутри A
класс B
, это константа B
, вложенная внутри A
. Подумайте об этом:
C = A::B
Теперь класс доступен под двумя именами: A::B
и C
. Непосредственно очевидно, что C
является глобальным и не вложен внутри A
. (Ну, на самом деле, C
вложен внутри Object
, потому что на самом деле также нет глобальных констант, но это рядом с точкой.) Но так как C
и A::B
являются одним и тем же классом, это, очевидно, не может быть как вложенные, так и не вложенные. Единственный логический вывод состоит в том, что сам класс не вложен.
Определяющая особенность вложенных классов заключается в том, что поиск метода проходит по двум измерениям: вверх по цепочке наследования, а также через вложенность. Ruby, как и 99,9% всех языков OO, поддерживает только первый. (В некотором смысле вложенные классы наследуют не только функции своего суперкласса, но также и функции их окружающего класса.)
Это только для lulz:
class A
def a
puts "hello from a"
end
class B
def b
Module.nesting[1].new.a()
end
end
end
Я обычно делаю что-то вроде этого:
class A
def a
puts "hi"
end
def createB
B.new self
end
class B
def initialize(parent)
@parent=parent
end
def b
@parent.a
end
end
end
A.new.createB.b
Если вы хотите, чтобы вложенный класс расширил внешний класс, сделайте следующее:
class Outer
class Inner < Outer
def use_outer_method
outer_method("hi mom!")
end
end
def outer_method(foo)
puts foo
end
end
foo = Outer::Inner.new
foo.use_outer_method #<= "hi mom"
foo.outer_method("hi dad!") #<= "hi dad"
Хорошо, в зависимости от ваших обстоятельств есть на самом деле решение, довольно легкое в этом. Ruby позволяет захватывать вызовы методов, которые не захватываются объектом. Итак, для вашего примера вы можете сделать:
def class A
def a
raise "hi" #can't be reached
end
class B
def initialize()
@parent = A.new
end
def b
a() #does find method a.
end
def method_missing(*args)
if @parent.respond_to?(method)
@parent.send(*args)
else
super
end
end
end
end
Итак, если вы это сделаете:
A::B.new().b
вы получаете:
!! #<RuntimeError: hi>
Это, вероятно, более простой способ сделать что-то вроде SubController, который обрабатывает только определенные действия, но может легко вызвать базовые методы контроллера (вы хотите отправить родительский контроллер в качестве аргумента в инициализаторе, хотя).
Очевидно, что это следует использовать экономно, и это может действительно запутать, если вы используете его повсюду, но может быть очень полезно упростить ваш код.
Предполагалось ли a
быть метод класса для класса a
?
class A
def self.a
raise "hi"
end
class B
def b
A::a
end
end
end
A::B.new.b
Если вы хотите сохранить его как метод экземпляра, у вас, очевидно, будет обращение к нему на экземпляр, например, A.new.a
.