YkLib 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +34 -0
- data/LICENSE.txt +21 -0
- data/README.md +44 -0
- data/Rakefile +6 -0
- data/YkLib.gemspec +29 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/YkLib/Yk/__advance__.rb +151 -0
- data/lib/YkLib/Yk/__defun__.rb +44 -0
- data/lib/YkLib/Yk/__hook__.rb +244 -0
- data/lib/YkLib/Yk/__minmax__.rb +123 -0
- data/lib/YkLib/Yk/__stdlog.rb +329 -0
- data/lib/YkLib/Yk/adhocLiterals/email.rb +119 -0
- data/lib/YkLib/Yk/adhocLiterals/path.rb +402 -0
- data/lib/YkLib/Yk/adhocLiterals/tag.rb +19 -0
- data/lib/YkLib/Yk/adhocLiterals/url.rb +36 -0
- data/lib/YkLib/Yk/adhocLiterals.rb +199 -0
- data/lib/YkLib/Yk/auto_escseq.rb +5 -0
- data/lib/YkLib/Yk/auto_pstore.rb +179 -0
- data/lib/YkLib/Yk/bsearch.rb +120 -0
- data/lib/YkLib/Yk/clambda.rb +309 -0
- data/lib/YkLib/Yk/confLine.rb +423 -0
- data/lib/YkLib/Yk/create_tty_width_available.rb +24 -0
- data/lib/YkLib/Yk/crypt.rb +26 -0
- data/lib/YkLib/Yk/debug2 +1 -0
- data/lib/YkLib/Yk/debug2.rb +473 -0
- data/lib/YkLib/Yk/debugout.rb +139 -0
- data/lib/YkLib/Yk/email_tz.rb +533 -0
- data/lib/YkLib/Yk/enum_expect.rb +170 -0
- data/lib/YkLib/Yk/errlog.rb +5 -0
- data/lib/YkLib/Yk/escseq.rb +59 -0
- data/lib/YkLib/Yk/eval_alt.rb +281 -0
- data/lib/YkLib/Yk/expector.rb +93 -0
- data/lib/YkLib/Yk/fetch.rb +556 -0
- data/lib/YkLib/Yk/fetch_old.rb +290 -0
- data/lib/YkLib/Yk/fib.rb +158 -0
- data/lib/YkLib/Yk/file_aux.rb +843 -0
- data/lib/YkLib/Yk/file_aux2.rb +919 -0
- data/lib/YkLib/Yk/file_aux_old.rb +160 -0
- data/lib/YkLib/Yk/filemod.rb +19 -0
- data/lib/YkLib/Yk/force_escseq.rb +3 -0
- data/lib/YkLib/Yk/generator__.rb +144 -0
- data/lib/YkLib/Yk/generator__.rb.org +139 -0
- data/lib/YkLib/Yk/indenter/argless_case.rb +46 -0
- data/lib/YkLib/Yk/indenter/each_token.rb +671 -0
- data/lib/YkLib/Yk/indenter/free_case.rb +313 -0
- data/lib/YkLib/Yk/indenter/if_less.rb +53 -0
- data/lib/YkLib/Yk/indenter/independent_ensure.rb +23 -0
- data/lib/YkLib/Yk/indenter/independent_rescue.rb +23 -0
- data/lib/YkLib/Yk/indenter/operand_circumflex.rb +0 -0
- data/lib/YkLib/Yk/indenter/operand_period.rb +16 -0
- data/lib/YkLib/Yk/indenter/parenless_and.rb +37 -0
- data/lib/YkLib/Yk/indenter/post_test.rb +48 -0
- data/lib/YkLib/Yk/indenter/token.rb +1525 -0
- data/lib/YkLib/Yk/indenter.rb +1382 -0
- data/lib/YkLib/Yk/inot.rb +265 -0
- data/lib/YkLib/Yk/intf.rb +815 -0
- data/lib/YkLib/Yk/io_aux.rb +1332 -0
- data/lib/YkLib/Yk/ioctl.rb +60 -0
- data/lib/YkLib/Yk/ipcc.rb +87 -0
- data/lib/YkLib/Yk/ipcountry.rb +207 -0
- data/lib/YkLib/Yk/ipv4adr.rb +318 -0
- data/lib/YkLib/Yk/localmail.rb +276 -0
- data/lib/YkLib/Yk/method_chain.rb +359 -0
- data/lib/YkLib/Yk/misc_tz.rb +1716 -0
- data/lib/YkLib/Yk/missing_method.rb +50 -0
- data/lib/YkLib/Yk/mojiConv.rb +257 -0
- data/lib/YkLib/Yk/nostdlog.rb +4 -0
- data/lib/YkLib/Yk/on_marshal.rb +20 -0
- data/lib/YkLib/Yk/overrider.rb +47 -0
- data/lib/YkLib/Yk/path.rb +293 -0
- data/lib/YkLib/Yk/path_aux.rb +883 -0
- data/lib/YkLib/Yk/path_aux_alt.rb +0 -0
- data/lib/YkLib/Yk/path_rep.rb +1267 -0
- data/lib/YkLib/Yk/pg_setup.rb +917 -0
- data/lib/YkLib/Yk/procinfo.rb +314 -0
- data/lib/YkLib/Yk/proclist.rb +492 -0
- data/lib/YkLib/Yk/property.rb +863 -0
- data/lib/YkLib/Yk/ranger.rb +606 -0
- data/lib/YkLib/Yk/resolv_tz.rb +88 -0
- data/lib/YkLib/Yk/rlprompt.rb +73 -0
- data/lib/YkLib/Yk/rootexec.rb +48 -0
- data/lib/YkLib/Yk/rpm-packageproxy.rb +784 -0
- data/lib/YkLib/Yk/rpm-packageproxy2.rb +1430 -0
- data/lib/YkLib/Yk/rwhen.rb +21 -0
- data/lib/YkLib/Yk/selector.rb +124 -0
- data/lib/YkLib/Yk/set.rb +170 -0
- data/lib/YkLib/Yk/shellquote.rb +300 -0
- data/lib/YkLib/Yk/sio.rb +1001 -0
- data/lib/YkLib/Yk/sio0.rb +835 -0
- data/lib/YkLib/Yk/sio_aux.rb +1524 -0
- data/lib/YkLib/Yk/sio_inot.rb +86 -0
- data/lib/YkLib/Yk/sock_aux.rb +42 -0
- data/lib/YkLib/Yk/spipe.rb +843 -0
- data/lib/YkLib/Yk/sql_table.rb +565 -0
- data/lib/YkLib/Yk/stdlog.rb +4 -0
- data/lib/YkLib/Yk/syscommand.rb +173 -0
- data/lib/YkLib/Yk/sysinit.rb +75 -0
- data/lib/YkLib/Yk/ttyFontWidth.rb +46113 -0
- data/lib/YkLib/Yk/tty_char.dump +0 -0
- data/lib/YkLib/Yk/tty_char.rb +47 -0
- data/lib/YkLib/Yk/tty_char_create.rb +437031 -0
- data/lib/YkLib/Yk/tty_char_static.rb +437016 -0
- data/lib/YkLib/Yk/tty_rewrite.rb +142 -0
- data/lib/YkLib/Yk/tty_str.rb +461 -0
- data/lib/YkLib/Yk/tty_width.dat.rb +114 -0
- data/lib/YkLib/Yk/tty_width.rb +180 -0
- data/lib/YkLib/Yk/tty_width_available +569 -0
- data/lib/YkLib/Yk/tty_width_list +0 -0
- data/lib/YkLib/Yk/tty_width_list.linux +280 -0
- data/lib/YkLib/Yk/tty_width_list.windows +324 -0
- data/lib/YkLib/Yk/tz_tty +0 -0
- data/lib/YkLib/Yk/tz_tty.rb +0 -0
- data/lib/YkLib/Yk/uprepos.rb +94 -0
- data/lib/YkLib/Yk/userinfo.rb +91 -0
- data/lib/YkLib/Yk/with.rb +109 -0
- data/lib/YkLib/version.rb +3 -0
- data/lib/YkLib.rb +6 -0
- metadata +170 -0
@@ -0,0 +1,276 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
require 'Yk/path_aux'
|
4
|
+
require 'net/smtp'
|
5
|
+
require 'net/pop'
|
6
|
+
require 'thread'
|
7
|
+
require 'Yk/misc_tz'
|
8
|
+
require 'Yk/procinfo'
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
class RemoteMail < String
|
13
|
+
def send (content, subject = nil)
|
14
|
+
LocalMail.each do |m|
|
15
|
+
m.sendTo(self, content, subject)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
def self.setMails (lmdir = "/etc/local_mail/remote".check_dir)
|
19
|
+
if !defined? @@mails
|
20
|
+
@@mails = []
|
21
|
+
lmdir.each_entry do |f|
|
22
|
+
if f =~ /\@/
|
23
|
+
i = 0
|
24
|
+
@@mails.push RemoteMail.new(f.basename)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
if !@@mails.significant?
|
28
|
+
raise LocalMail::Error.new("cannot find mail configuration")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
@@mails
|
32
|
+
end
|
33
|
+
def self.send (content, subject = nil)
|
34
|
+
if !defined? @@mails
|
35
|
+
setMails
|
36
|
+
end
|
37
|
+
@@mails.each do |e|
|
38
|
+
e.send content, subject
|
39
|
+
end
|
40
|
+
LocalMail.flush
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
class LocalMail < String
|
46
|
+
class Error < Exception
|
47
|
+
end
|
48
|
+
DEF_LIST = %w[
|
49
|
+
SMTP_SERVER
|
50
|
+
SMTP_ACCOUNT
|
51
|
+
SMTP_PASSWD
|
52
|
+
POP_SERVER
|
53
|
+
POP_ACCOUNT
|
54
|
+
POP_PASSWD
|
55
|
+
POP_BEFORE_SMTP
|
56
|
+
]
|
57
|
+
@@localMails = []
|
58
|
+
def initialize (fileName)
|
59
|
+
super fileName.basename
|
60
|
+
if CYGWIN || Process.euid == 0
|
61
|
+
fileName.read_each_line do |ln|
|
62
|
+
ln.strip_comment!
|
63
|
+
if ln.significant?
|
64
|
+
res = ln.getDefinition DEF_LIST do |k, v|
|
65
|
+
instanceVariableSet(k, v)
|
66
|
+
end
|
67
|
+
if !res
|
68
|
+
raise LocalMail::Error.new("illeagal line `#{ln}' at #{i}")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
if !@popAccount
|
73
|
+
@popAccount = self
|
74
|
+
end
|
75
|
+
if !@smtpAccount
|
76
|
+
@smtpAccount = @popAccount
|
77
|
+
end
|
78
|
+
if !@smtpPasswd
|
79
|
+
@smtpPasswd = @popPasswd
|
80
|
+
end
|
81
|
+
end
|
82
|
+
@mutex = Mutex.new
|
83
|
+
@fmutex = Mutex.new
|
84
|
+
@rmutex = Mutex.new
|
85
|
+
@mail = self
|
86
|
+
@queue = []
|
87
|
+
@@localMails.push self
|
88
|
+
end
|
89
|
+
def recieve mode = nil
|
90
|
+
@rmutex.synchronize do
|
91
|
+
begin
|
92
|
+
pobj = Net::POP3.new(@popServer, 110)
|
93
|
+
pobj.open_timeout = 1200
|
94
|
+
pobj.start(@popAccount, @popPasswd) do |pop|
|
95
|
+
if mode == ""
|
96
|
+
next
|
97
|
+
end
|
98
|
+
hash = Hash.new
|
99
|
+
pop.each_mail do |m|
|
100
|
+
if mode == "flush"
|
101
|
+
m.delete
|
102
|
+
next
|
103
|
+
end
|
104
|
+
pop = m.pop.gsub /\r\n/, "\n"
|
105
|
+
begin
|
106
|
+
begin
|
107
|
+
yield pop #MailipReciever::MailContent.new(m.pop)
|
108
|
+
ensure
|
109
|
+
m.delete
|
110
|
+
end
|
111
|
+
rescue Exception, SignalException => e
|
112
|
+
raise Reexception.new
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
rescue Reexception => e
|
117
|
+
e.reraise
|
118
|
+
rescue Exception, SignalException => e
|
119
|
+
emsg = ""
|
120
|
+
if e.to_s != ""
|
121
|
+
emsg = " (#{e.to_s.gsub(/\s+/, ' ').strip})"
|
122
|
+
end
|
123
|
+
errln "#{e.class.to_s}: failed to retrieve a mail from #{@mail}#{emsg}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
def sendTo (toAdr, content, subject = nil)
|
128
|
+
if @popBeforeSmtp
|
129
|
+
recieve @popBeforeSmtp
|
130
|
+
end
|
131
|
+
if subject
|
132
|
+
t = content
|
133
|
+
content = subject
|
134
|
+
subject = t
|
135
|
+
end
|
136
|
+
c = -%{
|
137
|
+
Date: #{arr = Time.now.localtime.to_s.split; arr[0] + ', ' + arr[2] + ' ' + arr[1] + ' ' + arr[5] + ' ' + arr[3] + ' ' + arr[4]}
|
138
|
+
From: #{ProcInfo.current.cmdline.shellDQuote} <#{self}>
|
139
|
+
To: #{toAdr}
|
140
|
+
Subject: #{subject}
|
141
|
+
}
|
142
|
+
c += "\n" + content.ln
|
143
|
+
@mutex.synchronize do
|
144
|
+
@queue.push [c, self, toAdr]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
def flush
|
148
|
+
@mutex.synchronize do
|
149
|
+
if @queue.size == 0
|
150
|
+
return
|
151
|
+
end
|
152
|
+
end
|
153
|
+
@fmutex.synchronize do
|
154
|
+
connectRetryCount = 0
|
155
|
+
begin
|
156
|
+
connectRetryCount += 1
|
157
|
+
Net::SMTP.start(@smtpServer, 25, 'localhost.localdomain', @smtpAccount, @smtpPasswd, :login) do |smtp|
|
158
|
+
while true
|
159
|
+
gotItem = false
|
160
|
+
params = nil
|
161
|
+
@mutex.synchronize do
|
162
|
+
if @queue.size > 0
|
163
|
+
params = @queue.shift
|
164
|
+
gotItem = true
|
165
|
+
end
|
166
|
+
end
|
167
|
+
if !gotItem
|
168
|
+
break
|
169
|
+
end
|
170
|
+
content, fromAdr, toAdr = params
|
171
|
+
retryCount = 0
|
172
|
+
begin
|
173
|
+
retryCount += 1
|
174
|
+
smtp.send_mail content, fromAdr, toAdr
|
175
|
+
rescue Exception => e
|
176
|
+
errln "cannot send from #{fromAdr} to #{toAdr} (#{e.class}:#{e.to_s.gsub(/\s+/, ' ')}.strip); Retring....".ln
|
177
|
+
sleep 10
|
178
|
+
if retryCount > 3
|
179
|
+
errln "All retrials failed. Giving up sending from #{fromAdr} to #{toAdr}.".ln
|
180
|
+
else
|
181
|
+
retry
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
rescue => e
|
187
|
+
errln "cannot complete sending mails from #{self} (#{e.class}:#{e.to_s.gsub(/\s+/, ' ')}.strip); Retrying....".ln
|
188
|
+
sleep 10
|
189
|
+
if connectRetryCount > 3
|
190
|
+
errln "All retrials failed. Giving up sending mails from #{self}.".ln
|
191
|
+
else
|
192
|
+
retry
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
def self.chkMails
|
198
|
+
if !defined? @@mails
|
199
|
+
setMails
|
200
|
+
end
|
201
|
+
end
|
202
|
+
def self.recieve
|
203
|
+
chkMails
|
204
|
+
tList = []
|
205
|
+
@@localMails.each do |m|
|
206
|
+
t = Thread.new do
|
207
|
+
m.recieve do |c|
|
208
|
+
yield c
|
209
|
+
end
|
210
|
+
end
|
211
|
+
tList.push t
|
212
|
+
end
|
213
|
+
tList.each do |t|
|
214
|
+
t.join
|
215
|
+
end
|
216
|
+
end
|
217
|
+
def self.setMails (lmdir = "/etc/local_mail/local".check_dir)
|
218
|
+
if !defined? @@mails
|
219
|
+
@@mails = []
|
220
|
+
lmdir.each_entry do |f|
|
221
|
+
if f =~ /\@/
|
222
|
+
i = 0
|
223
|
+
@@mails.push LocalMail.new(f)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
if !@@mails.significant?
|
227
|
+
raise LocalMail::Error.new("cannot find mail configuration")
|
228
|
+
end
|
229
|
+
end
|
230
|
+
@@mails
|
231
|
+
end
|
232
|
+
def self.each
|
233
|
+
chkMails
|
234
|
+
@@mails.each do |e|
|
235
|
+
yield e
|
236
|
+
end
|
237
|
+
end
|
238
|
+
def self.flush
|
239
|
+
chkMails
|
240
|
+
@@localMails.each do |m|
|
241
|
+
m.flush
|
242
|
+
end
|
243
|
+
end
|
244
|
+
def self.keep
|
245
|
+
chkMails
|
246
|
+
@@localMails.each do |m|
|
247
|
+
m.receive ""
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
|
253
|
+
class RemoteMail < String
|
254
|
+
def send (content, subject)
|
255
|
+
sendToAdmin(content, subject)
|
256
|
+
#LocalMail.each do |m|
|
257
|
+
# m.sendTo(self, content, subject)
|
258
|
+
#end
|
259
|
+
end
|
260
|
+
def sendTo (mail, content, subject)
|
261
|
+
LocalMail.each do |m|
|
262
|
+
m.sendTo(mail, content, subject)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
def sendToAdmin (content, subject)
|
266
|
+
if (mf = "/etc/local_mail/admin").readable_file?
|
267
|
+
adminMail = mf.read.strip
|
268
|
+
sendTo adminMail, content, subject
|
269
|
+
else
|
270
|
+
STDERR.write "#{$0}: cannot send mail: please set /etc/local_mail/admin\n"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
|
@@ -0,0 +1,359 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
require 'binding_of_caller'
|
5
|
+
|
6
|
+
|
7
|
+
class Module
|
8
|
+
def get_instence_method label
|
9
|
+
begin
|
10
|
+
org_mth = instance_method(label) # original method
|
11
|
+
rescue NameError
|
12
|
+
end
|
13
|
+
if org_mth && instance_methods(false).include?(label)
|
14
|
+
return org_mth
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def Modules *marr, &bl
|
20
|
+
marr.each do |m|
|
21
|
+
if m.is_a?(Symbol) || m.is_a?(String)
|
22
|
+
m = binding.of_caller(1).eval(m.to_s)
|
23
|
+
end
|
24
|
+
case m
|
25
|
+
when ::Class
|
26
|
+
m.class_eval &bl
|
27
|
+
when ::Module
|
28
|
+
m.module_eval &bl
|
29
|
+
else
|
30
|
+
raise ArgumentError.new("'#{m.inspect}' is not a module")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Class
|
36
|
+
def include *modules
|
37
|
+
MethodChain.doExtend self, *modules do
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
class Object
|
45
|
+
def extend *modules
|
46
|
+
cls = class << self; self; end
|
47
|
+
MethodChain.doExtend cls, *modules do
|
48
|
+
super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
def __method_chain_caller__ l
|
52
|
+
if caller[1] =~ /^(.+?):(\d+)(?::in `(.*)')?/
|
53
|
+
f, lno, fname = $1, $2.to_i, $3
|
54
|
+
callerMethod = MethodChain.getMethod($1, $2.to_i, l)
|
55
|
+
mp = MethodChain::PrevList[callerMethod]
|
56
|
+
if mp
|
57
|
+
return mp
|
58
|
+
else
|
59
|
+
mdl = MethodChain::ModList[callerMethod]
|
60
|
+
if om = MethodChain::OrgList[[mdl, l]]
|
61
|
+
return om
|
62
|
+
else
|
63
|
+
as = (class << self; self; end).ancestors
|
64
|
+
(as.index(mdl) + 1 ... as.size).each do |i|
|
65
|
+
c = as[i]
|
66
|
+
if ent = MethodChain::EntryList[c][l]
|
67
|
+
return ent
|
68
|
+
elsif om = MethodChain::OrgList[[c, l]]
|
69
|
+
return om
|
70
|
+
elsif m = c.get_instence_method(l)
|
71
|
+
if m.source_location[0] != "(MethodChain)"
|
72
|
+
return m
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
raise ArgumentError.new("No super method defined for '#{l}'")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
else
|
80
|
+
raise ArgumentError.new("Unknown error: cannot find '#{l}'")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class MethodChain
|
86
|
+
def self.doExtend cls, *modules
|
87
|
+
ks = Hash.new
|
88
|
+
(modules + [cls]).each do |mdl|
|
89
|
+
MethodChain::EntryList[mdl]&.keys&.each do |k|
|
90
|
+
ks[k] = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
yield
|
94
|
+
ks.keys.each do |k|
|
95
|
+
MethodChain.checkDispatcher k
|
96
|
+
if !MethodChain::EntryList[cls][k]
|
97
|
+
om = cls.get_instance_method(k)
|
98
|
+
if !om || om.source_location[0] != "(MethodChain)"
|
99
|
+
MethodChain::OrgList[[cls, k]] ||= om
|
100
|
+
cls.class_eval %{
|
101
|
+
def #{k} (...)
|
102
|
+
cls = ::ObjectSpace._id2ref(#{cls.__id__})
|
103
|
+
cls.ancestors.each do |a|
|
104
|
+
if ent = MethodChain::EntryList[a][:#{k}]
|
105
|
+
return mth.bind(self).call(...)
|
106
|
+
elsif om = MethodChain::OrgList[[cls, :#{k}]]
|
107
|
+
return om.bind(self).call(...)
|
108
|
+
elsif m = c.get_instence_method(l)
|
109
|
+
if m.source_location[0] != "(MethodChain)"
|
110
|
+
return m.bind(self).call(...)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
raise ArgumentError.new("No method defined for '#{l}'")
|
115
|
+
end
|
116
|
+
}, "(MethodChain)", 1
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
PrevList = Hash.new
|
122
|
+
EntryList = Hash.new{|h, k| h[k] = {}}
|
123
|
+
OrgList = {}
|
124
|
+
ModList = {}
|
125
|
+
def self.getMethod f, lno, label
|
126
|
+
MethodRange.getMethod(f, lno, label)
|
127
|
+
end
|
128
|
+
def self.checkDispatcher l
|
129
|
+
if !(Object.instance_method("__method_chain_caller_#{l}") rescue nil)
|
130
|
+
Object.class_eval %{
|
131
|
+
def __method_chain_caller_#{l} (...)
|
132
|
+
mth = __method_chain_caller__ :#{l}
|
133
|
+
mth.bind(self).call(...)
|
134
|
+
end
|
135
|
+
}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
def self.override &bl
|
139
|
+
cm = binding.of_caller(1).eval("self")
|
140
|
+
cm = ::Object if cm == TOPLEVEL_BINDING.eval("self")
|
141
|
+
if !cm.is_a? ::Module
|
142
|
+
raise Exception.new("called at non-module context")
|
143
|
+
end
|
144
|
+
new_defs = Module.new &bl
|
145
|
+
new_defs.instance_methods(false).each do |l| # newly defined method
|
146
|
+
checkDispatcher l
|
147
|
+
new_mth = MethodRange.emerge(cm, new_defs.instance_method(l), "__method_chain_caller_#{l}") # new_mth redefined as __method_chain_caller_
|
148
|
+
ModList[new_mth] = cm
|
149
|
+
old_ent = EntryList[cm][l]
|
150
|
+
EntryList[cm][l] = new_mth
|
151
|
+
if !old_ent
|
152
|
+
OrgList[[cm, l]] = cm.get_instence_method(l) # original method defined in this class
|
153
|
+
if cm.is_a? ::Class
|
154
|
+
cm.class_eval %{
|
155
|
+
def #{l} (...)
|
156
|
+
cls = ::ObjectSpace._id2ref(#{cm.__id__})
|
157
|
+
cls.ancestors.each do |a|
|
158
|
+
mth = MethodChain::EntryList[a][:#{l}]
|
159
|
+
if mth
|
160
|
+
return mth.bind(self).call(...)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
}, "(MethodChain)", 1
|
165
|
+
end
|
166
|
+
else
|
167
|
+
PrevList[new_mth] = old_ent
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
class MethodRange
|
172
|
+
class DefnList
|
173
|
+
DFNList = {}
|
174
|
+
def self.getRangeByStart f, name, lno
|
175
|
+
(DFNList[f] ||= new(f)).getRangeByStart name, lno
|
176
|
+
end
|
177
|
+
def initialize f
|
178
|
+
storedF = ENV['HOME'] + "/.tmp/ruby/Yk/#{File.basename($0)}/" + File.expand_path(f) + "/defnList"
|
179
|
+
if File.mtime(f) < (File.mtime(storedF) rescue Time.at(0))
|
180
|
+
@defnList = Marshal.load(IO.binread(storedF))
|
181
|
+
return
|
182
|
+
end
|
183
|
+
if f == "(eval)"
|
184
|
+
raise ArgumentError.new("cannot use MethodChain for method in evaluated value")
|
185
|
+
end
|
186
|
+
root = RubyVM::AbstractSyntaxTree.parse_file(f)
|
187
|
+
@defnList = Hash.new
|
188
|
+
(regMethodDef = -> node do
|
189
|
+
if node.inspect =~/\A#\<RubyVM::AbstractSyntaxTree::Node:DEFN@(\d+):\d+\-(\d+):\d+/
|
190
|
+
rg = $1.to_i .. $2.to_i
|
191
|
+
lst = (@defnList[node.children[0]] ||= [])
|
192
|
+
pos = lst.bsearch_index do |item|
|
193
|
+
item.first >= rg.first
|
194
|
+
end
|
195
|
+
pos ||= lst.size
|
196
|
+
if pos
|
197
|
+
lst.insert pos, rg
|
198
|
+
else
|
199
|
+
lst.push rg
|
200
|
+
end
|
201
|
+
end
|
202
|
+
if defined?(node.children)
|
203
|
+
node.children.each do |e|
|
204
|
+
regMethodDef.(e)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end).(root)
|
208
|
+
require "fileutils"
|
209
|
+
FileUtils.mkdir_p File.dirname(storedF)
|
210
|
+
IO.binwrite(storedF, Marshal.dump(@defnList))
|
211
|
+
end
|
212
|
+
def getRangeByStart name, lno
|
213
|
+
lst = @defnList[name]
|
214
|
+
pos = lst.bsearch_index do |item|
|
215
|
+
item.first >= lno
|
216
|
+
end
|
217
|
+
if pos && lst[pos]
|
218
|
+
if [pos - 1, pos + 1].find{lst[_1]&.first == lno}
|
219
|
+
raise ArgumentError.new("multiple definition of method '#{name}', found in one line")
|
220
|
+
else
|
221
|
+
lst[pos]
|
222
|
+
end
|
223
|
+
else
|
224
|
+
nil
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
OList = {}
|
229
|
+
FLnList = {}
|
230
|
+
List = Hash.new{|h, k| h[k] = []}
|
231
|
+
Item = Struct.new(:rg, :mth)
|
232
|
+
attr_reader :method_chain_caller
|
233
|
+
def self.emerge cls, mth, l
|
234
|
+
(OList[[cls, mth]] ||= new cls, mth, l).method_chain_caller
|
235
|
+
end
|
236
|
+
def initialize cls, mth, l
|
237
|
+
f, lno = mth.source_location
|
238
|
+
if f == "(eval)"
|
239
|
+
raise ArgumentError.new("cannot use MethodChain for method in evaluated value")
|
240
|
+
end
|
241
|
+
mrg = DefnList.getRangeByStart f, mth.name, lno
|
242
|
+
if !mrg
|
243
|
+
raise ArgumentError.new("cannot find 'def #{mth.name}': please note that currently alias_method and method defined in eval are not supported")
|
244
|
+
end
|
245
|
+
lns = (FLnList[f] ||= IO.readlines(f))
|
246
|
+
if (toEv = lns[mrg.first - 1 .. mrg.last - 1].join).sub! /\A\s*def\s+(\w+)/, "def #{l}"
|
247
|
+
(m = Module.new).module_eval toEv, f, mrg.first
|
248
|
+
@method_chain_caller = m.instance_method(l)
|
249
|
+
else
|
250
|
+
raise ArgumentError.new("cannot find 'def #{mth.name}': please note that currently alias_method and method defined in eval are not supported")
|
251
|
+
end
|
252
|
+
pos = (l = List[[f, mth.name]]).bsearch_index{|e| e.rg.first >= mrg.first}
|
253
|
+
if pos
|
254
|
+
if l[pos].rg.first != mrg.first
|
255
|
+
l.insert pos, Item.new(mrg, mth)
|
256
|
+
else
|
257
|
+
raise ArgumentError.new("method, '#{mth.name}' is defined twice in the same line")
|
258
|
+
end
|
259
|
+
else
|
260
|
+
l.push Item.new(mrg, @method_chain_caller)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
def self.getMethod f, lno, label
|
264
|
+
lst = List[[f, label]]
|
265
|
+
pos = lst.bsearch_index{|e| lno <= e.rg.first}
|
266
|
+
if pos == nil
|
267
|
+
pos = lst.size
|
268
|
+
end
|
269
|
+
smallestIdx = nil
|
270
|
+
smallestRangeSize = nil
|
271
|
+
if pos
|
272
|
+
hit = -> i do
|
273
|
+
item = lst[i]
|
274
|
+
if item
|
275
|
+
if item.rg.first < lno && lno < item.rg.last
|
276
|
+
if !smallestRangeSize&.<=(item.rg.size)
|
277
|
+
smallestRangeSize = item.rg.size
|
278
|
+
smallestIdx = i
|
279
|
+
end
|
280
|
+
break item.mth
|
281
|
+
elsif item.rg.first == lno || lno == item.rg.last
|
282
|
+
raise ArgumentEror.new("ambigous calling origin: 'super' should not be located in the same line with method definition starting by 'def' nor finising by 'end'")
|
283
|
+
end
|
284
|
+
end
|
285
|
+
nil
|
286
|
+
end
|
287
|
+
i = pos - 1
|
288
|
+
while hit.(i)
|
289
|
+
i -= 1
|
290
|
+
end
|
291
|
+
i = pos
|
292
|
+
while hit.(i)
|
293
|
+
i += 1
|
294
|
+
end
|
295
|
+
if !smallestIdx
|
296
|
+
raise ArgumentError.new("cannot find caller")
|
297
|
+
end
|
298
|
+
return lst[smallestIdx].mth
|
299
|
+
end
|
300
|
+
raise ArgumentError.new("cannot find calling origin, 'super'")
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
|
306
|
+
if File.expand_path($0) == File.expand_path(__FILE__)
|
307
|
+
|
308
|
+
class Ans
|
309
|
+
def test1
|
310
|
+
p ":Ans::org_test1"
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
|
315
|
+
|
316
|
+
|
317
|
+
class Des < Ans
|
318
|
+
def test1
|
319
|
+
p ":Des::org_test1"
|
320
|
+
super
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
Des.new.test1
|
325
|
+
|
326
|
+
|
327
|
+
class Des
|
328
|
+
MethodChain.override do
|
329
|
+
def test1
|
330
|
+
p ":Des::new_test1"
|
331
|
+
super
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
(d = Des.new).test1
|
337
|
+
|
338
|
+
class << d
|
339
|
+
MethodChain.override do
|
340
|
+
def test1
|
341
|
+
p ":Singleton::new_test1"
|
342
|
+
super
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
|
348
|
+
class << d
|
349
|
+
MethodChain.override do
|
350
|
+
def test1
|
351
|
+
p ":Singleton::new_new_test1"
|
352
|
+
super
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
d.test1
|
358
|
+
|
359
|
+
end
|