Ruby:如何使用父类中的方法调用子类?

时间:2014-07-03 03:51:58

标签: ruby module

我试图使用名为subscriptions的方法在CurrentPlan中调用CurrentPlan :: Subscription。我有2个文件。这是我的代码


current_plan.rb

require_relative 'current_plan/subscription'

class CurrentPlan
  # Get all subscriptions through current_plan
  def subscriptions
    CurrentPlan::Subscription.all
  end
end

current_plan = CurrentPlan.new()
current_plan.subscriptions


current_plan/subscription.rb

require_relative '../current_plan'

class CurrentPlan::Subscription
  def self.all
    %w[subscription_1 subscription_2 subscription_3]
  end
end


我收到的错误。

<CurrentPlan:0x0000010191ebd0>
/Users/foobar/Sites/ruby_apps/current_plan.rb:18:in `subscriptions': uninitialized     constant CurrentPlan::Subscription (NameError)
from /Users/foobar/Sites/ruby_apps/current_plan.rb:25:in `<top (required)>'
from /Users/foobar/Sites/ruby_apps/current_plan/subscription.rb:3:in `require_relative'
from /Users/foobar/Sites/ruby_apps/current_plan/subscription.rb:3:in `<top (required)>'
from current_plan.rb:14:in `require_relative'
from current_plan.rb:14:in `<main>'

5 个答案:

答案 0 :(得分:2)

current_plan/subscription.rb中,更改为:

require_relative '../current_plan'

class CurrentPlan
  class Subscription
    def self.all
      %w[subscription_1 subscription_2 subscription_3]
    end
  end
end

当Ruby甚至不知道CurrentPlan::Subscription是什么时,感到困惑,试图解决CurrentPlan ...

另一种方法是将require语句放在文件末尾的current_plan.rb中(在类声明之后),在这种情况下你不需要修改subscription.rb,但这可能会导致其他问题。

答案 1 :(得分:2)

这里有两个问题。首先,你是require - 一个圆圈中的文件。如果从底部开始查看错误的回溯,则要执行的第一件事是调用require_relative 'current_plan/subscription'。该文件的第一行是对require_relative '../current_plan'的调用,这是已经在加载过程中的原始文件。

Ruby现在将尝试要求此文件,并将跳过对require_relative 'current_plan/subscription'的调用,因为它识别出已经需要该文件(即使它尚未完成需要)。定义CurrentPlan类是可以的,因为即使该方法引用了未定义的常量,它也没有被调用。当执行到达current_plan.rb的最后两行时,它会创建一个CurrentPlan实例,并尝试在其上调用subscriptions。这是发生错误的地方,因为subscriptions指的是尚未定义的CurrentPlan::Subscription(我们仍然没有从require_relative顶部的subscription.rb调用返回}})。

仅当需要的文件是最初执行的文件时才会出现此问题,即在这种情况下,您运行$ ruby current_plan.rb然后调用require 'current_plan'(或require_relative)。如果其他文件需要current_plan,那么require_relative '../current_plan'中的subscription.rb将被跳过,因为Ruby会将该文件识别为已经被要求。

修复这个很简单,jut删除行

require_relative '../current_plan'

来自subscription.rb。 (您可能需要确保current_plan.rb以外的文件不要直接尝试subscriptions

修复会暴露其他问题。在尝试要求subscription时,尚未定义班级CurrentPlan,因此class CurrentPlan::Subscription将失败。

有几种方法可以解决这个问题,最直接的方法是改变

class CurrentPlan::Subscription
  ...
end

class CurrentPlan
  class Subscription
    ...
  end
end

以便在尝试定义CurrentPlan时确保定义Subscription。另一种方法是将require_relative中的current_plan.rb的呼叫移至CurrentPlan定义之下(甚至在其中)。

答案 2 :(得分:1)

试试这个:

module A
  class Subscription
    def self.all
      puts "all method of Subscription" 
    end
  end
end

class CurrentPlan
  include A
  def subscriptions
    CurrentPlan::Subscription.all
  end
end

current_plan = CurrentPlan.new()
current_plan.subscriptions  # => all method of Subscription

答案 3 :(得分:0)

好吧,如果你想继承行为,只需使用......好吧,继承。但请注意,Ruby不支持嵌套类,比如Java。

如果需要,可以使用Inner类来扩展外部类:

class Outer

  class Inner < Outer
    def outer_method
      my_outer_method("hey!")
    end
  end

  def my_outer_method(foo)
    puts foo
  end

end

foo = Outer::Inner.new
foo.outer_method           #<= "hey!"
foo.my_outer_method("hi!") #<= "hi!"

顺便说一下,这更简单。

您仍然可以考虑命名空间/模块,例如:

module CurrentPlan #this is your namespace
end

class CurrentPlan::Subscription #this is your class
end

subs = CurrentPlan::Subscription.new #this is your instance

虽然在Ruby中你不能拥有模块的实例(在这种情况下,无法实例化CurrentPlan)。但您可以使用extend包含模块的方法。

答案 4 :(得分:0)

这对我来说很有用!感谢大家的帮助

current_plan.rb

require_relative 'current_plan/subscription'

class CurrentPlan
  def subscription
    CurrentPlan::Subscription.new
  end
end

current_plan = CurrentPlan.new
puts current_plan.subscription.all


current_plan/subscription.rb

class CurrentPlan
  class Subscription
    def all
      %w[asd asdadsadasdas njasdnjasndjasd subscription_1 subscription_2]
    end
  end
end