angry_mob 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. data/LICENSE +21 -0
  2. data/README.md +123 -0
  3. data/bin/mob +139 -0
  4. data/lib/angry_mob.rb +28 -0
  5. data/lib/angry_mob/act.rb +111 -0
  6. data/lib/angry_mob/act/scheduler.rb +143 -0
  7. data/lib/angry_mob/action.rb +11 -0
  8. data/lib/angry_mob/builder.rb +115 -0
  9. data/lib/angry_mob/extend.rb +10 -0
  10. data/lib/angry_mob/extend/array.rb +30 -0
  11. data/lib/angry_mob/extend/blank.rb +108 -0
  12. data/lib/angry_mob/extend/blankslate.rb +109 -0
  13. data/lib/angry_mob/extend/dictionary.rb +140 -0
  14. data/lib/angry_mob/extend/hash.rb +67 -0
  15. data/lib/angry_mob/extend/object.rb +21 -0
  16. data/lib/angry_mob/extend/pathname.rb +23 -0
  17. data/lib/angry_mob/extend/string.rb +8 -0
  18. data/lib/angry_mob/log.rb +28 -0
  19. data/lib/angry_mob/mob.rb +77 -0
  20. data/lib/angry_mob/mob_loader.rb +115 -0
  21. data/lib/angry_mob/node.rb +44 -0
  22. data/lib/angry_mob/notifier.rb +76 -0
  23. data/lib/angry_mob/target.rb +257 -0
  24. data/lib/angry_mob/target/arguments.rb +71 -0
  25. data/lib/angry_mob/target/call.rb +57 -0
  26. data/lib/angry_mob/target/default_resource_locator.rb +11 -0
  27. data/lib/angry_mob/target/defaults.rb +23 -0
  28. data/lib/angry_mob/target/mother.rb +66 -0
  29. data/lib/angry_mob/target/notify.rb +57 -0
  30. data/lib/angry_mob/target/tracking.rb +96 -0
  31. data/lib/angry_mob/ui.rb +247 -0
  32. data/lib/angry_mob/util.rb +11 -0
  33. data/lib/angry_mob/vendored.rb +8 -0
  34. data/lib/angry_mob/version.rb +3 -0
  35. data/vendor/angry_hash/Rakefile +17 -0
  36. data/vendor/angry_hash/VERSION +1 -0
  37. data/vendor/angry_hash/angry_hash.gemspec +47 -0
  38. data/vendor/angry_hash/examples/accessors_eg.rb +46 -0
  39. data/vendor/angry_hash/examples/creation_eg.rb +43 -0
  40. data/vendor/angry_hash/examples/dsl.eg.rb +18 -0
  41. data/vendor/angry_hash/examples/dup_eg.rb +86 -0
  42. data/vendor/angry_hash/examples/eg_helper.rb +24 -0
  43. data/vendor/angry_hash/examples/merge_eg.rb +135 -0
  44. data/vendor/angry_hash/lib/angry_hash.rb +215 -0
  45. data/vendor/angry_hash/lib/angry_hash/dsl.rb +44 -0
  46. data/vendor/angry_hash/lib/angry_hash/extension_tracking.rb +12 -0
  47. data/vendor/angry_hash/lib/angry_hash/merge_string.rb +58 -0
  48. data/vendor/json/COPYING +58 -0
  49. data/vendor/json/GPL +340 -0
  50. data/vendor/json/README +360 -0
  51. data/vendor/json/lib/json/common.rb +371 -0
  52. data/vendor/json/lib/json/pure.rb +77 -0
  53. data/vendor/json/lib/json/pure/generator.rb +443 -0
  54. data/vendor/json/lib/json/pure/parser.rb +303 -0
  55. data/vendor/json/lib/json/version.rb +8 -0
  56. data/vendor/thor/CHANGELOG.rdoc +89 -0
  57. data/vendor/thor/LICENSE +20 -0
  58. data/vendor/thor/README.rdoc +297 -0
  59. data/vendor/thor/Thorfile +69 -0
  60. data/vendor/thor/bin/rake2thor +86 -0
  61. data/vendor/thor/bin/thor +6 -0
  62. data/vendor/thor/lib/thor.rb +244 -0
  63. data/vendor/thor/lib/thor/actions.rb +275 -0
  64. data/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  65. data/vendor/thor/lib/thor/actions/directory.rb +91 -0
  66. data/vendor/thor/lib/thor/actions/empty_directory.rb +134 -0
  67. data/vendor/thor/lib/thor/actions/file_manipulation.rb +223 -0
  68. data/vendor/thor/lib/thor/actions/inject_into_file.rb +104 -0
  69. data/vendor/thor/lib/thor/base.rb +540 -0
  70. data/vendor/thor/lib/thor/core_ext/file_binary_read.rb +9 -0
  71. data/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  72. data/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
  73. data/vendor/thor/lib/thor/error.rb +30 -0
  74. data/vendor/thor/lib/thor/group.rb +271 -0
  75. data/vendor/thor/lib/thor/invocation.rb +180 -0
  76. data/vendor/thor/lib/thor/parser.rb +4 -0
  77. data/vendor/thor/lib/thor/parser/argument.rb +67 -0
  78. data/vendor/thor/lib/thor/parser/arguments.rb +150 -0
  79. data/vendor/thor/lib/thor/parser/option.rb +128 -0
  80. data/vendor/thor/lib/thor/parser/options.rb +169 -0
  81. data/vendor/thor/lib/thor/rake_compat.rb +66 -0
  82. data/vendor/thor/lib/thor/runner.rb +314 -0
  83. data/vendor/thor/lib/thor/shell.rb +83 -0
  84. data/vendor/thor/lib/thor/shell/basic.rb +239 -0
  85. data/vendor/thor/lib/thor/shell/color.rb +108 -0
  86. data/vendor/thor/lib/thor/task.rb +102 -0
  87. data/vendor/thor/lib/thor/util.rb +224 -0
  88. data/vendor/thor/lib/thor/version.rb +3 -0
  89. data/vendor/thor/spec/actions/create_file_spec.rb +170 -0
  90. data/vendor/thor/spec/actions/directory_spec.rb +131 -0
  91. data/vendor/thor/spec/actions/empty_directory_spec.rb +91 -0
  92. data/vendor/thor/spec/actions/file_manipulation_spec.rb +271 -0
  93. data/vendor/thor/spec/actions/inject_into_file_spec.rb +135 -0
  94. data/vendor/thor/spec/actions_spec.rb +292 -0
  95. data/vendor/thor/spec/base_spec.rb +263 -0
  96. data/vendor/thor/spec/core_ext/hash_with_indifferent_access_spec.rb +43 -0
  97. data/vendor/thor/spec/core_ext/ordered_hash_spec.rb +115 -0
  98. data/vendor/thor/spec/fixtures/application.rb +2 -0
  99. data/vendor/thor/spec/fixtures/bundle/execute.rb +6 -0
  100. data/vendor/thor/spec/fixtures/bundle/main.thor +1 -0
  101. data/vendor/thor/spec/fixtures/doc/%file_name%.rb.tt +1 -0
  102. data/vendor/thor/spec/fixtures/doc/README +3 -0
  103. data/vendor/thor/spec/fixtures/doc/config.rb +1 -0
  104. data/vendor/thor/spec/fixtures/group.thor +90 -0
  105. data/vendor/thor/spec/fixtures/invoke.thor +112 -0
  106. data/vendor/thor/spec/fixtures/script.thor +145 -0
  107. data/vendor/thor/spec/fixtures/task.thor +10 -0
  108. data/vendor/thor/spec/group_spec.rb +171 -0
  109. data/vendor/thor/spec/invocation_spec.rb +107 -0
  110. data/vendor/thor/spec/parser/argument_spec.rb +47 -0
  111. data/vendor/thor/spec/parser/arguments_spec.rb +64 -0
  112. data/vendor/thor/spec/parser/option_spec.rb +202 -0
  113. data/vendor/thor/spec/parser/options_spec.rb +292 -0
  114. data/vendor/thor/spec/rake_compat_spec.rb +68 -0
  115. data/vendor/thor/spec/runner_spec.rb +210 -0
  116. data/vendor/thor/spec/shell/basic_spec.rb +205 -0
  117. data/vendor/thor/spec/shell/color_spec.rb +41 -0
  118. data/vendor/thor/spec/shell_spec.rb +34 -0
  119. data/vendor/thor/spec/spec.opts +1 -0
  120. data/vendor/thor/spec/spec_helper.rb +54 -0
  121. data/vendor/thor/spec/task_spec.rb +69 -0
  122. data/vendor/thor/spec/thor_spec.rb +237 -0
  123. data/vendor/thor/spec/util_spec.rb +163 -0
  124. data/vendor/thor/thor.gemspec +120 -0
  125. metadata +199 -0
@@ -0,0 +1,67 @@
1
+ class Hash
2
+ def delete_all_of(*keys)
3
+ keys = keys.map {|k| [ k.to_s, k.to_sym ]}.flatten.uniq
4
+ values = values_at(*keys).flatten.compact.uniq
5
+ keys.each {|k| delete k}
6
+ values
7
+ end
8
+
9
+ # from ActiveSupport:
10
+ #
11
+ # Returns a new hash with +self+ and +other_hash+ merged recursively.
12
+ def deep_merge(other_hash)
13
+ self.merge(other_hash) do |key, oldval, newval|
14
+ oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
15
+ newval = newval.to_hash if newval.respond_to?(:to_hash)
16
+ oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? oldval.deep_merge(newval) : newval
17
+ end
18
+ end
19
+
20
+ # Returns a new hash with +self+ and +other_hash+ merged recursively.
21
+ # Modifies the receiver in place.
22
+ def deep_merge!(other_hash)
23
+ replace(deep_merge(other_hash))
24
+ end
25
+
26
+ # Return a new hash with all keys converted to symbols.
27
+ def symbolize_keys
28
+ inject({}) do |options, (key, value)|
29
+ options[(key.to_sym rescue key) || key] = value
30
+ options
31
+ end
32
+ end
33
+
34
+ # Destructively convert all keys to symbols.
35
+ def symbolize_keys!
36
+ self.replace(self.symbolize_keys)
37
+ end
38
+
39
+ def deep_symbolize_keys
40
+ inject({}) do |options, (key, value)|
41
+ options[(key.to_sym rescue key) || key] = __recurse_deep_symbolize_keys(value)
42
+ options
43
+ end
44
+ end
45
+
46
+ def __recurse_deep_symbolize_keys(value)
47
+ case value
48
+ when Hash
49
+ value.deep_symbolize_keys
50
+ when Array
51
+ value.map {|v| __recurse_deep_symbolize_keys(v)}
52
+ else
53
+ value
54
+ end
55
+ end
56
+
57
+
58
+ end
59
+
60
+ class AngryHash
61
+ def delete_all_of(*keys)
62
+ keys.map {|k| delete(k.to_s)}.compact.uniq
63
+ end
64
+
65
+ require 'angry_hash/merge_string'
66
+ include AngryHash::MergeString
67
+ end
@@ -0,0 +1,21 @@
1
+ require 'pp'
2
+
3
+ class Object
4
+ def tapp(tag=nil)
5
+ print "#{tag}=" if tag
6
+ pp self
7
+ self
8
+ end
9
+
10
+ def stapp(tag=nil)
11
+ print "#{tag} " if tag
12
+ puts "c=#{self.class} i=#{self.inspect[0..100]}"
13
+ self
14
+ end
15
+
16
+
17
+ def returning(obj)
18
+ yield obj
19
+ obj
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ require 'fileutils'
2
+
3
+ class Pathname
4
+ def self.here(file)
5
+ Pathname(file).dirname.expand_path
6
+ end
7
+
8
+ def pathname
9
+ Pathname(self)
10
+ end
11
+
12
+ def touch
13
+ FileUtils.touch(self)
14
+ end
15
+
16
+ def cp_to(to)
17
+ FileUtils.cp(self,to)
18
+ end
19
+
20
+ def ls
21
+ Pathname.glob(self+'*').reject {|e| e.basename.to_s[0] == '.'}
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ require 'pathname'
2
+
3
+ class String
4
+ def pathname
5
+ Pathname(self)
6
+ end
7
+ alias_method :p, :pathname
8
+ end
@@ -0,0 +1,28 @@
1
+ class AngryMob
2
+ module Log
3
+
4
+ def __class_to_s
5
+ @__class_to_s ||= __class_to_s!
6
+ end
7
+ def __class_to_s!
8
+ @__class_to_s = self.class.to_s.sub(/^AngryMob::/,'AM::').sub(/^Target\[/,'T[')
9
+ @__class_to_s[0..19]
10
+ end
11
+
12
+ def log(*msg)
13
+ puts " %-20s| #{msg * ' '}" % __class_to_s
14
+ rescue
15
+ puts "#{self.class.to_s} | #{msg * ' '}"
16
+ ensure
17
+ $stdout.flush
18
+ end
19
+
20
+ def debug(*msg)
21
+ puts "* %-20s| #{msg * ' '}" % __class_to_s
22
+ rescue
23
+ puts "Debug #{self.class.to_s} | #{msg * ' '}"
24
+ ensure
25
+ $stdout.flush
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,77 @@
1
+ class AngryMob
2
+ class MobError < StandardError; end
3
+ class Mob
4
+ attr_reader :node, :notifier, :act_scheduler, :target_mother
5
+
6
+ def initialize
7
+ @target_mother = Target::Mother.new(self)
8
+ @act_scheduler = Act::Scheduler.new(self)
9
+ end
10
+
11
+ # delegate to the curren ui
12
+ def self.ui
13
+ (@ui ||= ui!).current
14
+ end
15
+ def self.ui!
16
+ @ui = UI.new
17
+ end
18
+ def self.ui=(ui)
19
+ @ui = ui
20
+ end
21
+ def ui
22
+ self.class.ui
23
+ end
24
+
25
+ # main entry point the the whole system
26
+ def riot!(nodename, attributes)
27
+ start = Time.now
28
+ ui.info "An AngryMob is rioting on #{nodename}."
29
+
30
+ @node = Node.new(nodename, attributes)
31
+ @act_scheduler.node = @node
32
+ @notifier = Notifier.new(self)
33
+
34
+ setup!
35
+ run!
36
+
37
+ ui.info "beaten in #{Time.now-start}s"
38
+ ui.info "#{nodename} has been beaten by an AngryMob. Have a nice day!"
39
+
40
+ @target_mother.clear_instances!
41
+ @act_scheduler.reset!
42
+ end
43
+
44
+ # bind selected targets to the node
45
+ def setup!
46
+ ui.task "setting up node"
47
+ defaults = AngryHash.new
48
+
49
+ setup_node[node,defaults] if setup_node
50
+ node_defaults[node,defaults] if node_defaults
51
+ consolidate_node[node,defaults] if consolidate_node
52
+
53
+ node.setup_finished!
54
+
55
+ ui.good "setup complete"
56
+
57
+ self
58
+ end
59
+
60
+ # runs acts and then delayed targets
61
+ def run!
62
+ act_scheduler.run!
63
+ end
64
+
65
+ # building
66
+ # builder populates the following with definition blocks
67
+
68
+ # node defaults
69
+ attr_accessor :setup_node, :consolidate_node, :node_defaults
70
+
71
+ # acts
72
+ def acts
73
+ @acts ||= Dictionary.new
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,115 @@
1
+ require 'tsort'
2
+
3
+ class AngryMob
4
+ class MobLoadingError < StandardError; end
5
+
6
+ ::Target = AngryMob::Target
7
+
8
+ class MobLoader
9
+ attr_reader :builder, :mobs, :loaded_mobs
10
+
11
+ def ui
12
+ Mob.ui
13
+ end
14
+
15
+ def initialize
16
+ @builder = Builder.new
17
+ @mobs = Dictionary.new
18
+ @loaded_mobs = {}
19
+ end
20
+
21
+ def add_mob(path,name=nil)
22
+ path = Pathname(path).expand_path
23
+ name ||= path.basename.to_s
24
+
25
+ ui.log "added mob #{name} from #{path}"
26
+
27
+ mobs[name] ||= path
28
+ end
29
+
30
+ def load_a_mob(name)
31
+ path = mobs[name]
32
+ raise "unable to load unknown mob #{name}" unless path
33
+
34
+ return if loaded_mobs[name]
35
+ loaded_mobs[name] = true
36
+
37
+ old_path,@current_path = @current_path,path
38
+
39
+ ui.push("loading mob #{name} at path #{path}") do
40
+
41
+ mob_root = path
42
+
43
+ loader = path+'load_mob.rb'
44
+
45
+ if loader.exist?
46
+ instance_eval(loader.read,loader.to_s)
47
+ else
48
+ load_lib(path+'lib')
49
+ load_targets(path+'targets')
50
+ load_acts(path+'acts')
51
+ end
52
+ end
53
+
54
+ self
55
+ ensure
56
+ @current_path = old_path
57
+ end
58
+
59
+ def load_mobs
60
+ mobs.keys.each do |name|
61
+ load_a_mob(name)
62
+ end
63
+ end
64
+
65
+ def to_mob
66
+ load_mobs
67
+ @builder.to_mob
68
+ end
69
+
70
+
71
+ # API
72
+
73
+ alias_method :depends_on_mob, :load_a_mob
74
+
75
+ def load_targets(path=nil)
76
+ path ||= mob_root + 'targets'
77
+
78
+ raise "targets path #{path} didn't exist" unless path.exist?
79
+ ui.log "loading targets from #{path}"
80
+
81
+ $LOAD_PATH << path
82
+ Pathname.glob(path+'**/*.rb').each do |file|
83
+ require file
84
+ end
85
+ end
86
+
87
+ def load_lib(path=nil)
88
+ path ||= mob_root + 'lib'
89
+
90
+ raise "lib path #{path} didn't exist" unless path.exist?
91
+
92
+ ui.log "adding load path #{path}"
93
+ $LOAD_PATH << path
94
+ end
95
+
96
+ def load_acts(path=nil)
97
+ path ||= mob_root + 'acts'
98
+
99
+ raise "acts path #{path} didn't exist" unless path.exist?
100
+ ui.log "loading acts from #{path}"
101
+
102
+ Pathname.glob(path+'**/*.rb').each do |file|
103
+ @builder.from_file(file)
104
+ end
105
+ end
106
+
107
+ def load_act_file(path)
108
+ raise "act file at path #{path} didn't exist" unless path.exist?
109
+ ui.log "loading acts from #{path}"
110
+
111
+ @builder.from_file(path)
112
+ end
113
+
114
+ end
115
+ end
@@ -0,0 +1,44 @@
1
+ class AngryMob
2
+ class Node < Struct.new(:name,:attributes,:resource_locator)
3
+ include Log
4
+
5
+ def initialize(name, attributes)
6
+ self.name = name
7
+ self.attributes = AngryHash[attributes]
8
+ end
9
+
10
+ def merge_defaults!(attrs)
11
+ puts "merging defaults"
12
+ attributes.reverse_deep_merge!(attrs)
13
+ end
14
+
15
+ def setup_finished!
16
+ self.resource_locator ||= AngryMob::Target::DefaultResourceLocator.new
17
+ end
18
+
19
+ def consolidate!
20
+ node = self
21
+ __consolidate_hash(attributes,{})
22
+ end
23
+
24
+
25
+ def __consolidate_hash(hash,seen)
26
+
27
+ return if seen.key?(hash)
28
+ seen[hash] = true
29
+
30
+ hash.each do |key,value|
31
+ case value
32
+ when Hash
33
+ __consolidate_hash(value,seen)
34
+ when Proc
35
+ hash[key] = value[self]
36
+ end
37
+ end
38
+ end
39
+
40
+ def method_missing(method,*args,&block)
41
+ attributes.__send__(method,*args)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,76 @@
1
+ class AngryMob
2
+ class NotificationInspector
3
+ attr_reader :nickname, :options
4
+ def initialize(scheduler,nickname,options={},&block)
5
+ @scheduler,@nickname,@options = scheduler,nickname.to_s,options
6
+
7
+ unless notifications.empty?
8
+ yield_in_context(self,&block)
9
+ end
10
+ end
11
+
12
+ def yield_in_context(*args,&block)
13
+ if o = options[:context]
14
+ o.instance_exec(*args,&block)
15
+ else
16
+ block.call(*args)
17
+ end
18
+ end
19
+
20
+ def notifications
21
+ @notifications ||= @scheduler.notifications.select {|n| n.target == nickname}
22
+ end
23
+
24
+ def action?(*actions)
25
+ actions.norm!.all? {|action| notifications.any? {|n| n.actions.include?(action.to_s)}}
26
+ end
27
+
28
+ def select_and_run_action(actions, &block)
29
+ if matched = actions.find {|action| action?(action)}
30
+ yield_in_context matched, &block
31
+ end
32
+ end
33
+ end
34
+
35
+ class Notifier < Struct.new(:mob)
36
+ def ui; mob.ui end
37
+
38
+ # The list of delayed targets.
39
+ def notifications
40
+ @notifications ||= []
41
+ end
42
+
43
+ def for(nickname,options={},&block)
44
+ NotificationInspector.new(self,nickname,options,&block)
45
+ end
46
+
47
+ def select(&block); notifications.select(&block) end
48
+ def find(&block); notifications.find(&block) end
49
+ def any?(&block); notifications.any?(&block) end
50
+ def all?(&block); notifications.all?(&block) end
51
+
52
+ # queries
53
+ def include_nickname?(nickname)
54
+ nickname = nickname.to_s
55
+ notifications.any? {|n| n.target == nickname}
56
+ end
57
+
58
+ def __predicate_to_lambda()
59
+ args = Target::Arguments.parse(*args)
60
+ end
61
+
62
+ # Handles a notification, by either placing it on the queue or calling it now
63
+ def notify(notification)
64
+ if AngryMob::Target::Notify === notification
65
+ notifications << notification
66
+ elsif Proc === notification
67
+ notification[mob]
68
+ end
69
+ end
70
+
71
+ def schedule_notification(call)
72
+ notifications << call
73
+ end
74
+
75
+ end
76
+ end