Newby non/programmer trying to understand classes

Hello.
Brief disclaimer. I’m coming from a bourne shell back ground and
currently all of my ruby scripts look like shell scripts where I
create methods like i would a shell function and now that I understand
some of the language basics (variables, loops, exceptions) I want to
improve my skills and try to leverage the language instead of just
brute forcing my way through problems. I’m not looking for a one
liner wizardry solution but some help getting a better understanding
of classes and ruby in general to change my approach to writing ruby
scripts.

I’ve scaled down my project to the most basic components that will
still allow me to express my areas of confusion. I have a file that
changes daily which contains a list of people in this format

bob.smith
bill.johnson
betty.joe
tony.johnson
wilbur.smith

Additionally I have a directory populated with 1 file per uniq last
name (ie: smith, johnson, joe). I need to parse through the days list
and then cleanse the last name files of the previous entries and
insert the updated list. I’ve got the script that does this it is
not very efficient (ie: i must define all the last names in
advance). So now i’ve started to rewrite the script and this is
where I’m stuck

I just barely understand setter/getter enough so can create LastName

objects and then

read the @first or @last variables

class LastName
def initialize(n)
@first, @last = n.split(".")[0], n.split(".")[1]
end

attr_accessor :first, :last

def get_last
@last
end
end

Here I am trying to dynamically define all of the last name

variables which would contain

all of the strings that have the given last name.

nf = File.open(“people”, “r”)
surnames = []
nf.each_line do |l|
p = LastName.new(l)
sur = p.get_last
sur << l
surnames << sur
end

I try to access the various “sur” variables which should contain the

list of people with a specific last

name but cannot figure out how to call the specific instance of

“sur”. Is their some way I could

dynamically create the “sur” variable as say “smith” and then

include them in the “surnames”

array so later I could loop through the surnames.uniq array and get

the name of all the “sur”

variables. Here is my pseudo code

surnames.uniq.each do |s|
namefile = File.open(s,“w+”)
namefile << s
end

I realize that my problem is pretty rudimentary but so far i’ve only

been able to create basic classes

and instantiate 1 object at a time to understand the getter/setter

methods. Trying to iterate

through a list my pea brain gets mired in all the different objects

and how do I look at certain ones.

Anyhoo I’d appreciate comments on my specific dynamic variable
problem or any other pointers
to help my get to the “AH HA!” moment with constructing and using
classes which I feel I’m pretty close to.
TIA. G

ps: I own many ruby books and have spent about 20 hours trying to
solve this pretty basic situation and dont know where else to go for
help.

from the code you have provided you don’t really need classes and all
the
machinery they provide. your code simply adds strings to a list which
you
call surnames. if you want to access the names as well as last names
then
when you create your lastName object you shouldn’t extract the last name
and
add it to the list but just append the lastName object to the list.

On Jun 28, 2007, at 6:45 PM, [email protected] wrote:

wilbur.smith

Additionally I have a directory populated with 1 file per uniq last
name (ie: smith, johnson, joe). I need to parse through the days list
and then cleanse the last name files of the previous entries and
insert the updated list.

So when you’re done, you have “==>filename<==” followed
by content lines like:

==>smith<==
bob.smith
wilbur.smith

==>johnson<==
bill.johnson

==>joe<==
betty.joe

Is there any reason that you can’t wipe the directory clean (remove
all the previous lastname files) when you start?

  sur = p.get_last
  sur << l
    surnames << sur

end

surnames.uniq.each do |s|
namefile = File.open(s,“w+”)
namefile << s
end

Let’s translate the filename/content structure that you want to end
with into a simple key/value hash:

{ “smith” => [ “bob.smith”, “wilbur.smith” ],
“johnson” => [ “bill.johnson” ],
“joe” => [ “betty.joe” ]
}

…and then build that:

create a Hash where referencing a non-existent

key makes its value an empty Array

names = Hash.new { |h,k| h[k] = [] }

File.open(‘people’, ‘r’) do |f|
f.each do |name|
name.chomp! # remove the line-ending
# so “first.mi.last” will be [“first”, “mi.last”]
first_name, last_name = name.split(‘.’, 2)
names[last_name] << name
end
end

Anyhoo I’d appreciate comments on my specific dynamic variable
problem or any other pointers
to help my get to the “AH HA!” moment with constructing and using
classes which I feel I’m pretty close to.
TIA. G

ps: I own many ruby books and have spent about 20 hours trying to
solve this pretty basic situation and dont know where else to go for
help.

Then you just need to create the output. A simple way to
check in irb (you do use irb, right?) might be:

