Милен обнови решението на 29.12.2016 10:28 (преди почти 8 години)
+module EntryPoint
+ attr_accessor :variables
+
+ def its_showtime
+ @variables = {}
+ end
+
+ def you_have_been_terminated
+ @variables = {}
+ end
+end
+
+module VariableInitializer
+ attr_reader :current_variable
+
+ def get_to_the_chopper(variable)
+ @variables[variable] = nil
+ @current_variable = variable
+ end
+
+ def here_is_my_invitation(value)
+ @variables[@current_variable] = get_value_or_variable(value)
+ end
+
+ # operator +
+ def get_up(value)
+ previous = @variables[@current_variable]
+ @variables[@current_variable] = previous + get_value_or_variable(value)
+ end
+
+ # operator -
+ def get_down(value)
+ previous = @variables[@current_variable]
+ @variables[@current_variable] = previous - get_value_or_variable(value)
+ end
+
+ # operator *
+ def youre_fired(value)
+ previous = @variables[@current_variable]
+ @variables[@current_variable] = previous * get_value_or_variable(value)
+ end
+
+ # operator /
+ def he_had_to_split(value)
+ previous = @variables[@current_variable]
+ @variables[@current_variable] = previous / get_value_or_variable(value)
+ end
+
+ # operator %
+ def i_let_him_go(value)
+ previous = @variables[@current_variable]
+ @variables[@current_variable] = previous % get_value_or_variable(value)
+ end
+
+ def enough_talk
+ @current_variable = nil
+ end
+end
+
+module LogicalOperatorMethods
+ def i_lied
+ 0
+ end
+
+ def no_problemo
+ 1
+ end
+
+ def true?(value)
+ # everything different from 0
+ value != i_lied
+ end
+
+ # operator or
+ def consider_that_a_divorce(value)
+ # value could be variable
+ # that is the reason to use get_value_or_variable(value)
+
+ previous = @variables[@current_variable]
+ new_value = true?(previous) ? previous : get_value_or_variable(value)
+ @variables[@current_variable] = new_value
+ end
+
+ # operator and
+ def knock_knock(value)
+ # value could be variable
+
+ previous = @variables[@current_variable]
+ new_value = true?(previous) ? get_value_or_variable(value) : previous
+ @variables[@current_variable] = new_value
+ end
+end
+
+module ComparableOperators
+ # operator >
+ def let_off_some_steam_bennet(value)
+ # value could be variable
+
+ current_value = @variables[@current_variable]
+ @variables[@current_variable] = current_value > get_value_or_variable(value)
+ end
+end
+
+module FunctionDeclarations
+ attr_accessor :function_name
+ attr_accessor :parameters
+ attr_accessor :is_void_function
+
+ def listen_to_me_very_carefully(function_name)
+ @function_name = function_name
+ @parameters = {}
+ @is_void_function = true
+ end
+
+ def i_need_your_clothes_your_boots_and_your_motorcycle(parameter)
+ @parameters[parameter] = nil
+ end
+
+ def give_these_people_air
+ @is_void_function = false
+ end
+
+ def ill_be_back(return_value = nil)
+ # TODO: value could be variable
+ return_value.nil? ? 0 : return_value
+ end
+
+ def hasta_la_vista_baby
+ # TODO: create body for method
+ end
+end
+
+module ArnoldCPM
+ class << ArnoldCPM
+ include EntryPoint
+ include VariableInitializer
+ include LogicalOperatorMethods
+ include ComparableOperators
+ include FunctionDeclarations
+
+ attr_accessor :printer
+
+ def talk_to_the_hand(value)
+ to_print = get_value_or_variable(value)
+ ArnoldCPM.printer.print(to_print)
+ end
+
+ def get_value_or_variable(value)
+ # when variable -> it is symbol
+ # when number -> only value
+ @variables.key?(value) ? @variables[value] : value
+ end
+
+ def method_missing(name)
+ name
+ end
+
+ def totally_recall(&block)
+ instance_eval(&block)
+ end
+ end
+end
Лог от изпълнението при ръчна проверка:
...FFFFFFFFF.............FFFF
Failures:
1) ArnoldCPM can define and call functions with arguments
Failure/Error: talk_to_the_hand _n
#<Double "printer"> received :print with unexpected arguments
expected: (11)
got: (:_n)
# ./solution.rb:140:in `talk_to_the_hand'
# ./spec.rb:478:in `block (3 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:475:in `block (2 levels) in <top (required)>'
2) ArnoldCPM can define and call functions with return value
Failure/Error: get_your_ass_to_mars _invocation_result
ArgumentError:
wrong number of arguments (given 2, expected 1)
# ./solution.rb:149:in `method_missing'
# ./spec.rb:508:in `block (3 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:499:in `block (2 levels) in <top (required)>'
3) ArnoldCPM returns 0 by default
Failure/Error: get_your_ass_to_mars _invocation_result
ArgumentError:
wrong number of arguments (given 2, expected 1)
# ./solution.rb:149:in `method_missing'
# ./spec.rb:532:in `block (3 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:525:in `block (2 levels) in <top (required)>'
4) ArnoldCPM can take functions as arguments
Failure/Error: talk_to_the_hand 6
(Double "printer").print(6)
expected: 0 times with arguments: (6)
received: 1 time with arguments: (6)
# ./solution.rb:140:in `talk_to_the_hand'
# ./spec.rb:564:in `block (3 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:556:in `block (2 levels) in <top (required)>'
5) ArnoldCPM can return functions
Failure/Error: get_your_ass_to_mars _forty_two_printer
ArgumentError:
wrong number of arguments (given 2, expected 1)
# ./solution.rb:149:in `method_missing'
# ./spec.rb:605:in `block (3 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:593:in `block (2 levels) in <top (required)>'
6) ArnoldCPM defines new inner functions for each function invocation
Failure/Error: get_your_ass_to_mars _first_invocation
ArgumentError:
wrong number of arguments (given 2, expected 1)
# ./solution.rb:149:in `method_missing'
# ./spec.rb:635:in `block (3 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:625:in `block (2 levels) in <top (required)>'
7) ArnoldCPM supports basic recursion
Failure/Error: get_up 1
NoMethodError:
undefined method `+' for :_from:Symbol
# ./solution.rb:27:in `get_up'
# ./spec.rb:674:in `block (3 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:666:in `block (2 levels) in <top (required)>'
8) ArnoldCPM can calculate fibonacci(20) recursively
Failure/Error: let_off_some_steam_bennet _n
ArgumentError:
comparison of Fixnum with :_n failed
# ./solution.rb:97:in `>'
# ./solution.rb:97:in `let_off_some_steam_bennet'
# ./spec.rb:720:in `block (3 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:714:in `block (2 levels) in <top (required)>'
9) ArnoldCPM can use closures in very convoluted ways
Failure/Error: get_your_ass_to_mars _result
ArgumentError:
wrong number of arguments (given 2, expected 1)
# ./solution.rb:149:in `method_missing'
# ./spec.rb:776:in `block (3 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:765:in `block (2 levels) in <top (required)>'
10) ArnoldCPM has branching mechanism that can execute if statements
Failure/Error: because_im_going_to_say_please no_problemo
ArgumentError:
wrong number of arguments (given 2, expected 1)
# ./solution.rb:149:in `method_missing'
# ./spec.rb:336:in `block (4 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:334:in `block (3 levels) in <top (required)>'
11) ArnoldCPM has branching mechanism that can execute if-else statements
Failure/Error: because_im_going_to_say_please no_problemo
ArgumentError:
wrong number of arguments (given 2, expected 1)
# ./solution.rb:149:in `method_missing'
# ./spec.rb:363:in `block (4 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:361:in `block (3 levels) in <top (required)>'
12) ArnoldCPM has branching mechanism that can nest if-else statements
Failure/Error: because_im_going_to_say_please no_problemo
ArgumentError:
wrong number of arguments (given 2, expected 1)
# ./solution.rb:149:in `method_missing'
# ./spec.rb:410:in `block (4 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:408:in `block (3 levels) in <top (required)>'
13) ArnoldCPM has branching mechanism that considers functions truthy
Failure/Error: because_im_going_to_say_please _function
ArgumentError:
wrong number of arguments (given 2, expected 1)
# ./solution.rb:149:in `method_missing'
# ./spec.rb:456:in `block (4 levels) in <top (required)>'
# ./solution.rb:154:in `instance_eval'
# ./solution.rb:154:in `totally_recall'
# ./spec.rb:451:in `block (3 levels) in <top (required)>'
Finished in 0.0238 seconds (files took 0.10159 seconds to load)
29 examples, 13 failures
Failed examples:
rspec ./spec.rb:466 # ArnoldCPM can define and call functions with arguments
rspec ./spec.rb:489 # ArnoldCPM can define and call functions with return value
rspec ./spec.rb:517 # ArnoldCPM returns 0 by default
rspec ./spec.rb:540 # ArnoldCPM can take functions as arguments
rspec ./spec.rb:583 # ArnoldCPM can return functions
rspec ./spec.rb:613 # ArnoldCPM defines new inner functions for each function invocation
rspec ./spec.rb:651 # ArnoldCPM supports basic recursion
rspec ./spec.rb:695 # ArnoldCPM can calculate fibonacci(20) recursively
rspec ./spec.rb:760 # ArnoldCPM can use closures in very convoluted ways
rspec ./spec.rb:324 # ArnoldCPM has branching mechanism that can execute if statements
rspec ./spec.rb:347 # ArnoldCPM has branching mechanism that can execute if-else statements
rspec ./spec.rb:378 # ArnoldCPM has branching mechanism that can nest if-else statements
rspec ./spec.rb:441 # ArnoldCPM has branching mechanism that considers functions truthy
На пръв поглед изглежда чисто, но като цяло стратегията за отделяне на логика "събери кофа подобни методи в модул и го include-ни" единствено води до това да търсиш имплементацията на едно нещо на много места. Нещо, което може да ти подскаже, че многото неща всъщност са едно нещо, е използването на едно и също състояние - @variables
. Може да погледнеш нашето решение относно как сме сметнали да разделим различните отговорности.
Самият ArnoldCPM
не трябваше да пази друг контекст освен printer
-a. Ако реша да пусна две програми една след друга, променливите от първата ще бъдат налични във втората.
Надявам се задачата да ти е била интересна и полезна.