Designing a Cabinet class

Hello all,

I’m a 6 month newbie to the Ruby programming language. I’ve been
hesitant in the past to participate in the ruby community simply because
I feel my knowledge and experience is lacking, but I have been
encouraged by the numerous sources that have said that the ruby
community is open and friendly, so I’m giving this a try.

My project of the day is to design a simple Cabinet class. I’ve attached
what code I have written thus far.

The end goal of this project is to create a simple cabinet object that
has three drawers that can have objects placed into or removed from
them. Also, I hope to write methods that would allow me to generate a
report of what objects are in which drawers as well as inquiry methods
that would establish whether a particular drawer was full or empty.

I’m struggling with understanding how to place things in each drawer
such that when I consider what code to write to retrieve those items, I
am stumped. Does the problem lie in the fact that I haven’t considered
that the drawers are their own objects as well, and I need to figure out
how to make multiple objects interact with one another to create a
functioning virtual cabinet?

While sample code that would create a functioning Cabinet class is
appreciated, I feel that my lack of understanding doesn’t simply stem
from the fact that I don’t know the exact code, but rather that I do not
understand a more general concept of ruby programming. Explanations that
would help with this would be appreciated. Thanks!

~Mike

Subject: Designing a Cabinet class
Date: gio 27 giu 13 09:07:09 +0900

Quoting Mike V. ([email protected]):

While sample code that would create a functioning Cabinet class is
appreciated, I feel that my lack of understanding doesn’t simply stem
from the fact that I don’t know the exact code, but rather that I do not
understand a more general concept of ruby programming. Explanations that
would help with this would be appreciated. Thanks!

Your idea of creating a drawer class is not only a good Ruby practice:
it is THE sound object-oriented direction to take: the cabinet holds
drawers, and the drawer holds objects. Experiment with creating such a
class, and assigning to it the property of holding objects: the add,
remove, and test methods should belong there.

Your cabinet will then contain an array (or maybe a hash) of
drawers. And your drawer will contain an array (or maybe a hash) of
objects.

If you are not familiar with hashes or arrays, there is much to read
about them. If you are not familiar with the Ruby implementation of
arrays and hashes, you can type this:

ri Array

and

ri Hash

These manual pages are quite well-made…

Happy coding

Carlo

The key here is to understand instance variables. That’s these:
@one, @two, @three

Those variables are unique to each Instance of your Class. That means
they hold the “state” of an individual Cabinet.

All you need to do is to set the value of @one, @two, or @three inside
your methods.

There are a lot of ways to go about doing this, but we’ll run with a
basic one for now:

def place
puts “What would you like to put into the cabinet?”
thing = gets.chomp
puts “What drawer number would you like to place #{thing} in? One,
two, or three?”
drawer_number = gets.chomp.downcase
case drawer_number
when ‘one’
@one = thing
puts “#{thing} has been placed in drawer one.”
when ‘two’
@two = thing
puts “#{thing} has been placed in drawer two.”
when ‘three’
@three = thing
puts “#{thing} has been placed in drawer three.”
else
puts “I’m sorry, please select from one, two, or three.”
end

end

def remove(thing)
#a method to remove an object from a drawer
# Question code here…
# Remove the object, for example:
@one = nil
end

Subject: Re: Designing a Cabinet class
Date: gio 27 giu 13 09:53:49 +0900

Quoting Mike V. ([email protected]):

Thank you for your reply. I had a feeling that this was going to be the
proscribed approach. My next question, then, is how to get objects to
play together. Is this where :belongs_to and :has_many come into play?
Please don’t feel obligated to give me a comprehensive response if you
feel that there is a good piece written on the subject that you could
point me to. Thanks!

You are mixing environments here. :belongs_to and :has_many are
concepts that relate to how you map objects to database tables. They
are not part of Ruby. You should investigate subjects like Datamapper
and ActiveRecord to understand more about them. This list won’t be of
much help about those territories.

In Ruby, your cabinet has drawers as soon as you create an instance
variable that holds the drawers. So, for example, your Cabinet class
may contain something like:

@drawers=[Drawer::new(…),Drawer::new(…),…]

and from that point on, your cabinet will have drawers.

Carlo

Carlo E. Prelz wrote in post #1113706:

