简体   繁体   中英

Ruby Undefined method '<<' for class?

Going through a tutorial using modules (namespaces). I receive the following error:

    blog.rb:25:in `insert_random_comment': undefined method `<<' for 
    #<Blog::Comment:0x007f1370368be0> (NoMethodError)
    from modules.rb:13:in `<main>'

In the insert_random_comment I puts the class and methods. The class is Blog::Comment and there is no method shown for <<. So it seems I am expecting the instance variable @comment to be a list of objects but it is a single object. Would I be correct in saying that when instantiating the Blog post object I should initialize the comment with a list with contents a single blog comment?

module.rb

post = Blog::Post.new   author: "Stevie G",
                        title: "A title",
                        body: "A body",
                        comments: Blog::Comment.new(    user: "Jeffrey Way",
                                                        body: "A Comment")

post.insert_random_comment

blog.rb

module Blog

  class Post
        attr_reader :author, :title, :body, :comments

        def initialize options
                @author = options[:author]
                @title  = options[:title]
                @body   = options[:body]
                @comments = options[:comments] || []
        end

        #*splat (only 1 splat in method signature)
        #first param, *comments
        # insert_comments first, second, *thirds, options, &block
        def insert_comment first, second, *thirds, options, &block
                comments.each { |c| @comments << c }
        end

        def insert_random_comment
                p @comments.class
                p @comments.methods
                @comments << Comment.new(user: "jose Mota", body: "A body")
        end
  end

  class Comment
        attr_reader :user, :body

        def initialize options
                @user = options[:user]
                @body = options[:body]
        end
  end
end

Base on your module.rb, you will assign Post.comments as an Comment object when you initialize a Post object.

post = Blog::Post.new   author: "Stevie G",
                        title: "A title",
                        body: "A body",
                        comments: Blog::Comment.new(    user: "Jeffrey Way",
                                                        body: "A Comment")   #This is an object of Comment

So you could:

post = Blog::Post.new   author: "Stevie G",
                        title: "A title",
                        body: "A body",
                        comments: [Blog::Comment.new(    user: "Jeffrey Way",
                                                        body: "A Comment")]   #This is an Array of Comments

When you are dealing with array, but expecting the single value may occur as an input, you might want to use ruby magick:

value = *[arg]

will hold an array, despite whether arg is an array or not:

arg = [1,2,3]
value = *[arg]
# => [
#   [0] [
#     [0] 1,
#     [1] 2,
#     [2] 3
#   ]
# ]

arg = 1
value = *[arg]
# => [
#   [0] [
#     [0] 1
#   ]
# ]

So, in your case you might want to initialize an object with either single comment or with an array:

@comments = [*options[:comments]]

Would do the trick. The problem was actially that you passed the single Comment object in call to Blog::Post.new (4th argument.)

UPD: Thanks to @PatriceGahide, handling of nil was done erroneously.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM