Monkey Patching Galore
March 03, 2008Here is some code I just threw together for fun, I don't actually use it. Some would call this monkey patching.
1 class Symbol 2 def to_proc 3 Proc.new { |*args| args.shift.__send__(self, *args) } 4 end 5 end 6 7 class Array 8 def all?(*args, &block) 9 !!self.each { |e| return false unless block.call(e, *args) } 10 end 11 12 def array_of?(klass) 13 self.all?(klass, &:is_a?) 14 end 15 end 16 17 18 puts ["Will", "this", "work?"].array_of?(String) # => true 19 20 puts ["But", "this", 1, "will", "be false"].array_of?(String) # => false 21 22 puts ["But", "wait", "this still works"].all?(&:to_s) # => true
Alright, so I used the well-known Symbol#to_proc, redefined Array#all? and added a method Array#array_of?. But look, Array#all? still works when you try to use it the original way. If you don't like my code, don't use it. I wouldn't.
What would have been a non-monkey patch way of doing this?
1 class SingleTypedArray < Array 2 def array_of?(klass) 3 !!self.each { |e| return false unless e.is_a?(klass) } 4 end 5 end
But hey, that's gross. I lose my ability to do [elem1, elem2], I have to do SingleTypedArray.new(elem1, elem2, ...).
I've run into a lot of Rails plugins that add functionality to existing classes, such as ActiveRecord and some of them do it in an obtrusive way, so I simply choose not to use that plugin. You are not required to use a plugin, library, or gem that does something you want if it does it grossly. There are a lot of plugins and gems out there, but a lot of them suck and are poorly designed. Pick and choose the ones that do it right.
Basically: it's not Ruby, it's some programmers.
"Guns don't kill people. People kill people."
Comments
Or more appropriate would be,
"Ruby doesn't kill programming. People kill programming."
Which is precisely what I said.
This is very easy to say when you are just one programmer working on personal projects. When you have are working on a tens or hundreds of kloc project which has been under development for years by dozens of developers, you can't always pick and choose the libraries which, for whatever legacy reasons, the project now depends on.
The real drift of my posts, though, is that a lot of the dynamic class modification that goes on in Ruby (and especially Rails) libraries is not only unnecessary, but actually more complicated and harder to write than the alternative techniques!
I've never said anything against Ruby. I'm happy with Ruby the way it is. What's wrong with introducing "some programmers" to alternative ways of solving problems? When you work on a large project with a tight schedule, and find yourself having to waste precious time re-implementing or patching otherwise useful libraries because they were implemented in an unsustainable way, helping people avoid those mistakes in the first place starts to seem more and more important.
Leave a Comment