The Downside of Cleverness
Ruby lets you do all sorts of clever, fancy tricks. This cleverness is a big part of what makes Ruby so elegant, but it also can be downright dangerous in the wrong hands. To illustrate this, we’ll look at the kind of trouble you can get in if you aren’t careful.
The Evils of eval()
Throughout this book, we’ve dynamically evaluated code blocks all
over the place. However, what you have not seen much of is the use of
eval(), class_eval(), or even instance_eval() with a string. Some might
wonder why this is, because eval()
can be so useful! For example, imagine that you are exposing a way for
users to filter through some data. You would like to be able to support
an interface like this:
user1 = User.new("Gregory Brown", balance: 2500)
user2 = User.new("Arthur Brown", balance: 3300)
user3 = User.new("Steven Brown", balance: 3200)
f = Filter.new([user1, user2, user3])
f.search("balance > 3000") #=> [user2, user3]Armed with instance_eval, this
task is so easy that you barely bat an eye as you type out the following
code:
class User
def initialize(name, options)
@name = name
@balance = options[:balance]
end
attr_reader :name, :balance
end
class Filter
def initialize(enum)
@collection = enum
end
def search(query)
@collection.select { |e| e.instance_eval(query) }
end
endRunning the earlier example, you see that this code works great, exactly as expected. But unfortunately, trouble strikes when you see queries like this:
>> f.search("@balance = 0") => [#<User:0x40caa4 ...Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access