From: Jamey Cribbs Date: 2006-03-05T03:04:16+09:00 Subject: Re: Kirbybase Hacks NilClass Jamey Cribbs wrote: > dblack@wobblini.net wrote: > >> Hi -- >> >> On Sun, 5 Mar 2006, James Edward Gray II wrote: >> >>> I'm examining Kirbybase for use it a project and was surprised to >>> find this bit of code in it: >>> >>> #--------------------------------------------------------------------------- >>> >>> # NilClass >>> #--------------------------------------------------------------------------- >>> >>> class NilClass >>> >>> def method_missing(method_id, *stuff) >>> return nil >>> end >>> end >>> >>> This has been a popular discussion lately, but I just don't think >>> loading a database library should fundamentally change the >>> language. ActiveRecord doesn't hack NilClass and we seem to do okay >>> with that. Why can't the above example just be coded as: >>> >>> select { |r| r.speed and r.speed > 300 } >>> >>> or: >>> >>> select { |r| r.speed > 300 rescue false } >> >> >> >> Or, depending on circumstances: r.speed.to_i > 300. I would ... > > > Thanks very much for the feedback on my overriding > NilClass#medthod_missing in KirbyBase. I don't think the three > examples shown above would really be acceptable, because, could you > imagine having to do this for every query where there was a chance > that a #method_missing could be thrown? I think that would get old > very fast. > > However, the last example does give me an idea. I'm going to take a > look at the KBTable#select method and see if I can wrap the query > processing logic in a begin/rescue block. It may be as simple as what > David shows here, have the rescue return false. The problem I can see > is when there is an OR condition in the block, i.e.: > > #select { |r| r.speed > 300 or r.range < 900 } > > Now, here's a *very* simplified version of KBTable#select, with a > proposed adding of a begin/rescue block around the query instead of > the current redefining of NilClass#method_missing: > > def select(&query_block) > valid_matches = [] > table_records.each do |table_record| > begin > if query_block(table_record) > valid_matches << table_record > end > rescue NoMethodError > end > end > end > > Now, lets say we are looping through the table records and we get to a > record where :speed is nil and :range is 800. According to the query > block, this record should qualify as a valid match. But, if I don't > override NilClass#method_missing to return fasle, but, instead, try to > catch it with a begin/rescue block like I show in the code above, the > record will *not* be added to valid matches. The problem with the > code above is that I can't get granular enough. There is no way to > get inside the query block and put a begin/rescue around *each* > condition within the block. > If I could get enough info about the calling method, when I'm inside > NilClass#method_missing, then maybe I could conditionally return a > false only when it was apparent that the #method_missing exception was > raised in KBTable#select. But, the arguments passed into > #method_missing are the symbol of the method, in this case :> and an > array containing the arguments passed to the missing method, in this > case [300]; not enough info for me to determine if this came from > KBTable#select. > > I would be very interested in any suggestions, ideas, or feedback on > this issue. Hey, I think I will just respond to myself with a suggestion. :-) What has been kicked around when this question has come up before is for me to create something like a NULL class and use this to designate a null value in the database, instead of using nil. This would take care of having to override NilClass#method_missing. It would bring up a few other problems, namely, what if someone wants to store the string value NULL in a field. But I imagine these could be overcome. If this is indeed a really big issue (meaning KirbyBase's overriding of NilClass#method_missing), then I could get to work on this. Thoughts? Jamey