Subject: Designing a Cabinet class
Date: gio 27 giu 13 09:07:09 +0900
Your idea of creating a drawer class is not only a good Ruby practice:
it is THE sound object-oriented direction to take: the cabinet holds
drawers, and the drawer holds objects. Experiment with creating such a
class, and assigning to it the property of holding objects: the add,
remove, and test methods should belong there.

Carlos,

Thank you for your reply. I had a feeling that this was going to be the
proscribed approach. My next question, then, is how to get objects to
play together. Is this where :belongs_to and :has_many come into play?
Please don’t feel obligated to give me a comprehensive response if you
feel that there is a good piece written on the subject that you could
point me to. Thanks!

One option would a combination of Hash and Array…

@drawers = {}
@drawers[ :one ] = []
@drawers[ :two ] = []
@drawers[ :three ] = []

@drawers is a Hash, and each drawer in @drawers is an Array.
You could then insert and remove things through these Arrays.

thing1 = “This”
thing2 = “That”

@drawers[ :one ] << thing1
#=> [ “This” ]

@drawers[ :one ] << thing2
#=> [ “This”, "That ]

@drawers[ :one ].delete( thing1 )
#=> [“This”]

@drawers[ :one ]
#=> [ “That” ]

Subject: Re: Designing a Cabinet class
Date: ven 28 giu 13 09:01:48 +0900

Quoting Mike V. ([email protected]):

When a user goes to remove an item from the drawer, they will be
presented with a list of items in the drawer. This list will be
populated by the drawer_contents array. Instead of asking them to type a
number that would correspond to the the item’s array index, I want them
to simply type the item name and have it removed from the
drawer_contents array. I feel like there should be an easy way to do
this, but I am stumped.

To remove an item from an array, you have array#delete(object). But
what you are not doing is using instance variables. If you want
variables to survive as long as your object exists, you must prepend a
‘@’ to the variable name. And of course, you are missing the
initialization method (called ‘initialize’), where instance variables
should be initialized at beginning.

You should go through some elementary-level Ruby tutorial to learn
about these things. If you look at the archive of this list, there
have been several threads where fine tutorials have been mentioned. A
good page to start from is this one, from within Ruby’s home page:

http://www.ruby-lang.org/en/documentation/

Carlo

FYI, this line doesn’t do what you think it does:

puts drawer_contents.each {|item| puts item}

What that will do is iterate through each item and output it to the
console… but then that “puts” at the beginning of the line will output
the return value of “each”, which will be the array.
Effectively you’ll output everything twice.

A simpler way to do this would be:

puts drawer_contents

So I decided to take Carlo’s advice and make an effort to create a
separate Drawer class, moving the #place and #remove functionality over
from the Cabinet class to the Drawer class. I also added #open and
#close functionality to the Drawer as well. I think I correctly wrote
the code for #open, #close, and #place, but I’m having quite a bit of
difficulty with #remove. Adding an element to an array is simple enough,
but to remove a specified item in that array is proving a bit more
difficult.

What I’m trying to do:

When a user goes to remove an item from the drawer, they will be
presented with a list of items in the drawer. This list will be
populated by the drawer_contents array. Instead of asking them to type a
number that would correspond to the the item’s array index, I want them
to simply type the item name and have it removed from the
drawer_contents array. I feel like there should be an easy way to do
this, but I am stumped.

Once again, I’ve attached the file I’m working on for reference. Thanks!

~Mike

So here is my most recent work. I decided to completely set aside the
idea of class Cabinet for now, and I have since designed a working class
Drawer with the desired functionality. It works. I have run the program
through and through and it accomplishes what I set out to do with a
Drawer.

My next challenge is understanding how to make a drawer object interact
with its parent object Chest_of_drawers. I want to be able to write the
following code:

chest_of_drawers = Chest_of_drawers.new(4)

and have a new chest of drawers object that contains 4 drawers. This
goal pushes me past my understanding. I have no clue where to go next.
Once again, sample code is welcomed, but ideally I’d like to have an
explanation or a direction to some materials that I can read, and then
try (and likely fail) on my own first before someone hands me ready made
code that will accomplish what I’m looking for. I find that trial and
error tend to teach me much more effectively than simply reading through
correct code (though I see the value in that as well.)

@tamouse: I really appreciate your feed back (along with everyone
else’s). I’m curious, in what ways can I remove the user interaction
portion of my code from my instance method and still have a class that
will allow me to have an object with which I can interact?

Mike V. [email protected] wrote:

Hello all,

Hi, Mike, welcome to the wonderful world of Ruby!

