On 28/08/05, David Brady <ruby_talk / shinybit.com> wrote:
> Okay, one more question from a C++ leopard trying to change his spots:
> 
> I want to set up a program that uses some predefined values to determine
> its logic.  For example, a method could analyze some data and return
> "Good", "Fair", "Poor", or "Out of Bounds" based on a set of
> thresholds.  I want to be able to refer to these values by name in my
> code, so constants or symbols make a good choice here.  But I also want
> to build a sort of rule set around these values: some function returns
> values in the range of (0.0..1.0) and I want to be able to say that 0.8
> is the minimum score for "Good", etc.  I also want the word "Good"
> stored in a specific single place so that I don't make any typos each
> time I need to print the description.
> 
> In C++, I would use an enum for each of the values, then build arrays of
> floats and strings indexed by those enums to hold the thresholds and
> descriptions.
> 
> What's the Ruby idiom for this?
> 
> Perhaps Struct followed by some initializer arrays?  This seems like a
> good start but I end up wanting to build a set of constants first to use
> as keys to a hash containing the Structs.  Perhaps the Structs should be
> the constants themselves, like:
> 
> Struct.new("RatingData", name, threshold, description)
> 
> RATING_GOOD = Struct::RatingData( :Good, 0.8, "Good Rating" )
> RATING_FAIR = Struct::RatingData( :Fair, 0.5, "Fair Rating" )
> 
> ...etc.  The analyze_data could return RATING_GOOD if things were fine.  So:
> 
> rating = analyze_data data
> puts "Analysis: #{rating.description}"
> 
> Though this doesn't let me treat the values as though they are ordered, e.g.
> 
> puts "*** Warning: Rating below Fair ***" if rating < RATING_FAIR
> 
> Thoughts?
> 

Simply expanding on your thoughts:

--------8<--------8<--------
module RATING
  RatingData = Struct.new(:name, :threshold, :description)

  class RatingData
    include Comparable

    def <=>(o)
      if o.respond_to?:threshold
	self.threshold <=> o.threshold
      else
	self.threshold <=> o
      end
    end
  end
  
  GOOD = RatingData.new( :Good, 0.8, "Good Rating" )
  FAIR = RatingData.new( :Fair, 0.5, "Fair Rating" )
  POOR = RatingData.new( :Poor, 0.2, "Poor Rating" )
end

rating = RATING::POOR
puts "Analysis: #{rating.description}"

puts "*** Warning: Rating below Fair ***" if rating < RATING::FAIR
--------8<--------8<--------

would be a possibility. Throw in some metaprogramming and it can get
really nice.

regards,

Brian

-- 
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/