【问题标题】:Ruby 2.1: Composing a Bicycle of Parts -> private method `select' called for nil:NilClass (NoMethodError)Ruby 2.1:组成零件自行车 -> 调用 nil:NilClass (NoMethodError) 的私有方法 `select'
【发布时间】:2014-09-07 07:43:01
【问题描述】:

运行此代码时出现错误。以下是输出:

L
Bicycle#Ex3.rb:32:in `spares': private method `select' called for nil:NilClass (NoMethodError)
    from Bicycle#Ex3.rb:10:in `spares'
    from Bicycle#Ex3.rb:111:in `<main>'

代码如下:

class Bicycle
  attr_reader :size, :parts

  def initialize(args={})
    @size     = args[:size]
    @parts    = args[:parts]
  end

  def spares
    parts.spares # return an array
  end

  def lead_days
    1
  end
  #...
end

class Parts
  attr_reader :parts

  def initialize(args={})
    @parts = parts
  end

  def size
    parts.size
  end

  def spares
    parts.select{|part| part.needs_spare} 
  end
end

class Part
  attr_reader :name, :description, :needs_spare

  def initialize(args)
    @name      = args[:name]
    @description = args[:description]
    @needs_spare = args.fetch(:needs_spare, true)
  end
end

class RoadBikeParts < Parts
  attr_reader :tape_color

  def post_initialize(args)
    @tape_color = args[:tape_color]
  end

  def local_spares
    {tape_color: tape_color}
  end

  def default_tire_size
    '23'
  end
end 

class MountainBikeParts < Parts
  attr_reader :front_shock, :rear_shock

  def post_initialize(args)
    @front_shock = args[:front_shock]
    @rear_shock = args[:rear_shock]
  end

  def local_spares
      { rear_shock: rear_shock}
  end

  def default_tire_size
    '2.1'
  end
end

chain = Part.new(
                 name: 'chain',
                 description: '10 speed')

road_tire = Part.new(
                     name: 'tape_size', 
                     description: '23')
tape = Part.new(
               name: 'tape_color',
               description: 'red')
mountain_tire = Part.new(
                         name: 'tire_size',
                         description: '2.1')
rear_shock = Part.new(
                      name: 'rear_shock',
                      description: 'Fox')

front_shock = Part.new(
                       name: 'front_shock',
                       description: 'Manitou',
                       needs_spare: false)

road_bike_part = Parts.new([chain, road_tire, tape])                                

road_bike = Bicycle.new(
                        size: 'L',
                        parts: Parts.new([chain,
                                          road_tire,
                                          tape]))

puts road_bike.size
#puts road_bike.parts.size
puts road_bike.spares.size

很明显,这一行 --> puts road_bike.spares.size 给出了错误 NoMethodError,但是,我不确定如何解决此示例的问题。备用方法返回一个 Part 对象数组,但似乎我的问题在于备用方法 .select 是调用对象的私有方法。

任何修改此代码的建议都会很棒。谢谢。

【问题讨论】:

  • 例外情况说得很清楚,您在 nil 上调用 spares 方法。查看代码我也怀疑您是否知道自己在做什么。为什么不是 AR?
  • 感谢您的快速回复。当您询问 AR 时,我不确定您指的是什么?你能澄清一下吗?
  • 这篇文章是关于纯 Ruby 而不是 Rails,因此这些不是 AR (ActiveRecord) 实例。虽然在 Rails 中你也可以拥有不是 AR 子类的类@Michal Szyndel ;)
  • @fivedigit 我知道,但是如果它看起来像 AR 并且像 AR 一样庸医,我可能会认为发生了一些可疑的事情,对吧?而且你必须承认它非常类似于 AR……
  • @Michal Szyndel,这是真的。如果我没记错的话,这段代码实际上是基于 Sandy Metz 的 Practical Object Oriented Design in Ruby 中的一个示例

标签: ruby oop conventions


【解决方案1】:

这里发生的是Parts#partsnil。您在这一行收到错误:

# parts is nil
parts.select{|part| part.needs_spare}

Parts的初始化器中,它的parts属性没有被正确分配:

def initialize(args={})
  @parts = parts
end

所以在初始化的时候,它给@parts赋值parts。但由于parts 不是那里的局部变量,它调用Parts#parts 方法,该方法返回nil

如果您将初始化程序更改为以下内容:

def initialize(parts)
  @parts = parts
end

您将能够运行代码。但是Parts 的子类似乎期望在初始化程序中使用Hash,而不是像它们的超类那样使用Array

【讨论】:

  • 感谢您对子类的回复和跟进。在我完成这些示例的过程中,下一部分是解决数组问题以及重构代码的可能选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 2016-06-15
  • 2013-02-17
  • 2014-03-16
  • 1970-01-01
相关资源
最近更新 更多