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?
you could use enums : it's easy enough to do clearly in ruby
http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/6f37e998434e65e5/ea5a7cc77156ee36?q=ara+howard+enum&rnum=1#ea5a7cc77156ee36
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.
i often do something like this:
harp:~ > cat a.rb
class C
module RATING
LIST = [
GOOD = 'GOOD',
FAIR = 'FAIR',
POOR = 'POOR',
]
end
RAITINGS = RATING::LIST
end
p C::RATING::GOOD
p C::RAITINGS
C::RAITINGS.each{|r| p r}
harp:~ > ruby a.rb
"GOOD"
["GOOD", "FAIR", "POOR"]
"GOOD"
"FAIR"
"POOR"
remember - the main reason to use ints for enums in c/c++ is to be able to use
'==' with the variables but a language like ruby can do just as well with
strings.
puts "*** Warning: Rating below Fair ***" if rating < RATING_FAIR
Thoughts?
in any case, reading over your description i'd be inclined to wrap Raitings as
as objects and design a class generator that sets appropriate constants to
configurable raitings, something like:
harp:~ > cat a.rb
module RuleSet
class Raiting
include Comparable
attr 'description'
attr 'value'
def initialize d, v
@description, @value = String(d), Float(v)
end
def <=> other
ov = other.value rescue other
value <=> ov
end
def to_s
"#{ description }(#{ value })"
end
alias inspect to_s
end
module ClassMehods
attr 'raitings'
def inspect; raitings.inspect; end
def to_s; raitings.inspect; end
end
module InstanceMethods
end
class << self
def new(spec = {'good' => 0.8, 'fair' => 0.5, 'poor' => 0.2,})
klass = Class::new {
include InstanceMethods
extend ClassMehods
@raitings =
%w( good fair poor ).each do |k|
c = k.upcase
ks = k.to_s
ki = ks.intern
keys = [k, ki, ks.downcase, ks.upcase]
v = nil
keys.each{|k| v = spec[k] and break}
r = Raiting::new k, v
const_set c, r
@raitings << r
end
}
end
alias new
end
end
rule_set = RuleSet::new
p rule_set::raitings
p(rule_set::GOOD < 42)
p rule_set::GOOD.description
p rule_set::GOOD.value
rs =
RuleSet[
:good => 42,
:fair => 41,
:poor => 40,
]
p rs
p(rs::GOOD == 42)
harp:~ > ruby a.rb
[good(0.8), fair(0.5), poor(0.2)]
true
"good"
0.8
[good(42.0), fair(41.0), poor(40.0)]
true
hth.
-a
···
On Sun, 28 Aug 2005, David Brady wrote:
--
email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna
===============================================================================