Blog

The difference between instance_eval and instance_exec

by Jim

There’s an important difference between instance_eval and instance_exec. And there’s a great lesson about how to use them well in FactoryGirl

But first, before you go rushing off to build your fantastic DSL, let’s look at what instance_eval is and does.

The simplest of examples can be taken straight from the Ruby docs:

class KlassWithSecret
  def initialize
    @secret = 99
  end
end
k = KlassWithSecret.new
k.instance_eval { @secret } #=> 99

The current value for self inside the provided block will be the object on which you call instance_eval. So in this case the k object is the current context for the block; @secret is a variable stored inside k and instance_eval opens up access to that object and all of it’s internal variables.

The interface that FactoryGirl provides is simple and straightforward. Here’s an example from it’s “Getting Started” documentation:

FactoryGirl.define do
  factory :user do
    first_name "Kristoff"
    last_name  "Bjorgman"
    admin false
  end
end

Here, FactoryGirl uses instance_eval to execute the blocks of code passed to factory.

Let’s take a look at some representative code from how FactoryGirl makes this work:

def factory(name, &block)
  factory = Factory.new(name)
  factory.instance_eval(&block) if block_given?
  # ... more code
end

That’s not actually the code from FactoryGirl, but it represents roughly what happens. When the method factory is called a new Factory is created and then the block is executed in the context of that object. In other words where you see first_name it’s as if you had that factory instance before it and instead had factory.first_name. By using instance_eval, the users of FactoryGirl don’t need to specify the factory object, it’s implicitly applied to it.

Ok, that’s all well and good, but what about instance_exec?

I’m glad you asked.

The instance_eval method can only evaluate a block (or a string) but that’s it. Need to pass arguments into the block? You’ll be frozen in your tracks.

But instance_exec on the other hand, will evaluate a provide block and allow you to pass arguments to it. Let’s take a look…

FactoryGirl allows you to handle callbacks to perform some action, for example, after the object is created.

FactoryGirl.define do
  factory :user do
    first_name "Kristoff"
    last_name "Bjorgman"
    admin false

    after(:create) do |user, evaluator|
      create_list(:post, evaluator.posts_count, user: user)
    end
  end
end

In this sample, the after(:create) is run after the object is created, but the block accepts two arguments: user and evaluator. The user argument is the user that was created. The evaluator is an object which stores all the values created by the factory.

Let’s take a look at how this is implemented:

def run(instance, evaluator)
  case block.arity
  when 1, -1 then syntax_runner.instance_exec(instance, &block)
  when 2 then syntax_runner.instance_exec(instance, evaluator, &block)
  else        syntax_runner.instance_exec(&block)
  end
end

FactoryGirl will create a callback object named by the argument given to the after method. The callback is created with a name, :create in this case, and with a block of code.

The block that we used in our example had two arguments.

The run method decides how to execute the code from the block.

The callback object stores the provided block and Ruby allows us to check the arity of the block, or in other words, it allows us to check the number of arguments.

When looking at a case statement, it’s a good idea to check the else clause first. This gives you an idea of what will happen if there’s no match for whatever code exists in the when parts.

There we see syntax_runner.instance_exec(&block) and this could easily be changed to use instance_eval instead. Ruby will evaluate, or execute, the block in the context of the syntax_runner object.

If the block’s arity is greater than zero, FactoryGirl needs to provide the objects to the block so that our code works the way we expect.

The second part of the case checks if the block arity is equal to 2.

when 2 then syntax_runner.instance_exec(instance, evaluator, &block)

If it is, the syntax_runner receives the instance (or in our case user) and the evaluator.

If, however, the arity is 1 or -1 then the block will only receive the instance object.

So what is that -1 value? Let’s look at the ways we could create a callback:

# Two arguments and arity of 2
after(:create) do |user, evaluator|
  create_list(:post, evaluator.posts_count, user: user)
end
# One argument and arity of 1
after(:create) do |user|
  create_group(:people, user: user)
end
# Zero arguments and arity of 0
after(:create) do
  puts "Yay!"
end
# Any arguments and arity of -1
after(:create) do |*args|
  puts "The user is #{args.first}"
end

Ruby doesn’t know how many args you’ll give it with *args so it throws up it’s hands and tells you that it’s some strange number: -1.

This is the power of understanding how and when to use instance_exec; users of the DSL will expect it to make sense, and it will.

But wait! There’s more!

What if you want to specify the same value for multiple attributes?

FactoryGirl.define do
  factory :user do
    first_name "Kristoff"
    last_name  "Bjorgman"

    password "12345"
    password_confirmation "12345"
  end
end

In the above example, both the password and password_confirmation are set to the same value. This could be bad. What if you change the password for one, but forget to change the other? If they are inherently tied in their implementation, then that could lead to some unexpected behavior when they are not the same.

I would, and probably you would too, prefer to tell FactoryGirl to just use the value I’d already configured.

Fortunately FactoryGirl allows us to use a great trick in Ruby using the to_proc method. Here’s what it looks like in use:

FactoryGirl.define do
  factory :user do
    first_name "Kristoff"
    last_name  "Bjorgman"

    password "12345"
    password_confirmation &:password
  end
end

The important part is the &:password value provided to password_confirmation. Ruby will see the & character and treat the following as a block by calling to_proc on it. To implement this feature, FactoryGirl defines to_proc on attributes and there will use instance_exec to provide the symbol password to the block:

def to_proc
  block = @block

  -> {
    value = case block.arity
            when 1, -1 then instance_exec(self, &block)
            else instance_exec(&block)
            end
    raise SequenceAbuseError if FactoryGirl::Sequence === value
    value
  }
end

What about lambdas and procs?

Some commenters in Reddit raised an important question about how these methods behave when given lambdas and procs.

If you provide a lambda which accepts no arguments as the block, instance_eval will raise an error:

object = Object.new
argless = ->{ puts "foo" }
object.instance_eval(&argless) #=> ArgumentError: wrong number of arguments (1 for 0)

This error occurs because Ruby will yield the current object to the provided block as self. So you can fix it by providing a lambda which accepts an argument:

args = ->(obj){ puts "foo" }
object.instance_eval(&args) #=> "foo"

This changes a bit if you use instance_exec:

object.instance_exec(&argless) #=> "foo"
object.instance_exec(&args) #=> ArgumentError: wrong number of arguments (0 for 1)
object.instance_exec("some argument", &args) #=> "foo"

Because a proc is less restrictive with argument requirements, it will allow either approach to work without error:

p_argless = proc{ puts "foo" }
object.instance_eval(&p_argless) #=> "foo"

p_args = proc{|obj| puts "foo" }
object.instance_eval(&p_args) #=> "foo"

object.instance_exec(&p_args) #=> "foo"
object.instance_exec(&p_argless) #=> "foo"

Now you know, instance_exec and instance_eval are similar in the way they behave, but you’ll reach for instance_exec if you need to pass variables around.

Announcing Ruby Metaprogramming Masterclass

I’m offering a new online class where I’ll be teaching you how to master metaprogramming in Ruby on April 30th (the day after my birthday!)

I’m keeping the spaces limited to 25 so attendees will be able to talk and ask questions but already over a quarter of the seats are gone. So grab a seat now, before they’re all gone.

Clean Up Your Code

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below.

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

Locality and Cohesion

by Jim

“The primary feature for easy maintenance is locality: Locality is that characteristic of source code that enables a programmer to understand that source by looking at only a small portion of it.” — Richard Gabriel

This advice is from Patterns of Software by Richard Gabriel.

Keeping cohesive parts of our system together can help us understand it. By managing locality we can keep cohesive parts together.

It’s easy to see coupling in our code. When one object can’t do it’s job without another, we experience frustration in the face of change. We often think about dependencies in our code, but cohesion is the relatedness of the behaviors and plays an import part in how we organize the ideas to support our domain.

def process_payment(amount)
  gateway.authorize_and_charge(amount) do
    deliver_cart
  end
  logger.info "handling payment: #{amount}"
  logger.info "cart delivered: #{id}"
end

The exact purpose of this completely-made-up code isn’t that important. But we can look at parts of this procedure and extract them into a related method:

def process_payment(amount)
  gateway.authorize_and_charge(amount) do
    deliver_cart
  end
  log_purchase(amount)
end

def log_purchase(amount)
  logger.info "handling payment: #{amount}"
  logger.info "cart delivered: #{id}"
end

As Gabriel points out in his book, we can compress a procedure into a simple phrase like log_purchase but this compression carries a cost. In order to understand the behavior of this log_purchase phrase, we need to understand the context around it.

Indeed, we might look at this and realize that there’s a problem with the way we managed the locality of the procedure. Instead of easily understanding a single method, we might look at process_payment and realize there’s a bit more to it than we first expect.

We’re forced to understand the log_purchase and the context which previously surrounded it’s procedure. A second look at this extraction might lead us to reconsider and to go back to inline the method. Let’s keep this code with a tighter locality:

def process_payment(amount)
  gateway.authorize_and_charge(amount) do
    deliver_cart
  end
  logger.info "handling payment: #{amount}"
  logger.info "cart delivered: #{id}"
end

While extracting the log_purchase method was easy, given the original code, it added a bit too much for us to understand and it doesn’t feel quite right. Handling the locality of this code helps us to better understand it and to make better decisions about how to improve the main process_payment method.

Consider this: How much must you pack into your head before you can begin evaluating a part of your code?

While breaking procedures up into small methods can be a useful way to make easy to understand (and easy to test) parts, we may do so to the detriment of understanding.

This is something to consider if you are building a DSL to compress ideas in your code or if you’re trying to create objects to manage your business logic. I’ll be writing more about the value of controlling the locality of behavior in your system, but I’d love to hear how you manage locality. What do you do to ensure that related bits stay together?

Clean Up Your Code

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below.

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

The 4 Rules of East-oriented Code: Rule 4

by Jim

Often the rules we create are defined by their exceptions.

It is difficult to create a program which continually passes objects and never returns data. Often the first rule of “Always return self” is met with immediate rejection because it’s easy to see the difficulty you’d encounter if that rule is continually followed for every object.

In my presentation for RubyConf, I showed how we break the rules to allow value objects to handle data for a template. I previously wrote about the approach I used in the presentation to push data into a value object.

class Address
  def display(template)
    if protect_privacy?
      template.display_address(private_version)
    else
      template.display_address(public_version)
    end
    self
  end
end

In the sample above, an Address instance commands a template to display_address with different versions of data: private_version or public_version. This makes a flexible interface that allows Address to create any number of different versions if necessary. Perhaps the requirements will demand a semi_public_version in the future; our design of the template need not change.

This is a great way to break the rules. Value objects allow us to parameterize a collection of data in a single object. The alternative to this approach would be to use setter methods on the template object:

class Address
  def display(template)
    unless protect_privacy?
      template.street = street
      template.apartment = apartment
      template.postal_code = postal_code
    end
    template.city = city
    template.province = province
    template.display_address
    self
  end
end

We can plainly see that although the code follows the rules by commanding the template object, there’s also quite a lot happening in this display method on Address. If the requirements change we might feel encouraged to complicate the unless block or “refactor” it into a case statement. While that might solve our problem, the resulting code could lead to some difficult to read and understand implementation details.

By breaking the rules with a value object we can better encapsulate the ideas in a private address object or public or any other type we desire.

But we’re not just breaking the rules inside the Address methods; the template breaks the rules too. Rule 2 says that objects may query themselves and subsequently means they should not query other objects. But by choosing to break the rules we make a design decision at a specific location to make things better.

No matter what rules you follow, you decide not only to follow them, but decide to break them as well. To make your program easy to understand and to create reasonable expectations, you can lean on creating barriers. Preventing yourself from doing one thing frees you to do another.

Embrace constraints.

How do you add constraints to your programs? What are you better able to do by adding restrictions?

Clean Up Your Code

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below.

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

The 4 Rules of East-oriented Code: Rule 3

by Jim

When I set out to create my presentation for RubyConf, I wanted to provide the audience with something they could easily try. By doing that, one could walk away and put themselves in a position to think about their code differently. While, James Ladd, the creator of East-oriented Code made some basic rules, I decide to take them and frame it in the specific context of Ruby:

  1. Always return self
  2. Objects may query themselves
  3. Factories are exempt
  4. Break the rules sparingly

After writing about Rule 1 and Rule 2 I’m very eager to get to Rule 3. It’s an easy way to break the intent of this style without breaking the rules.

Factories are Exempt

They must be. If you returned self from Object.new you’d just get Object back, not an instance of an object. So factories are exempt from returning self.

The best way to get around any of these rules is to just make something into a factory. But here lies the danger. It’s important to first think about what these objects are doing. For what are they responsible?

We could create a class to sweep our messy code under the rug.

user = User.new
signup = UserSignupProcess.new
signup.create_with(user)

The code above, we could say, is East-oriented. The factories create instances, and the signup object is told to create_with and given the user object.

Beyond this (inside create_with), it could easily be an enormous mess. While we can and probably should use different programming techniques for different situations, taking a load of if statements and sweeping it into a class could still be problematic.

Now, the sample code above is completely made up to show how you can take part of your program and say “this part is East-oriented, but over here I used this other technique. I call it If-oriented.”

Examining your domain and creating a program to support it requires that you carefully evaluate what objects should exist, what their responsibilities are, and what you will name them.

East-orientation is all about designating responsibilities.

This leads us to breaking the rules…

We’ll be getting to that later. There’s likely very good reasons to break any particular programming rule, but it probably depends on the context.

I wrote Clean Ruby and the chapter on East-oriented Code before I set up the 4 rules for my presentation, but the same lessons are there. I’ll be adding more to it, particularly as discussion and ideas around DCI evolve, but I’m putting effort toward wrapping up the Ruby DSL Handbook. It will soon be complete and the $12 price will go up to $24, so pick it up now if you’re interested.

Ruby DSL Handbook is about how to create a DSL without headaches from metaprogramming and I just released an update with a chapter about creating a DSL without metaprogramming at all. Much like this discussion today, it’s all about managing responsibilities.

Clean Up Your Code

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below.

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

The 4 Rules of East-oriented Code: Rule 2

by Jim

In a previous article I wrote about the first rule of East-oriented Code.

Here again are the rules I set forth in my presentation at RubyConf:

  1. Always return self
  2. Objects may query themselves
  3. Factories are exempt
  4. Break the rules sparingly

The second rule, that “Objects may query themselves”, allows the design of objects to work with their own attributes.

When we design our systems of interacting objects we can use the Tell, Don’t Ask approach to limit the decisions in the code to objects which are responsible for the data used to make them.

The Tell, Don’t Ask article begins by quoting Alec Sharp:

Procedural code gets information then makes decisions. Object-oriented code tells objects to do things.

In order for objects to do things, they may need to ask questions about their own data. Though the first rule of East-oriented Code says that you should return self, internal private methods don’t need to follow this rule. We can and might need to create query methods to allow the object to make decisions.

It’s easy to begin designing an object by specifying what it’s attributes are:

class Person
  attr_reader :name, :nickname, :gender
end

When we do that, we also implicitly allow other objects to use these attributes and make decisions:

if person.nickname =~ /^DJ/
  person.setup_playlist_preferences('house')
else
  person.setup_playlist_preferences('classical')
end

In the sample code above we’re using a method setup_playlist_preferences which accepts a single argument. The decision about what value to set is made outside of the person object. As additional options are added to the system, this if may have elsif clauses added to it or it may turn into a case statement. With public attributes, those changes can appear in multiple places in your system, which can lead to headaches when the structures of your objects change.

Alternatively, we could command the object to do what we want:

person.setup_playlist_preferences

Any decision about what to do to setup preferences can be made inside the setup_playlist_preferences method.

Here’s a summary from the C2 wiki

Very very short summary: It is okay to use accessors to get the state of an object, as long as you don’t use the result to make decisions outside the object. Any decisions based entirely upon the state of one object should be made ‘inside’ the object itself.

One way to prevent decisions about an object from being made outside that object is to limit the public information:

