[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Class behaviour

Geoff Barnes

9/2/2006 5:32:00 PM

Just curious, can I write a class that can check values as they are
assigned to objects?

foo = Klass.new
foo.legal_values = (4..10)

foo.value = 5 # OK
foo.value = 11 # ERROR - out of bounds, raise exception or something

Also, do I have to have an explicit method for the 'value', or can it
operate like a "builtin" class, like this :

foo = Klass.new
foo.legal_values = (4..10)

foo = 5 # OK
foo = 11 # ERROR - out of bounds, raise exception or something

In Perl, I would probably use tiescalar for something like this, where I
can intercept an assignment...

Also, it may not be numbers, but enums as well.

Thanks.

--
Posted via http://www.ruby-....

4 Answers

Paul Lutus

9/2/2006 5:57:00 PM

0

Geoff Barnes wrote:

> Just curious, can I write a class that can check values as they are
> assigned to objects?

Sure, just declare accessors in the usual way, then write your own methods
to check the values:

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

#!/usr/bin/ruby

class Suspicious
attr_accessor :a
def a=(v)
raise "Number Range Error" if v < 0 || v > 5
@a = v
end
end

s = Suspicious.new

s.a = 10 # number range error

puts s.a # never gets here

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

--
Paul Lutus
http://www.ara...

Robert Klemme

9/2/2006 6:47:00 PM

0

Geoff Barnes wrote:
> Just curious, can I write a class that can check values as they are
> assigned to objects?
>
> foo = Klass.new
> foo.legal_values = (4..10)
>
> foo.value = 5 # OK
> foo.value = 11 # ERROR - out of bounds, raise exception or something

You can define a special class method as a replacement for attr_accessor:

class Module
def checked_attr(name,&test)
define_method("#{name}=") do |val|
test[val] or raise ArgumentError
instance_variable_set "@#{name}", val
end

attr_reader name
end
end

class T
checked_attr :foo do |x|
x >= 0
end
end

irb(main):018:0* t=T.new
=> #<T:0x392088>
irb(main):019:0> t.foo = 10
=> 10
irb(main):020:0> t.foo = -10
ArgumentError: ArgumentError
from (irb):4:in `foo='
from (irb):20
from :0
irb(main):021:0>

> Also, do I have to have an explicit method for the 'value', or can it
> operate like a "builtin" class, like this :
>
> foo = Klass.new
> foo.legal_values = (4..10)
>
> foo = 5 # OK
> foo = 11 # ERROR - out of bounds, raise exception or something

You cannot interfere here so there is no way to check these assignments.

> In Perl, I would probably use tiescalar for something like this, where I
> can intercept an assignment...
>
> Also, it may not be numbers, but enums as well.

I'm not sure I understand you here.

Kind regards

robert

Gavin Kistner

9/2/2006 6:51:00 PM

0

Geoff Barnes wrote:
> foo = Klass.new
> foo.legal_values = (4..10)
>
> foo.value = 5 # OK
> foo.value = 11 # ERROR - out of bounds, raise exception or something

Do you want the legal values to be different per instance, or set for
the whole class?
Here are two options:

class Klass
class << self
attr_accessor :legal_values
end

attr_reader :value
def value=( new_value )
if value_range = self.class.legal_values
raise "Out of Range" unless value_range.include?( new_value )
end
@value = new_value
end
end

foo = Klass.new
bar = Klass.new
Klass.legal_values = 4..10

foo.value = 8
puts foo.value #=> 8

bar.value = 17 #=> RuntimeError: Out of Range


class Klass
attr_accessor :legal_values
attr_reader :value

def value=( new_value )
if @legal_values
raise "Out of Range" unless @legal_values.include?( new_value )
end
@value = new_value
end

def legal_values=( new_range )
raise "Value outside Range" if @value && !new_range.include?( value
)
@legal_values = new_range
end
end

foo = Klass.new
foo.legal_values = 4..10

foo.value = 8
puts foo.value #=> 8

bar = Klass.new
bar.value = 200
puts bar.value #=> 200

bar.legal_values = 1..10 #=> RuntimeError: Value outside Range



> Also, do I have to have an explicit method for the 'value', or can it
> operate like a "builtin" class, like this :
>
> foo = Klass.new
> foo.legal_values = (4..10)
>
> foo = 5 # OK
> foo = 11 # ERROR - out of bounds, raise exception or something

No, you can't do this - there is no assignment method (=) that you can
override to do something different. "foo = 5" will always change the
local variable 'foo' to point to a Fixnum of 5.

Geoff Barnes

9/2/2006 8:01:00 PM

0

Perfect, thanks for the ideas. Makes sense...

--
Posted via http://www.ruby-....