MonkeyEngine 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.idea/.name +1 -0
  4. data/.idea/.rakeTasks +7 -0
  5. data/.idea/MonkeyEngine.iml +133 -0
  6. data/.idea/codeStyleSettings.xml +13 -0
  7. data/.idea/encodings.xml +5 -0
  8. data/.idea/misc.xml +5 -0
  9. data/.idea/modules.xml +9 -0
  10. data/.idea/runConfigurations/All_specs_in_test__MonkeyEngine.xml +38 -0
  11. data/.idea/runConfigurations/IRB_console.xml +25 -0
  12. data/.idea/runConfigurations/Start_Yard_Server.xml +26 -0
  13. data/.idea/runConfigurations/monkey_run.xml +26 -0
  14. data/.idea/scopes/scope_settings.xml +5 -0
  15. data/.idea/vcs.xml +7 -0
  16. data/.idea/workspace.xml +886 -0
  17. data/.ruby-version +1 -0
  18. data/Gemfile +4 -0
  19. data/LICENSE.txt +22 -0
  20. data/README.md +29 -0
  21. data/Rakefile +3 -0
  22. data/lib/Action/action.rb +29 -0
  23. data/lib/Monkey.rb +1 -0
  24. data/lib/Monkey/monkey.rb +108 -0
  25. data/lib/MonkeyAction/monkey_action.rb +14 -0
  26. data/lib/MonkeyAction/monkey_action_dead.rb +26 -0
  27. data/lib/MonkeyAction/monkey_action_eat.rb +31 -0
  28. data/lib/MonkeyAction/monkey_action_pause.rb +32 -0
  29. data/lib/MonkeyAction/monkey_action_sleep.rb +31 -0
  30. data/lib/MonkeyAction/monkey_action_type.rb +40 -0
  31. data/lib/MonkeyAction/monkey_action_wake.rb +26 -0
  32. data/lib/MonkeyAction/monkey_timed_action.rb +27 -0
  33. data/lib/MonkeyActions.rb +6 -0
  34. data/lib/MonkeyEngine.rb +1 -0
  35. data/lib/MonkeyEngine/action_rules.rb +111 -0
  36. data/lib/MonkeyEngine/exceptions.rb +21 -0
  37. data/lib/MonkeyEngine/monkey_engine.rb +53 -0
  38. data/lib/MonkeyEngine/version.rb +3 -0
  39. data/lib/MonkeyFactory.rb +1 -0
  40. data/lib/MonkeyFactory/monkey_factory.rb +14 -0
  41. data/lib/MonkeyKeyboard/keyboard_char.rb +10 -0
  42. data/lib/MonkeyKeyboard/keyboard_input.rb +14 -0
  43. data/lib/MonkeyKeyboard/keyboard_key.rb +26 -0
  44. data/lib/MonkeyKeyboard/keyboard_key_evaluator.rb +25 -0
  45. data/lib/MonkeyKeyboard/monkey_keyboard_en_us.rb +137 -0
  46. data/lib/MonkeyKeyboardEnUs.rb +1 -0
  47. data/lib/MonkeyManager.rb +1 -0
  48. data/lib/MonkeyManager/monkey_manager.rb +162 -0
  49. data/lib/MonkeyService.rb +1 -0
  50. data/lib/MonkeyService/monkey_service.rb +137 -0
  51. data/lib/tasks/engine.rb +91 -0
  52. data/monkeyengine.gemspec +32 -0
  53. data/spec/action_rules_spec.rb +59 -0
  54. data/spec/engine_spec.rb +56 -0
  55. data/spec/keyboard_char_spec.rb +12 -0
  56. data/spec/keyboard_key_spec.rb +15 -0
  57. data/spec/monkey_action_eat_spec.rb +86 -0
  58. data/spec/monkey_action_pause_spec.rb +91 -0
  59. data/spec/monkey_action_sleep_spec.rb +90 -0
  60. data/spec/monkey_action_type_spec.rb +94 -0
  61. data/spec/monkey_action_wake_spec.rb +58 -0
  62. data/spec/monkey_factory_spec.rb +23 -0
  63. data/spec/monkey_keyboard_en_us_spec.rb +42 -0
  64. data/spec/monkey_manager_spec.rb +8 -0
  65. data/spec/monkey_service_spec.rb +96 -0
  66. data/spec/monkey_spec.rb +8 -0
  67. data/spec/spec_helpers.rb +20 -0
  68. data/spec/support/shared_examples.rb +41 -0
  69. metadata +258 -0
@@ -0,0 +1 @@
1
+ require_relative 'MonkeyManager/monkey_manager'
@@ -0,0 +1,162 @@
1
+ require 'singleton'
2
+ require 'forwardable'
3
+
4
+ module MonkeyEngine
5
+
6
+ # The MonkeyManager.
7
+ #
8
+ # This class provides the functionality needed to manage Monkeys (See Monkey, MonkeyService)
9
+ #
10
+ class MonkeyManager
11
+ include Enumerable
12
+ extend Forwardable
13
+
14
+ def_delegators :@monkeys, :each
15
+
16
+ include Singleton
17
+
18
+ # The constructor
19
+ #
20
+ def initialize
21
+ @monkeys = Array.new
22
+ end
23
+
24
+ public
25
+
26
+ # Adds the Monkey to the list of Monkeys to be managed.
27
+ #
28
+ # @param (Monkey, #read) monkey The Monkey to add.
29
+ #
30
+ # @return [Monkey] the Monkey added.
31
+ #
32
+ # @raise [MonkeyEngine::Exceptions::InvalidArgumentTypeException] if parameter monkey is not a Monkey object.
33
+ # @raise [MonkeyEngine::Exceptions::UniqueObjectException] if monkey already exists.
34
+ #
35
+ def add(monkey)
36
+ raise MonkeyEngine::Exceptions::InvalidArgumentTypeException.new "Parameter 'monkey' is not Monkey object" unless monkey.is_a? Monkey
37
+ raise MonkeyEngine::Exceptions::UniqueObjectException.new "Monkeys must be unique" if exists? monkey
38
+
39
+ @monkeys.push(monkey)
40
+ monkey
41
+ end
42
+
43
+ # Returns the total count of Monkey objects being managed by this MonkeyManager.
44
+ #
45
+ # @return [int] The Monkey count.
46
+ #
47
+ def count
48
+ @monkeys.count
49
+ end
50
+
51
+ # Returns a [Boolean] indicating whether or not the Monkey exists (e.g. is currently being managed by this MonkeyManager).
52
+ #
53
+ # @param [Monkey, #read] monkey The Monkey to check.
54
+ #
55
+ # @return [Boolean] true if the Monkey is currently being manager by this MonkeyManager, false otherwise.
56
+ #
57
+ def exists?(monkey)
58
+ true unless get(monkey).nil?
59
+ end
60
+
61
+ # Returns a [Boolean] indicating whether or not the Monkey is alive (Monkey#alive?).
62
+ #
63
+ # @param [Monkey] monkey The Monkey to check.
64
+ #
65
+ # @return [Boolean] true if the Monkey is currently active (Monkey#.alive?), false otherwise.
66
+ #
67
+ def alive?(monkey)
68
+ monkey = get(monkey)
69
+ monkey.alive? unless monkey.nil?
70
+ end
71
+
72
+ # Returns the Monkey indicated by *monkey*.
73
+ #
74
+ # @param [Monkey, Symbol, String, #read] monkey The Monkey to return.
75
+ #
76
+ # @note Monkey#monkey_symbol is interrogated. If *monkey* is a [Monkey] object, Monkey#monkey_symbol is used;
77
+ # if *monkey* is a [Symbol], it is used; if *monkey* is a [String], String#to_sym is used.
78
+ #
79
+ # @return [Monkey] The Monkey if it exists.
80
+ #
81
+ # @raise [MonkeyEngine::Exceptions::InvalidArgumentTypeException] if parameter monkey is not a Monkey, Symbol, or String object.
82
+ #
83
+ def get(monkey)
84
+ return nil if @monkeys.empty?
85
+
86
+ # TODO: This seems inefficient.
87
+ return @monkeys.select { |m| m.monkey_symbol == monkey }.first if monkey.is_a? Symbol
88
+ return @monkeys.select { |m| m.monkey_symbol == monkey.to_sym }.first if monkey.is_a? String
89
+ return @monkeys.select { |m| m.monkey_symbol == monkey.monkey_symbol }.first if monkey.is_a? Monkey
90
+
91
+ raise MonkeyEngine::Exceptions::InvalidArgumentTypeException.new "Parameter 'monkey' is not a Symbol, String or Monkey object"
92
+ end
93
+
94
+ # Returns a duplicate Array of Monkey objects managed by this MonkeyManager.
95
+ #
96
+ # @return [Array] An Array of Monkey objects managed by this MonkeyManager.
97
+ #
98
+ def get_all
99
+ @monkeys.dup
100
+ end
101
+
102
+ # Removes the Monkey from the list of Monkeys being managed by this MonkeyManager.
103
+ #
104
+ # @param [Monkey] monkey The Monkey to delete.
105
+ #
106
+ # @note The Monkey to be deleted becomes unmanaged; the Monkey is NOT killed (Monkey#kill)
107
+ #
108
+ # @return [Monkey, nil] Returns the deleted Monkey, or nil if no matching Monkey was found to delete.
109
+ #
110
+ def delete(monkey)
111
+ @monkeys.delete(monkey)
112
+ end
113
+
114
+ # Suspends the calling threads execution until all Monkey threads exit, or,
115
+ # until _limit_ seconds have passed.
116
+ #
117
+ # @param [int] limit The seconds to wait for all Monkey threads to exit, or _nil_ to
118
+ # wait indefinitely.
119
+ #
120
+ # @return [Array, nil] Returns an [Array] of Monkey objects, or, nil, if no Monkey objects are being managed by
121
+ # this MonkeyManager.
122
+ #
123
+ def join_all(limit=nil)
124
+ limit = 0 unless limit.nil?
125
+ @monkeys.each { |monkey| monkey.join limit } unless @monkeys.empty?
126
+ end
127
+
128
+ # Kills the monkey.
129
+ #
130
+ # @param [Monkey, #read/#write, Symbol, String] monkey the Monkey to kill.
131
+ #
132
+ # @note The Monkey#monkey_do method executed continually by Monkey#thread is
133
+ # terminated.
134
+ #
135
+ # @return [Monkey] the Monkey that was killed.
136
+ #
137
+ def kill!(monkey)
138
+ monkey = get(monkey)
139
+ return if monkey.nil?
140
+
141
+ @monkeys.delete(monkey)
142
+ monkey.kill
143
+
144
+ monkey
145
+ end
146
+
147
+ # Kills all monkeys managed by this MonkeyManager.
148
+ #
149
+ # @note The Monkey#monkey_do method executed continually by Monkey#thread, for each Monkey is
150
+ # terminated.
151
+ #
152
+ # @return [Array] an Array of Monkey objects that were killed.
153
+ #
154
+ def kill_all!
155
+ @monkeys.each { |monkey| monkey.kill } unless @monkeys.empty?
156
+ monkeys = @monkeys.dup
157
+ @monkeys.clear
158
+
159
+ monkeys
160
+ end
161
+ end
162
+ end
@@ -0,0 +1 @@
1
+ require_relative 'MonkeyService/monkey_service'
@@ -0,0 +1,137 @@
1
+ require 'singleton'
2
+ require 'observer'
3
+ require 'forwardable'
4
+
5
+ require 'Monkey'
6
+ require 'MonkeyEngine'
7
+ require 'MonkeyManager'
8
+
9
+ module MonkeyEngine
10
+
11
+ # The monkey service.
12
+ #
13
+ # Provides the main interface for all functionality relating to
14
+ # the MonkeyEngine (see MonkeyEngine) and this gem. This class wraps
15
+ # MonkeyManager and MonkeyEngine classes.
16
+ #
17
+ class MonkeyService
18
+ include Singleton
19
+ include Observable
20
+ include Enumerable
21
+ extend Forwardable
22
+
23
+ def_delegators :@monkey_manager, :alive?, :get, :get_all, :count, :exists?, :join_all
24
+
25
+ def initialize
26
+ @monkey_manager = MonkeyEngine::MonkeyManager.instance
27
+ @engine = MonkeyEngine::Engine.instance
28
+ end
29
+
30
+ # Adds the Monkey to be managed.
31
+ #
32
+ # @param [Monkey, #read] monkey the Monkey to add.
33
+ #
34
+ # @note Observers are notified after this operation in the form of these update method params:
35
+ # ObserverKlass#update(param1, param2, param3); where param1=Time of the operation,
36
+ # param2=Symbol representing the operation (in this case, :add), param3=The following Hash:
37
+ # {monkey: [monkey]} where monkey=The Monkey added.
38
+ #
39
+ def add(monkey)
40
+ @monkey_manager.add(monkey).start
41
+ do_notify_observers(:add, {monkey: monkey})
42
+ end
43
+
44
+ # Determines if any Monkeys that are being managed by the
45
+ # underlining MonkeyManager are alive.
46
+ #
47
+ # @note A Monkey is considered alive if the Monkey#thread.alive? is true.
48
+ #
49
+ # @return [Boolean] true if any Monkeys are alive, false otherwise.
50
+ #
51
+ def any_alive?
52
+ return false if @monkey_manager.count == 0
53
+
54
+ alive_count = 0
55
+
56
+ @monkey_manager.each { |monkey| alive_count += 1 if monkey.alive? }
57
+
58
+ alive_count > 0
59
+ end
60
+
61
+ # Kills the monkey.
62
+ #
63
+ # @param [Monkey, #read/#write] monkey the Monkey to kill.
64
+ #
65
+ # @note The Monkey#monkey_do method executed continually by Monkey#thread is
66
+ # terminated.
67
+ #
68
+ # @note Observers are notified after this operation in the form of these update method params:
69
+ # ObserverKlass#update(param1, param2, param3); where param1=Time of the operation,
70
+ # param2=Symbol representing the operation (in this case, :kill!), param3=The following Hash:
71
+ # {monkey: [monkey]} where monkey=The Monkey killed.
72
+ #
73
+ def kill!(monkey)
74
+ @monkey_manager.kill!(monkey)
75
+ do_notify_observers(:kill!, {monkey: monkey})
76
+ end
77
+
78
+ # Kills all monkeys managed by the underlying MonkeyManager.
79
+ #
80
+ # @note The Monkey#monkey_do method executed continually by Monkey#thread, for each Monkey is
81
+ # terminated.
82
+ #
83
+ # @note Observers are notified after this operation in the form of these update method params:
84
+ # ObserverKlass#update(param1, param2, param3); where param1=Time of the operation,
85
+ # param2=Symbol representing the operation (in this case, :kill_all!), param3=nil.
86
+ #
87
+ # @return [Array] an Array of Monkey objects that were killed.
88
+ #
89
+ def kill_all!
90
+ monkey_array = @monkey_manager.kill_all!
91
+ do_notify_observers(:kill_all!, nil)
92
+ monkey_array
93
+ end
94
+
95
+ def new_action(monkey)
96
+ @engine.new_action monkey
97
+ end
98
+
99
+ # Performs the action against the Monkey associated with this action.
100
+ #
101
+ # @param [MonkeyActionDead, MonkeyActionEat, MonkeyActionPause, MonkeyActionSleep, MonkeyActionType, MonkeyActionWake, etc., #read/#write]
102
+ # action the action to apply against the Monkey associated with this action.
103
+ #
104
+ # @note Observers are notified after this operation in the form of these update method params:
105
+ # ObserverKlass#update(param1, param2, param3); where param1=Time of the operation,
106
+ # param2=Symbol representing the operation (in this case, :action_complete), param3=The following Hash:
107
+ # {action: [action]} where action=The action that was completed.
108
+ #
109
+ # @return (Boolean) true if the action performed has been completed (Action#action_completed?), false otherwise.
110
+ #
111
+ def monkey_do(action)
112
+ do_notify_observers(:action_completed, {action: action}) if @engine.do_action action
113
+ end
114
+
115
+ # Evaluates the given action, to determine whether or not the action is completed (Action#action_completed?).
116
+ #
117
+ # @param [MonkeyActionDead, MonkeyActionEat, MonkeyActionPause, MonkeyActionSleep, MonkeyActionType, MonkeyActionWake, etc., #read]
118
+ # action the action to interrogate as to whether or not it is completed (Action#action_completed?).
119
+ #
120
+ # @return (Boolean) true if the action is completed (Action#action_completed?), false otherwise.
121
+ #
122
+ def action_eval!(action)
123
+ @engine.action_eval! action
124
+ end
125
+
126
+ private
127
+
128
+ # Notifies all observers.
129
+ #
130
+ def do_notify_observers(param1, param2)
131
+ changed
132
+ notify_observers(Time.now, param1, param2)
133
+ end
134
+
135
+ end
136
+
137
+ end
@@ -0,0 +1,91 @@
1
+ require 'pry'
2
+
3
+ require 'yaml'
4
+ require "minitest/autorun"
5
+ require 'LittleWeasel'
6
+
7
+ require File.expand_path('../../MonkeyFactory', __FILE__)
8
+ require File.expand_path('../../MonkeyEngine', __FILE__)
9
+
10
+ module Runner
11
+
12
+ class MonkeyRun
13
+ attr_reader :monkey_service, :runtime, :thread, :words
14
+
15
+ def initialize(monkey_service, runtime)
16
+ @words = Array.new
17
+ @monkey_service = monkey_service
18
+ @runtime = runtime.to_i
19
+
20
+ @monkey_service.add_observer self
21
+
22
+ @thread = Thread.new {
23
+ go
24
+ sleep @runtime
25
+ }
26
+
27
+ self
28
+ end
29
+
30
+ #protected
31
+
32
+ def go
33
+ @monkey_service.add(MonkeyFactory::create :groucho)
34
+ @monkey_service.add(MonkeyFactory::create :harpo)
35
+ @monkey_service.add(MonkeyFactory::create :chico)
36
+ @monkey_service.add(MonkeyFactory::create :zeppo)
37
+ end
38
+
39
+ def update(time, action, param)
40
+ begin
41
+
42
+ return unless param.is_a?(Hash) && param.has_key?(:action)
43
+
44
+ if param[:action].is_a?(MonkeyActionType) && action == :action_completed
45
+
46
+ monkey = param[:action].monkey.monkey_symbol.to_s
47
+ is_word = param[:action].keyboard_input.is_word
48
+ word = param[:action].keyboard_input.input_to_s
49
+
50
+ #if param[:action].is_a?(MonkeyActionType) && action == :action_completed
51
+ puts "Monkey: [#{monkey.capitalize}] | Is Word: [#{is_word}] | Value: [#{word.capitalize}]"
52
+ #end
53
+
54
+ if is_word
55
+ @words << { word: word, monkey: monkey }
56
+ end
57
+ end
58
+ rescue Exception => e
59
+ puts "Exception: #{e}"
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+
66
+ namespace :engine do
67
+ desc "Run the MonkeyEngine"
68
+ task :run do
69
+ runtime = 10 #ARGV[0]
70
+
71
+ service = MonkeyEngine::MonkeyService.instance
72
+
73
+ LittleWeasel::Checker.instance.options = {exclude_alphabet: true, strip_whitespace: false, ignore_numeric: false}
74
+
75
+ runner = Runner::MonkeyRun.new service, runtime
76
+ runner.thread.join
77
+
78
+ service.kill_all!
79
+ service.join_all(10)
80
+
81
+ puts "Total valid words: #{runner.words.count}"
82
+
83
+ runner.words.sort!{|a,b| a[:monkey]<=>b[:monkey]}
84
+
85
+ runner.words.each { |word|
86
+ puts "Monkey [#{word[:monkey].capitalize}] typed [#{word[:word].capitalize}]"
87
+ }
88
+ end
89
+ end
90
+
91
+
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'MonkeyEngine/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "MonkeyEngine"
8
+ spec.version = MonkeyEngine::VERSION
9
+ spec.authors = ["Gene M. Angelo, Jr."]
10
+ spec.email = ["public.gma@gmail.com"]
11
+ spec.description = %q{MonkeyEngine - FUN!}
12
+ spec.summary = %q{The engine that drives my monkeys!}
13
+ spec.homepage = "http://www.geneangelo.com"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.required_ruby_version = '~> 2.1'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.3'
24
+ spec.add_development_dependency 'rake', '~> 0'
25
+ spec.add_development_dependency 'rspec', '~> 3.0', '>= 3.0.0'
26
+ spec.add_development_dependency 'yard', '0.8.6.2'
27
+ spec.add_development_dependency 'redcarpet', '~> 2.3', '>= 2.3.0'
28
+ spec.add_development_dependency 'pry'
29
+
30
+ spec.add_runtime_dependency 'LittleWeasel', '~> 3.0'
31
+ spec.add_runtime_dependency 'ProtectedConstructor', '~> 2.0', '>=2.0.0'
32
+ end
@@ -0,0 +1,59 @@
1
+ require_relative 'spec_helpers'
2
+
3
+ require 'Monkey'
4
+ require 'MonkeyFactory'
5
+ require 'MonkeyEngine'
6
+ require 'MonkeyManager'
7
+ require 'MonkeyActions'
8
+ require_relative '../lib/MonkeyKeyboard/keyboard_input'
9
+
10
+ describe 'ActionRules' do
11
+
12
+ before(:each) do
13
+ end
14
+
15
+ after(:all) do
16
+ end
17
+
18
+ context 'get_next_action' do
19
+
20
+ it 'should throw an exception if the action is not completed' do
21
+ monkey = MonkeyFactory::create :groucho
22
+
23
+ monkey.extend(SpecHelpers::SetMonkeyAction)
24
+
25
+ keyboard_input = KeyboardInput.new
26
+ keyboard_input.input = %w{H e l l o}
27
+
28
+ action = MonkeyActionType.new(monkey, keyboard_input)
29
+ action.action_completed = false
30
+
31
+ monkey.set_action(action)
32
+
33
+ lambda { ActionRules.instance.get_next_action monkey }.should raise_error MonkeyEngine::Exceptions::InvalidOperationException
34
+ end
35
+
36
+ it 'should get correct action if current action is nil?' do
37
+ monkey = MonkeyFactory::create :groucho
38
+
39
+ monkey.extend(SpecHelpers::SetMonkeyAction)
40
+
41
+ monkey.set_action(nil)
42
+
43
+ ActionRules.instance.get_next_action(monkey).is_a?(MonkeyActionWake).should == true
44
+ end
45
+
46
+ it 'should get correct action if current action is MonkeyActionSleep' do
47
+ monkey = MonkeyFactory::create :groucho
48
+
49
+ monkey.extend(SpecHelpers::SetMonkeyAction)
50
+
51
+ action = MonkeyActionSleep.new(monkey, 6 * 60)
52
+ action.action_completed = true
53
+
54
+ monkey.set_action(action)
55
+
56
+ ActionRules.instance.get_next_action(monkey).is_a?(MonkeyActionWake).should == true
57
+ end
58
+ end
59
+ end