class Person
  private
  attr_reader :name, :nickname, :gender
end

If you like this, check out the new book I’m writing: Ruby DSL Handbook which is currently half-off the final price. It’s designed to be a guide to help you make decisions about how to build your own DSL and compressions of concepts.

Permalink…

The 4 Rules of East-oriented Code: Rule 1

by Jim

4 simple rules are pretty easy to remember, but a bit harder to understand and apply.

A key concept of East-oriented Code is to enforce the use of commands by returning the object receiving a message.

Here’s a simple example of what that looks like:

def do_something
  # logic for doing something omitted...
  self
end

It’s incredibly simple to follow.

Here are the rules I set forth in my presentation at RubyConf:

  1. Always return self
  2. Objects may query themselves
  3. Factories are exempt
  4. Break the rules sparingly

The first three are hard rules. The fourth, obviously, is more lenient. We’ll get to some guidance on breaking the rules in the future but for now let’s look at applying this to your code.

Rule 1: Always return self

Although this rule is simple at first, it inevitably leads to the queston of getter methods.

What if your objects had no getters? What if an object’s name attribute simply was inaccessible to an external object?

You can make your data private by either marking your attr_accessors as private:

attr_accessor :name
private :name

Or you can use the private method to mark all of the following defined methods to be private:

private
attr_accessor :name

How you choose to do it will depend upon your code, but this would help you remove any getter methods.

Now this leaves you with a conundrum. How do you use the information?

If you have a need for that name, what can you do?

The only answer is to create a command which will apply the data to the thing you need.

def apply_name_to(form)
  form.name = name
  self
end

The restricitions we put in our code are often self-imposed.

We can make whatever we want, so what’s to stop us from putting Rails model data manipulation in it’s view template? Nothing concrete stops us from doing so.

The same goes for getter methods like name. If it is publicly accessible by external objects, then we can create whatever if and case statements we want. We can put logic wherever we want.

If we create our own restrictions, we can guide ourselves and other programmers to the direction we intend for our application’s structure.

Creating restrictions

I’ve written about the Forwardable library in the past not only because of it’s usefulness, but because we can copy the same pattern to create our own DSL.

Forwardable provides methods which create getter methods for related objects. But what if we created our own DSL for commands to related objects? What if we could pass the messages on, but allow the related object to handle the values?

Here’s what that could look like:

class Person
  command :send_email => :emailer
end
person = Person.find(1) # get some record
person.emailer = Emailer.get # get some object to handle the emailing
person.send_email

That’s a lot of pseudo-code but the parts we care about are sending the command to a related object. Commands return the receiving object, queries will return a value.

Here’s what that code would look like without our (yet unimplemented) command DSL.

class Person
  def send_email
    emailer.send_email
    self
  end
end

Any code which uses a Person will have to rely on the command to do its own thing. This prevents a programmer from leaking logic out of the person.

What should happen when the email is sent? With the structure above, this code, can’t make decisions:

if person.send_email
  # do one thing
else
  # this will never work now
end

If you find that you often write code like the if statement above, you might wonder “where does that logic go now?” Now, you’ll be forced to write this code:

person.send_email

And this means that your send_email now has the job of handling what to do:

class Person
  def send_email
    emailer.send_email
    # do some other things...
    self
  end
end

That might provide you with better cohesion; the related behaviors remain together.

Getting back to that command DSL we used above…

This was the final point of my presentation at RubyConf: you can build guidlines like this for yourself.

I created a gem called direction to handle enforcing this East-oriented approach. I’ll write more about that later, but it shows that I can create signals to other developers on my team. I can take a simple concept like a command and simplify my code to show other developers what’s happening:

class Person
  command :send_email => :emailer
end

Building a DSL can aid in communication. The language and terminology we use can compress ideas into easily digestible parts.

If you like this, check out my new book: Ruby DSL Handbook designed to be a guide to help you build your own compressions of concepts.

Permalink…

1999 - 2015 © Saturn Flyer LLC 2321 S. Buchanan St. Arlington, VA 22206

Call Jim Gay at 571 403 0338