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.
Files changed (125) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +6 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +7 -0
  7. data/Gemfile.lock +34 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +44 -0
  10. data/Rakefile +6 -0
  11. data/YkLib.gemspec +29 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/lib/YkLib/Yk/__advance__.rb +151 -0
  15. data/lib/YkLib/Yk/__defun__.rb +44 -0
  16. data/lib/YkLib/Yk/__hook__.rb +244 -0
  17. data/lib/YkLib/Yk/__minmax__.rb +123 -0
  18. data/lib/YkLib/Yk/__stdlog.rb +329 -0
  19. data/lib/YkLib/Yk/adhocLiterals/email.rb +119 -0
  20. data/lib/YkLib/Yk/adhocLiterals/path.rb +402 -0
  21. data/lib/YkLib/Yk/adhocLiterals/tag.rb +19 -0
  22. data/lib/YkLib/Yk/adhocLiterals/url.rb +36 -0
  23. data/lib/YkLib/Yk/adhocLiterals.rb +199 -0
  24. data/lib/YkLib/Yk/auto_escseq.rb +5 -0
  25. data/lib/YkLib/Yk/auto_pstore.rb +179 -0
  26. data/lib/YkLib/Yk/bsearch.rb +120 -0
  27. data/lib/YkLib/Yk/clambda.rb +309 -0
  28. data/lib/YkLib/Yk/confLine.rb +423 -0
  29. data/lib/YkLib/Yk/create_tty_width_available.rb +24 -0
  30. data/lib/YkLib/Yk/crypt.rb +26 -0
  31. data/lib/YkLib/Yk/debug2 +1 -0
  32. data/lib/YkLib/Yk/debug2.rb +473 -0
  33. data/lib/YkLib/Yk/debugout.rb +139 -0
  34. data/lib/YkLib/Yk/email_tz.rb +533 -0
  35. data/lib/YkLib/Yk/enum_expect.rb +170 -0
  36. data/lib/YkLib/Yk/errlog.rb +5 -0
  37. data/lib/YkLib/Yk/escseq.rb +59 -0
  38. data/lib/YkLib/Yk/eval_alt.rb +281 -0
  39. data/lib/YkLib/Yk/expector.rb +93 -0
  40. data/lib/YkLib/Yk/fetch.rb +556 -0
  41. data/lib/YkLib/Yk/fetch_old.rb +290 -0
  42. data/lib/YkLib/Yk/fib.rb +158 -0
  43. data/lib/YkLib/Yk/file_aux.rb +843 -0
  44. data/lib/YkLib/Yk/file_aux2.rb +919 -0
  45. data/lib/YkLib/Yk/file_aux_old.rb +160 -0
  46. data/lib/YkLib/Yk/filemod.rb +19 -0
  47. data/lib/YkLib/Yk/force_escseq.rb +3 -0
  48. data/lib/YkLib/Yk/generator__.rb +144 -0
  49. data/lib/YkLib/Yk/generator__.rb.org +139 -0
  50. data/lib/YkLib/Yk/indenter/argless_case.rb +46 -0
  51. data/lib/YkLib/Yk/indenter/each_token.rb +671 -0
  52. data/lib/YkLib/Yk/indenter/free_case.rb +313 -0
  53. data/lib/YkLib/Yk/indenter/if_less.rb +53 -0
  54. data/lib/YkLib/Yk/indenter/independent_ensure.rb +23 -0
  55. data/lib/YkLib/Yk/indenter/independent_rescue.rb +23 -0
  56. data/lib/YkLib/Yk/indenter/operand_circumflex.rb +0 -0
  57. data/lib/YkLib/Yk/indenter/operand_period.rb +16 -0
  58. data/lib/YkLib/Yk/indenter/parenless_and.rb +37 -0
  59. data/lib/YkLib/Yk/indenter/post_test.rb +48 -0
  60. data/lib/YkLib/Yk/indenter/token.rb +1525 -0
  61. data/lib/YkLib/Yk/indenter.rb +1382 -0
  62. data/lib/YkLib/Yk/inot.rb +265 -0
  63. data/lib/YkLib/Yk/intf.rb +815 -0
  64. data/lib/YkLib/Yk/io_aux.rb +1332 -0
  65. data/lib/YkLib/Yk/ioctl.rb +60 -0
  66. data/lib/YkLib/Yk/ipcc.rb +87 -0
  67. data/lib/YkLib/Yk/ipcountry.rb +207 -0
  68. data/lib/YkLib/Yk/ipv4adr.rb +318 -0
  69. data/lib/YkLib/Yk/localmail.rb +276 -0
  70. data/lib/YkLib/Yk/method_chain.rb +359 -0
  71. data/lib/YkLib/Yk/misc_tz.rb +1716 -0
  72. data/lib/YkLib/Yk/missing_method.rb +50 -0
  73. data/lib/YkLib/Yk/mojiConv.rb +257 -0
  74. data/lib/YkLib/Yk/nostdlog.rb +4 -0
  75. data/lib/YkLib/Yk/on_marshal.rb +20 -0
  76. data/lib/YkLib/Yk/overrider.rb +47 -0
  77. data/lib/YkLib/Yk/path.rb +293 -0
  78. data/lib/YkLib/Yk/path_aux.rb +883 -0
  79. data/lib/YkLib/Yk/path_aux_alt.rb +0 -0
  80. data/lib/YkLib/Yk/path_rep.rb +1267 -0
  81. data/lib/YkLib/Yk/pg_setup.rb +917 -0
  82. data/lib/YkLib/Yk/procinfo.rb +314 -0
  83. data/lib/YkLib/Yk/proclist.rb +492 -0
  84. data/lib/YkLib/Yk/property.rb +863 -0
  85. data/lib/YkLib/Yk/ranger.rb +606 -0
  86. data/lib/YkLib/Yk/resolv_tz.rb +88 -0
  87. data/lib/YkLib/Yk/rlprompt.rb +73 -0
  88. data/lib/YkLib/Yk/rootexec.rb +48 -0
  89. data/lib/YkLib/Yk/rpm-packageproxy.rb +784 -0
  90. data/lib/YkLib/Yk/rpm-packageproxy2.rb +1430 -0
  91. data/lib/YkLib/Yk/rwhen.rb +21 -0
  92. data/lib/YkLib/Yk/selector.rb +124 -0
  93. data/lib/YkLib/Yk/set.rb +170 -0
  94. data/lib/YkLib/Yk/shellquote.rb +300 -0
  95. data/lib/YkLib/Yk/sio.rb +1001 -0
  96. data/lib/YkLib/Yk/sio0.rb +835 -0
  97. data/lib/YkLib/Yk/sio_aux.rb +1524 -0
  98. data/lib/YkLib/Yk/sio_inot.rb +86 -0
  99. data/lib/YkLib/Yk/sock_aux.rb +42 -0
  100. data/lib/YkLib/Yk/spipe.rb +843 -0
  101. data/lib/YkLib/Yk/sql_table.rb +565 -0
  102. data/lib/YkLib/Yk/stdlog.rb +4 -0
  103. data/lib/YkLib/Yk/syscommand.rb +173 -0
  104. data/lib/YkLib/Yk/sysinit.rb +75 -0
  105. data/lib/YkLib/Yk/ttyFontWidth.rb +46113 -0
  106. data/lib/YkLib/Yk/tty_char.dump +0 -0
  107. data/lib/YkLib/Yk/tty_char.rb +47 -0
  108. data/lib/YkLib/Yk/tty_char_create.rb +437031 -0
  109. data/lib/YkLib/Yk/tty_char_static.rb +437016 -0
  110. data/lib/YkLib/Yk/tty_rewrite.rb +142 -0
  111. data/lib/YkLib/Yk/tty_str.rb +461 -0
  112. data/lib/YkLib/Yk/tty_width.dat.rb +114 -0
  113. data/lib/YkLib/Yk/tty_width.rb +180 -0
  114. data/lib/YkLib/Yk/tty_width_available +569 -0
  115. data/lib/YkLib/Yk/tty_width_list +0 -0
  116. data/lib/YkLib/Yk/tty_width_list.linux +280 -0
  117. data/lib/YkLib/Yk/tty_width_list.windows +324 -0
  118. data/lib/YkLib/Yk/tz_tty +0 -0
  119. data/lib/YkLib/Yk/tz_tty.rb +0 -0
  120. data/lib/YkLib/Yk/uprepos.rb +94 -0
  121. data/lib/YkLib/Yk/userinfo.rb +91 -0
  122. data/lib/YkLib/Yk/with.rb +109 -0
  123. data/lib/YkLib/version.rb +3 -0
  124. data/lib/YkLib.rb +6 -0
  125. 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