From: Josh Cheek Date: 2011-05-31T23:26:08+09:00 Subject: Re: CORE - Specialized Attribute Definition --90e6ba4fc1c03f861f04a4932f39 Content-Type: text/plain; charset=ISO-8859-1 On Tue, May 31, 2011 at 8:05 AM, Ilias Lazaridis wrote: > ruby 1.9 > > (this is about the *abilities* or the ruby 1.9 language) > > class Persnon > attrib name String opt1 opt2 > attrib age Integer > end > > The main questions: > a) Can such an "attrib" method be implemented with ruby code? > b) Can such an "attrib" functionality be implemented on the C-level > (as extension, not as modification of source)? > > Any examples? > > Please notice the requirements: > > 1) "name" and not ":name" > 2) no comma between "name" and "String" and "opt1" ... > > > Almost certain this can't be done. You could do something somewhat close to that, as seen in the below example. But it relies on hacking method_missing and defining constants as methods which catch their call and store them for later evaluation, eventually being evaluated when arriving at the attrib method. However, you would be susceptible to all the method_missing bugs. In fact, your example even hit one, because Class.new.respond_to?(:name) is true, it wouldn't hit method_missing. This is why in the example, it must be called name2. Also, to implement this, you must interfere with the natural flow of method missing, so if you actually do invoke a missing method anywhere, then this code will think it is part of a signature for some method you're passing to attrib. module ImDoingThisForTheChallengeEvenThoughItsAHorribleIdea def next_meth_sig @next_meth_sig ||= [] end def attrib(signature) methname, *to_return = signature.reverse signature.clear define_method(methname) { to_return } end def method_missing(meth, *args, &block) # when empty, args may be [String], [Integer], etc # because they get treated as const lookup when doing attrib a Integer # but get treated as method call when doing attrib a Integer b return next_meth_sig << meth unless next_meth_sig.empty? next_meth_sig.concat args << meth end [String, Integer].each do |const| define_method const.to_s do |args| next_meth_sig << const end end end require 'rspec' describe "ImDoingThisForTheChallengeEvenThoughItsAHorribleIdea#attrib" do before :each do @class = Class.new do extend ImDoingThisForTheChallengeEvenThoughItsAHorribleIdea end end context 'when given "attrib name2"' do before { @class.instance_eval { attrib name2 } } subject { @class.new } it { should respond_to :name2 } its(:name2) { should == [] } end context 'when given "attrib name2 String"' do before { @class.instance_eval { attrib name2 String } } subject { @class.new } its(:name2) { should == [String] } end context 'when given "attrib name2 String opt1 opt2"' do before { @class.instance_eval { attrib name2 String opt1 opt2 } } subject { @class.new } it { should respond_to :name2 } its(:name2) { should == [String, :opt1, :opt2] } end specify '"attrib age Integer" should define #age which returns [Integer]' do @class.instance_eval { attrib age Integer } @class.new.age.should == [Integer] end it "should work with Illias' example" do class Persnon extend ImDoingThisForTheChallengeEvenThoughItsAHorribleIdea attrib name2 String opt1 opt2 attrib age Integer end p = Persnon.new p.name2.should == [String, :opt1, :opt2] p.age.should == [Integer] end end --90e6ba4fc1c03f861f04a4932f39--