Code Worrier

Teaching myself to RTFM

Passing Symbols, a Kata Lesson

| Comments

In my post about the kata gem, I promised to share something I learned from the calculator kata. Here goes.

The calculator kata asks you to construct a Calculator class the instances of which are initialized with comma-delimited strings of integers. Next you are asked, one by one, to create a series of instance methods—#sum, #prod, #div, #diff—for the class that perform arithmetic operations on the stored integers.

Starting with #sum only, I wrote the class, obviously enough, like this:

1
2
3
4
5
6
7
8
9
10
11
  class Calculator

    def initialize expr
      @expr = expr
    end

    def sum
      @expr.split(/\,/).map(&:to_i).inject(&:+) || 0
    end

  end

After adding in another instance method, it made sense to move to conversion from string to array into the initialization method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  class Calculator

    def initialize expr
      @expr_array = expr.split(/\,/).map(&:to_i)
    end

    def sum
      @expr_array.inject(&:+) || 0
    end

    def prod
      @expr_array.inject(&:*)
    end

  end

I went on to add analogous subtraction and division methods, and then I started to get an itch: Could I avoid writing “inject” four times? More importantly, could I find a way that to write this class that reflected the underlying similarity in function shared by these four methods?

On a kata-fuelled lark, I decided to write the code I wished would work, even though I had no reason to think it would. I passed the arithmetic operation symbols into the methods as arguments, and then into the inject blocks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  class Calculator

    def initialize expr
      @expr_array = expr.split(/\,/).map(&:to_i)
    end

    def sum
      inject_op(:+) || 0
    end

    def prod
      inject_op(:*)
    end

    # etc.

    private

    def inject_op op
      @expr_array.inject(& op)
    end

  end

To my surprise this actually does work!!

My initial reaction was: Go Ruby! And then: Thank you, kata.

But, finally, in the spirit of the aphorism that “magic is code you don’t understand yet,” I thought: How do these & blocks work, anyway? More on that in a later post.

Comments