Wednesday, January 17, 2007

Some Weird Weird Ruby (or nest Classes and Inheritence)

Thinking cap time. I am working on a CMS and the short of it is that a Page will have many PageBlock objects. The PageBlock is versioned and can have multiple things associated with it (i.e. Links or Files or Other Stuff, thankfully each page block is homogenous). I decided that the Links/Files will be serialized. So I wrote a serializing helper object. This serializing object


class PageBlock < ActiveRecord::Base
class << self
# I want to be able to configure the underlying DataSerializer
# in the containing class
delegate :set_valid_serialized_keys, :to => :data_serializing_class
def data_serializing_class
self::DataSerializer
end
end
class DataSerializer
class << self
def set_valid_serialized_keys( *attrs )
write_inheritable_attribute :valid_serialized_keys, attrs
class_inheritable_reader :valid_serialized_keys
end
end

def add_data(data = {})
data.assert_valid_keys(valid_serialized_keys)
... do the magic ...
end
end
end


Now

$ PageBlock.valid_serialized_keys
=> NoMethodError: undefined method `valid_serialized_keys' for PageBlock::DataSerializer:Class



class PageLinkBlock < PageBlock
set_valid_serialized_keys :path, :name
end



$ PageBlock.valid_serialized_keys
=> [:path, :name]


DOH!!! Man that is definitely not the behavior I want. I guess my nested Class has some behavior that I'm not aware of. I'm certain the behavior is intentional, I just didn't know about it

So the solution?


class PageBlock < ActiveRecord::Base
class << self
# I want to be able to configure the underlying DataSerializer
# in the containing class
delegate :set_valid_serialized_keys, :to => :data_serializing_class

def data_serializing_class
self::DataSerializer
end

def inherited(page_block_subclass)
page_block_subclass.module_eval <<-EOV
class DataSerializer < PageBlock::DataSerializer
end
EOV
super
end

end
class DataSerializer
class << self
def set_valid_serialized_keys( *attrs )
write_inheritable_attribute :valid_serialized_keys, attrs
class_inheritable_reader :valid_serialized_keys
end
end

def add_data(data = {})
data.assert_valid_keys(valid_serialized_keys)
... do the magic ...
end
end
end


Then I define PageLinkBlock and


$ PageBlock.valid_serialized_keys
=> NoMethodError: undefined method `valid_serialized_keys' for PageBlock::DataSerializer:Class


Alas, the behavior that I want. Time to dig out the Pickaxe Book to see if there is a reference to this.

No comments: