Google+

Tiny Study Notes for Shoes Built-in Samples II

The 2nd is simple_calc. Learned the Module#define_method. :-D

simple-calc.png

simple-calc.rb link
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
**simple-calc.png**
  # simple-calc.rb
  class Calc              #1
    def initialize        #2
      @number = 0
      @previous = nil
      @op = nil
    end
  
    def to_s              #3
      @number.to_s
    end
  
    (0..9).each do |n|                              #4
      define_method "press_#{n}" do
        @number = @number.to_i * 10 + n
      end
    end
  
    def press_clear
      @number = 0
    end
  
    {'add' => '+', 'sub' => '-', 'times' => '*', 'div' => '/'}.each do |meth, op|   #5
      define_method "press_#{meth}" do
        if @op                                      #6
          press_equals
        end
        @op = op
        @previous, @number = @number, nil           #7
      end
    end
  
    def press_equals                                #8
      @number = @previous.send(@op, @number.to_i)
      @op = nil
    end
  
  end
  
  number_field = nil
  number = Calc.new                                                 #9
  Shoes.app :height => 250, :width => 200, :resizable => false do
    background "#EEC".."#996", :curve => 5, :margin => 2
  
    stack :margin => 2 do
  
      stack :margin => 8 do
        number_field = para strong(number)                          #10
      end
  
      flow :width => 218, :margin => 4 do
        %w(7 8 9 / 4 5 6 * 1 2 3 - 0 Clr = +).each do |btn|
          button btn, :width => 46, :height => 46 do                #11
            method = case btn
              when /[0-9]/; 'press_'+btn
              when 'Clr'; 'press_clear'
              when '='; 'press_equals'
              when '+'; 'press_add'
              when '-'; 'press_sub'
              when '*'; 'press_times'
              when '/'; 'press_div'
            end
  
            number.send(method)                                     #12
            number_field.replace strong(number)                     #13
          end
        end
      end
    end
  
  end

Study Note

#1:
Define a class Calc. This class has the following 18 methods. - initialize - to_s - press_0, press_1, ….. , press_9 - press_clear - press_add, press_sub, press_times, press_div - press_equal

#2:
Define a method initialize. This method is used once in the above code to create just one object at #9.

#3:
Define a method to_s. In Shoes, para uses to_s implicitly at #10. If you comment out to_s definition lines, you will see the following output.

simple-calc-1.png

simple-calc-1.png

#4:
Define methods press_0, press_1, ….. , press_9 with the method define_method. See ri Module#define_method. They are the same as the following.

long_hand.rb
1
2
3
4
5
6
 def press_0
    @number = @number.to_i * 10 + n
  end
  def press_1
    @number = @number.to_i * 10 + 1
  end

: : (and so on)

The .to_i is necessary for the case that @number is nil.

#5:
Define methods press_add, press_sub, press_times, press_div.

#6:
Execute the previous calculation (one of +, -, *, /).

#7:
To clear the number_field at #13 (to show nothing), assign nil to @number instead of 0.

#8:
Define a method press_equals. See the following small IRB snippet.

irb_session
1
2
3
 C:\>irb --simple-prompt
  >> 23.send '+', 5
  => 28

#12:
Send the value (character string) that was assigned to the local variable method to the object number that was created at #9. See the following small IRB snippet.

irb_session.irb
1
2
3
4
5
6
7
8
9
10
11
 C:\>irb --simple-prompt
  >> class Calc
  >>   def press_add
  >>     puts 'DEBUG: hi.'
  >>   end
  >> end
  => nil
  >> Calc.new.send 'press_add'
  DEBUG: hi.
  => nil
  >>

#13:
This line is defined within the button definition block (#11), hence every time when any button is clicked, number_field area will be refreshed.

Alternative Simple Calc

This is an alternative code. There is no interesting tips but it’s simple, I guess. :)

sample61.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 Shoes.app :height => 250, :width => 200, :resizable => false do
    def do_calc
      @number = @previous.send(@op, @number)  if @op
      @op = nil
    end
  
    @previous, @number, @op = 0, 0, nil
  
    background "#EEC".."#996", :curve => 5, :margin => 2
  
    stack :margin => 2 do
      stack :margin => 8 do
        @number_field = para strong(@number)
      end
  
      flow :width => 218, :margin => 4 do
        %w(7 8 9 / 4 5 6 * 1 2 3 - 0 Clr = +).each do |btn|
          button btn, :width => 46, :height => 46 do
            case btn
              when /[0-9]/
                @number = @number.to_i * 10 + btn.to_i
              when 'Clr'
                @previous, @number, @op = 0, 0, nil
              when '='
                do_calc
              else
                do_calc
                @previous, @number = @number, nil
                @op = btn
            end
            @number_field.replace strong @number
          end
        end
      end
    end
  end

Policeman

Replaced : to ; for Ruby 1.9. Then the simple-calc.rb worked well with Shoes-0.r1263.