YkLib 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,199 @@
1
+
2
+ class String
3
+ def ssubst rg, str, anot
4
+ @anotList ||= [nil] * size
5
+ ed = rg.exclude_end? ? rg.end - 1 : rg.end
6
+ tail = [[anot, rg.begin]] * str.size + @anotList[ed + 1 .. -1]
7
+ @anotList[rg.begin .. -1] = tail
8
+ self[rg] = str
9
+ end
10
+ def anot i
11
+ @anotList ? nil : @anotList[i]
12
+ end
13
+ end
14
+
15
+ class AdhocLiterals
16
+ Literals = {}
17
+ class Error < Exception
18
+ end
19
+ def self.[] arg
20
+ Literals[arg]
21
+ end
22
+ def self.resolveRequirements opts
23
+ Opts.merge opts
24
+ if opts[:adhoc_literals].is_a? Array
25
+ opts[:adhoc_literals].each do |s|
26
+ e = File.expand_path(__FILE__)
27
+ d = File.dirname(e)
28
+ sd = File.basename(e, ".rb")
29
+ begin
30
+ Literals[s] = true
31
+ require "#{d}/#{sd}/" + s.to_s.downcase
32
+ rescue
33
+ raise Error.new("Adhoc literal, #{s} is not defined")
34
+ end
35
+ end
36
+ end
37
+ end
38
+ def self.require arg
39
+ e = File.expand_path(__FILE__)
40
+ d = File.dirname(e)
41
+ sd = File.basename(e, ".rb")
42
+ require "#{d}/#{sd}/" + arg
43
+ end
44
+ end
45
+
46
+ =begin
47
+ res = 25 * g.foo "\r\n" \ ln
48
+ case ln
49
+ when 3
50
+ break 1
51
+ when 4
52
+ break 2
53
+ _ .to_i + 5
54
+ def test
55
+
56
+ end
57
+ doc = <<>
58
+ !ENTITY open-hatch
59
+ asdf
60
+ asdf2
61
+ asdf3
62
+ <html
63
+ `foo
64
+ <table class=asdf
65
+ 10.times
66
+ <tr height=1
67
+ <td width=3
68
+ <div id=subdoc
69
+ `#{_1}
70
+ <td
71
+ 2
72
+ 5.times
73
+ test
74
+ 3
75
+ <input type=button onClick=test
76
+ <input type=text name=a accessor
77
+ <td
78
+
79
+ `pqr
80
+ !--
81
+ comment
82
+ def doc.test # direct
83
+ subdoc.innerHTML = <H2
84
+ `This is test
85
+ a.value = "success"
86
+ but1.enabled = false
87
+ doc.__defun__ :testAjax
88
+ doc.subdoc.innerHTML = getFooDocElem #if not defined in doc, request Ajax by XMLHttpRequest
89
+ asdf
90
+ _1 + _1
91
+ _
92
+ _1 + _1
93
+ Fiber.fork
94
+ doc.show
95
+ while
96
+ sleep 10
97
+ doc.byId.subdoc.innerHTML = <H2
98
+ ``Time.now
99
+ doc.byId.
100
+
101
+ def expect &c
102
+ lp: loop buff += getc rescue break
103
+ all_not_match = true
104
+ c.when.each \ *args, bl
105
+ args.each \ r
106
+ buff =~ r
107
+ case $/.status
108
+ when :partial
109
+ all_not_match &&= false
110
+ when :complete
111
+ bl.call
112
+ buff.clear
113
+ lp.next
114
+ if all_not_match
115
+ c.else&.call
116
+ buff.clear
117
+
118
+
119
+
120
+
121
+
122
+ `ls -la`.open 2, [1, 0] => :tty, timeout: 5, status: ^es \ ferr, ftty
123
+ fork
124
+ ferr.expect \ e
125
+ e.when /(^|\n)password:/
126
+ ftty.write pwd
127
+ e.else
128
+ printerr _1
129
+ lns = ftty.lines
130
+ if cmd.exitstatus != 0
131
+
132
+
133
+
134
+ # 1. a = /*1*/ 1 # is comment 'cause the comment closed witin a line
135
+ # 1'. a = /"*1*"/ # is a path '/*1*/'
136
+ # 2. a = /* # is comment beginning
137
+ # 2. a, b = /*, /* # the first '/*' is path, second is comment beginning
138
+ # 2'. a = /"*" # is a path, '/*'
139
+ # 3. a = /etc/* # is a path, '/etc/*'
140
+ =end
141
+ =begin
142
+ # opts : tab, tabstop, tab_stop
143
+ # underscore_line_continuation
144
+ # block_label
145
+ # omittable_if, omittable_do
146
+ # c_comment
147
+ # nested_when
148
+ # adhoc_pathname
149
+ # url
150
+ # ip
151
+ # safe_cmd
152
+ # SLASH_NOT_REG_NOR_PATH = ROOT_PATH | REG_EXPR # DIVIDE OPERATOR
153
+ # IS_SUBJECT = /\s+(\.\w|\#|\/\*)|\s*((\,|\:|\;)(?!<SLASH_NOT_REG_NOR_PATH>)|(\}|\]|\))(?!<REG_END>))|$/
154
+ # REG_END = /\/[uesnimxo]+(?=<IS_SUBJECT>)/
155
+ # ROOT_PATH = /\/([\w\d\.\*\?\-]+|)(?=<IS_SUBJECT>)/
156
+ # PATH_OR_REG
157
+ # PATH
158
+ # REG
159
+ # <PATH> , .\w+ / ; : } ] ) /\s
160
+ # x = [/, /asd, /foo]
161
+ # x = / # path
162
+ # x = / / foo # path => Pathname.new("/") / foo
163
+ # x, y = /, / foo / # path => Pathname.new("/") / foo
164
+ # / foo /
165
+ # /etc # path
166
+ # someResult = foo /proc, /, sys, /etc/, /bin/ /* comment */
167
+ while expr =~ /
168
+ ::` # possible unclosed `
169
+ | :` # possible unclosed `
170
+ | :\/ # possible unclosed \/
171
+ | \.+\/ # path
172
+ | \. # possible unclosed ` ; maybe over comment ".."
173
+ # or possible reserved word as method name
174
+ | \bend\b
175
+ | \bdef\b # possible unclosed ` ; maybe over comment
176
+ | \b(?<reserved>(class|module|if|unless|while|until|for|rescue|ensure|else|elsif|case|when|in|then|do))\b
177
+ | \b__DATA__\b
178
+ | \w[\w\d]*
179
+ | \$[\/'`"%] # possible unclosed
180
+ | ;
181
+ | (?<bracket_start>[({[])
182
+ | (?<space>[\t\r\f\v\x20]+)
183
+ | \\\n
184
+ | (?<ln>(\n|$))
185
+ | \b_\b
186
+ | (?<comment>\#.*(\n|$)) # traditional style comment, interpreted as new line
187
+ | (?<c_comment>\/\*.*?\*\/) # c comment, interpreted as space
188
+ | \/\* # c comment start
189
+ | \`
190
+ | \'
191
+ | \"
192
+ | \/\n # regular expression
193
+ | \/(?![$\s]) # regular expression or ad hoc file path
194
+ | \<\<(~|-|)([\'\"\`]|)\w+ # line literal
195
+ | \%([a-zA-Z]|)([^\w\s]|_) # percent expression
196
+ | \d+\.\d+
197
+ | \W+
198
+ /x
199
+ =end
@@ -0,0 +1,5 @@
1
+
2
+ require 'Yk/escseq'
3
+ Escseq.beIncludedBy String
4
+
5
+
@@ -0,0 +1,179 @@
1
+
2
+ require 'pstore'
3
+ require 'Yk/path_aux'
4
+
5
+
6
+ class AutoPstore
7
+ @@readOnly = false
8
+ @@fileName = File.basename($0)
9
+ def initialize
10
+ dbFile = "/var/tmp/#{@@fileName}.auto_pstore.db"
11
+ dbFileDeb = "/var/tmp/#{@@fileName}.auto_pstore.debug.db"
12
+ if $DEBUG
13
+ if !dbFileDeb.exist? && dbFile.exist?
14
+ dbFile.copy(dbFileDeb)
15
+ end
16
+ dbFile = dbFileDeb
17
+ end
18
+ if defined?(@@readTemp) && @@readTemp
19
+ "/var/tmp/#{@@fileName}.auto_pstore.lock".lock_sh do
20
+ db = PStore.new(dbFile)
21
+ db.transaction true do
22
+ @objList = db["root"]
23
+ end
24
+ end
25
+ else
26
+ retried = false
27
+ begin
28
+ "/var/tmp/#{@@fileName}.auto_pstore.lock".setpid
29
+ rescue File::CannotGetLock
30
+ raise Exception.new("AutoPstore: second instance is not allowed")
31
+ end
32
+ begin
33
+ db = PStore.new(dbFile)
34
+ rescue
35
+ if !retried
36
+ dbFile.rm_f
37
+ retried = true
38
+ retry
39
+ else
40
+ raise Exception.new("cannot open database\n")
41
+ exit 1
42
+ end
43
+ end
44
+ @sleeping = false
45
+ @thread = Thread.new do
46
+ db.transaction @@readOnly do
47
+ @objList = db["root"] ||= Hash.new
48
+ Thread.pass
49
+ @sleeping = true
50
+ sleep
51
+ end
52
+ end
53
+ ctmp = 0
54
+ while !@objList
55
+ Thread.pass
56
+ sleep 0.1
57
+ ctmp += 1
58
+ if ctmp > 10
59
+ raise Exception.new("cannot open/create database\n")
60
+ end
61
+ end
62
+ @objList.each_value do |e|
63
+ if e.respond_to? :check_recover
64
+ e.check_recover
65
+ end
66
+ end
67
+ @finalizer = Hash.new{ |h, k| h[k] = Hash.new }
68
+ at_exit do
69
+ close
70
+ end
71
+ end
72
+ end
73
+ def setFinalizer (name, obj = nil, &bl)
74
+ @finalizer[name][obj] = bl
75
+ end
76
+ def method_missing (name, *args)
77
+ if name.to_s[-1] == ?=
78
+ tmp = name.to_s.chop
79
+ # if @objList[tmp] != nil
80
+ # raise Exception.new("cannot register twice (#{tmp})\n")
81
+ # else
82
+ @objList[tmp] = args[0]
83
+ # end
84
+ else
85
+ @objList[name.to_s]
86
+ end
87
+ end
88
+ def each
89
+ @objList.each do |k, v|
90
+ yield k, v
91
+ end
92
+ end
93
+ def AutoPstore.method_missing (name, *args)
94
+ if !defined?(@@autoPstore) || @@readTemp
95
+ @@autoPstore = AutoPstore.new
96
+ end
97
+ @@autoPstore.method_missing(name, *args)
98
+ end
99
+ def AutoPstore.each
100
+ if !defined? @@autoPstore
101
+ @@autoPstore = AutoPstore.new
102
+ end
103
+ @@autoPstore.each do |k, v|
104
+ yield k, v
105
+ end
106
+ end
107
+ def AutoPstore.setFinalizer (name, target)
108
+ if !defined? @@autoPstore
109
+ @@autoPstore = AutoPstore.new
110
+ end
111
+ @@autoPstore.setFinalizer(name, target)
112
+ end
113
+ def AutoPstore.close
114
+ if defined? @@autoPstore
115
+ @@autoPstore.close
116
+ @@autoPstore = nil
117
+ end
118
+ end
119
+ def AutoPstore.transaction
120
+ if !defined? @@autoPstore
121
+ @@autoPstore = AutoPstore.new
122
+ begin
123
+ yield
124
+ ensure
125
+ close
126
+ end
127
+ else
128
+ raise Exception.new("AutoPstore already opened\n")
129
+ end
130
+ end
131
+ def AutoPstore.setReadOnly
132
+ @@readOnly = true
133
+ self
134
+ end
135
+ def AutoPstore.setFileName f
136
+ @@fileName = f
137
+ self
138
+ end
139
+ def AutoPstore.readTemp
140
+ @@readTemp = true
141
+ self
142
+ end
143
+ def close
144
+ if !@closed
145
+ @closed = true
146
+ if @finalizer
147
+ @finalizer.each do |name, o|
148
+ o.each_value do |prc|
149
+ prc.call @objList[name]
150
+ end
151
+ end
152
+ while !@sleeping
153
+ begin
154
+ @thread.run
155
+ rescue ThreadError
156
+ Thread.pass
157
+ sleep 1
158
+ if !@sleeping
159
+ raise Exception.new("abnormal variable @sleep = #{@sleep} detected at #{__LINE__} in #{__FILE__}.")
160
+ end
161
+ end
162
+ Thread.pass
163
+ sleep 1
164
+ end
165
+ begin
166
+ @thread.run
167
+ rescue ThreadError
168
+ end
169
+ begin
170
+ @thread.join
171
+ rescue ThreadError
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+
179
+
@@ -0,0 +1,120 @@
1
+ #
2
+ # Ruby/Bsearch - a binary search library for Ruby.
3
+ #
4
+ # Copyright (C) 2001 Satoru Takabayashi <satoru@namazu.org>
5
+ # All rights reserved.
6
+ # This is free software with ABSOLUTELY NO WARRANTY.
7
+ #
8
+ # You can redistribute it and/or modify it under the terms of
9
+ # the Ruby's licence.
10
+ #
11
+ # Example:
12
+ #
13
+ # % irb -r ./bsearch.rb
14
+ # >> %w(a b c c c d e f).bsearch_first {|x| x <=> "c"}
15
+ # => 2
16
+ # >> %w(a b c c c d e f).bsearch_last {|x| x <=> "c"}
17
+ # => 4
18
+ # >> %w(a b c e f).bsearch_first {|x| x <=> "c"}
19
+ # => 2
20
+ # >> %w(a b e f).bsearch_first {|x| x <=> "c"}
21
+ # => nil
22
+ # >> %w(a b e f).bsearch_last {|x| x <=> "c"}
23
+ # => nil
24
+ # >> %w(a b e f).bsearch_lower_boundary {|x| x <=> "c"}
25
+ # => 2
26
+ # >> %w(a b e f).bsearch_upper_boundary {|x| x <=> "c"}
27
+ # => 2
28
+ # >> %w(a b c c c d e f).bsearch_range {|x| x <=> "c"}
29
+ # => 2...5
30
+ # >> %w(a b c d e f).bsearch_range {|x| x <=> "c"}
31
+ # => 2...3
32
+ # >> %w(a b d e f).bsearch_range {|x| x <=> "c"}
33
+ # => 2...2
34
+
35
+ module Bsearch
36
+ VERSION = '1.5'
37
+ end
38
+
39
+ class Array
40
+ #
41
+ # The binary search algorithm is extracted from Jon Bentley's
42
+ # Programming Pearls 2nd ed. p.93
43
+ #
44
+
45
+ #
46
+ # Return the lower boundary. (inside)
47
+ #
48
+ def bsearch_lower_boundary (range = 0 ... self.length, &block)
49
+ lower = range.first() -1
50
+ upper = if range.exclude_end? then range.last else range.last + 1 end
51
+ while lower + 1 != upper
52
+ mid = ((lower + upper) / 2).to_i # for working with mathn.rb (Rational)
53
+ if yield(self[mid]) < 0
54
+ lower = mid
55
+ else
56
+ upper = mid
57
+ end
58
+ end
59
+ return upper
60
+ end
61
+
62
+ #
63
+ # This method searches the FIRST occurrence which satisfies a
64
+ # condition given by a block in binary fashion and return the
65
+ # index of the first occurrence. Return nil if not found.
66
+ #
67
+ def bsearch_first (range = 0 ... self.length, &block)
68
+ boundary = bsearch_lower_boundary(range, &block)
69
+ if boundary >= self.length || yield(self[boundary]) != 0
70
+ return nil
71
+ else
72
+ return boundary
73
+ end
74
+ end
75
+
76
+ alias bsearch bsearch_first
77
+
78
+ #
79
+ # Return the upper boundary. (outside)
80
+ #
81
+ def bsearch_upper_boundary (range = 0 ... self.length, &block)
82
+ lower = range.first() -1
83
+ upper = if range.exclude_end? then range.last else range.last + 1 end
84
+ while lower + 1 != upper
85
+ mid = ((lower + upper) / 2).to_i # for working with mathn.rb (Rational)
86
+ if yield(self[mid]) <= 0
87
+ lower = mid
88
+ else
89
+ upper = mid
90
+ end
91
+ end
92
+ return lower + 1 # outside of the matching range.
93
+ end
94
+
95
+ #
96
+ # This method searches the LAST occurrence which satisfies a
97
+ # condition given by a block in binary fashion and return the
98
+ # index of the last occurrence. Return nil if not found.
99
+ #
100
+ def bsearch_last (range = 0 ... self.length, &block)
101
+ # `- 1' for canceling `lower + 1' in bsearch_upper_boundary.
102
+ boundary = bsearch_upper_boundary(range, &block) - 1
103
+
104
+ if (boundary <= -1 || yield(self[boundary]) != 0)
105
+ return nil
106
+ else
107
+ return boundary
108
+ end
109
+ end
110
+
111
+ #
112
+ # Return the search result as a Range object.
113
+ #
114
+ def bsearch_range (range = 0 ... self.length, &block)
115
+ lower = bsearch_lower_boundary(range, &block)
116
+ upper = bsearch_upper_boundary(range, &block)
117
+ return lower ... upper
118
+ end
119
+ end
120
+