Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Ruby Ruby Booleans Build a Simple Todo List Program Part 5: Marking Todo Items Complete

Jason Payne
Jason Payne
2,913 Points

Quick beginners questions...

Hi, just looking for the reason why I can't write the following code outside of a method to mark an item complete at an index?

todo_items[2].mark_complete!

Works fine when placed inside a method but when I try to place it outside, I get an error...

5 Answers

Maciej Czuchnowski
Maciej Czuchnowski
36,441 Points

OK, I'm not sure where to start, because I don't know how comfortable you are with object oriented programming. You first have to understand the basics of Ruby object oriented programming - what classes are, what instances of classes are, how they work internally, what is executed when you run this code.

When you run this code, ruby loads the todo_item.rb file which has all the definition code associated with TodoItem class. Then the code associated with TodoList class is loaded. And after that some commands are executed. The code inside the class definition code is just the setup that will later be used on the instances of that class. In short, the stuff that is between def and end is not executed yet at this point - it just sits there and gets executed when it's called on proper objects. But if you put something inside this class that is not a definition, it gets executed (the line you tried is an executable code). You tried to execute something inside the class and it didn't know what to do with your code - it doesn't know what todo_items is yet, because it's just a class, without any instance of itself and surely without any todo items instantiated and added to it.

It can be executed later on, when called on an instance of the TodoItem class, which in turn is inside an object that is an instance of the TodoList class.

To use some absurd analogy - you are trying to get inside an empty car factory assembly line and to drive a car :)

Maciej Czuchnowski
Maciej Czuchnowski
36,441 Points

What exactly are you trying to do? And what error are you getting? Based on the info above I assume you're outside of the scope of a local variable.

Jason Payne
Jason Payne
2,913 Points

NameError: undefined local variable or method ‘todo_items’ for TodoList:Class

I was just trying to call the mark_complete! method (from the TodoItem class file) directly on an index from the todo_items array in the TodoList class file... But I see you can only do that within a method in the TodoList class file... i.e. it can't be done outside a method (in a single direct line of text in the TodoList class file...)... Just interested in the explanation of why, etc.

Thanks a lot...

Jason Payne
Jason Payne
2,913 Points

Thanks very much for the reply Maciej, much appreciated...

When I try to place the code directly after a point (where I believe :-)) it is being created, I get an error... This is the code that I am incorrectly using:

  def mark_complete(name)
    if index = find_index(name)
      todo_items[index].mark_complete!
      return true
    else
      return false
    end
  end
todo_list = TodoList.new("Groceries")

todo_list.add_item("Eggs")
todo_list.add_item("Butter")
todo_list.add_item("Bread")
todo_list.add_item("Apples")

todo_list.mark_complete("Eggs")
#todo_list.mark_complete("Bread")

todo_items[2].mark_complete!

I guess in my head the todo_items array has been created when I create todo_list and add items to its todo_items array... Hence I am trying to get my head around why I can't call the mark_complete! method directly on it (i.e. above, the todo_list.mark_complete("Bread") works fine but todo_items[2].mark_complete! is wrong - does not work...)

Really appreciate any insights you can offer to help me 'get it'... many thanks...

Maciej Czuchnowski
Maciej Czuchnowski
36,441 Points

todo_items does not exist outside the todo_list. But you can chain this failing line to the todo_list variable which you have:

todo_list.todo_items[2].mark_complete!

This should work properly, because you're taking the todo_list object that you instantiated a few lines above, you look into the third element of its internal todo_items array and call the mark_complete! method on that object (the method in turn is defined in the TodoItem class).

Jason Payne
Jason Payne
2,913 Points

Great... thanks a lot... works perfectly (and I understand it... now :-))...