butler 1.8.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/CHANGELOG +4 -0
- data/GPL.txt +340 -0
- data/LICENSE.txt +52 -0
- data/README +37 -0
- data/Rakefile +334 -0
- data/bin/botcontrol +230 -0
- data/data/butler/config_template.yaml +4 -0
- data/data/butler/dialogs/backup.rb +19 -0
- data/data/butler/dialogs/botcontrol.rb +4 -0
- data/data/butler/dialogs/config.rb +1 -0
- data/data/butler/dialogs/create.rb +53 -0
- data/data/butler/dialogs/delete.rb +3 -0
- data/data/butler/dialogs/en/backup.yaml +6 -0
- data/data/butler/dialogs/en/botcontrol.yaml +5 -0
- data/data/butler/dialogs/en/create.yaml +11 -0
- data/data/butler/dialogs/en/delete.yaml +2 -0
- data/data/butler/dialogs/en/help.yaml +17 -0
- data/data/butler/dialogs/en/info.yaml +13 -0
- data/data/butler/dialogs/en/list.yaml +4 -0
- data/data/butler/dialogs/en/notyetimplemented.yaml +2 -0
- data/data/butler/dialogs/en/rename.yaml +3 -0
- data/data/butler/dialogs/en/start.yaml +3 -0
- data/data/butler/dialogs/en/sync_plugins.yaml +3 -0
- data/data/butler/dialogs/en/uninstall.yaml +5 -0
- data/data/butler/dialogs/en/unknown_command.yaml +2 -0
- data/data/butler/dialogs/help.rb +11 -0
- data/data/butler/dialogs/info.rb +27 -0
- data/data/butler/dialogs/interactive.rb +1 -0
- data/data/butler/dialogs/list.rb +10 -0
- data/data/butler/dialogs/notyetimplemented.rb +1 -0
- data/data/butler/dialogs/rename.rb +4 -0
- data/data/butler/dialogs/selectbot.rb +2 -0
- data/data/butler/dialogs/start.rb +5 -0
- data/data/butler/dialogs/sync_plugins.rb +30 -0
- data/data/butler/dialogs/uninstall.rb +17 -0
- data/data/butler/dialogs/unknown_command.rb +1 -0
- data/data/butler/plugins/core/logout.rb +41 -0
- data/data/butler/plugins/core/plugins.rb +134 -0
- data/data/butler/plugins/core/privilege.rb +103 -0
- data/data/butler/plugins/core/user.rb +166 -0
- data/data/butler/plugins/dev/eval.rb +64 -0
- data/data/butler/plugins/dev/nometa.rb +14 -0
- data/data/butler/plugins/dev/onhandlers.rb +93 -0
- data/data/butler/plugins/dev/raw.rb +36 -0
- data/data/butler/plugins/dev/rawlog.rb +77 -0
- data/data/butler/plugins/games/eightball.rb +54 -0
- data/data/butler/plugins/games/mastermind.rb +174 -0
- data/data/butler/plugins/irc/action.rb +36 -0
- data/data/butler/plugins/irc/join.rb +38 -0
- data/data/butler/plugins/irc/notice.rb +36 -0
- data/data/butler/plugins/irc/part.rb +38 -0
- data/data/butler/plugins/irc/privmsg.rb +36 -0
- data/data/butler/plugins/irc/quit.rb +36 -0
- data/data/butler/plugins/operator/deop.rb +41 -0
- data/data/butler/plugins/operator/devoice.rb +41 -0
- data/data/butler/plugins/operator/limit.rb +47 -0
- data/data/butler/plugins/operator/op.rb +41 -0
- data/data/butler/plugins/operator/voice.rb +41 -0
- data/data/butler/plugins/public/help.rb +69 -0
- data/data/butler/plugins/public/login.rb +72 -0
- data/data/butler/plugins/public/usage.rb +49 -0
- data/data/butler/plugins/service/clones.rb +56 -0
- data/data/butler/plugins/service/define.rb +47 -0
- data/data/butler/plugins/service/log.rb +183 -0
- data/data/butler/plugins/service/svn.rb +91 -0
- data/data/butler/plugins/util/cycle.rb +98 -0
- data/data/butler/plugins/util/load.rb +41 -0
- data/data/butler/plugins/util/pong.rb +29 -0
- data/data/butler/strings/random/acknowledge.en.yaml +5 -0
- data/data/butler/strings/random/gratitude.en.yaml +3 -0
- data/data/butler/strings/random/hello.en.yaml +4 -0
- data/data/butler/strings/random/ignorance.en.yaml +7 -0
- data/data/butler/strings/random/ignorance_about.en.yaml +3 -0
- data/data/butler/strings/random/insult.en.yaml +3 -0
- data/data/butler/strings/random/rejection.en.yaml +12 -0
- data/data/man/botcontrol.1 +17 -0
- data/lib/access.rb +187 -0
- data/lib/access/admin.rb +16 -0
- data/lib/access/privilege.rb +122 -0
- data/lib/access/role.rb +102 -0
- data/lib/access/savable.rb +18 -0
- data/lib/access/user.rb +180 -0
- data/lib/access/yamlbase.rb +126 -0
- data/lib/butler.rb +188 -0
- data/lib/butler/bot.rb +247 -0
- data/lib/butler/control.rb +93 -0
- data/lib/butler/dialog.rb +64 -0
- data/lib/butler/initialvalues.rb +40 -0
- data/lib/butler/irc/channel.rb +135 -0
- data/lib/butler/irc/channels.rb +96 -0
- data/lib/butler/irc/client.rb +351 -0
- data/lib/butler/irc/hostmask.rb +53 -0
- data/lib/butler/irc/message.rb +184 -0
- data/lib/butler/irc/parser.rb +125 -0
- data/lib/butler/irc/parser/commands.rb +83 -0
- data/lib/butler/irc/parser/generic.rb +343 -0
- data/lib/butler/irc/socket.rb +378 -0
- data/lib/butler/irc/string.rb +186 -0
- data/lib/butler/irc/topic.rb +15 -0
- data/lib/butler/irc/user.rb +265 -0
- data/lib/butler/irc/users.rb +112 -0
- data/lib/butler/plugin.rb +249 -0
- data/lib/butler/plugin/configproxy.rb +35 -0
- data/lib/butler/plugin/mapper.rb +85 -0
- data/lib/butler/plugin/matcher.rb +55 -0
- data/lib/butler/plugin/onhandlers.rb +70 -0
- data/lib/butler/plugin/trigger.rb +58 -0
- data/lib/butler/plugins.rb +147 -0
- data/lib/butler/version.rb +17 -0
- data/lib/cloptions.rb +217 -0
- data/lib/cloptions/adapters.rb +24 -0
- data/lib/cloptions/switch.rb +132 -0
- data/lib/configuration.rb +223 -0
- data/lib/dialogline.rb +296 -0
- data/lib/dialogline/localizations.rb +24 -0
- data/lib/durations.rb +57 -0
- data/lib/event.rb +295 -0
- data/lib/event/at.rb +64 -0
- data/lib/event/every.rb +56 -0
- data/lib/event/timed.rb +112 -0
- data/lib/installer.rb +75 -0
- data/lib/iterator.rb +34 -0
- data/lib/log.rb +68 -0
- data/lib/log/comfort.rb +85 -0
- data/lib/log/converter.rb +23 -0
- data/lib/log/entry.rb +152 -0
- data/lib/log/fakeio.rb +55 -0
- data/lib/log/file.rb +54 -0
- data/lib/log/filereader.rb +81 -0
- data/lib/log/forward.rb +49 -0
- data/lib/log/methods.rb +39 -0
- data/lib/log/nolog.rb +18 -0
- data/lib/log/splitter.rb +26 -0
- data/lib/ostructfixed.rb +26 -0
- data/lib/ruby/array/columnize.rb +38 -0
- data/lib/ruby/dir/mktree.rb +28 -0
- data/lib/ruby/enumerable/join.rb +13 -0
- data/lib/ruby/exception/detailed.rb +24 -0
- data/lib/ruby/file/append.rb +11 -0
- data/lib/ruby/file/write.rb +11 -0
- data/lib/ruby/hash/zip.rb +15 -0
- data/lib/ruby/kernel/bench.rb +15 -0
- data/lib/ruby/kernel/daemonize.rb +42 -0
- data/lib/ruby/kernel/non_verbose.rb +17 -0
- data/lib/ruby/kernel/safe_fork.rb +18 -0
- data/lib/ruby/range/stepped.rb +11 -0
- data/lib/ruby/string/arguments.rb +72 -0
- data/lib/ruby/string/chunks.rb +15 -0
- data/lib/ruby/string/post_arguments.rb +44 -0
- data/lib/ruby/string/unescaped.rb +17 -0
- data/lib/scheduler.rb +164 -0
- data/lib/scriptfile.rb +101 -0
- data/lib/templater.rb +86 -0
- data/test/cloptions.rb +134 -0
- data/test/cv.rb +28 -0
- data/test/irc/client.rb +85 -0
- data/test/irc/client_login.txt +53 -0
- data/test/irc/client_subscribe.txt +8 -0
- data/test/irc/message.rb +30 -0
- data/test/irc/messages.txt +64 -0
- data/test/irc/parser.rb +13 -0
- data/test/irc/profile_parser.rb +12 -0
- data/test/irc/users.rb +28 -0
- metadata +256 -0
data/lib/log/nolog.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module Log
|
|
10
|
+
# discards all messages
|
|
11
|
+
class NoLog
|
|
12
|
+
def respond_to?(m,*a)
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
def method_missing(*a)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/log/splitter.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Log
|
|
2
|
+
class Splitter
|
|
3
|
+
def initialize(*receivers)
|
|
4
|
+
@receivers = receivers
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def delete(receiver)
|
|
8
|
+
@receivers.delete(receiver)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def add(receiver)
|
|
12
|
+
@receivers << receiver
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def method_missing(*a, &b)
|
|
16
|
+
@receivers.each { |r| r.__send__(*a, &b)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def inspect
|
|
20
|
+
"#<%s:%08x %s %s>" % [
|
|
21
|
+
self.class,
|
|
22
|
+
object_id,
|
|
23
|
+
@receivers.map { |r| r.inspect }.join(', ')
|
|
24
|
+
]
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/ostructfixed.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
require 'ostruct'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class OpenStruct
|
|
14
|
+
def [](field)
|
|
15
|
+
@table[field.to_sym]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def []=(field,value)
|
|
19
|
+
new_ostruct_member(field)
|
|
20
|
+
@table[field.to_sym] = value
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_hash
|
|
24
|
+
@table.dup
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Array
|
|
10
|
+
ColumnizeDefaults = {
|
|
11
|
+
:prepend => "",
|
|
12
|
+
:orientation => :vertical,
|
|
13
|
+
:spacing => 1
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
def columnize(columns=nil, opts={})
|
|
17
|
+
pre, ori, space = ColumnizeDefaults.merge(opts).values_at(:prepend, :orientation, :spacing)
|
|
18
|
+
columns ||= 2
|
|
19
|
+
numrows = length.quo(columns).ceil
|
|
20
|
+
sizes, print = Array.new(columns) { [] }, Array.new(numrows) { [] }
|
|
21
|
+
|
|
22
|
+
if ori == :vertical then
|
|
23
|
+
(self+Array.new(numrows*columns-length,"")).each_with_index { |e,i|
|
|
24
|
+
sizes[i.div(numrows)] << e
|
|
25
|
+
print[i%numrows] << e
|
|
26
|
+
}
|
|
27
|
+
else
|
|
28
|
+
(self+Array.new(numrows*columns-length,"")).each_with_index { |e,i|
|
|
29
|
+
sizes[i%columns] << e
|
|
30
|
+
print[i.div(columns)] << e
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
sizes = sizes.map { |e| e.map { |f| f.length }.max+space }
|
|
35
|
+
format = "#{pre}%-#{sizes.join('s %-')}s"
|
|
36
|
+
print.map { |e| format % e }.join("\n")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class <<Dir
|
|
10
|
+
# create directory structure
|
|
11
|
+
# Dir.mktree(
|
|
12
|
+
# "a" => {
|
|
13
|
+
# "b" => [
|
|
14
|
+
# "d",
|
|
15
|
+
# "e"
|
|
16
|
+
# ],
|
|
17
|
+
# },
|
|
18
|
+
# "in/directory"
|
|
19
|
+
# )
|
|
20
|
+
def mktree(tree, base=Dir.pwd)
|
|
21
|
+
dir = [];
|
|
22
|
+
tree.each { |dir, sub|
|
|
23
|
+
current = "#{base}/#{dir}"
|
|
24
|
+
mkdir(current)
|
|
25
|
+
mktree(sub, current) if sub
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class Exception
|
|
2
|
+
module Detailed
|
|
3
|
+
def self.extended(obj)
|
|
4
|
+
obj.initialize_details
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def initialize_details
|
|
8
|
+
@prepend = []
|
|
9
|
+
@append = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def prepend(string)
|
|
13
|
+
@prepend.unshift string
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def append(string)
|
|
17
|
+
@append.unshift string
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_s
|
|
21
|
+
(@prepend+[super]+@append).join(' ')
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# create a hash from an array with keys and an array with values
|
|
10
|
+
# you can set default or provide a block just as with Hash::new
|
|
11
|
+
def Hash.zip(keys, values, default=nil, &block)
|
|
12
|
+
hash = block_given? ? Hash.new(&block) : Hash.new(default)
|
|
13
|
+
keys.zip(values) { |k,v| hash[k]=v }
|
|
14
|
+
hash
|
|
15
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
require 'ruby/kernel/safe_fork'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
module Kernel
|
|
15
|
+
# This method causes the current running process to become a daemon
|
|
16
|
+
# All further printing is relied to the error.log
|
|
17
|
+
# FIXME doesn't belong into Butler::Bot, rather into botcontrol
|
|
18
|
+
def daemonize(chdir=nil, &on_sighup)
|
|
19
|
+
srand # Split rand streams between spawning and daemonized process
|
|
20
|
+
safe_fork and exit # Fork and exit from the parent
|
|
21
|
+
|
|
22
|
+
# Detach from the controlling terminal
|
|
23
|
+
raise "Can't detach from controlling terminal" unless sess_id = Process.setsid
|
|
24
|
+
|
|
25
|
+
# Prevent the possibility of acquiring a controlling terminal
|
|
26
|
+
trap('SIGHUP', 'IGNORE')
|
|
27
|
+
exit if safe_fork
|
|
28
|
+
|
|
29
|
+
# In daemon mode, a SIGHUP means termination
|
|
30
|
+
trap('SIGHUP', &on_sighup)
|
|
31
|
+
|
|
32
|
+
# We can't get the originally controlling terminals stdout/stdin anymore
|
|
33
|
+
STDIN.reopen("/dev/null")
|
|
34
|
+
STDOUT.reopen("/dev/null", "a")
|
|
35
|
+
STDERR.reopen(STDOUT)
|
|
36
|
+
|
|
37
|
+
Dir.chdir(chdir) if chdir
|
|
38
|
+
File.umask 0033 # FIXME ask somebody knowledgable about a sensible value
|
|
39
|
+
|
|
40
|
+
sess_id
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module Kernel
|
|
10
|
+
def non_verbose
|
|
11
|
+
old_verbose = $VERBOSE
|
|
12
|
+
$VERBOSE = false
|
|
13
|
+
yield
|
|
14
|
+
ensure
|
|
15
|
+
$VERBOSE = old_verbose
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module Kernel
|
|
10
|
+
# Try to fork if at all possible retrying every +delay+ sec (5s default)
|
|
11
|
+
# if the maximum process limit for the system has been reached
|
|
12
|
+
def safe_fork(delay=5)
|
|
13
|
+
fork
|
|
14
|
+
rescue Errno::EWOULDBLOCK
|
|
15
|
+
sleep(delay)
|
|
16
|
+
retry
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
require 'ruby/string/unescaped'
|
|
10
|
+
|
|
11
|
+
class String
|
|
12
|
+
# the exception raised by String#arguments if an odd number of arguments is encountered.
|
|
13
|
+
# you can still extract the other parts of the parsing via its accessors.
|
|
14
|
+
class SingleQuoteException < RuntimeError
|
|
15
|
+
attr_reader :index
|
|
16
|
+
attr_reader :pre
|
|
17
|
+
attr_reader :post
|
|
18
|
+
def initialize(args, index)
|
|
19
|
+
@index, @pre, @post = index, args[0,index], args[index+1,args.length-index]
|
|
20
|
+
super("A single unescaped quote as argument #{index}")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# parse a string of single/double/unquoted arguments (or any mix of)
|
|
25
|
+
# raises an exception if an odd number of quotes is matched
|
|
26
|
+
# examples:
|
|
27
|
+
# 'hello hello "ruby world"'.arguments # => ["hello", "hello", "ruby world"]
|
|
28
|
+
# 'hello hello ruby\ world'.arguments # => ["hello", "hello", "ruby world"]
|
|
29
|
+
# 'hello hello ruby\ world'.arguments(false) # => ["hello", "hello", "ruby\\ world"]
|
|
30
|
+
def arguments(unescape=true)
|
|
31
|
+
args = scan(
|
|
32
|
+
/
|
|
33
|
+
# match a double quoted string
|
|
34
|
+
"(?:\\.|[^\\"])*" |
|
|
35
|
+
|
|
36
|
+
# match a single quoted string
|
|
37
|
+
'(?:\\.|[^\\'])*' |
|
|
38
|
+
|
|
39
|
+
# match non-quoted words (may contain escaped spaces)
|
|
40
|
+
(?:\\.|[^\\'"\s])+ |
|
|
41
|
+
|
|
42
|
+
# match a single " or '
|
|
43
|
+
["']
|
|
44
|
+
/x
|
|
45
|
+
)
|
|
46
|
+
if unescape
|
|
47
|
+
args.map! { |arg| ((arg[0,1] == '"' && arg[1]) ? arg[1..-2] : arg).unescaped }
|
|
48
|
+
else
|
|
49
|
+
args.map! { |arg| ((arg[0,1] == '"' && arg[1]) ? arg[1..-2] : arg) }
|
|
50
|
+
end
|
|
51
|
+
if (sq = args.index('"')) || (sq = args.index("'")) then
|
|
52
|
+
raise SingleQuoteException.new(args, sq)
|
|
53
|
+
end
|
|
54
|
+
args
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if __FILE__ == $0 then
|
|
59
|
+
require 'test/unit'
|
|
60
|
+
class TestStringArguments < Test::Unit::TestCase
|
|
61
|
+
def test_all
|
|
62
|
+
assert_equal(%w(), ''.arguments)
|
|
63
|
+
assert_equal(%w(hello world those are arguments), 'hello world those are arguments'.arguments)
|
|
64
|
+
assert_equal(%w(hello ruby\ world those are arguments), 'hello "ruby world" those are arguments'.arguments)
|
|
65
|
+
assert_equal(%w(hello ruby\ world), 'hello "ruby world"'.arguments)
|
|
66
|
+
assert_equal(%w(ruby\ world those are arguments), '"ruby world" those are arguments'.arguments)
|
|
67
|
+
assert_equal(%w(hello ruby\ world those are arguments), 'hello ruby\ world those are arguments'.arguments)
|
|
68
|
+
assert_raise(String::SingleQuoteException) { 'hello " ruby'.arguments }
|
|
69
|
+
assert_raise(String::SingleQuoteException) { "hello ' ruby".arguments }
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class String
|
|
10
|
+
# splits a string into chunks of length 'len'
|
|
11
|
+
def chunks(chunk_length)
|
|
12
|
+
scan(/.{1,#{chunk_length}}/)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# See LICENSE.txt for permissions.
|
|
5
|
+
#++
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
require 'ruby/string/arguments'
|
|
10
|
+
|
|
11
|
+
class String
|
|
12
|
+
def post_arguments(unescaped=true)
|
|
13
|
+
post = []
|
|
14
|
+
offset = -1
|
|
15
|
+
found = 0
|
|
16
|
+
arguments = begin
|
|
17
|
+
arguments(false)
|
|
18
|
+
rescue SingleQuoteException => ex
|
|
19
|
+
ex.pre+[ex.post.join(" ")]
|
|
20
|
+
end
|
|
21
|
+
arguments.each { |argument|
|
|
22
|
+
post << (unescaped ? self[offset+1..-1].unescaped : self[offset+1..-1])
|
|
23
|
+
found = index(argument, offset+1)
|
|
24
|
+
offset = found+argument.length
|
|
25
|
+
}
|
|
26
|
+
post
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
if __FILE__ == $0 then
|
|
31
|
+
require 'test/unit'
|
|
32
|
+
class TestStringArguments < Test::Unit::TestCase
|
|
33
|
+
def test_all
|
|
34
|
+
#assert_equal(%w(), ''.arguments)
|
|
35
|
+
#assert_equal(%w(hello world those are arguments), 'hello world those are arguments'.arguments)
|
|
36
|
+
#assert_equal(%w(hello ruby\ world those are arguments), 'hello "ruby world" those are arguments'.arguments)
|
|
37
|
+
#assert_equal(%w(hello ruby\ world), 'hello "ruby world"'.arguments)
|
|
38
|
+
#assert_equal(%w(ruby\ world those are arguments), '"ruby world" those are arguments'.arguments)
|
|
39
|
+
#assert_equal(%w(hello ruby\ world those are arguments), 'hello ruby\ world those are arguments'.arguments)
|
|
40
|
+
#assert_raise(String::SingleQuoteException) { 'hello " ruby'.arguments }
|
|
41
|
+
#assert_raise(String::SingleQuoteException) { "hello ' ruby".arguments }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|