# Class behaviour

**URL:** <https://www.ruby-forum.com/t/class-behaviour/67358>\
**Category:** Ruby\
**Created:** [September 2, 2006, 7:31pm UTC](https://www.ruby-forum.com/t/class-behaviour/67358 "2006-09-02T19:31:48Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![glub](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/e480ec/32.png) [@glub](https://www.ruby-forum.com/u/glub)\
**Post date:** [September 2, 2006, 7:31pm UTC](https://www.ruby-forum.com/t/class-behaviour/67358/1 "2006-09-02T19:31:48Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![glub](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/e480ec/32.png) [@glub](https://www.ruby-forum.com/u/glub)\
**Post date:** [September 2, 2006, 8:06pm UTC](https://www.ruby-forum.com/t/class-behaviour/67358/2 "2006-09-02T20:06:54Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![glub](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/e480ec/32.png) [@glub](https://www.ruby-forum.com/u/glub)\
**Post date:** [September 2, 2006, 8:51pm UTC](https://www.ruby-forum.com/t/class-behaviour/67358/3 "2006-09-02T20:51:01Z")

</div>

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
```

---

<div class="post-metadata">

**Author:** ![glub](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/e480ec/32.png) [@glub](https://www.ruby-forum.com/u/glub)\
**Post date:** [September 2, 2006, 10:00pm UTC](https://www.ruby-forum.com/t/class-behaviour/67358/4 "2006-09-02T22:00:46Z")

</div>

Perfect, thanks for the ideas. Makes sense…

---

<div class="post-metadata">

**Author:** ![glub](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/e480ec/32.png) [@glub](https://www.ruby-forum.com/u/glub)\
**Post date:** [September 2, 2006, 8:57pm UTC](https://www.ruby-forum.com/t/class-behaviour/67358/5 "2006-09-02T20:57:01Z")

</div>

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.
