A feature I recently added to my Ruby feed fetching and parsing library, Feedzirra, is a call to sanitize the html in feed entries to protect from cross site scripting attacks. Adding the functionality was simple because of Dryopteris, a library written by Mike Dalessio and Bryan Helmkamp. The only thing left to decide was what I wanted to API to look like.
I settled on an odd pattern that I haven't used before and I offer it up here for your review. It was inspired by how the named_scope functionality in ActiveRecord works. I have no idea what you call this, so I refer to it in the title of this post as a proxy object. (here's a gist of my proxy object example for nicer reading)
# Let's say we have a feed entry object
entry = feed.entries.first
# now I could provide access to sanitization a few ways
sanitized_content = Feedzirra::Feed.sanitize(entry.content)
# but that's verbose and ugly, so maybe I could do this
sanitized_content = entry.sanitized_content
# that looks better, but I still didn't like it for some reason.
# I could also do this
santitized_content = entry.sanitized(:title)
# and define the sanitized method in entry like so
def sanitized(method)
Dryopteris.sanitize(send(method))
end
# However, what I really wanted was something like this
sanitized_content = entry.sanitized.content
# I think this reads a little better
# Here's the code inside of entry that makes this possible
def sanitized
dispatcher = Class.new do
def initialize(entry)
@entry = entry
end
def method_missing(method, *args)
Dryopteris.sanitize(@entry.send(method))
end
end
dispatcher.new(self)
end
# So in the sanitized method I'm creating a new proxy class
# on the fly. I'm redefining method_missing to send
# it to the method straight back to the entry.
# The last is an initialization of this proxy object that
# passes the entry itself in so it can have methods called against
# it later. So now I can also do
entry.sanitized.author
entry.sanitized.title
I'm still debating whether this is a good idea or just completely stupid. I think the API looks pretty clean, but it may just be confusing. Would I be better off just going with one of the first three examples? Would it be better to do something completely different?
I like it :)
Posted by: Alex MacCaw | February 13, 2009 at 10:49 AM
I like it! Calling entry.sanitized.foo does exactly what you'd expect it to -- I don't see how you could get any clearer than that.
Posted by: Jason Adams | February 13, 2009 at 11:33 AM
I'm on the fence.
It kind of looks like a LoD violation at first glance. And another route not in the gist is to offer entry.sanitized_title (implemented perhaps via method missing).
OTOH, I like that you could provide a collaborator (like a view renderer) with the result of entry.sanitized and then it has no way to do the wrong thing.
Posted by: Luke Melia | February 14, 2009 at 12:42 AM
I tried to trackback, but it always seemed like spam:
http://interblah.net/re-paul-dix-proxy-object
Posted by: James Adam | February 14, 2009 at 06:46 AM
No, I don't like it. You better stick woith the convention of zooming in on specifics left to right, similar to
so
Posted by: Mike | February 14, 2009 at 08:05 AM
Like a few others, I prefer:
Posted by: Gabe Hollombe | February 14, 2009 at 09:38 AM
Interesting but I think entry.title.sanitized is better. You could just add a method to string to cover all or extend the functionality on the specific returns. Just a thought.
Posted by: John Nunemaker | February 15, 2009 at 12:31 AM
Oh, that is beautiful. I'm not sure in this particular case whether I like entry.sanitized.title or entry.title.sanitized better. However, once you've decided you want a proxy object, the use of Class.new is brilliant. I needed this idom badly a year ago when I wrote Rubot, which is a DSL for behavior-based robots. I actually named a class BehaviorFactoryBuilder. How sad is that?
http://github.com/Peeja/rubot/blob/fd04d1444a0ddaf5b92f07e85cb3d082ad7e45a1/lib/rubot/dsl.rb
(Man, I've improved a lot in the last year.) :)
Posted by: Peter Jaros | February 18, 2009 at 12:19 PM
Vimax pills are created by a professional team of doctors who have many years of experience, working to achieve the best penis enlargement pills on the market.
Posted by: mumuk | July 20, 2009 at 09:47 AM