Hello Everybody,

First of all, thank you so much for participating to this list and  
help poor Ruby newbies like me!

I feel the need to start this email with an apology. I am a terrible  
programmer.
Ruby is the only thing that could possibly convince me to start  
programming again. I hadn't fallen in love with a computer language  
in a _long_ time!

I can say that I "know" Ruby. I have a very good memory, which helped  
me along the way. I don't know it well, and I lack the necessary  
experience to be comfortable with it, but I "know" it.

However, I am absolutely hopeless at *designing* anything in terms of  
objects and OOP. This is why I have the feeling I am just about to  
embarrass myself. But hey...

I started writing my first "real" program in Ruby, and here I am,  
thinking: is this correct? Would a "real" programmer do this like way?

So, here I am. I have a file system, with the following contents:

[...]/A/
[...]/B/
[...]/C/
[...]/D

Under /A/, there is:

/A/abcexample / iinet.net.au/

In each directory, there are the following files:

name
surname
password
state
unconfirmed_flag
moderator_flag <-- The file can exist (flag = true ) or not exist  
(flag = false)

I know there are much better ways of doing so, and that this approach  
creates a lot of tiny files, but unfortunately, at least for now, I  
am stuck with it.
If you are curious, this is how the subscribers' information is  
stored for Free Software Magazine (http://www.freesoftwaremagazine.com).

I wrote (see: I didn't write "designed"! :-) ) a class to access this  
information on the file system.

Here it is:

---------------------------------------------------
#!/usr/local/bin/ruby -w

class Subscribers

         # Get the config file's contents
         #
         begin
                 @@config_data_dir=IO.read("#{ENV['HOME']}/.subs/ 
data_dir")
                 @@config_data_dir.chomp!
         rescue SystemCallError
                 STDERR.puts("WARNING! Can't find the config file!");
                 @@config_data_dir=""
         end

         def initialize()
                 @good_state=false # This might be completely useless
                 @first_letter=""
                 @full_path=""
                 @attr_values={}
         end


         # This is the same as initialize... for now!
         # (who knows...)
         #
         def de_initialize
                 @good_state=false
                 @first_letter=""
                 @full_path=""
                 @attr_values={}
         end

         # This just checks that the directory actually
         # exists. It creates a "link"
         #
         def link_to_fs(email)

                 # Gets the person's information
                 #
                 @good_state=true
                 @first_letter=email[0,1].upcase
                 @full_path=@@config_data_dir+"/current/"+
                                 @first_letter+"/"+email+"/"
                 @attr_values={}
                 @attr_values[:email]=email

                 # Hang on: if the file doesn't exist, undo everything
                 #
                 if ! File.exist?(@full_path)
                         de_initialize()
                         return false
                 end

                 true

         end

         def get_flag(flag)
                 File.exist?(@full_path+flag.to_s)
         end

         def get_field(field)

                 # Email is special: it's not in a file
                 #
                 if( field == :email)
                         return @attr_values[:email]
                 end

                 # Either return the existing @attr_values[field], or
                 # (if it's nil) reads it from the file system.
                 # CACHE!
                 #
                 begin
                         @attr_values[field]||=IO::read(@full_path 
+field.to_s)
                 rescue SystemCallError
                         nil
                 end

         end


         def set_field(field,value)

                 # Email cannot be set
                 #
                 if(field == :email)
                         return nil
                 end


                 # Open the file
                 #
                 begin
                         ios=File::open(@full_path+field.to_s,"w")
                 rescue SystemCallError
                         return nil
                 end

                 # Set the value to nil. This is to reflect the
                 # "real" state of the variable (the file has just been
                 # cleared up by the previous call)
                 #
                 @attr_values[field]=nil

                 begin
                         ios.print(value)
                 rescue SystemCallError
                         ios.close
                         return nil
                 end

                 # OK, it worked: assign the new value
                 #
                 ios.close
                 @attr_values[field]=value
         end

         def set_flag(flag,value)
                 # NOT DONE YET. Ask the mailing list if I wrote a pile
                 # of crap first... :-|


         end

	# TODO: methods to create a new entry (just creates the directory),
	# methods to get ALL of the parameters in one go in a Hash, etc.

end


a_subscriber=Subscribers.new()
puts a_subscriber.link_to_fs("merc2 / mobily.com")
puts a_subscriber.get_field(:email)
puts a_subscriber.get_flag(:premium_flag)
puts a_subscriber.get_flag(:moderator_flag)
puts "OK:"
puts a_subscriber.set_field(:name,"BLAH!!!")
puts a_subscriber.get_field(:name)

----------------------------------------------------------

Now... here are my questions:

* Is it sane for the class to set the class variable  
@@config_data_dir? @@config_data_dir=IO.read("#{ENV['HOME']}/.subs/ 
data_dir")

* Would it make more sense to create a new person with the  
method ::new? In this case, what would you call the method to access  
an existing person?

* Is this solution OO sound?

I can't think of a way, in Ruby, to do access the information like  
this: a_subscriber.get_field[:name] or a_subscriber.get_flag 
[:moderator_flag]. This is the tricky part, and that's where my lack  
of understanding of OOP shows blatantly.

a.subscriber.get_field[:name] is the equivalent of saying  
a.subscriber.get_field.[](name)

This implies that get_field returns an object of some kind able to  
respond to []. If this were the way to go design-wise (which I doubt,  
but now I am confused, so...), where would such an object be created?  
How would it access the class information such as @@config_data_dir,  
or the subscriber's instance variable?

* I am thinking about a container class for this:  
SubscribersContainer. The class would implement the method each(), so  
that I can scan through the list of people stored (creating a  
Subscriber object for iteration). Is this a sane approach?


I am just a little scared of doing anything right now. Did I design  
it all wrong? Should I have created the classes SubscribersFlags and  
SubscribersAttributes, and have two instance variables in Subscribers  
derived from SubscribersFlags and SubscribersAttributes?

* The most important of all: can you suggest a book or a web site  
which would help me design more decent classes? Possibly something  
that is Ruby-centric...

Thanks a lot!

Merc.