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.
- data/LICENSE +21 -0
- data/README.md +123 -0
- data/bin/mob +139 -0
- data/lib/angry_mob.rb +28 -0
- data/lib/angry_mob/act.rb +111 -0
- data/lib/angry_mob/act/scheduler.rb +143 -0
- data/lib/angry_mob/action.rb +11 -0
- data/lib/angry_mob/builder.rb +115 -0
- data/lib/angry_mob/extend.rb +10 -0
- data/lib/angry_mob/extend/array.rb +30 -0
- data/lib/angry_mob/extend/blank.rb +108 -0
- data/lib/angry_mob/extend/blankslate.rb +109 -0
- data/lib/angry_mob/extend/dictionary.rb +140 -0
- data/lib/angry_mob/extend/hash.rb +67 -0
- data/lib/angry_mob/extend/object.rb +21 -0
- data/lib/angry_mob/extend/pathname.rb +23 -0
- data/lib/angry_mob/extend/string.rb +8 -0
- data/lib/angry_mob/log.rb +28 -0
- data/lib/angry_mob/mob.rb +77 -0
- data/lib/angry_mob/mob_loader.rb +115 -0
- data/lib/angry_mob/node.rb +44 -0
- data/lib/angry_mob/notifier.rb +76 -0
- data/lib/angry_mob/target.rb +257 -0
- data/lib/angry_mob/target/arguments.rb +71 -0
- data/lib/angry_mob/target/call.rb +57 -0
- data/lib/angry_mob/target/default_resource_locator.rb +11 -0
- data/lib/angry_mob/target/defaults.rb +23 -0
- data/lib/angry_mob/target/mother.rb +66 -0
- data/lib/angry_mob/target/notify.rb +57 -0
- data/lib/angry_mob/target/tracking.rb +96 -0
- data/lib/angry_mob/ui.rb +247 -0
- data/lib/angry_mob/util.rb +11 -0
- data/lib/angry_mob/vendored.rb +8 -0
- data/lib/angry_mob/version.rb +3 -0
- data/vendor/angry_hash/Rakefile +17 -0
- data/vendor/angry_hash/VERSION +1 -0
- data/vendor/angry_hash/angry_hash.gemspec +47 -0
- data/vendor/angry_hash/examples/accessors_eg.rb +46 -0
- data/vendor/angry_hash/examples/creation_eg.rb +43 -0
- data/vendor/angry_hash/examples/dsl.eg.rb +18 -0
- data/vendor/angry_hash/examples/dup_eg.rb +86 -0
- data/vendor/angry_hash/examples/eg_helper.rb +24 -0
- data/vendor/angry_hash/examples/merge_eg.rb +135 -0
- data/vendor/angry_hash/lib/angry_hash.rb +215 -0
- data/vendor/angry_hash/lib/angry_hash/dsl.rb +44 -0
- data/vendor/angry_hash/lib/angry_hash/extension_tracking.rb +12 -0
- data/vendor/angry_hash/lib/angry_hash/merge_string.rb +58 -0
- data/vendor/json/COPYING +58 -0
- data/vendor/json/GPL +340 -0
- data/vendor/json/README +360 -0
- data/vendor/json/lib/json/common.rb +371 -0
- data/vendor/json/lib/json/pure.rb +77 -0
- data/vendor/json/lib/json/pure/generator.rb +443 -0
- data/vendor/json/lib/json/pure/parser.rb +303 -0
- data/vendor/json/lib/json/version.rb +8 -0
- data/vendor/thor/CHANGELOG.rdoc +89 -0
- data/vendor/thor/LICENSE +20 -0
- data/vendor/thor/README.rdoc +297 -0
- data/vendor/thor/Thorfile +69 -0
- data/vendor/thor/bin/rake2thor +86 -0
- data/vendor/thor/bin/thor +6 -0
- data/vendor/thor/lib/thor.rb +244 -0
- data/vendor/thor/lib/thor/actions.rb +275 -0
- data/vendor/thor/lib/thor/actions/create_file.rb +103 -0
- data/vendor/thor/lib/thor/actions/directory.rb +91 -0
- data/vendor/thor/lib/thor/actions/empty_directory.rb +134 -0
- data/vendor/thor/lib/thor/actions/file_manipulation.rb +223 -0
- data/vendor/thor/lib/thor/actions/inject_into_file.rb +104 -0
- data/vendor/thor/lib/thor/base.rb +540 -0
- data/vendor/thor/lib/thor/core_ext/file_binary_read.rb +9 -0
- data/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
- data/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
- data/vendor/thor/lib/thor/error.rb +30 -0
- data/vendor/thor/lib/thor/group.rb +271 -0
- data/vendor/thor/lib/thor/invocation.rb +180 -0
- data/vendor/thor/lib/thor/parser.rb +4 -0
- data/vendor/thor/lib/thor/parser/argument.rb +67 -0
- data/vendor/thor/lib/thor/parser/arguments.rb +150 -0
- data/vendor/thor/lib/thor/parser/option.rb +128 -0
- data/vendor/thor/lib/thor/parser/options.rb +169 -0
- data/vendor/thor/lib/thor/rake_compat.rb +66 -0
- data/vendor/thor/lib/thor/runner.rb +314 -0
- data/vendor/thor/lib/thor/shell.rb +83 -0
- data/vendor/thor/lib/thor/shell/basic.rb +239 -0
- data/vendor/thor/lib/thor/shell/color.rb +108 -0
- data/vendor/thor/lib/thor/task.rb +102 -0
- data/vendor/thor/lib/thor/util.rb +224 -0
- data/vendor/thor/lib/thor/version.rb +3 -0
- data/vendor/thor/spec/actions/create_file_spec.rb +170 -0
- data/vendor/thor/spec/actions/directory_spec.rb +131 -0
- data/vendor/thor/spec/actions/empty_directory_spec.rb +91 -0
- data/vendor/thor/spec/actions/file_manipulation_spec.rb +271 -0
- data/vendor/thor/spec/actions/inject_into_file_spec.rb +135 -0
- data/vendor/thor/spec/actions_spec.rb +292 -0
- data/vendor/thor/spec/base_spec.rb +263 -0
- data/vendor/thor/spec/core_ext/hash_with_indifferent_access_spec.rb +43 -0
- data/vendor/thor/spec/core_ext/ordered_hash_spec.rb +115 -0
- data/vendor/thor/spec/fixtures/application.rb +2 -0
- data/vendor/thor/spec/fixtures/bundle/execute.rb +6 -0
- data/vendor/thor/spec/fixtures/bundle/main.thor +1 -0
- data/vendor/thor/spec/fixtures/doc/%file_name%.rb.tt +1 -0
- data/vendor/thor/spec/fixtures/doc/README +3 -0
- data/vendor/thor/spec/fixtures/doc/config.rb +1 -0
- data/vendor/thor/spec/fixtures/group.thor +90 -0
- data/vendor/thor/spec/fixtures/invoke.thor +112 -0
- data/vendor/thor/spec/fixtures/script.thor +145 -0
- data/vendor/thor/spec/fixtures/task.thor +10 -0
- data/vendor/thor/spec/group_spec.rb +171 -0
- data/vendor/thor/spec/invocation_spec.rb +107 -0
- data/vendor/thor/spec/parser/argument_spec.rb +47 -0
- data/vendor/thor/spec/parser/arguments_spec.rb +64 -0
- data/vendor/thor/spec/parser/option_spec.rb +202 -0
- data/vendor/thor/spec/parser/options_spec.rb +292 -0
- data/vendor/thor/spec/rake_compat_spec.rb +68 -0
- data/vendor/thor/spec/runner_spec.rb +210 -0
- data/vendor/thor/spec/shell/basic_spec.rb +205 -0
- data/vendor/thor/spec/shell/color_spec.rb +41 -0
- data/vendor/thor/spec/shell_spec.rb +34 -0
- data/vendor/thor/spec/spec.opts +1 -0
- data/vendor/thor/spec/spec_helper.rb +54 -0
- data/vendor/thor/spec/task_spec.rb +69 -0
- data/vendor/thor/spec/thor_spec.rb +237 -0
- data/vendor/thor/spec/util_spec.rb +163 -0
- data/vendor/thor/thor.gemspec +120 -0
- 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,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
|