YkLib 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.
- 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
|