daemon-kit 0.1.7 → 0.1.7.4
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/Configuration.txt +58 -0
- data/History.txt +24 -0
- data/Manifest.txt +50 -2
- data/PostInstall.txt +1 -1
- data/README.rdoc +7 -9
- data/Rakefile +2 -4
- data/TODO.txt +6 -5
- data/app_generators/daemon_kit/daemon_kit_generator.rb +5 -0
- data/app_generators/daemon_kit/templates/Rakefile +3 -1
- data/app_generators/daemon_kit/templates/bin/daemon.erb +1 -1
- data/app_generators/daemon_kit/templates/config/arguments.rb +12 -0
- data/app_generators/daemon_kit/templates/config/boot.rb +2 -2
- data/app_generators/daemon_kit/templates/script/console +3 -0
- data/app_generators/daemon_kit/templates/script/destroy +14 -0
- data/app_generators/daemon_kit/templates/script/generate +14 -0
- data/daemon_generators/amqp/templates/config/amqp.yml +5 -5
- data/daemon_generators/deploy_capistrano/deploy_capistrano_generator.rb +4 -23
- data/daemon_generators/deploy_capistrano/templates/USAGE +10 -0
- data/daemon_generators/deploy_capistrano/templates/config/deploy.rb +3 -1
- data/lib/daemon_kit.rb +33 -5
- data/lib/daemon_kit/amqp.rb +2 -1
- data/lib/daemon_kit/application.rb +136 -11
- data/lib/daemon_kit/arguments.rb +151 -0
- data/lib/daemon_kit/commands/console.rb +38 -0
- data/lib/daemon_kit/config.rb +1 -0
- data/lib/daemon_kit/console_daemon.rb +2 -0
- data/lib/daemon_kit/core_ext.rb +1 -0
- data/lib/daemon_kit/core_ext/string.rb +22 -0
- data/lib/daemon_kit/deployment/capistrano.rb +6 -9
- data/lib/daemon_kit/error_handlers/mail.rb +52 -15
- data/lib/daemon_kit/initializer.rb +95 -41
- data/lib/daemon_kit/pid_file.rb +61 -0
- data/lib/daemon_kit/tasks/environment.rake +5 -4
- data/lib/daemon_kit/tasks/framework.rake +15 -1
- data/lib/daemon_kit/tasks/god.rake +62 -0
- data/lib/daemon_kit/tasks/log.rake +8 -0
- data/lib/daemon_kit/tasks/monit.rake +29 -0
- data/spec/argument_spec.rb +51 -0
- data/spec/config_spec.rb +77 -0
- data/spec/daemon_kit_spec.rb +2 -2
- data/spec/error_handlers_spec.rb +23 -0
- data/spec/fixtures/env.yml +15 -0
- data/spec/fixtures/noenv.yml +4 -0
- data/spec/initializer_spec.rb +4 -3
- data/spec/spec_helper.rb +8 -11
- data/templates/god/god.erb +69 -0
- data/templates/monit/monit.erb +14 -0
- data/test/test_daemon-kit_generator.rb +6 -1
- data/test/test_deploy_capistrano_generator.rb +1 -2
- data/vendor/tmail-1.2.3/tmail.rb +5 -0
- data/vendor/tmail-1.2.3/tmail/address.rb +426 -0
- data/vendor/tmail-1.2.3/tmail/attachments.rb +46 -0
- data/vendor/tmail-1.2.3/tmail/base64.rb +46 -0
- data/vendor/tmail-1.2.3/tmail/compat.rb +41 -0
- data/vendor/tmail-1.2.3/tmail/config.rb +67 -0
- data/vendor/tmail-1.2.3/tmail/core_extensions.rb +63 -0
- data/vendor/tmail-1.2.3/tmail/encode.rb +581 -0
- data/vendor/tmail-1.2.3/tmail/header.rb +960 -0
- data/vendor/tmail-1.2.3/tmail/index.rb +9 -0
- data/vendor/tmail-1.2.3/tmail/interface.rb +1130 -0
- data/vendor/tmail-1.2.3/tmail/loader.rb +3 -0
- data/vendor/tmail-1.2.3/tmail/mail.rb +578 -0
- data/vendor/tmail-1.2.3/tmail/mailbox.rb +495 -0
- data/vendor/tmail-1.2.3/tmail/main.rb +6 -0
- data/vendor/tmail-1.2.3/tmail/mbox.rb +3 -0
- data/vendor/tmail-1.2.3/tmail/net.rb +248 -0
- data/vendor/tmail-1.2.3/tmail/obsolete.rb +132 -0
- data/vendor/tmail-1.2.3/tmail/parser.rb +1476 -0
- data/vendor/tmail-1.2.3/tmail/port.rb +379 -0
- data/vendor/tmail-1.2.3/tmail/quoting.rb +118 -0
- data/vendor/tmail-1.2.3/tmail/require_arch.rb +58 -0
- data/vendor/tmail-1.2.3/tmail/scanner.rb +49 -0
- data/vendor/tmail-1.2.3/tmail/scanner_r.rb +261 -0
- data/vendor/tmail-1.2.3/tmail/stringio.rb +280 -0
- data/vendor/tmail-1.2.3/tmail/utils.rb +337 -0
- data/vendor/tmail-1.2.3/tmail/version.rb +39 -0
- data/vendor/tmail.rb +13 -0
- metadata +57 -18
- data/daemon_generators/deploy_capistrano/USAGE +0 -5
- data/lib/daemon_kit/patches/force_kill_wait.rb +0 -120
@@ -0,0 +1,58 @@
|
|
1
|
+
#:stopdoc:
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
# Attempts to require anative extension.
|
5
|
+
# Falls back to pure-ruby version, if it fails.
|
6
|
+
#
|
7
|
+
# This uses Config::CONFIG['arch'] from rbconfig.
|
8
|
+
|
9
|
+
def require_arch(fname)
|
10
|
+
arch = Config::CONFIG['arch']
|
11
|
+
begin
|
12
|
+
path = File.join("tmail", arch, fname)
|
13
|
+
require path
|
14
|
+
rescue LoadError => e
|
15
|
+
# try pre-built Windows binaries
|
16
|
+
if arch =~ /mswin/
|
17
|
+
require File.join("tmail", 'mswin32', fname)
|
18
|
+
else
|
19
|
+
raise e
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# def require_arch(fname)
|
26
|
+
# dext = Config::CONFIG['DLEXT']
|
27
|
+
# begin
|
28
|
+
# if File.extname(fname) == dext
|
29
|
+
# path = fname
|
30
|
+
# else
|
31
|
+
# path = File.join("tmail","#{fname}.#{dext}")
|
32
|
+
# end
|
33
|
+
# require path
|
34
|
+
# rescue LoadError => e
|
35
|
+
# begin
|
36
|
+
# arch = Config::CONFIG['arch']
|
37
|
+
# path = File.join("tmail", arch, "#{fname}.#{dext}")
|
38
|
+
# require path
|
39
|
+
# rescue LoadError
|
40
|
+
# case path
|
41
|
+
# when /i686/
|
42
|
+
# path.sub!('i686', 'i586')
|
43
|
+
# when /i586/
|
44
|
+
# path.sub!('i586', 'i486')
|
45
|
+
# when /i486/
|
46
|
+
# path.sub!('i486', 'i386')
|
47
|
+
# else
|
48
|
+
# begin
|
49
|
+
# require fname + '.rb'
|
50
|
+
# rescue LoadError
|
51
|
+
# raise e
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
# retry
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
#:startdoc:
|
@@ -0,0 +1,49 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
|
3
|
+
= Scanner for TMail
|
4
|
+
|
5
|
+
=end
|
6
|
+
#--
|
7
|
+
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
|
8
|
+
#
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
10
|
+
# a copy of this software and associated documentation files (the
|
11
|
+
# "Software"), to deal in the Software without restriction, including
|
12
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
13
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
14
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
15
|
+
# the following conditions:
|
16
|
+
#
|
17
|
+
# The above copyright notice and this permission notice shall be
|
18
|
+
# included in all copies or substantial portions of the Software.
|
19
|
+
#
|
20
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
21
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
22
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
23
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
24
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
25
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
26
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27
|
+
#
|
28
|
+
# Note: Originally licensed under LGPL v2+. Using MIT license for Rails
|
29
|
+
# with permission of Minero Aoki.
|
30
|
+
#++
|
31
|
+
#:stopdoc:
|
32
|
+
#require 'tmail/require_arch'
|
33
|
+
require 'tmail/utils'
|
34
|
+
require 'tmail/config'
|
35
|
+
|
36
|
+
module TMail
|
37
|
+
# NOTE: It woiuld be nice if these two libs could boith be called "tmailscanner", and
|
38
|
+
# the native extension would have precedence. However RubyGems boffs that up b/c
|
39
|
+
# it does not gaurantee load_path order.
|
40
|
+
begin
|
41
|
+
raise LoadError, 'Turned off native extentions by user choice' if ENV['NORUBYEXT']
|
42
|
+
require('tmail/tmailscanner') # c extension
|
43
|
+
Scanner = TMailScanner
|
44
|
+
rescue LoadError
|
45
|
+
require 'tmail/scanner_r'
|
46
|
+
Scanner = TMailScanner
|
47
|
+
end
|
48
|
+
end
|
49
|
+
#:stopdoc:
|
@@ -0,0 +1,261 @@
|
|
1
|
+
# scanner_r.rb
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
# a copy of this software and associated documentation files (the
|
8
|
+
# "Software"), to deal in the Software without restriction, including
|
9
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
# the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be
|
15
|
+
# included in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
#
|
25
|
+
# Note: Originally licensed under LGPL v2+. Using MIT license for Rails
|
26
|
+
# with permission of Minero Aoki.
|
27
|
+
#++
|
28
|
+
#:stopdoc:
|
29
|
+
require 'tmail/config'
|
30
|
+
|
31
|
+
module TMail
|
32
|
+
|
33
|
+
class TMailScanner
|
34
|
+
|
35
|
+
Version = '1.2.3'
|
36
|
+
Version.freeze
|
37
|
+
|
38
|
+
MIME_HEADERS = {
|
39
|
+
:CTYPE => true,
|
40
|
+
:CENCODING => true,
|
41
|
+
:CDISPOSITION => true
|
42
|
+
}
|
43
|
+
|
44
|
+
alnum = 'a-zA-Z0-9'
|
45
|
+
atomsyms = %q[ _#!$%&`'*+-{|}~^/=? ].strip
|
46
|
+
tokensyms = %q[ _#!$%&`'*+-{|}~^@. ].strip
|
47
|
+
atomchars = alnum + Regexp.quote(atomsyms)
|
48
|
+
tokenchars = alnum + Regexp.quote(tokensyms)
|
49
|
+
iso2022str = '\e(?!\(B)..(?:[^\e]+|\e(?!\(B)..)*\e\(B'
|
50
|
+
|
51
|
+
eucstr = "(?:[\xa1-\xfe][\xa1-\xfe])+"
|
52
|
+
sjisstr = "(?:[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])+"
|
53
|
+
utf8str = "(?:[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf])+"
|
54
|
+
|
55
|
+
quoted_with_iso2022 = /\A(?:[^\\\e"]+|#{iso2022str})+/n
|
56
|
+
domlit_with_iso2022 = /\A(?:[^\\\e\]]+|#{iso2022str})+/n
|
57
|
+
comment_with_iso2022 = /\A(?:[^\\\e()]+|#{iso2022str})+/n
|
58
|
+
|
59
|
+
quoted_without_iso2022 = /\A[^\\"]+/n
|
60
|
+
domlit_without_iso2022 = /\A[^\\\]]+/n
|
61
|
+
comment_without_iso2022 = /\A[^\\()]+/n
|
62
|
+
|
63
|
+
PATTERN_TABLE = {}
|
64
|
+
PATTERN_TABLE['EUC'] =
|
65
|
+
[
|
66
|
+
/\A(?:[#{atomchars}]+|#{iso2022str}|#{eucstr})+/n,
|
67
|
+
/\A(?:[#{tokenchars}]+|#{iso2022str}|#{eucstr})+/n,
|
68
|
+
quoted_with_iso2022,
|
69
|
+
domlit_with_iso2022,
|
70
|
+
comment_with_iso2022
|
71
|
+
]
|
72
|
+
PATTERN_TABLE['SJIS'] =
|
73
|
+
[
|
74
|
+
/\A(?:[#{atomchars}]+|#{iso2022str}|#{sjisstr})+/n,
|
75
|
+
/\A(?:[#{tokenchars}]+|#{iso2022str}|#{sjisstr})+/n,
|
76
|
+
quoted_with_iso2022,
|
77
|
+
domlit_with_iso2022,
|
78
|
+
comment_with_iso2022
|
79
|
+
]
|
80
|
+
PATTERN_TABLE['UTF8'] =
|
81
|
+
[
|
82
|
+
/\A(?:[#{atomchars}]+|#{utf8str})+/n,
|
83
|
+
/\A(?:[#{tokenchars}]+|#{utf8str})+/n,
|
84
|
+
quoted_without_iso2022,
|
85
|
+
domlit_without_iso2022,
|
86
|
+
comment_without_iso2022
|
87
|
+
]
|
88
|
+
PATTERN_TABLE['NONE'] =
|
89
|
+
[
|
90
|
+
/\A[#{atomchars}]+/n,
|
91
|
+
/\A[#{tokenchars}]+/n,
|
92
|
+
quoted_without_iso2022,
|
93
|
+
domlit_without_iso2022,
|
94
|
+
comment_without_iso2022
|
95
|
+
]
|
96
|
+
|
97
|
+
|
98
|
+
def initialize( str, scantype, comments )
|
99
|
+
init_scanner str
|
100
|
+
@comments = comments || []
|
101
|
+
@debug = false
|
102
|
+
|
103
|
+
# fix scanner mode
|
104
|
+
@received = (scantype == :RECEIVED)
|
105
|
+
@is_mime_header = MIME_HEADERS[scantype]
|
106
|
+
|
107
|
+
atom, token, @quoted_re, @domlit_re, @comment_re = PATTERN_TABLE[TMail.KCODE]
|
108
|
+
@word_re = (MIME_HEADERS[scantype] ? token : atom)
|
109
|
+
end
|
110
|
+
|
111
|
+
attr_accessor :debug
|
112
|
+
|
113
|
+
def scan( &block )
|
114
|
+
if @debug
|
115
|
+
scan_main do |arr|
|
116
|
+
s, v = arr
|
117
|
+
printf "%7d %-10s %s\n",
|
118
|
+
rest_size(),
|
119
|
+
s.respond_to?(:id2name) ? s.id2name : s.inspect,
|
120
|
+
v.inspect
|
121
|
+
yield arr
|
122
|
+
end
|
123
|
+
else
|
124
|
+
scan_main(&block)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
RECV_TOKEN = {
|
131
|
+
'from' => :FROM,
|
132
|
+
'by' => :BY,
|
133
|
+
'via' => :VIA,
|
134
|
+
'with' => :WITH,
|
135
|
+
'id' => :ID,
|
136
|
+
'for' => :FOR
|
137
|
+
}
|
138
|
+
|
139
|
+
def scan_main
|
140
|
+
until eof?
|
141
|
+
if skip(/\A[\n\r\t ]+/n) # LWSP
|
142
|
+
break if eof?
|
143
|
+
end
|
144
|
+
|
145
|
+
if s = readstr(@word_re)
|
146
|
+
if @is_mime_header
|
147
|
+
yield [:TOKEN, s]
|
148
|
+
else
|
149
|
+
# atom
|
150
|
+
if /\A\d+\z/ === s
|
151
|
+
yield [:DIGIT, s]
|
152
|
+
elsif @received
|
153
|
+
yield [RECV_TOKEN[s.downcase] || :ATOM, s]
|
154
|
+
else
|
155
|
+
yield [:ATOM, s]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
elsif skip(/\A"/)
|
160
|
+
yield [:QUOTED, scan_quoted_word()]
|
161
|
+
|
162
|
+
elsif skip(/\A\[/)
|
163
|
+
yield [:DOMLIT, scan_domain_literal()]
|
164
|
+
|
165
|
+
elsif skip(/\A\(/)
|
166
|
+
@comments.push scan_comment()
|
167
|
+
|
168
|
+
else
|
169
|
+
c = readchar()
|
170
|
+
yield [c, c]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
yield [false, '$']
|
175
|
+
end
|
176
|
+
|
177
|
+
def scan_quoted_word
|
178
|
+
scan_qstr(@quoted_re, /\A"/, 'quoted-word')
|
179
|
+
end
|
180
|
+
|
181
|
+
def scan_domain_literal
|
182
|
+
'[' + scan_qstr(@domlit_re, /\A\]/, 'domain-literal') + ']'
|
183
|
+
end
|
184
|
+
|
185
|
+
def scan_qstr( pattern, terminal, type )
|
186
|
+
result = ''
|
187
|
+
until eof?
|
188
|
+
if s = readstr(pattern) then result << s
|
189
|
+
elsif skip(terminal) then return result
|
190
|
+
elsif skip(/\A\\/) then result << readchar()
|
191
|
+
else
|
192
|
+
raise "TMail FATAL: not match in #{type}"
|
193
|
+
end
|
194
|
+
end
|
195
|
+
scan_error! "found unterminated #{type}"
|
196
|
+
end
|
197
|
+
|
198
|
+
def scan_comment
|
199
|
+
result = ''
|
200
|
+
nest = 1
|
201
|
+
content = @comment_re
|
202
|
+
|
203
|
+
until eof?
|
204
|
+
if s = readstr(content) then result << s
|
205
|
+
elsif skip(/\A\)/) then nest -= 1
|
206
|
+
return result if nest == 0
|
207
|
+
result << ')'
|
208
|
+
elsif skip(/\A\(/) then nest += 1
|
209
|
+
result << '('
|
210
|
+
elsif skip(/\A\\/) then result << readchar()
|
211
|
+
else
|
212
|
+
raise 'TMail FATAL: not match in comment'
|
213
|
+
end
|
214
|
+
end
|
215
|
+
scan_error! 'found unterminated comment'
|
216
|
+
end
|
217
|
+
|
218
|
+
# string scanner
|
219
|
+
|
220
|
+
def init_scanner( str )
|
221
|
+
@src = str
|
222
|
+
end
|
223
|
+
|
224
|
+
def eof?
|
225
|
+
@src.empty?
|
226
|
+
end
|
227
|
+
|
228
|
+
def rest_size
|
229
|
+
@src.size
|
230
|
+
end
|
231
|
+
|
232
|
+
def readstr( re )
|
233
|
+
if m = re.match(@src)
|
234
|
+
@src = m.post_match
|
235
|
+
m[0]
|
236
|
+
else
|
237
|
+
nil
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def readchar
|
242
|
+
readstr(/\A./)
|
243
|
+
end
|
244
|
+
|
245
|
+
def skip( re )
|
246
|
+
if m = re.match(@src)
|
247
|
+
@src = m.post_match
|
248
|
+
true
|
249
|
+
else
|
250
|
+
false
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def scan_error!( msg )
|
255
|
+
raise SyntaxError, msg
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
end # module TMail
|
261
|
+
#:startdoc:
|
@@ -0,0 +1,280 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
=begin rdoc
|
3
|
+
|
4
|
+
= String handling class
|
5
|
+
|
6
|
+
=end
|
7
|
+
#--
|
8
|
+
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
|
9
|
+
#
|
10
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
11
|
+
# a copy of this software and associated documentation files (the
|
12
|
+
# "Software"), to deal in the Software without restriction, including
|
13
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
14
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
15
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
16
|
+
# the following conditions:
|
17
|
+
#
|
18
|
+
# The above copyright notice and this permission notice shall be
|
19
|
+
# included in all copies or substantial portions of the Software.
|
20
|
+
#
|
21
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
22
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
23
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
24
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
25
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
26
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
27
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
28
|
+
#
|
29
|
+
# Note: Originally licensed under LGPL v2+. Using MIT license for Rails
|
30
|
+
# with permission of Minero Aoki.
|
31
|
+
#++
|
32
|
+
|
33
|
+
class StringInput#:nodoc:
|
34
|
+
|
35
|
+
include Enumerable
|
36
|
+
|
37
|
+
class << self
|
38
|
+
|
39
|
+
def new( str )
|
40
|
+
if block_given?
|
41
|
+
begin
|
42
|
+
f = super
|
43
|
+
yield f
|
44
|
+
ensure
|
45
|
+
f.close if f
|
46
|
+
end
|
47
|
+
else
|
48
|
+
super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
alias open new
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize( str )
|
57
|
+
@src = str
|
58
|
+
@pos = 0
|
59
|
+
@closed = false
|
60
|
+
@lineno = 0
|
61
|
+
end
|
62
|
+
|
63
|
+
attr_reader :lineno
|
64
|
+
|
65
|
+
def string
|
66
|
+
@src
|
67
|
+
end
|
68
|
+
|
69
|
+
def inspect
|
70
|
+
"#<#{self.class}:#{@closed ? 'closed' : 'open'},src=#{@src[0,30].inspect}>"
|
71
|
+
end
|
72
|
+
|
73
|
+
def close
|
74
|
+
stream_check!
|
75
|
+
@pos = nil
|
76
|
+
@closed = true
|
77
|
+
end
|
78
|
+
|
79
|
+
def closed?
|
80
|
+
@closed
|
81
|
+
end
|
82
|
+
|
83
|
+
def pos
|
84
|
+
stream_check!
|
85
|
+
[@pos, @src.size].min
|
86
|
+
end
|
87
|
+
|
88
|
+
alias tell pos
|
89
|
+
|
90
|
+
def seek( offset, whence = IO::SEEK_SET )
|
91
|
+
stream_check!
|
92
|
+
case whence
|
93
|
+
when IO::SEEK_SET
|
94
|
+
@pos = offset
|
95
|
+
when IO::SEEK_CUR
|
96
|
+
@pos += offset
|
97
|
+
when IO::SEEK_END
|
98
|
+
@pos = @src.size - offset
|
99
|
+
else
|
100
|
+
raise ArgumentError, "unknown seek flag: #{whence}"
|
101
|
+
end
|
102
|
+
@pos = 0 if @pos < 0
|
103
|
+
@pos = [@pos, @src.size + 1].min
|
104
|
+
offset
|
105
|
+
end
|
106
|
+
|
107
|
+
def rewind
|
108
|
+
stream_check!
|
109
|
+
@pos = 0
|
110
|
+
end
|
111
|
+
|
112
|
+
def eof?
|
113
|
+
stream_check!
|
114
|
+
@pos > @src.size
|
115
|
+
end
|
116
|
+
|
117
|
+
def each( &block )
|
118
|
+
stream_check!
|
119
|
+
begin
|
120
|
+
@src.each(&block)
|
121
|
+
ensure
|
122
|
+
@pos = 0
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def gets
|
127
|
+
stream_check!
|
128
|
+
if idx = @src.index(?\n, @pos)
|
129
|
+
idx += 1 # "\n".size
|
130
|
+
line = @src[ @pos ... idx ]
|
131
|
+
@pos = idx
|
132
|
+
@pos += 1 if @pos == @src.size
|
133
|
+
else
|
134
|
+
line = @src[ @pos .. -1 ]
|
135
|
+
@pos = @src.size + 1
|
136
|
+
end
|
137
|
+
@lineno += 1
|
138
|
+
|
139
|
+
line
|
140
|
+
end
|
141
|
+
|
142
|
+
def getc
|
143
|
+
stream_check!
|
144
|
+
ch = @src[@pos]
|
145
|
+
@pos += 1
|
146
|
+
@pos += 1 if @pos == @src.size
|
147
|
+
ch
|
148
|
+
end
|
149
|
+
|
150
|
+
def read( len = nil )
|
151
|
+
stream_check!
|
152
|
+
return read_all unless len
|
153
|
+
str = @src[@pos, len]
|
154
|
+
@pos += len
|
155
|
+
@pos += 1 if @pos == @src.size
|
156
|
+
str
|
157
|
+
end
|
158
|
+
|
159
|
+
alias sysread read
|
160
|
+
|
161
|
+
def read_all
|
162
|
+
stream_check!
|
163
|
+
return nil if eof?
|
164
|
+
rest = @src[@pos ... @src.size]
|
165
|
+
@pos = @src.size + 1
|
166
|
+
rest
|
167
|
+
end
|
168
|
+
|
169
|
+
def stream_check!
|
170
|
+
@closed and raise IOError, 'closed stream'
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
class StringOutput#:nodoc:
|
177
|
+
|
178
|
+
class << self
|
179
|
+
|
180
|
+
def new( str = '' )
|
181
|
+
if block_given?
|
182
|
+
begin
|
183
|
+
f = super
|
184
|
+
yield f
|
185
|
+
ensure
|
186
|
+
f.close if f
|
187
|
+
end
|
188
|
+
else
|
189
|
+
super
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
alias open new
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
def initialize( str = '' )
|
198
|
+
@dest = str
|
199
|
+
@closed = false
|
200
|
+
end
|
201
|
+
|
202
|
+
def close
|
203
|
+
@closed = true
|
204
|
+
end
|
205
|
+
|
206
|
+
def closed?
|
207
|
+
@closed
|
208
|
+
end
|
209
|
+
|
210
|
+
def string
|
211
|
+
@dest
|
212
|
+
end
|
213
|
+
|
214
|
+
alias value string
|
215
|
+
alias to_str string
|
216
|
+
|
217
|
+
def size
|
218
|
+
@dest.size
|
219
|
+
end
|
220
|
+
|
221
|
+
alias pos size
|
222
|
+
|
223
|
+
def inspect
|
224
|
+
"#<#{self.class}:#{@dest ? 'open' : 'closed'},#{object_id}>"
|
225
|
+
end
|
226
|
+
|
227
|
+
def print( *args )
|
228
|
+
stream_check!
|
229
|
+
raise ArgumentError, 'wrong # of argument (0 for >1)' if args.empty?
|
230
|
+
args.each do |s|
|
231
|
+
raise ArgumentError, 'nil not allowed' if s.nil?
|
232
|
+
@dest << s.to_s
|
233
|
+
end
|
234
|
+
nil
|
235
|
+
end
|
236
|
+
|
237
|
+
def puts( *args )
|
238
|
+
stream_check!
|
239
|
+
args.each do |str|
|
240
|
+
@dest << (s = str.to_s)
|
241
|
+
@dest << "\n" unless s[-1] == ?\n
|
242
|
+
end
|
243
|
+
@dest << "\n" if args.empty?
|
244
|
+
nil
|
245
|
+
end
|
246
|
+
|
247
|
+
def putc( ch )
|
248
|
+
stream_check!
|
249
|
+
@dest << ch.chr
|
250
|
+
nil
|
251
|
+
end
|
252
|
+
|
253
|
+
def printf( *args )
|
254
|
+
stream_check!
|
255
|
+
@dest << sprintf(*args)
|
256
|
+
nil
|
257
|
+
end
|
258
|
+
|
259
|
+
def write( str )
|
260
|
+
stream_check!
|
261
|
+
s = str.to_s
|
262
|
+
@dest << s
|
263
|
+
s.size
|
264
|
+
end
|
265
|
+
|
266
|
+
alias syswrite write
|
267
|
+
|
268
|
+
def <<( str )
|
269
|
+
stream_check!
|
270
|
+
@dest << str.to_s
|
271
|
+
self
|
272
|
+
end
|
273
|
+
|
274
|
+
private
|
275
|
+
|
276
|
+
def stream_check!
|
277
|
+
@closed and raise IOError, 'closed stream'
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|