[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: Classes and OO design - help

Tony Mobily

2/21/2006 8:59:00 AM

Hi,

> Not really on the low level, short of starting the garbage
> collector. You'd
> call the deletion method explicitly.

OK.

> Or plain keep this bit in the initializer as it was, the value is
> bound to be
> used anyway. Keeping the path generation bit where it's used seems
> a taaad
> bit cleaner to me.

True. I did some testing, the overhead is negligible.

> Wouldn't call it messy. Either way works, depends on how you use
> the objects.
> If you're can handle the difference between creating new records
> and loading
> old ones cleanly, it's fine.

OK.

> I think ActiveRecord only requires explicit saves on newly created
> objects and
> makes modifications to existing records transparently as you intend.

OK.

>>> Yes. This class could also store the data directory path and manage
>>> the
>>> lifecycle of Subscriber objects, reducing those to only data
>>> retrieval /
>>> caching.
>> You mean with something like:
>> sub_container=SubscribersContainer.new()
>
> A particularly sick thing to do would be making SubscribersContainer a
> singleton and then delegate calls to the class object to the single
> instance.
> Not really useful though.

I don't have enough experience in Ruby to even understand why you'd
do that, or when it would make sense to create singleton classes.
In fact: when does it make sense to mix a class with Singleton?

>> sub_container['merc'].name="tony"
>>
>> ...?
>> When the method [](email) is called, the object SubscribersContainer
>> would need to create a new object (if necessary), or return the one
>> already created at some point in the past. Is that right?
> I'd still keep the creation and loading as separate operations to
> avoid
> clobbering some data by mistake when thinking you're making a new
> record.

Wooops... Maybe we had a misunderstanding here? I meant that
sub_container['merc'] would need to create a new *object* (of type
Subscriber) and link it to the file system. I wasn't thinking about
creating a new record on disk.
So, my question was: if each one of these calls:

p sub_container['merc'].name
p sub_container['dave'].name
p sub_container['bridget'].name
p sub_container['anna'].name

Allocates a Subscriber object in the collection, after 14000 I'd have
allocated 14000 Subscriber objects.

Or maybe my understanding of containers is still far too poor to
follow you properly.

> There are other ways to preventing that though, like providing a
> method to
> check whether a given record exists.

OK.
Right now, I must admit I have no idea where I'd start creating a
container.

>> I am not sure why you say that this class would need the data
>> directory...!
> Well, I thought of this class providing the created Subscriber with
> the full
> record path and the e-mail address when creating the object. That
> way, you'd
> keep the what's stored where bit out of the Subscriber class.
>
> You could also determine / change the config file directory at
> runtime from a
> parameter to the application more intuitively
> (SubscriberContainer.new("/path/to/record/directory/") instead of
> hardcoding
> it or manipulating class variables), or even have several
> containers - even
> if this would probably be rarely useful.

Very true.

> Last, but not least, at least to me it makes more sense for the
> container to
> have the information where its contents are stored.

You're completely right.
Now that I have a better understanding of scoping, this makes sense.

>> Also, I wonder if accessing too many objects that way wouldn't
>> clutter the collection too much (the "real" number of subscribers we
>> have is about 14000. I KNOW we need a DB. We didn't expect quite so
>> many. I am planning to switch to DB)
> You wouldn't have to actually store the retrieved object in the
> container
> after creation / loading, just have the container do this work and
> dumb down
> the Subscriber storage to data transfer and mutation, those being
> ignorant to
> as much context as possible.

But this would surely mean that "Subscriber" is not really usable
without the container... wouldn't it?
(maybe that's not a problem?)

>>> If you wanted to go extreme, you could also separate the data
>>> retrieval part
>>> and keep subscribers only as dumb data structured, but I'd say it
>>> would only
>>> be deconstructing code for the sake of deconstruction, and more
>>> confusing
>>> than anything else in this case.
>>
>> I'll ask about this later...
>> The question will include the fact that I would like to make this
>> class "generic", so that in the future I can change it so that it
>> connects to a DB rather than reading the file system. At this point,
>> I am not sure what the right path is. Maybe create a subscribers
>> class, and then create a SubscriberFileSystem subclass which needs to
>> implement get_flag, set_flag, get_field, set_field...?
> For a SQL DB, I'd just skip the whole issue, use an ORM library
> like Og, port
> the code using Subscriber to it and not care about this bit.
> Possibly the
> easiest way if you can do an "instantaneous" migration between the
> filesystem
> backend and the SQL one.

OK.

> The very generic solution would be worth the effort if you had to
> use the two
> wildly differing backends simultaneously. In that case, I'd
> definately keep
> the "housekeeping" to a container class, have the Subscriber
> objects know
> what container they belong in, and have them call on the container
> to sasve
> changes to them to disc. This would also possibly let you relocate
> objects
> between containers if that was of any use at all. You'd probably
> want to
> store which field(s) was changed to avoid unnecessary file access
> with this
> approach.

OK.

>>> I'd say read through the Gang of Four and Refactoring,
>> Woops... I've lost you here. Are you talking about one specific book?
>> Or two books?
> Well, THE Refactoring book *cackle*. But Dave Cantrell already
> answered this
> perfectly. Gang of Four is a nickname of the four authors of the
> book. Not
> quite up-to-date as far as the patterns mentioned are concerned -
> there are
> already droves more that have been invented since. But I like the
> case study
> bit as an explanation that shows an example of quite a few of those
> applied
> in a single program.

OK.
I find that a lot of these books apply to Java or C++. Is there a
Ruby Patterns book out there?
If not... well, it *should* exist!

>> Well... here is the latest version of my class.
>> It would be fantastic if you could have a quick look at it, and let
>> me know if I actually got it right design-wise.
>> I haven't actually tested it properly - I am more interested in the
>> big picture for now...
>>
>> THANKS AGAIN!
>>
>> #!/usr/local/bin/ruby -w
>>
>> class Subscriber
>>
>> # Set the config file.
>> #
>> 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
> Very minor quibble: I don't quite like too much code executed
> inline in class
> definitions, and would probably move this along with all other
> application
> initialization into one place.

Where abouts?

> Quite possibly a matter of taste more than
> anything else though - since the code doesn't have side-effects,
> it's not
> likely to cause any obscure bug due to initialization timing.

OK.

>> @country=nil
>> @creation_date=nil
>> @name=nil
>> @password=nil
>> @postcode=nil
>> @premium_expiry_date=nil
>> @questionnaire_res=nil
>> @subscriber_code=nil
>> @subscriber_comments=nil
> This shouldn't be necessary. Reading uninitialized instance
> variables results
> in a nil by default.

This is me being me. It's nice to know WHAT instance variables are
there. I'm an obsessive compulsive, you see :-)
OK, comments exists for that reason...

>> def set_field(field,value)
>>
>> return nil if ! @email
>>
>> # Open the file
>> #
>> begin
>> ios=File::open(self.full_path
>> +field.to_s,"w")
>> rescue SystemCallError
>> return nil
>> end
>>
>
> You might not want to ignore the error here. It probably means
> something
> really, really unexpected happened - the only thing short of a
> kernel-ish
> problem, like a file system faliure or the file handle table
> filling up that
> could call an error in this I can imagine is that a file of the
> same name
> without the necessary write permissions exists, and that seems
> unlikely for
> this application. Either way, a SystemCallError sounds like a
> showstopper for
> me.

I wasn't sure about this bit, and you confirmed my fear.
Thanks a lot!
I added a "raise" there.

>> # 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)
>> #
>> begin
>> ios.print(value)
>> rescue SystemCallError
>> ios.close
>> return nil
>> end
>>
>
> I'd merge this code block with the previous one, and possibly
> handle the
> exception somewhere else, reporting it to the user as a severe
> failure, and
> logging it. You could also use the block form of File::open here.

OK.
I didn't have logging abilities in the object right now. I have no
idea where to start, with that.
I also divided the block in two, because in the second half of the
code I close the file if there was a problem.
I can see that with the "block" in File::open I can do everything at
once...!

So, the function has become:

def set_field(field,value)

return nil if ! @email

# Open the file
#
begin
File::open(self.full_path+field.to_s,"w") do
|ios|
ios.print(value)
end
rescue SystemCallError
raise
return nil
end
value

end


> You'd end up cluttering the code with checks for nil all the time,
> which is
> only proper if you expect the issue to appear during more-or-less
> regular
> operation; e.g. for calls where a failure isn't abnormal.

OK.

> Same here as in the previous method, just let the SystemCallError
> pass up on
> the stack -it's probably not possible to gracefully recover from it.

OK.
I've just put "raise" there:

def set_flag(flag,value)

return nil if ! @email

if(value)
begin
File.open(self.full_path+flag.to_s,"w")
rescue SystemCallError
raise
end
return true
else
begin
File.delete(self.full_path+fiag.to_s)
rescue SystemCallError
raise
end
return false
end
end

Well, the only obscure bit now is how to make this "containable".
It's probably not necessary, because the class works well "as it is".
However...

OK, I am assuming that to make the container, basically I would have:

* A class called "SubscribersContainer". This class would have the
methods "country=", country(), and so on; those methods would all use
the methods set_field and get_field, NOT implemented in the container

* A class called SubscriberFS (which I have), which would ONLY
implement get_field, set_field, get_flag, set_flag. These methods
will be used by the container to do the "real" work

* I could also have a class called SubscribersDB, which would do the
same things but connecting to a database

However, I have so many questions in this case... For example,
SubscribersDB would need far more information than just a path (like
SubscribersFS). Where would this information be stored? What if it
changed?
And what would actually *happen* when I did Subscriber
['merc2@mobily.com'].name="Tony", data-wise?

I feel I am out of my leagues here.


If you have time, David (or anybody else), I would love it if you
could write a basic skeleton for the two classes - something that
would make me understand what goes where.
However, I feel I am abusing of your time. So... let's say that I'm
not expecting it!

Bye,

Merc.


1 Answer

Ron Hamilton

9/1/2009 3:02:00 AM

0

Science@Science.com wrote:
> On Mon, 31 Aug 2009 13:41:35 -0700, Wilson Woods
> <banmilk@hotmail.com> wrote:
>
>> Science@Science.com wrote:
>>> On Mon, 31 Aug 2009 07:20:19 -0700, Wilson Woods
>>> <banmilk@hotmail.com> wrote:
>>>
>>>>> If it didn't mitigate and help alleviate racism and
>>>>> discrimination---why are you whining about it?
>>>> Because it *IS* racist and discriminatory
>>>
>>> Without the law----you get to discriminate at will
>> No, that's a lie. "affirmative action" has nothing to do with laws
>> forbidding discrimination.
>
> Sure they do.

No, it doesn't.


> Forces the white power structure to aid in promotion of
> equality and less discrimination

No, it doesn't. "affirmative action" *is* discrimination, and it
epitomizes *inequality*.

You're just wrong.