不能使用Ruby Hash的子类调用puts

时间:2013-12-17 15:57:13

标签: ruby hash tostring

我已经构建了一个Hash的子类,每当我用我的类的实例作为参数调用puts时,我得到以下内容:

> puts data
TypeError: can't convert Reporting::Search::Data to Array (Reporting::Search::Data#to_ary gives Reporting::Search::Data)

有谁知道该怎么办?我希望它输出一个Hash的字符串表示,就像用普通Hash调用puts一样。

我的课很简单:

  class Data < HashWithIndifferentAccess
    def method_missing meth, *args, &block
      if meth.to_s =~ /=$/
        send :[]=, meth.slice(0...-1), *args
      elsif args.empty?
        fetch meth, Data.new
      else
        super meth, *args, &block
      end
    end

    def compact!
      delete_if do |k,v|
        v.compact! if v.is_a?(Data)
        v.blank?
      end
    end
  end

3 个答案:

答案 0 :(得分:1)

您有两种选择,可以编写to_s方法。或者你可以看到.inspect实例方法给你的东西,虽然它可能不是很有用!

您是否尝试过添加这样的to_s方法?

def to_s
  super.to_s
end

此外,它可能不是您遇到问题的唯一原因,但您已将您的子类Data命名为Ruby中的类。

答案 1 :(得分:1)

看起来问题与您使用method_missing有关。

当你调用puts时,它会尝试以人类可读的形式输出对象,因此它会在对象上调用to_ary。但是,您尚未在课程中定义to_ary,因此它会回到method_missing,因为它会混淆并失败。

to_ary定义为存根,我不再收到错误。

def to_ary
end

这是Ruby中元编程的许多陷阱之一!

答案 2 :(得分:0)

您以各种方式违反了Ruby的类型转换协议。

首先,您的对象会响应to_intto_floatto_strto_ary等,而实际上不是整数,浮点数,字符串或数组。这些类型转换方法的三个字母( ahem float ahem )版本应该仅用于 ,如果有问题的对象真的绝对肯定整数,浮点数,字符串或数组,而不是表示为IntegerFloatStringArray的实例

但是,您的对象不是Array,而是地图。因此,它应该只响应to_hash,如果有的话。

其次,to_intto_floatto_strto_ary等的返回值应该是Integer的实例,{{1 }},FloatString类。

因此,您正在实现一些您甚至不应该首先实现的方法您从它们返回错误的值。对于那些深深植根于Ruby核心内容的东西来说,就像它的类型转换协议一样,必然会带来各种各样的破坏,你只能看到它的开始。