[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Passing a block into a class_eval

Clifford Heath

2/17/2007 2:22:00 AM

Here's a function similar to attr_accessor, except it takes a block,
which is used to validate assignments to the attribute, and substitute
in a string value to be used as a key to the hash inside class_eval.

It's just ugly having to use a hash to store the block. class_eval and
friends should support saving parameters into global variables for the
duration? Or is there an obvious way of doing this that I've missed?
I removed some checking for simplicity.

Clifford Heath.

def validated_attr(*names, &block)
begin
Thread.critical = true
$__VALIDATOR_BLOCK ||= {}
while $__VALIDATOR_BLOCK.has_key?([r = (rand*16777216).to_i]); end
$__VALIDATOR_BLOCK[r] = block
ensure
Thread.critical = false
end

names.each{|name|
class_eval <<-END
def #{name}
@#{name}
end
def #{name}=(__val)
if !$__VALIDATOR_BLOCK[#{r.to_s}.to_i].call(__val)
throw "Invalid assignment of \#{__val.inspect} to #{name}"
end
@#{name} = __val
end
END
}
end

class Foo
validated_attr(:bar) {|v| v.kind_of?(Integer) && (0..14).include?(v)}
end

f = Foo.new

begin
f.bar = 2 # Ok
rescue => e
puts e.to_s
end

begin
f.bar = 15 # Not ok
rescue => e
puts e.to_s
end

begin
f.bar = "Hi there" # Not ok
rescue => e
puts e.to_s
end
14 Answers

Austin Ziegler

2/17/2007 2:50:00 AM

0

On 2/16/07, Clifford Heath <no@spam.please.net> wrote:
> Here's a function similar to attr_accessor, except it takes a block,
> which is used to validate assignments to the attribute, and substitute
> in a string value to be used as a key to the hash inside class_eval.

Ruby 1.9 accepts blocks as parameters to blocks.

-austin
--
Austin Ziegler * halostatue@gmail.com * http://www.halo...
* austin@halostatue.ca * http://www.halo...feed/
* austin@zieglers.ca

Clifford Heath

2/17/2007 2:52:00 AM

0

Austin Ziegler wrote:
> Ruby 1.9 accepts blocks as parameters to blocks.

I can't immediately see how that solves this problem...?
I need to create a string to eval so I can fabricate the
method names, and I want a block to be available within
that eval. Can you show a quick example?

dblack

2/17/2007 3:16:00 AM

0

Clifford Heath

2/17/2007 3:30:00 AM

0

dblack@wobblini.net wrote:
> I guess my first take on it would be this:
> (using define_method rather than def so that the local variable block
> will still be in scope).

Excellent! I added the missing instance_variable_set and I'm away.
My full example has type checking, and whether nil is allowed.
Oh, and type-checked array attributes in the same fashion.
Will post soon... or is there an existing package to add this to?

class Foo
MAX = 14
typed_attr Integer, nil, :foo {|v| v <= MAX }
array_attr Range, :bar {|v| v.end+(v.exclude_end? ? 0 : 1) < MAX }
end

Clifford Heath.

Clifford Heath

2/17/2007 3:50:00 AM

0

Of course, that should be:

class Foo
MAX = 14
typed_attr(Integer, nil, :foo) {|v| v <= MAX }
array_attr(Range, :bar) {|v| v.end+(v.exclude_end? ? 0 : 1) < MAX }
end

Can't use a block without parenthesizing the params...

dblack

2/17/2007 4:16:00 PM

0

dblack

2/17/2007 11:43:00 PM

0

Clifford Heath

2/18/2007 4:08:00 AM

0

dblack@wobblini.net wrote:
>> My full example has type checking, and whether nil is allowed.
> I'll bet you mean class checking :-) But that's another (long)
> story....

It is. class checking is a limited form of type checking however, and
you can omit class checking and/or let the block can do whatever extra
type checking is needed. :-) It's nice to automatically allow/disallow
assignment of nil also.

Thanks for the note on do...end, I almost never use it, but this is a
rare case where having the same feature at a different precedence is
a good idea.

This is ready to be made a gem when I've done the unit tests. I think
I'll call it "checked". I use the "method as superclass" magic to
create checked subclasses of Array, and support both simple attributes
(with a default value) and array attributes. Hmm, perhaps I should do
hashes also... later :-).

Clifford Heath.

dblack

2/18/2007 10:25:00 AM

0

Clifford Heath

3/1/2007 5:56:00 PM

0

dblack@wobblini.net wrote:
>> This is ready to be made a gem when I've done the unit tests. I think
>> I'll call it "checked".
> How about "chattr"? :-)

Thanks for the suggestion.

Chattr is in Rubyforge now, with RDoc, (new) RSpec tests, all tied up
with a nice Rakefile to build the gem and test it. Only SVN access,
I'll get a proper release file and announcement up in the next few
days. You might like a sneak peek though :-).

Clifford Heath.