Adam Wanninger
Aug 9, 2017 · 1 min read

Using class_eval to dynamically define predicate methods

Originally posted on agemofablog on 2017–07–11

A predicate method ends with ?, and returns true or false.

This post will be part one of a two part series about dynamically defining predicate methods with class_eval and define_method.

Often times in a Rails application, you end up storing state in your database. This state usually takes the form ofsome type of status attribute on a model. You end up needing to determine what state a specific instance of that model is in, which is a great use case for class_eval.

For example, if you have a model named User with four possible statuses you could use class_eval in the following manner:

class User
POSSIBLE_STATUSES = %w(Active Inactive Disabled Banned)
attr_accessor :status def initialize
@status = 'Inactive'
end
POSSIBLE_STATUSES.each do |status|
class_eval <<-CODE
def #{status.downcase}?
self.status == '#{status}'
end
CODE
end
end

This will dynamically define boolean methods on the User class. To test this code, just paste it into an irb session.

You can call the status method on a new user to see the default status, which we set in the initialize method:

irb(main):001:0> User.new.status
=> "Inactive"

Finally, lets test all of our boolean method. There will be one boolean method defined for each status within our POSSIBLE_STATUSES array.

irb(main):001:0> User.new.active?
=> false
irb(main):002:0> User.new.disabled?
=> false
irb(main):003:0> User.new.banned?
=> false
irb(main):004:0> User.new.inactive?
=> true

You can also use define_method in a similar way, which I will go over in my next post.

Adam Wanninger

Written by

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade