zmb 0.1.1

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.
@@ -0,0 +1,63 @@
1
+ class Command
2
+ attr_accessor :delegate, :signal, :help
3
+
4
+ def initialize(delegate, signal, commands=1, help=nil)
5
+ @delegate = delegate
6
+ @signal = signal
7
+ @help = help
8
+ @commands = commands
9
+ end
10
+
11
+ def help?
12
+ help != nil
13
+ end
14
+
15
+ def run(e, args)
16
+ if @commands == 0 then
17
+ args = Array.new
18
+ elsif args.size > @commands
19
+ a = args.first @commands-1 # Take one under amount of commands
20
+ a << args[@commands-1..-1].join(' ')
21
+ args = a
22
+ end
23
+
24
+ begin
25
+ @delegate.send(@signal, e, *args)
26
+ rescue ArgumentError
27
+ 'incorrect arguments'
28
+ rescue Exception
29
+ if e.respond_to?('user') and e.user.respond_to?('admin?') and e.user.admin? and e.private? then
30
+ "#{$!.message}\n#{$!.inspect}"
31
+ else
32
+ "command failed"
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ class PermCommand < Command
39
+ attr_accessor :perm
40
+
41
+ def initialize(perm, *args)
42
+ super(*args)
43
+ @perm = perm
44
+ end
45
+
46
+ def run(e, args)
47
+ if e.respond_to?('user') and e.user.permission?(@perm) then
48
+ super(e, args)
49
+ else
50
+ 'permission denied'
51
+ end
52
+ end
53
+ end
54
+
55
+ class AuthCommand < Command
56
+ def run(e, args)
57
+ if e.respond_to?('user') and e.user.authenticated? then
58
+ super(e, args)
59
+ else
60
+ 'permission denied'
61
+ end
62
+ end
63
+ end
data/lib/zmb/event.rb ADDED
@@ -0,0 +1,15 @@
1
+ class Event
2
+ attr_accessor :sender, :message
3
+
4
+ def initialize(sender)
5
+ @sender = sender
6
+ end
7
+
8
+ def message?
9
+ message != nil
10
+ end
11
+
12
+ def reply(message)
13
+ @sender.reply(self, message)
14
+ end
15
+ end
data/lib/zmb/plugin.rb ADDED
@@ -0,0 +1,110 @@
1
+ class PluginManager
2
+ attr_accessor :plugin_sources, :plugins
3
+
4
+ def initialize
5
+ @plugins = Array.new
6
+ @plugin_sources = Array.new
7
+ end
8
+
9
+ def plugin(name)
10
+ plugin = @plugins.find{|plugin| plugin.name == name}
11
+
12
+ if plugin then
13
+ plugin.object
14
+ else
15
+ nil
16
+ end
17
+ end
18
+
19
+ def load_plugin_source(file)
20
+ begin
21
+ definition = instance_eval(File.read(file))
22
+ definition.definitition_file = File.expand_path(file)
23
+ @plugins << definition
24
+ rescue Exception
25
+ nil
26
+ end
27
+ end
28
+
29
+ def add_plugin_source(directory)
30
+ @plugin_sources << directory
31
+
32
+ definition_files = Dir[
33
+ File.join(File.expand_path(directory), "*.rb"),
34
+ File.join(File.expand_path(directory), "*", "plugin.rb")
35
+ ]
36
+
37
+ definition_files.map do |file|
38
+ begin
39
+ load_plugin_source(file)
40
+ end
41
+ end
42
+ end
43
+
44
+ def refresh_plugin_sources
45
+ sources = @plugin_sources
46
+ @plugin_sources = nil
47
+ @plugins = nil
48
+
49
+ sources.each{|directory| add_plugin_source directory}
50
+ end
51
+
52
+ def reload_plugin(name)
53
+ plugin = @plugins.find{|plugin| plugin.name == name}
54
+
55
+ if plugin then
56
+ @plugins.delete(plugin)
57
+ reloaded = load_plugin_source plugin.definitition_file
58
+ @plugins << plugin if not reloaded
59
+ reloaded
60
+ end
61
+ end
62
+ end
63
+
64
+ class PluginBuilder
65
+ attr_accessor :plugin
66
+
67
+ def initialize(&block)
68
+ @plugin = Plugin.new
69
+ @block = block
70
+ end
71
+
72
+ def build
73
+ instance_eval(&@block)
74
+ end
75
+
76
+ def name(value)
77
+ @plugin.name = value
78
+ end
79
+
80
+ def description(value)
81
+ @plugin.description = value
82
+ end
83
+
84
+ def object(value)
85
+ @plugin.object = value
86
+ end
87
+
88
+ def multi_instances(value)
89
+ @plugin.multi_instances = value
90
+ end
91
+ end
92
+
93
+
94
+ class Plugin
95
+ attr_accessor :name, :description, :object, :definitition_file, :multi_instances
96
+
97
+ def self.define(&block)
98
+ builder = PluginBuilder.new(&block)
99
+ builder.build
100
+ builder.plugin
101
+ end
102
+
103
+ def multi_instances?
104
+ if @multi_instances then
105
+ @multi_instances
106
+ else
107
+ false
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,48 @@
1
+ begin
2
+ require 'json'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'json'
6
+ end
7
+
8
+ class Settings
9
+ def initialize(directory)
10
+ if not File.exist?(directory) then
11
+ FileUtils.makedirs(directory)
12
+ end
13
+
14
+ if not File.directory?(directory) and not File.owned?(directory) then
15
+ raise
16
+ end
17
+
18
+ @directory = directory
19
+ end
20
+
21
+ def setting_path(key)
22
+ File.join(@directory, key.gsub('/', '_') + '.json')
23
+ end
24
+
25
+ def setting(key)
26
+ begin
27
+ JSON.parse(File.read(setting_path(key)))
28
+ rescue
29
+ {}
30
+ end
31
+ end
32
+
33
+ def get(object, name, default=nil)
34
+ s = setting(object)
35
+
36
+ if s.respond_to?('has_key?') and s.has_key?(name) then
37
+ s[name]
38
+ else
39
+ default
40
+ end
41
+ end
42
+
43
+ def save(key, data)
44
+ f = File.open setting_path(key), 'w'
45
+ f.write data.to_json
46
+ f.close
47
+ end
48
+ end
data/lib/zmb/timer.rb ADDED
@@ -0,0 +1,28 @@
1
+ class Timer
2
+ require 'date'
3
+
4
+ attr_accessor :delegate
5
+
6
+ def initialize(delegate, symbol, interval, repeat=false) # interval is in seconds (decimals accepted)
7
+ @delegate = delegate
8
+ @symbol = symbol
9
+ @interval = interval
10
+ @repeat = repeat
11
+
12
+ @fire_at = Time.now + interval
13
+ end
14
+
15
+ def fire(sender)
16
+ @delegate.send @symbol
17
+
18
+ if not @repeat
19
+ sender.timer_delete(self) if sender.respond_to?('timer_delete')
20
+ else
21
+ @fire_at = Time.now + @interval
22
+ end
23
+ end
24
+
25
+ def timeout
26
+ @fire_at - Time.now
27
+ end
28
+ end
data/plugins/bank.rb ADDED
@@ -0,0 +1,101 @@
1
+ class Account
2
+ attr_accessor :username, :balance, :log
3
+
4
+ def initialize(username, balance=0)
5
+ @username = username
6
+ @balance = balance
7
+ @log = Array.new
8
+ log 'Opening account'
9
+ end
10
+
11
+ def self.create_settings(settings)
12
+ require 'time'
13
+ account = new(settings['username'], settings['balance'])
14
+ account.log = settings['log']
15
+ account
16
+ end
17
+
18
+ def to_json(*a)
19
+ { 'username' => @username, 'balance' => @balance, 'log' => @log }.to_json(*a)
20
+ end
21
+
22
+ def log(message)
23
+ @log << { 'message' => message, 'balance' => @balance, 'time' => Time.now }
24
+ end
25
+
26
+ def funds?(amount)
27
+ @balance >= amount
28
+ end
29
+
30
+ def transaction(amount, message=nil)
31
+ @balance += amount
32
+ log message if message
33
+ end
34
+
35
+ def transfer(account, amount)
36
+ transaction(amount*-1, "#{amount} transfered to #{account.username}")
37
+ account.transaction(amount, "#{amount} transfered from #{@username}")
38
+ end
39
+ end
40
+
41
+ class Event
42
+ attr_accessor :bank
43
+ end
44
+
45
+ class Bank
46
+ attr_accessor :accounts
47
+
48
+ def initialize(sender, settings={})
49
+ @accounts = settings['accounts'].map{ |acc| Account.create_settings(acc) } if settings.has_key?('accounts')
50
+ @accounts = Array.new if not @accounts
51
+ end
52
+
53
+ def to_json(*a)
54
+ { 'accounts' => @accounts, 'plugin' => 'bank' }.to_json(*a)
55
+ end
56
+
57
+ def create(username)
58
+ account = Account.new(username)
59
+ @accounts << account
60
+ account
61
+ end
62
+
63
+ def account!(username)
64
+ @accounts.find{|account| account.username == username}
65
+ end
66
+
67
+ def account(username)
68
+ account!(username) or create(username)
69
+ end
70
+
71
+ def pre_event(sender, e)
72
+ e.bank = account(e.user.username) if e.respond_to?('user') and e.user.respond_to?('username')
73
+ end
74
+
75
+ def commands
76
+ require 'zmb/commands'
77
+ {
78
+ 'balance' => AuthCommand.new(self, :balance, 0, 'See how much funds you have.'),
79
+ 'transfer' => AuthCommand.new(self, :transfer, 2, 'Transfer funds to another account'),
80
+ }
81
+ end
82
+
83
+ def balance(e)
84
+ "Your balance is #{e.bank.balance}"
85
+ end
86
+
87
+ def transfer(e, username, amount)
88
+ amount = Integer(amount)
89
+ return "#{e.user.username} attempted theft against #{username}" if amount < 0
90
+ return 'funds not availible' if not e.bank.funds?(amount)
91
+ return "#{username} doesn't appear to have a bank account, they need to open one with the balance command" if not r = account!(username)
92
+ e.bank.transfer(r, amount)
93
+ "#{amount} transfered to #{username}'s account"
94
+ end
95
+ end
96
+
97
+ Plugin.define do
98
+ name "bank"
99
+ description "virtual bank/money system"
100
+ object Bank
101
+ end
@@ -0,0 +1,119 @@
1
+ require 'zmb/commands'
2
+
3
+ class Commands
4
+ attr_accessor :cmds, :cc
5
+
6
+ def initialize(sender, settings={})
7
+ @cmds = Hash.new
8
+
9
+ @cc = settings['cc'] if settings.has_key?('cc')
10
+ @cc = '!' if @cc == nil
11
+
12
+ @cmds.merge!(commands)
13
+
14
+ sender.post('commands').each do |command|
15
+ @cmds.merge!(command)
16
+ end
17
+ end
18
+
19
+ def to_json(*a)
20
+ { 'cc' => @cc, 'plugin' => 'commands' }.to_json(*a)
21
+ end
22
+
23
+ def self.wizard
24
+ {
25
+ 'cc' => { 'help' => 'Control command, commands send to zmb must be prefixed with this.', 'default' => '.' },
26
+ }
27
+ end
28
+
29
+ def event(sender, e)
30
+ return if not e.message?
31
+
32
+ if e.message[0, @cc.length] == @cc then
33
+ line = e.message[@cc.length..-1].clone
34
+ elsif e.private? then
35
+ line = e.message.clone
36
+ end
37
+
38
+ # Encode escaped quotation marks
39
+ line.gsub!(/\\"|\\'/) { |m| m =~ /^\\"$/ ? "\000d\000" : "\000s\000" }
40
+
41
+ # Encode pipes inside quotation marks
42
+ line.gsub!(/"\w*\|\w*"/) { |m| m.sub('|', "\000p\000") }
43
+
44
+ # Check there are a even amount of "" and ''
45
+ if ((line.count("'") % 2) == 1) and ((line.count('""') % 2) == 1) then
46
+ return e.reply('Incorrect amount of quotation marks\'s')
47
+ end
48
+
49
+ # Split the commands up
50
+ commands = line.split('|')
51
+ input = nil
52
+
53
+ commands.each do |command|
54
+ command = command.reverse.chomp.reverse
55
+
56
+ # Split strings by quotation marks and spaces
57
+ args = command.split(/"([^"]*)"|'([^']*)'|\s/).reject{ |x| x.empty? }
58
+
59
+ # Decode escape quotation marks and pipes inside the args
60
+ args.each do |arg|
61
+ arg.sub!("\000d\000", '"')
62
+ arg.sub!("\000s\000", "'")
63
+ arg.sub!("\000p\000", '|')
64
+ end
65
+
66
+ cmd = args.delete_at(0)
67
+
68
+ if @cmds.has_key?(cmd) then
69
+ args << input if input
70
+ input = @cmds[cmd].run(e, args)
71
+ end
72
+ end
73
+
74
+ e.reply(input) if input
75
+ end
76
+
77
+ def plugin_loaded(key, instance)
78
+ @cmds.merge!(instance.commands) if instance.respond_to?('commands')
79
+ end
80
+
81
+ def plugin_unloaded(key, instance)
82
+ instance.commands.each{|command, cmd| @cmds.delete(command)} if instance.respond_to?('commands')
83
+ end
84
+
85
+ def commands
86
+ {
87
+ 'help' => Command.new(self, :help),
88
+ 'cc' => PermCommand.new('admin', self, :control_command),
89
+ }
90
+ end
91
+
92
+ def help(e, command=nil)
93
+ if command then
94
+ if @cmds.has_key?(command) and @cmds[command].help? then
95
+ "#{command}: #{@cmds[command].help}"
96
+ else
97
+ 'Command not found or no help availible for the command.'
98
+ end
99
+ else
100
+ @cmds.keys.join(', ')
101
+ end
102
+ end
103
+
104
+ def control_command(e, cc=nil)
105
+ if cc then
106
+ @cc = cc
107
+ else
108
+ @cc = '!'
109
+ end
110
+
111
+ "Control command set to #{@cc}"
112
+ end
113
+ end
114
+
115
+ Plugin.define do
116
+ name "commands"
117
+ description "This plugin is needed for other plugins to function properly."
118
+ object Commands
119
+ end