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
#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
#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.
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.
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.
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.
This is an alternative code. There is no interesting tips but it's simple, I guess. :)
#sample61.rb
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