names.each {|last,ary| puts “#{last}:\n #{ary.join(”\n “)}” }

But, if you need to remove all the existing files in the
directory and write out new ones, you’ll want something like:

(note that I’ve assumed that the ‘people’ file and the script
itself live in a directory other than where you’ll put the
lastname files [which is a subdirectory I called ‘work’])

#!/usr/bin/env ruby -w
names = Hash.new { |h,k| h[k] = [] }

File.open(‘people’, ‘r’) do |f|
f.each do |name|
name.chomp!
# so “first.mi.last” will be [“first”, “mi.last”]
first_name, last_name = name.split(‘.’, 2)
names[last_name] << name
end
end

Dir.chdir(‘work’) do |d|
File.delete(Dir[''])
names.each do |last,ary|
File.open(last, ‘w’) do |lname|
lname.puts ary.join(“\n”)
end
end
end

END

Now, that doesn’t deal with a new class of your own making, but you
don’t really seem to need anything beyond some standard classes
(Hash, Array, File, Dir). This should give you plenty to think (and
flip through your Pickaxe) about.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

On Jun 28, 2007, at 8:05 PM, Igor Sutton Lopes wrote:

On Jun 28, 2007, at 8:53 PM, Rob B. wrote:

create a Hash where referencing a non-existent

key makes its value an empty Array

names = Hash.new { |h,k| h[k] = [] }

Can I assume this is equivalent to perl’s autovivification?

Basically. If you just had:

names = Hash.new

then referencing non-existent keys gives nil, but they still do not
exist.

names[‘joe’] << ‘hello’

would give an error trying to call nil.<<(‘hello’)

By assigning to h[k], that key is created in the ‘names’ hash with
the indicated value (an empty Array in this case).

It’s about the same as:

names = Hash.new # or just names = {}
(names[‘joe’] ||= []) << ‘hello’

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

I also have many Ruby books and had a similar issue picking up
OOP.
I’m still very noob, but things are getting better and I’ve implemented
classes finally that serve a useful purpose. Unfortunately none of the
Ruby
books I’ve seen are any good at teaching OOP principles. They seem to
give
you a shallow introduction to the subject and then head straight to what
I
considered advanced OOP topics without showing very many practical
implications or reasons on why to do things. I understand the books are
written to teach Ruby, and not OOP but there just aren’t very many
programming books that take into account that not everyone is coming
from a
multi-language background with years of experience. I have the “Way”,
and
the “Axe” book. I find myself constantly poring over both and not find
any
example of things I need to do. Lots of experimentation has lead me to
by
best understanding of Ruby and OOP so far.

I can offer one resource I did find useful though.

http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/chapter_3_section_1.html

Low and behold. A “free” reference from Apple that I stumbled upon
teaching
OO concepts for people interested in Objective-c. I don’t actually
write
anything in Obj-c, but I did find this to be the best intro to OO so
far.
If anyone has any suggestions on a good OO book to read please tell.

  • Nathan

On Jun 28, 2007, at 9:16 PM, Rob B. wrote:

would give an error trying to call nil.<<(‘hello’)

By assigning to h[k], that key is created in the ‘names’ hash with
the indicated value (an empty Array in this case).

It’s about the same as:

names = Hash.new # or just names = {}
(names[‘joe’] ||= []) << ‘hello’

Thanks for your explanation!

On Jun 28, 2007, at 8:53 PM, Rob B. wrote:

create a Hash where referencing a non-existent

key makes its value an empty Array

names = Hash.new { |h,k| h[k] = [] }

Can I assume this is equivalent to perl’s autovivification?

I have to add to the list, Peter C.'s book, Beginning Ruby, is a
pretty gentle intro as well.
Consider yourself lucky, Ruby makes most things objects already, so
you don’t need to immediately create any classes yourself.
You can just play around with the existing objects and see how they
work and relate to eachother. irb is great for this, because you can
ask objects what they can do and who their parents are!

I have to disagree about Apple’s OOP intro for Objective-C. I had a
hard time with it. There is a good book on Objective-C from Stephen
Kochan, and it gives a pretty decent OOP intro, but not as good as
what’s in the Ruby books out there.

I’ve found that Ruby made OOP a lot easier to understand and
consequently makes other OOP languages make more sense to me.

Other OOP languages usually come a lot easier with a background in C
(Objective-C , Java, C++, etc…)

In my humble opinion, if you learn Ruby and C, the others will come a
lot easier!

hi
I Found this site very helpful when it came to understanding OO concepts
for
Ruby
http://poignantguide.net/ruby

hope this is useful

Hi,

I believe Chris P.'s “Learning to program” has been suggested as an
excellent introduction to OO programming. You might want to have a
look.

My short introduction to OO programming would go like this: describe
your problem in prose. Identify important nouns, these are likely
candidates for classes. Then go from there and find out how they have
to interact.

On 29.06.2007 00:43, [email protected] wrote:

I’ve scaled down my project to the most basic components that will
still allow me to express my areas of confusion. I have a file that
changes daily which contains a list of people in this format

So there we have the first noun that sounds like a candidate for a
class: “people” (or as a singular “person”). Apparently a Person has at
least two attributes, namely “last name” and “given name”.

You can create a person class pretty easily using Struct like this:

Person = Struct.new :given_name, :last_name

insert the updated list. I’ve got the script that does this it is
not very efficient (ie: i must define all the last names in
advance). So now i’ve started to rewrite the script and this is
where I’m stuck

So this pretty much gives an outline of the algorithm:

  1. read the updated list file and parse full names, remember persons in
    a smart way (for fast access)

  2. read the list of surname files

  3. delete all surname files where you do not have a person for

  4. recreate all surname files

Of course, other implementations would be possible. If you go with this
one way would be to create functions or methods for each of these steps
above.

You could, for example, place the reading of the name file into class
Person as a class method:

def Person.parse_persons(io)
persons = Hash.new {|h, k| h[k] = []}

io.each do |line|
if /^(\w+).(\w+)$/ =~ line
pers = new $1.lower, $2.lower
persons[pers.last_name] << pers
end

end
persons
end

This will return a Hash with last_names as keys and Person instances as
values. That way you retain all the information and can use it later
for the file deletions and creations.

Alternatively you could create a second class Persons and implement the
parse method and all other methods in that class). Maybe there is an
even better way to do it - could be that we do not yet know the whole
story and your script has to do other tasks as well.

