angry_mob 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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