I’m a 6 month newbie to the Ruby programming language. I’ve been
hesitant in the past to participate in the ruby community simply because
I feel my knowledge and experience is lacking, but I have been
encouraged by the numerous sources that have said that the ruby
community is open and friendly, so I’m giving this a try.

Good-o!

such that when I consider what code to write to retrieve those items, I
am stumped. Does the problem lie in the fact that I haven’t considered
that the drawers are their own objects as well, and I need to figure out
how to make multiple objects interact with one another to create a
functioning virtual cabinet?

While sample code that would create a functioning Cabinet class is
appreciated, I feel that my lack of understanding doesn’t simply stem
from the fact that I don’t know the exact code, but rather that I do not
understand a more general concept of ruby programming. Explanations that
would help with this would be appreciated. Thanks!

I think others have given you a good lead in terms of building classes
and associated data structures. I’m going to discuss something
else. That is separation of logic, data and presentation (the latter in
this case being your user interaction).

Structuring your classes deals with the logic and data of your
program. What struck me, though, was this:

def place
#a method to place an object in a drawer
puts “What would you like to put into the cabinet?”
thing = gets.chomp
puts “What drawer number would you like to place #{thing} in? One,
two, or three?”
drawer_number = gets.chomp.downcase
case drawer_number
when ‘one’
puts “#{thing} has been placed in drawer one.”
when ‘two’
puts “#{thing} has been placed in drawer two.”
when ‘three’
puts “#{thing} has been placed in drawer three.”
else
puts “I’m sorry, please select from one, two, or three.”
end

end

You Cabinet class and it’s containers and so on would ideally be
completely free of the machinations of getting the things to put in the
drawers. By mixing in the user interaction, you are making your class
much less usable for other projects. Realizing this is a kata, one of
the tenets of good practice is to follow more strict rules. “Wax on, Wax
off. Up and Down.” :slight_smile:

So a better approach is to make your Cabinet class’s methods as slim and
simple as possible, using some of the techniques others have shown. The
other huge advantage to this is that it makes your classes much much
easier to test. While doing this interactively seems easy, doing it
every time you make a change gets quite tedious. Having a set of tests
at hand makes things much faster.

The other thing is that writing tests really helps in solidifying what
you want your class to do and how it should behave from an external
point of view.

There are several test frameworks, but as you’re really in the beginning
stages, you might find them daunting (not that I want to discourage you
from looking!). But the simplest test is just a ruby script that calls
your classes with set values and makes sure they all work the way you
expect them to. Liberal use of puts will help.

On Tue, Jul 2, 2013 at 1:26 PM, Mike V. [email protected]
wrote:

chest_of_drawers = Chest_of_drawers.new(4)

and have a new chest of drawers object that contains 4 drawers. This
goal pushes me past my understanding. I have no clue where to go next.
Once again, sample code is welcomed, but ideally I’d like to have an
explanation or a direction to some materials that I can read, and then
try (and likely fail) on my own first before someone hands me ready made
code that will accomplish what I’m looking for. I find that trial and
error tend to teach me much more effectively than simply reading through
correct code (though I see the value in that as well.)

Create a new class which contains the drawers. In the initialize
method, you can create that number of drawers and store them in an
instance variable (start with @), for example in an array. You can
then create a method in the Chest_of_drawers class to get at each of
the drawers by index (0 to 3). By the way, the convention in Ruby is
to use CamelCase for class names: ChestOfDrawers.

@tamouse: I really appreciate your feed back (along with everyone
else’s). I’m curious, in what ways can I remove the user interaction
portion of my code from my instance method and still have a class that
will allow me to have an object with which I can interact?

You should move all the puts and gets to a different place (the top
level, for example), and change the interface of the Drawer class, so
that it receives the object to place, for example:

class Drawer
attr_reader :drawer_contents # this creates a method that returns
@drawer_contents
[…]

def place object
raise “The drawer appears to be closed. Try opening it first.”
unless @drawer_position
@drawer_contents << object
end
end

and in the main:

drawer = Drawer.new
puts “What would you like to put into the drawer for storage?”
thing_to_put_into_drawer = gets.chomp
drawer.place thing_to_put_into_drawer
puts “You now have #{drawer.drawer_contents} in the drawer”

This way, your Drawer class is much more reusable, for example if you
want to use it in a web application instead of a command line app. In
general a class should have one concern and mixing the drawer logic
with the user interaction logic is bad.

Jesus.