Just some food for thought. HTH

Kind regards

robert

Hi, welcome!

"I want to improve my skills and try to leverage the language instead of
just
brute forcing my way through problems. "

When i started on ruby, i was mostly doing php-style.

I had 0 classes, i used a lot of functions (in php), and i used a lot of
global vars as well.

However over the time I started to use classes everywhere. It makes the
code cleaner in my experience. You will surely find your personal style.
As a rule of thumb, these things helped me in ruby:

  • Only because a certain feature exists, you do not really have to use
    it if you arent sure about a use case. For me it was with lambda :wink: and
    one more were
    class variables (which I personally do not use. Less complexity is
    easier for me to manager, and i am not sure why to use a class var
    anyway)

  • Use namespaces! Many wrap their classes inside a module, but I find
    even a standalone module without a class totally neat.

  • Consistent code layout :slight_smile: tabs or spaces doesnt matter ( i use 2
    spaces…) as long as you stick to it

  • Back to your first post, and I see a user wrote that classes are not
    needed.
    I think it depends on your mind-set. For me, I write classes almost
    everywhere these days. It may be a little extrawork but I felt that
    wrapping methods to classes (or modules) is really nicer on the long
    run. I keep reusing my own code stuff in other apps i write

  • About attr_accessor :first, :last etc… i recommend to write all
    attr_'s in one place… at best on “top” of your class ie

class Foobar
attr_reader :matz

I even do this:

attr_reader :matz
attr_writer :really
attr_accessor :rocks

just because I like visual code formatting, but i think most others
write
multiple :foo, :bar on one line… :wink:

PS: No matter how you end up writing code, I believe its very important
to
provide docu which EXPLAINS to others what you were doing. Especially
sometimes I end up seeing code of other people which is really hard to
understand, not so much because I dont understand everything (i still
learn a lot of new things) but more so because they do it IMHO in a
complex manner … this is hard to understand sometimes.

PSS: Just my 1 cc to it, hope you have FUN with ruby! There are many
ways but one way is always the best in a given situation :slight_smile:

PS: No matter how you end up writing code, I believe its very
important
to
provide docu which EXPLAINS to others what you were doing. Especially
sometimes I end up seeing code of other people which is really hard to
understand, not so much because I dont understand everything (i still
learn a lot of new things) but more so because they do it IMHO in a
complex manner … this is hard to understand sometimes.

Don’t document your code for other people, do it for yourself!!
You WILL FORGET what something does!
Especially, when you’re new at it.
So don’t be afraid to over document in the beginning.
It takes time to develop a documentation style that is concise but
still clear.
Eventually, you will document less because Ruby is very readable, but
always say what a variable or object is supposed to do, what it
recieves, what it returns, and maybe even why.
Same for functions or code blocks. Refactoring code, basically
creating functions and blocks and classes that compartmentalize/
modularize code, is very good for you and for your code, but after it
grows, it will become harder to put it all together mentally.

  • Consistent code layout :slight_smile: tabs or spaces doesnt matter ( i use 2
    spaces…) as long as you stick to it

It does matter. The ruby standard is 2 spaces.

Aur

On Jul 1, 2007, at 12:36 PM, Chad P. wrote:

On Mon, Jul 02, 2007 at 02:25:22AM +0900, John J. wrote:

Don’t document your code for other people, do it for yourself!!
You WILL FORGET what something does!

When you come back to your code later, you are a different person.

Perhaps. This is a philosophical joke that could run in circles

“how” and comments should tell us “why”, then.
Not necessarily. If somebody is really just starting out, comments
are notes to self about how and why.

On Mon, Jul 02, 2007 at 02:25:22AM +0900, John J. wrote:

Don’t document your code for other people, do it for yourself!!
You WILL FORGET what something does!

When you come back to your code later, you are a different person.

Especially, when you’re new at it.
So don’t be afraid to over document in the beginning.
It takes time to develop a documentation style that is concise but
still clear.
Eventually, you will document less because Ruby is very readable, but
always say what a variable or object is supposed to do, what it
recieves, what it returns, and maybe even why.

I take it you don’t subscribe to the notion that code should tell us
“how” and comments should tell us “why”, then.