04.11
So there’s BlankSlate, and today tmm1 was doing something where he was delegating to Array, but wanted to actually have Array in the ancestor chain (for Class#===), so I came up with this:
def BS(superclass = nil, name = :BlankSlate) klass = eval(%w[ class #{name} #{" < #{superclass}" if superclass} end #{name} ]) klass.class_eval { instance_methods.each { |m| undef_method m unless m =~ /^__/ } } klass end
And then he came up with the anti-eval solution:
class BlankSlate instance_methods.each { |m| undef_method m unless m =~ /^__/ } end def BlankSlate superclass = nil if superclass @blank_slates ||= {} @blank_slates[superclass] ||= Class.new(superclass) do instance_methods.each { |m| undef_method m unless m =~ /^__/ } end else BlankSlate end end
refactors to:
class BlankSlate instance_methods.each { |m| undef_method m unless m =~ /^__/ } end def BlankSlate superclass = BlankSlate @blank_slates ||= Hash.new do |h,k| h[k] = Class.new(superclass) do instance_methods.each { |m| undef_method m unless m =~ /^__/ } end end @blank_slates[superclass] end
But watch out!!!:
a = StrokeDB::LazyMappingArray.new([1,2,3]) # => [1, 2, 3] Array === a # => true Array.new(a) # => [] [a].flatten # => [] # The last two are 'incorrect' behaviour (probably work on rubinius, # mind you, so did the delegation approach).
Anyway, you get the idea, mix and match, (feedback?), whatever. Enjoy.