1# 2# tk/variable.rb : treat Tk variable object 3# 4require 'tk' 5 6class TkVariable 7 include Tk 8 extend TkCore 9 10 include Comparable 11 12 #TkCommandNames = ['tkwait'.freeze].freeze 13 TkCommandNames = ['vwait'.freeze].freeze 14 15 #TkVar_CB_TBL = {} 16 #TkVar_ID_TBL = {} 17 TkVar_CB_TBL = TkCore::INTERP.create_table 18 TkVar_ID_TBL = TkCore::INTERP.create_table 19 (Tk_VARIABLE_ID = ["v".freeze, TkUtil.untrust("00000")]).instance_eval{ 20 @mutex = Mutex.new 21 def mutex; @mutex; end 22 freeze 23 } 24 TkCore::INTERP.init_ip_env{ 25 TkVar_CB_TBL.mutex.synchronize{ TkVar_CB_TBL.clear } 26 TkVar_ID_TBL.mutex.synchronize{ TkVar_ID_TBL.clear } 27 } 28 29 major, minor, type, patchlevel = TclTkLib.get_version 30 USE_OLD_TRACE_OPTION_STYLE = (major < 8) || (major == 8 && minor < 4) 31 32 #TkCore::INTERP.add_tk_procs('rb_var', 'args', 33 # "ruby [format \"TkVariable.callback %%Q!%s!\" $args]") 34 TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL') 35 if {[set st [catch {eval {ruby_cmd TkVariable callback} $args} ret]] != 0} { 36 set idx [string first "\n\n" $ret] 37 if {$idx > 0} { 38 global errorInfo 39 set tcl_backtrace $errorInfo 40 set errorInfo [string range $ret [expr $idx + 2] \ 41 [string length $ret]] 42 append errorInfo "\n" $tcl_backtrace 43 bgerror [string range $ret 0 [expr $idx - 1]] 44 } else { 45 bgerror $ret 46 } 47 return "" 48 #return -code $st $ret 49 } else { 50 return $ret 51 } 52 EOL 53 54 #def TkVariable.callback(args) 55 def TkVariable.callback(id, name1, name2, op) 56 #name1,name2,op = tk_split_list(args) 57 #name1,name2,op = tk_split_simplelist(args) 58 if cb_obj = TkVar_CB_TBL[id] 59 #_get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op)) 60 begin 61 _get_eval_string(cb_obj.trace_callback(name2, op)) 62 rescue SystemExit 63 exit(0) 64 rescue Interrupt 65 exit!(1) 66 rescue Exception => e 67 begin 68 msg = _toUTF8(e.class.inspect) + ': ' + 69 _toUTF8(e.message) + "\n" + 70 "\n---< backtrace of Ruby side >-----\n" + 71 _toUTF8(e.backtrace.join("\n")) + 72 "\n---< backtrace of Tk side >-------" 73 if TkCore::WITH_ENCODING 74 msg.force_encoding('utf-8') 75 else 76 msg.instance_variable_set(:@encoding, 'utf-8') 77 end 78 rescue Exception 79 msg = e.class.inspect + ': ' + e.message + "\n" + 80 "\n---< backtrace of Ruby side >-----\n" + 81 e.backtrace.join("\n") + 82 "\n---< backtrace of Tk side >-------" 83 end 84 fail(e, msg) 85 end 86=begin 87 begin 88 raise 'check backtrace' 89 rescue 90 # ignore backtrace before 'callback' 91 pos = -($!.backtrace.size) 92 end 93 begin 94 _get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op)) 95 rescue 96 trace = $!.backtrace 97 raise $!, "\n#{trace[0]}: #{$!.message} (#{$!.class})\n" + 98 "\tfrom #{trace[1..pos].join("\n\tfrom ")}" 99 end 100=end 101 else 102 '' 103 end 104 end 105 106 def self.new_hash(val = {}) 107 if val.kind_of?(Hash) 108 self.new(val) 109 else 110 fail ArgumentError, 'Hash is expected' 111 end 112 end 113 114 # 115 # default_value is available only when the variable is an assoc array. 116 # 117 def default_value(val=nil, &b) 118 if b 119 @def_default = :proc 120 @default_val = proc(&b) 121 else 122 @def_default = :val 123 @default_val = val 124 end 125 self 126 end 127 def set_default_value(val) 128 @def_default = :val 129 @default_val = val 130 self 131 end 132 alias default_value= set_default_value 133 def default_proc(cmd = Proc.new) 134 @def_default = :proc 135 @default_val = cmd 136 self 137 end 138 139 def undef_default 140 @default_val = nil 141 @def_default = false 142 self 143 end 144 145 def default_value_type 146 @type 147 end 148 def default_element_value_type(idxs) 149 if idxs.kind_of?(Array) 150 index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',') 151 else 152 index = _get_eval_string(idxs, true) 153 end 154 @element_type[index] 155 end 156 157 def _set_default_value_type_core(type, idxs) 158 if type.kind_of?(Class) 159 if type == NilClass 160 type = nil 161 elsif type == Numeric 162 type = :numeric 163 elsif type == TrueClass || type == FalseClass 164 type = :bool 165 elsif type == String 166 type = :string 167 elsif type == Symbol 168 type = :symbol 169 elsif type == Array 170 type = :list 171 elsif type <= TkVariable 172 type = :variable 173 elsif type <= TkWindow 174 type = :window 175 elsif TkComm._callback_entry_class?(type) 176 type = :procedure 177 else 178 type = nil 179 end 180 else 181 case(type) 182 when nil 183 type = nil 184 when :numeric, 'numeric' 185 type = :numeric 186 when true, false, :bool, 'bool' 187 type = :bool 188 when :string, 'string' 189 type = :string 190 when :symbol, 'symbol' 191 type = :symbol 192 when :list, 'list' 193 type = :list 194 when :numlist, 'numlist' 195 type = :numlist 196 when :variable, 'variable' 197 type = :variable 198 when :window, 'window' 199 type = :window 200 when :procedure, 'procedure' 201 type = :procedure 202 else 203 return _set_default_value_type_core(type.class, idxs) 204 end 205 end 206 if idxs 207 if idxs.kind_of?(Array) 208 index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',') 209 else 210 index = _get_eval_string(idxs, true) 211 end 212 @element_type[index] = type 213 else 214 @type = type 215 end 216 type 217 end 218 private :_set_default_value_type_core 219 220 def set_default_value_type(type) 221 _set_default_value_type_core(type, nil) 222 self 223 end 224 alias default_value_type= set_default_value_type 225 226 def set_default_element_value_type(idxs, type) 227 _set_default_value_type_core(type, idxs) 228 self 229 end 230 231 def _to_default_type(val, idxs = nil) 232 if idxs 233 if idxs.kind_of?(Array) 234 index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',') 235 else 236 index = _get_eval_string(idxs, true) 237 end 238 type = @element_type[index] 239 else 240 type = @type 241 end 242 return val unless type 243 if val.kind_of?(Hash) 244 val.keys.each{|k| val[k] = _to_default_type(val[k], idxs) } 245 val 246 else 247 begin 248 case(type) 249 when :numeric 250 number(val) 251 when :bool 252 TkComm.bool(val) 253 when :string 254 val 255 when :symbol 256 val.intern 257 when :list 258 tk_split_simplelist(val) 259 when :numlist 260 tk_split_simplelist(val).collect!{|v| number(v)} 261 when :variable 262 TkVarAccess.new(val) 263 when :window 264 TkComm.window(val) 265 when :procedure 266 TkComm.procedure(val) 267 else 268 val 269 end 270 rescue 271 val 272 end 273 end 274 end 275 private :_to_default_type 276 277 def _to_default_element_type(idxs, val) 278 _to_default_type(val, idxs) 279 end 280 private :_to_default_element_type 281 282 def initialize(val="", type=nil) 283 # @id = Tk_VARIABLE_ID.join('') 284 begin 285 Tk_VARIABLE_ID.mutex.synchronize{ 286 @id = Tk_VARIABLE_ID.join(TkCore::INTERP._ip_id_) 287 Tk_VARIABLE_ID[1].succ! 288 } 289 end until INTERP._invoke_without_enc('info', 'globals', @id).empty? 290 291 TkVar_ID_TBL.mutex.synchronize{ 292 TkVar_ID_TBL[@id] = self 293 } 294 295 @var = @id 296 @elem = nil 297 298 @def_default = false 299 @default_val = nil 300 301 @trace_var = nil 302 @trace_elem = nil 303 @trace_opts = nil 304 305 @type = nil 306 var = self 307 @element_type = Hash.new{|k,v| var.default_value_type } 308 309 self.default_value_type = type 310 311 # teach Tk-ip that @id is global var 312 INTERP._invoke_without_enc('global', @id) 313 #INTERP._invoke('global', @id) 314 315 # create and init 316 if val.kind_of?(Hash) 317 # assoc-array variable 318 self[''] = 0 319 self.clear 320 end 321 self.value = val 322 323=begin 324 if val == [] 325 # INTERP._eval(format('global %s; set %s(0) 0; unset %s(0)', 326 # @id, @id, @id)) 327 elsif val.kind_of?(Array) 328 a = [] 329 # val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))} 330 # s = '"' + a.join(" ").gsub(/[\[\]$"]/, '\\\\\&') + '"' 331 val.each_with_index{|e,i| a.push(i); a.push(e)} 332 #s = '"' + array2tk_list(a).gsub(/[\[\]$"]/, '\\\\\&') + '"' 333 s = '"' + array2tk_list(a).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' 334 INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) 335 elsif val.kind_of?(Hash) 336 #s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ 337 # .gsub(/[\[\]$"]/, '\\\\\&') + '"' 338 s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ 339 .gsub(/[\[\]$"\\]/, '\\\\\&') + '"' 340 INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) 341 else 342 #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' 343 s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' 344 INTERP._eval(format('global %s; set %s %s', @id, @id, s)) 345 end 346=end 347=begin 348 if val.kind_of?(Hash) 349 #s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ 350 # .gsub(/[\[\]$"]/, '\\\\\&') + '"' 351 s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ 352 .gsub(/[\[\]$"\\]/, '\\\\\&') + '"' 353 INTERP._eval(Kernel.format('global %s; array set %s %s', @id, @id, s)) 354 else 355 #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' 356 s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' 357 INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) 358 end 359=end 360 end 361 362 def wait(on_thread = false, check_root = false) 363 if $SAFE >= 4 364 fail SecurityError, "can't wait variable at $SAFE >= 4" 365 end 366 on_thread &= (Thread.list.size != 1) 367 if on_thread 368 if check_root 369 INTERP._thread_tkwait('variable', @id) 370 else 371 INTERP._thread_vwait(@id) 372 end 373 else 374 if check_root 375 INTERP._invoke_without_enc('tkwait', 'variable', @id) 376 else 377 INTERP._invoke_without_enc('vwait', @id) 378 end 379 end 380 end 381 def eventloop_wait(check_root = false) 382 wait(false, check_root) 383 end 384 def thread_wait(check_root = false) 385 wait(true, check_root) 386 end 387 def tkwait(on_thread = true) 388 wait(on_thread, true) 389 end 390 def eventloop_tkwait 391 wait(false, true) 392 end 393 def thread_tkwait 394 wait(true, true) 395 end 396 397 def id 398 @id 399 end 400 401 def ref(*idxs) 402 # "#{@id}(#{idxs.collect{|idx| _get_eval_string(idx)}.join(',')})" 403 TkVarAccess.new("#{@id}(#{idxs.collect{|idx| _get_eval_string(idx)}.join(',')})") 404 end 405 406 def is_hash? 407 #ITNERP._eval("global #{@id}; array exist #{@id}") == '1' 408 INTERP._invoke_without_enc('global', @id) 409 # INTERP._invoke_without_enc('array', 'exist', @id) == '1' 410 TkComm.bool(INTERP._invoke_without_enc('array', 'exist', @id)) 411 end 412 413 def is_scalar? 414 ! is_hash? 415 end 416 417 def exist?(*elems) 418 INTERP._invoke_without_enc('global', @id) 419 if elems.empty? 420 TkComm.bool(tk_call('info', 'exist', @id)) 421 else 422 # array 423 index = elems.collect{|idx| _get_eval_string(idx, true)}.join(',') 424 TkComm.bool(tk_call('info', 'exist', "#{@id}")) && 425 TkComm.bool(tk_call('info', 'exist', "#{@id}(#{index})")) 426 end 427 end 428 429 def keys 430 if (is_scalar?) 431 fail RuntimeError, 'cannot get keys from a scalar variable' 432 end 433 #tk_split_simplelist(INTERP._eval("global #{@id}; array get #{@id}")) 434 INTERP._invoke_without_enc('global', @id) 435 #tk_split_simplelist(INTERP._fromUTF8(INTERP._invoke_without_enc('array', 'names', @id))) 436 tk_split_simplelist(INTERP._invoke_without_enc('array', 'names', @id), 437 false, true) 438 end 439 440 def size 441 INTERP._invoke_without_enc('global', @id) 442 TkComm.number(INTERP._invoke_without_enc('array', 'size', @id)) 443 end 444 445 def clear 446 if (is_scalar?) 447 fail RuntimeError, 'cannot clear a scalar variable' 448 end 449 keys.each{|k| unset(k)} 450 self 451 end 452 453 def update(hash) 454 if (is_scalar?) 455 fail RuntimeError, 'cannot update a scalar variable' 456 end 457 hash.each{|k,v| self[k] = v} 458 self 459 end 460 461unless const_defined?(:USE_TCLs_SET_VARIABLE_FUNCTIONS) 462 USE_TCLs_SET_VARIABLE_FUNCTIONS = true 463end 464 465if USE_TCLs_SET_VARIABLE_FUNCTIONS 466 ########################################################################### 467 # use Tcl function version of set tkvariable 468 ########################################################################### 469 470 def _value 471 #if INTERP._eval("global #{@id}; array exist #{@id}") == '1' 472 INTERP._invoke_without_enc('global', @id) 473 # if INTERP._invoke('array', 'exist', @id) == '1' 474 if TkComm.bool(INTERP._invoke('array', 'exist', @id)) 475 #Hash[*tk_split_simplelist(INTERP._eval("global #{@id}; array get #{@id}"))] 476 Hash[*tk_split_simplelist(INTERP._invoke('array', 'get', @id))] 477 else 478 _fromUTF8(INTERP._get_global_var(@id)) 479 end 480 end 481 482 def value=(val) 483 val = val._value if !@type && @type != :variable && val.kind_of?(TkVariable) 484 if val.kind_of?(Hash) 485 self.clear 486 val.each{|k, v| 487 #INTERP._set_global_var2(@id, _toUTF8(_get_eval_string(k)), 488 # _toUTF8(_get_eval_string(v))) 489 INTERP._set_global_var2(@id, _get_eval_string(k, true), 490 _get_eval_string(v, true)) 491 } 492 self.value 493# elsif val.kind_of?(Array) 494=begin 495 INTERP._set_global_var(@id, '') 496 val.each{|v| 497 #INTERP._set_variable(@id, _toUTF8(_get_eval_string(v)), 498 INTERP._set_variable(@id, _get_eval_string(v, true), 499 TclTkLib::VarAccessFlag::GLOBAL_ONLY | 500 TclTkLib::VarAccessFlag::LEAVE_ERR_MSG | 501 TclTkLib::VarAccessFlag::APPEND_VALUE | 502 TclTkLib::VarAccessFlag::LIST_ELEMENT) 503 } 504 self.value 505=end 506# _fromUTF8(INTERP._set_global_var(@id, array2tk_list(val, true))) 507 else 508 #_fromUTF8(INTERP._set_global_var(@id, _toUTF8(_get_eval_string(val)))) 509 _fromUTF8(INTERP._set_global_var(@id, _get_eval_string(val, true))) 510 end 511 end 512 513 def _element_value(*idxs) 514 index = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',') 515 begin 516 _fromUTF8(INTERP._get_global_var2(@id, index)) 517 rescue => e 518 case @def_default 519 when :proc 520 @default_val.call(self, *idxs) 521 when :val 522 @default_val 523 else 524 fail e 525 end 526 end 527 #_fromUTF8(INTERP._get_global_var2(@id, index)) 528 #_fromUTF8(INTERP._get_global_var2(@id, _toUTF8(_get_eval_string(index)))) 529 #_fromUTF8(INTERP._get_global_var2(@id, _get_eval_string(index, true))) 530 end 531 532 def []=(*args) 533 val = args.pop 534 type = default_element_value_type(args) 535 val = val._value if !type && type != :variable && val.kind_of?(TkVariable) 536 index = args.collect{|idx| _get_eval_string(idx, true)}.join(',') 537 _fromUTF8(INTERP._set_global_var2(@id, index, _get_eval_string(val, true))) 538 #_fromUTF8(INTERP._set_global_var2(@id, _toUTF8(_get_eval_string(index)), 539 # _toUTF8(_get_eval_string(val)))) 540 #_fromUTF8(INTERP._set_global_var2(@id, _get_eval_string(index, true), 541 # _get_eval_string(val, true))) 542 end 543 544 def unset(*elems) 545 if elems.empty? 546 INTERP._unset_global_var(@id) 547 else 548 index = elems.collect{|idx| _get_eval_string(idx, true)}.join(',') 549 INTERP._unset_global_var2(@id, index) 550 end 551 end 552 alias remove unset 553 554else 555 ########################################################################### 556 # use Ruby script version of set tkvariable (traditional methods) 557 ########################################################################### 558 559 def _value 560 begin 561 INTERP._eval(Kernel.format('global %s; set %s', @id, @id)) 562 #INTERP._eval(Kernel.format('set %s', @id)) 563 #INTERP._invoke_without_enc('set', @id) 564 rescue 565 if INTERP._eval(Kernel.format('global %s; array exists %s', 566 @id, @id)) != "1" 567 #if INTERP._eval(Kernel.format('array exists %s', @id)) != "1" 568 #if INTERP._invoke_without_enc('array', 'exists', @id) != "1" 569 fail 570 else 571 Hash[*tk_split_simplelist(INTERP._eval(Kernel.format('global %s; array get %s', @id, @id)))] 572 #Hash[*tk_split_simplelist(_fromUTF8(INTERP._invoke_without_enc('array', 'get', @id)))] 573 end 574 end 575 end 576 577 def value=(val) 578 val = val._value if !@type && @type != :variable && val.kind_of?(TkVariable) 579 begin 580 #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' 581 s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' 582 INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) 583 #INTERP._eval(Kernel.format('set %s %s', @id, s)) 584 #_fromUTF8(INTERP._invoke_without_enc('set', @id, _toUTF8(s))) 585 rescue 586 if INTERP._eval(Kernel.format('global %s; array exists %s', 587 @id, @id)) != "1" 588 #if INTERP._eval(Kernel.format('array exists %s', @id)) != "1" 589 #if INTERP._invoke_without_enc('array', 'exists', @id) != "1" 590 fail 591 else 592 if val == [] 593 INTERP._eval(Kernel.format('global %s; unset %s; set %s(0) 0; unset %s(0)', @id, @id, @id, @id)) 594 #INTERP._eval(Kernel.format('unset %s; set %s(0) 0; unset %s(0)', 595 # @id, @id, @id)) 596 #INTERP._invoke_without_enc('unset', @id) 597 #INTERP._invoke_without_enc('set', @id+'(0)', 0) 598 #INTERP._invoke_without_enc('unset', @id+'(0)') 599 elsif val.kind_of?(Array) 600 a = [] 601 val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e, true))} 602 #s = '"' + a.join(" ").gsub(/[\[\]$"]/, '\\\\\&') + '"' 603 s = '"' + a.join(" ").gsub(/[\[\]$"\\]/, '\\\\\&') + '"' 604 INTERP._eval(Kernel.format('global %s; unset %s; array set %s %s', 605 @id, @id, @id, s)) 606 #INTERP._eval(Kernel.format('unset %s; array set %s %s', 607 # @id, @id, s)) 608 #INTERP._invoke_without_enc('unset', @id) 609 #_fromUTF8(INTERP._invoke_without_enc('array','set', @id, _toUTF8(s))) 610 elsif val.kind_of?(Hash) 611 #s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ 612 # .gsub(/[\[\]$"]/, '\\\\\&') + '"' 613 s = '"' + val.to_a.collect{|e| array2tk_list(e, true)}.join(" ")\ 614 .gsub(/[\[\]$\\"]/, '\\\\\&') + '"' 615 INTERP._eval(Kernel.format('global %s; unset %s; array set %s %s', 616 @id, @id, @id, s)) 617 #INTERP._eval(Kernel.format('unset %s; array set %s %s', 618 # @id, @id, s)) 619 #INTERP._invoke_without_enc('unset', @id) 620 #_fromUTF8(INTERP._invoke_without_enc('array','set', @id, _toUTF8(s))) 621 else 622 fail 623 end 624 end 625 end 626 end 627 628 def _element_value(*idxs) 629 index = idxs.collect{|idx| _get_eval_string(idx)}.join(',') 630 begin 631 INTERP._eval(Kernel.format('global %s; set %s(%s)', @id, @id, index)) 632 rescue => e 633 case @def_default 634 when :proc 635 @default_val.call(self, *idxs) 636 when :val 637 @default_val 638 else 639 fail e 640 end 641 end 642 #INTERP._eval(Kernel.format('global %s; set %s(%s)', @id, @id, index)) 643 #INTERP._eval(Kernel.format('global %s; set %s(%s)', 644 # @id, @id, _get_eval_string(index))) 645 #INTERP._eval(Kernel.format('set %s(%s)', @id, _get_eval_string(index))) 646 #INTERP._eval('set ' + @id + '(' + _get_eval_string(index) + ')') 647 end 648 649 def []=(*args) 650 val = args.pop 651 type = default_element_value_type(args) 652 val = val._value if !type && type != :variable && val.kind_of?(TkVariable) 653 index = args.collect{|idx| _get_eval_string(idx)}.join(',') 654 INTERP._eval(Kernel.format('global %s; set %s(%s) %s', @id, @id, 655 index, _get_eval_string(val))) 656 #INTERP._eval(Kernel.format('global %s; set %s(%s) %s', @id, @id, 657 # _get_eval_string(index), _get_eval_string(val))) 658 #INTERP._eval(Kernel.format('set %s(%s) %s', @id, 659 # _get_eval_string(index), _get_eval_string(val))) 660 #INTERP._eval('set ' + @id + '(' + _get_eval_string(index) + ') ' + 661 # _get_eval_string(val)) 662 end 663 664 def unset(*elems) 665 if elems.empty? 666 INTERP._eval(Kernel.format('global %s; unset %s', @id, @id)) 667 #INTERP._eval(Kernel.format('unset %s', @id)) 668 #INTERP._eval('unset ' + @id) 669 else 670 index = elems.collect{|idx| _get_eval_string(idx, true)}.join(',') 671 INTERP._eval(Kernel.format('global %s; unset %s(%s)', @id, @id, index)) 672 #INTERP._eval(Kernel.format('global %s; unset %s(%s)', 673 # @id, @id, _get_eval_string(elem))) 674 #INTERP._eval(Kernel.format('unset %s(%s)', @id, tk_tcl2ruby(elem))) 675 #INTERP._eval('unset ' + @id + '(' + _get_eval_string(elem) + ')') 676 end 677 end 678 alias remove unset 679 680end 681 682 protected :_value, :_element_value 683 684 def value 685 _to_default_type(_value) 686 end 687 688 def [](*idxs) 689 _to_default_element_type(idxs, _element_value(*idxs)) 690 end 691 692 def set_value(val) 693 self.value = val 694 self 695 end 696 697 def to_hash 698 hash = {} 699 self.keys.each{|k| 700 hash[k] = self[k] 701 } 702 hash 703 end 704 705 def set_element_value(idxs, val) 706 if idxs.kind_of?(Array) 707 self[*idxs]=val 708 else 709 self[idxs]=val 710 end 711 self 712 end 713 714 def set_value_type(val) 715 self.default_value_type = val.class 716 self.value = val 717 self 718 end 719 720 alias value_type= set_value_type 721 722 def set_element_value_type(idxs, val) 723 self.set_default_element_value_type(idxs, val.class) 724 if idxs.kind_of?(Array) 725 self[*idxs]=val 726 else 727 self[idxs]=val 728 end 729 self 730 end 731 732 def numeric 733 number(_value) 734 end 735 def numeric_element(*idxs) 736 number(_element_value(*idxs)) 737 end 738 def set_numeric(val) 739 case val 740 when Numeric 741 self.value=(val) 742 when TkVariable 743 self.value=(val.numeric) 744 else 745 raise ArgumentError, "Numeric is expected" 746 end 747 self 748 end 749 alias numeric= set_numeric 750 def set_numeric_element(idxs, val) 751 case val 752 when Numeric 753 val 754 when TkVariable 755 val = val.numeric 756 else 757 raise ArgumentError, "Numeric is expected" 758 end 759 if idxs.kind_of?(Array) 760 self[*idxs]=val 761 else 762 self[idxs]=val 763 end 764 self 765 end 766 def set_numeric_type(val) 767 @type = :numeric 768 self.numeric=(val) 769 self 770 end 771 alias numeric_type= set_numeric_type 772 def set_numeric_element_type(idxs, val) 773 self.set_default_element_value_type(idxs, :numeric) 774 self.set_numeric_element(idxs, val) 775 end 776 777 def bool 778 TkComm.bool(_value) 779=begin 780 # see Tcl_GetBoolean man-page 781 case _value.downcase 782 when '0', 'false', 'no', 'off' 783 false 784 else 785 true 786 end 787=end 788 end 789 def bool_element(*idxs) 790 TkComm.bool(_element_value(*idxs)) 791 end 792 def set_bool(val) 793 if ! val 794 self.value = '0' 795 else 796 case val.to_s.downcase 797 when 'false', '0', 'no', 'off' 798 self.value = '0' 799 else 800 self.value = '1' 801 end 802 end 803 self 804 end 805 alias bool= set_bool 806 def set_bool_element(idxs, val) 807 if ! val 808 val = '0' 809 else 810 case val.to_s.downcase 811 when 'false', '0', 'no', 'off' 812 val = '0' 813 else 814 val = '1' 815 end 816 end 817 if idxs.kind_of?(Array) 818 self[*idxs]=val 819 else 820 self[idxs]=val 821 end 822 self 823 end 824 def set_bool_type(val) 825 @type = :bool 826 self.bool=(val) 827 self 828 end 829 alias bool_type= set_bool_type 830 def set_bool_element_type(idxs, val) 831 self.set_default_element_value_type(idxs, :bool) 832 self.set_bool_element(idxs, val) 833 end 834 835 def variable 836 # keeps a Tcl's variable name 837 TkVarAccess.new(self._value) 838 end 839 def variable_element(*idxs) 840 TkVarAccess.new(_element_value(*idxs)) 841 end 842 def set_variable(var) 843 var = var.id if var.kind_of?(TkVariable) 844 self.value = var 845 self 846 end 847 alias variable= set_variable 848 def set_variable_element(idxs, var) 849 var = var.id if var.kind_of?(TkVariable) 850 if idxs.kind_of?(Array) 851 self[*idxs]=var 852 else 853 self[idxs]=var 854 end 855 self 856 end 857 def set_variable_type(var) 858 @type = :variable 859 var = var.id if var.kind_of?(TkVariable) 860 self.value = var 861 self 862 end 863 alias variable_type= set_variable_type 864 def set_variable_element_type(idxs, var) 865 self.set_default_element_value_type(idxs, :variable) 866 self.set_variable_element(idxs, var) 867 end 868 869 def window 870 TkComm.window(self._value) 871 end 872 def window_element(*idxs) 873 TkComm.window(_element_value(*idxs)) 874 end 875 def set_window(win) 876 win = win._value if win.kind_of?(TkVariable) 877 self.value = win 878 self 879 end 880 alias window= set_window 881 def set_window_element(idxs, win) 882 win = win._value if win.kind_of?(TkVariable) 883 if idxs.kind_of?(Array) 884 self[*idxs]=win 885 else 886 self[idxs]=win 887 end 888 self 889 end 890 def set_window_type(win) 891 @type = :window 892 self.window=(win) 893 self 894 end 895 alias window_type= set_window_type 896 def set_window_element_type(idxs, win) 897 self.set_default_element_value_type(idxs, :window) 898 self.set_window_element(idxs, win) 899 end 900 901 def procedure 902 TkComm.procedure(self._value) 903 end 904 def procedure_element(*idxs) 905 TkComm.procedure(_element_value(*idxs)) 906 end 907 def set_procedure(cmd) 908 self.value = cmd 909 self 910 end 911 alias procedure= set_procedure 912 def set_procedure_element(idxs, cmd) 913 cmd = cmd._value if cmd.kind_of?(TkVariable) 914 if idxs.kind_of?(Array) 915 self[*idxs]=cmd 916 else 917 self[idxs]=cmd 918 end 919 self 920 end 921 def set_procedure_type(cmd) 922 @type = :procedure 923 self.procedure=(cmd) 924 self 925 end 926 alias procedure_type= set_procedure_type 927 def set_procedure_element_type(idxs, cmd) 928 self.set_default_element_value_type(idxs, :procedure) 929 self.set_proceure_element(idxs, cmd) 930 end 931 932 def to_proc 933 cmd = self.procedure 934 if cmd.respond_to?(:call) 935 cmd 936 else 937 # cmd is a String 938 cmd.to_sym.to_proc 939 end 940 end 941 942 def to_i 943 number(_value).to_i 944 end 945 alias to_int to_i 946 def element_to_i(*idxs) 947 number(_element_value(*idxs)).to_i 948 end 949 950 def to_f 951 number(_value).to_f 952 end 953 def element_to_f(*idxs) 954 number(_element_value(*idxs)).to_f 955 end 956 957 def to_s 958 #string(value).to_s 959 _value 960 end 961 alias string to_s 962 alias to_str to_s 963 def element_to_s(*idxs) 964 _element_value(*idxs) 965 end 966 def string_element(*idxs) 967 _element_value(*idxs) 968 end 969 def set_string(val) 970 val = val._value if val.kind_of?(TkVariable) 971 self.value=val 972 self 973 end 974 alias string= set_string 975 def set_string_element(idxs, val) 976 val = val._value if val.kind_of?(TkVariable) 977 if idxs.kind_of?(Array) 978 self[*idxs]=val 979 else 980 self[idxs]=val 981 end 982 self 983 end 984 def set_string_type(val) 985 @type = :string 986 self.string=(val) 987 self 988 end 989 alias string_type= set_string_type 990 def set_string_element_type(idxs, val) 991 self.set_default_element_value_type(idxs, :string) 992 self.set_string_element(idxs, val) 993 end 994 995 def to_sym 996 _value.intern 997 end 998 alias symbol to_sym 999 def element_to_sym(*idxs) 1000 _element_value(*idxs).intern 1001 end 1002 alias symbol_element element_to_sym 1003 def set_symbol(val) 1004 val = val._value if val.kind_of?(TkVariable) 1005 self.value=val 1006 self 1007 end 1008 alias symbol= set_symbol 1009 def set_symbol_element(idxs, val) 1010 val = val._value if val.kind_of?(TkVariable) 1011 if idxs.kind_of?(Array) 1012 self[*idxs]=val 1013 else 1014 self[idxs]=val 1015 end 1016 self 1017 end 1018 def set_symbol_type(val) 1019 @type = :symbol 1020 self.value=(val) 1021 self 1022 end 1023 alias symbol_type= set_symbol_type 1024 def set_symbol_element_type(idxs, val) 1025 self.set_default_element_value_type(idxs, :symbol) 1026 self.set_symbol_element(idxs, val) 1027 end 1028 1029 def list 1030 #tk_split_list(value) 1031 tk_split_simplelist(_value) 1032 end 1033 alias to_a list 1034 alias to_ary list 1035 def list_element(*idxs) 1036 tk_split_simplelist(_element_value(*idxs)) 1037 end 1038 alias element_to_a list_element 1039 1040 def numlist 1041 list.collect!{|val| number(val)} 1042 end 1043 def numlist_element(*idxs) 1044 list_element(*idxs).collect!{|val| number(val)} 1045 end 1046 1047 def set_list(val) 1048 case val 1049 when Array 1050 self.value=(val) 1051 when TkVariable 1052 self.value=(val.list) 1053 else 1054 raise ArgumentError, "Array is expected" 1055 end 1056 self 1057 end 1058 alias list= set_list 1059 1060 alias set_numlist set_list 1061 alias numlist= set_numlist 1062 1063 def set_list_element(idxs, val) 1064 case val 1065 when Array 1066 val 1067 when TkVariable 1068 val = val.list 1069 else 1070 raise ArgumentError, "Array is expected" 1071 end 1072 if idxs.kind_of?(Array) 1073 self[*idxs]=val 1074 else 1075 self[idxs]=val 1076 end 1077 self 1078 end 1079 alias set_numlist_element set_list_element 1080 1081 def set_list_type(val) 1082 @type = :list 1083 self.list=(val) 1084 self 1085 end 1086 alias list_type= set_list_type 1087 def set_list_element_type(idxs, val) 1088 self.set_default_element_value_type(idxs, :list) 1089 self.set_list_element(idxs, val) 1090 end 1091 def set_numlist_type(val) 1092 @type = :numlist 1093 self.numlist=(val) 1094 self 1095 end 1096 alias numlist_type= set_numlist_type 1097 def set_numlist_element_type(idxs, val) 1098 self.set_default_element_value_type(idxs, :numlist) 1099 self.set_numlist_element(idxs, val) 1100 end 1101 1102 def lappend(*elems) 1103 tk_call('lappend', @id, *elems) 1104 self 1105 end 1106 def element_lappend(idxs, *elems) 1107 if idxs.kind_of?(Array) 1108 idxs = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',') 1109 end 1110 tk_call('lappend', "#{@id}(#{idxs})", *elems) 1111 self 1112 end 1113 1114 def lindex(idx) 1115 tk_call('lindex', self._value, idx) 1116 end 1117 alias lget lindex 1118 def element_lindex(elem_idxs, idx) 1119 if elem_idxs.kind_of?(Array) 1120 val = _element_value(*elem_idxs) 1121 else 1122 val = _element_value(elem_idxs) 1123 end 1124 tk_call('lindex', val, idx) 1125 end 1126 alias element_lget element_lindex 1127 1128 def lget_i(idx) 1129 number(lget(idx)).to_i 1130 end 1131 def element_lget_i(elem_idxs, idx) 1132 number(element_lget(elem_idxs, idx)).to_i 1133 end 1134 1135 def lget_f(idx) 1136 number(lget(idx)).to_f 1137 end 1138 def element_lget_f(elem_idxs, idx) 1139 number(element_lget(elem_idxs, idx)).to_f 1140 end 1141 1142 def lset(idx, val) 1143 tk_call('lset', @id, idx, val) 1144 self 1145 end 1146 def element_lset(elem_idxs, idx, val) 1147 if elem_idxs.kind_of?(Array) 1148 idxs = elem_idxs.collect{|i| _get_eval_string(i, true)}.join(',') 1149 end 1150 tk_call('lset', "#{@id}(#{idxs})", idx, val) 1151 self 1152 end 1153 1154 def inspect 1155 #Kernel.format "#<TkVariable: %s>", @id 1156 '#<TkVariable: ' + @id + '>' 1157 end 1158 1159 def coerce(other) 1160 case other 1161 when TkVariable 1162 [other._value, self._value] 1163 when String 1164 [other, self.to_s] 1165 when Symbol 1166 [other, self.to_sym] 1167 when Numeric 1168 [other, self.numeric] 1169 when Array 1170 [other, self.to_a] 1171 else 1172 [other, self._value] 1173 end 1174 end 1175 1176 def +@ 1177 self.numeric 1178 end 1179 def -@ 1180 -(self.numeric) 1181 end 1182 1183 def &(other) 1184 if other.kind_of?(Array) 1185 self.to_a & other.to_a 1186 else 1187 self.to_i & other.to_i 1188 end 1189 end 1190 def |(other) 1191 if other.kind_of?(Array) 1192 self.to_a | other.to_a 1193 else 1194 self.to_i | other.to_i 1195 end 1196 end 1197 def +(other) 1198 case other 1199 when Array 1200 self.to_a + other 1201 when String 1202 self._value + other 1203 else 1204 begin 1205 number(self._value) + other 1206 rescue 1207 self._value + other.to_s 1208 end 1209 end 1210 end 1211 def -(other) 1212 if other.kind_of?(Array) 1213 self.to_a - other 1214 else 1215 number(self._value) - other 1216 end 1217 end 1218 def *(other) 1219 num_or_str(self._value) * other 1220 #begin 1221 # number(self._value) * other 1222 #rescue 1223 # self._value * other 1224 #end 1225 end 1226 def /(other) 1227 number(self._value) / other 1228 end 1229 def %(other) 1230 num_or_str(self._value) % other 1231 #begin 1232 # number(self._value) % other 1233 #rescue 1234 # self._value % other 1235 #end 1236 end 1237 def **(other) 1238 number(self._value) ** other 1239 end 1240 def =~(other) 1241 self._value =~ other 1242 end 1243 1244 def ==(other) 1245 case other 1246 when TkVariable 1247 #self.equal?(other) 1248 self._value == other._value 1249 when String 1250 self.to_s == other 1251 when Symbol 1252 self.to_sym == other 1253 when Integer 1254 self.to_i == other 1255 when Float 1256 self.to_f == other 1257 when Array 1258 self.to_a == other 1259 when Hash 1260 # false if self is not an assoc array 1261 self._value == other 1262 else 1263 # false 1264 self._value == _get_eval_string(other) 1265 end 1266 end 1267 1268 def ===(other) 1269 if other.kind_of?(TkVariable) 1270 self.id == other.id 1271 else 1272 super 1273 end 1274 end 1275 1276 def zero? 1277 numeric.zero? 1278 end 1279 def nonzero? 1280 !(numeric.zero?) 1281 end 1282 1283 def <=>(other) 1284 if other.kind_of?(TkVariable) 1285 begin 1286 val = other.numeric 1287 other = val 1288 rescue 1289 other = other._value 1290 end 1291 elsif other.kind_of?(Numeric) 1292 begin 1293 return self.numeric <=> other 1294 rescue 1295 return self._value <=> other.to_s 1296 end 1297 elsif other.kind_of?(Array) 1298 return self.list <=> other 1299 else 1300 return self._value <=> other 1301 end 1302 end 1303 1304 def to_eval 1305 @id 1306 end 1307 1308 def trace_callback(elem, op) 1309 if @trace_var.kind_of? Array 1310 @trace_var.each{|m,e| e.call(self,elem,op) if m.index(op)} 1311 end 1312 if elem.kind_of?(String) && elem != '' 1313 if @trace_elem.kind_of?(Hash) && @trace_elem[elem].kind_of?(Array) 1314 @trace_elem[elem].each{|m,e| e.call(self,elem,op) if m.index(op)} 1315 end 1316 end 1317 end 1318 1319 def _check_trace_opt(opts) 1320 if opts.kind_of?(Array) 1321 opt_str = opts.map{|s| s.to_s}.join(' ') 1322 else 1323 opt_str = opts.to_s 1324 end 1325 1326 fail ArgumentError, 'null trace option' if opt_str.empty? 1327 1328 if opt_str =~ /[^arwu\s]/ 1329 # new format (Tcl/Tk8.4+?) 1330 if opts.kind_of?(Array) 1331 opt_ary = opts.map{|opt| opt.to_s.strip} 1332 else 1333 opt_ary = opt_str.split(/\s+|\|/) 1334 opt_ary.delete('') 1335 end 1336 if USE_OLD_TRACE_OPTION_STYLE 1337 opt_ary.uniq.map{|opt| 1338 case opt 1339 when 'array' 1340 'a' 1341 when 'read' 1342 'r' 1343 when 'write' 1344 'w' 1345 when 'unset' 1346 'u' 1347 else 1348 fail ArgumentError, "unsupported trace option '#{opt}' on Tcl/Tk#{Tk::TCL_PATCHLEVEL}" 1349 end 1350 }.join 1351 else 1352 opt_ary 1353 end 1354 else 1355 # old format 1356 opt_ary = opt_str.delete('^arwu').split(//).uniq 1357 if USE_OLD_TRACE_OPTION_STYLE 1358 opt_ary.join 1359 else 1360 opt_ary.map{|c| 1361 case c 1362 when 'a' 1363 'array' 1364 when 'r' 1365 'read' 1366 when 'w' 1367 'write' 1368 when 'u' 1369 'unset' 1370 end 1371 } 1372 end 1373 end 1374 end 1375 private :_check_trace_opt 1376 1377 def trace(opts, cmd = Proc.new) 1378 opts = _check_trace_opt(opts) 1379 (@trace_var ||= []).unshift([opts,cmd]) 1380 1381 if @trace_opts == nil 1382 TkVar_CB_TBL[@id] = self 1383 @trace_opts = opts.dup 1384 if USE_OLD_TRACE_OPTION_STYLE 1385 Tk.tk_call_without_enc('trace', 'variable', 1386 @id, @trace_opts, 'rb_var ' << @id) 1387 else 1388 Tk.tk_call_without_enc('trace', 'add', 'variable', 1389 @id, @trace_opts, 'rb_var ' << @id) 1390 end 1391 else 1392 newopts = @trace_opts.dup 1393 if USE_OLD_TRACE_OPTION_STYLE 1394 opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} 1395 if newopts != @trace_opts 1396 Tk.tk_call_without_enc('trace', 'vdelete', 1397 @id, @trace_opts, 'rb_var ' << @id) 1398 @trace_opts.replace(newopts) 1399 Tk.tk_call_without_enc('trace', 'variable', 1400 @id, @trace_opts, 'rb_var ' << @id) 1401 end 1402 else 1403 newopts |= opts 1404 unless (newopts - @trace_opts).empty? 1405 Tk.tk_call_without_enc('trace', 'remove', 'variable', 1406 @id, @trace_opts, 'rb_var ' << @id) 1407 @trace_opts.replace(newopts) 1408 Tk.tk_call_without_enc('trace', 'add', 'variable', 1409 @id, @trace_opts, 'rb_var ' << @id) 1410 end 1411 end 1412 end 1413 1414 self 1415 end 1416 1417 def trace_element(elem, opts, cmd = Proc.new) 1418 if @elem 1419 fail(RuntimeError, 1420 "invalid for a TkVariable which denotes an element of Tcl's array") 1421 end 1422 1423 opts = _check_trace_opt(opts) 1424 1425 ((@trace_elem ||= {})[elem] ||= []).unshift([opts,cmd]) 1426 1427 if @trace_opts == nil 1428 TkVar_CB_TBL[@id] = self 1429 @trace_opts = opts.dup 1430 if USE_OLD_TRACE_OPTION_STYLE 1431 Tk.tk_call_without_enc('trace', 'add', 'variable', 1432 @id, @trace_opts, 'rb_var ' << @id) 1433 else 1434 Tk.tk_call_without_enc('trace', 'variable', 1435 @id, @trace_opts, 'rb_var ' << @id) 1436 end 1437 else 1438 newopts = @trace_opts.dup 1439 if USE_OLD_TRACE_OPTION_STYLE 1440 opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} 1441 if newopts != @trace_opts 1442 Tk.tk_call_without_enc('trace', 'vdelete', 1443 @id, @trace_opts, 'rb_var ' << @id) 1444 @trace_opts.replace(newopts) 1445 Tk.tk_call_without_enc('trace', 'variable', 1446 @id, @trace_opts, 'rb_var ' << @id) 1447 end 1448 else 1449 newopts |= opts 1450 unless (newopts - @trace_opts).empty? 1451 Tk.tk_call_without_enc('trace', 'remove', 'variable', 1452 @id, @trace_opts, 'rb_var ' << @id) 1453 @trace_opts.replace(newopts) 1454 Tk.tk_call_without_enc('trace', 'add', 'variable', 1455 @id, @trace_opts, 'rb_var ' << @id) 1456 end 1457 end 1458 end 1459 1460 self 1461 end 1462 1463 def trace_info 1464 return [] unless @trace_var 1465 @trace_var.dup 1466 end 1467 alias trace_vinfo trace_info 1468 1469 def trace_info_for_element(elem) 1470 if @elem 1471 fail(RuntimeError, 1472 "invalid for a TkVariable which denotes an element of Tcl's array") 1473 end 1474 return [] unless @trace_elem 1475 return [] unless @trace_elem[elem] 1476 @trace_elem[elem].dup 1477 end 1478 alias trace_vinfo_for_element trace_info_for_element 1479 1480 def trace_remove(opts,cmd) 1481 return self unless @trace_var.kind_of? Array 1482 1483 opts = _check_trace_opt(opts) 1484 1485 idx = -1 1486 if USE_OLD_TRACE_OPTION_STYLE 1487 newopts = '' 1488 @trace_var.each_with_index{|e, i| 1489 if idx < 0 && e[1] == cmd 1490 diff = false 1491 ['a', 'r', 'w', 'u'].each{|c| 1492 break if (diff = e[0].index(c) ^ opts.index(c)) 1493 } 1494 unless diff 1495 #find 1496 idx = i 1497 next 1498 end 1499 end 1500 e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} 1501 } 1502 else 1503 newopts = [] 1504 @trace_var.each_with_index{|e, i| 1505 if idx < 0 && e[1] == cmd && 1506 e[0].size == opts.size && (e[0] - opts).empty? 1507 # find 1508 idx = i 1509 next 1510 end 1511 newopts |= e[0] 1512 } 1513 end 1514 1515 if idx >= 0 1516 @trace_var.delete_at(idx) 1517 else 1518 return self 1519 end 1520 1521 (@trace_elem ||= {}).each{|elem| 1522 @trace_elem[elem].each{|e| 1523 if USE_OLD_TRACE_OPTION_STYLE 1524 e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} 1525 else 1526 newopts |= e[0] 1527 end 1528 } 1529 } 1530 1531 if USE_OLD_TRACE_OPTION_STYLE 1532 diff = false 1533 @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))} 1534 if diff 1535 Tk.tk_call_without_enc('trace', 'vdelete', 1536 @id, @trace_opts, 'rb_var ' << @id) 1537 @trace_opts.replace(newopts) 1538 unless @trace_opts.empty? 1539 Tk.tk_call_without_enc('trace', 'variable', 1540 @id, @trace_opts, 'rb_var ' << @id) 1541 end 1542 end 1543 else 1544 unless (@trace_opts - newopts).empty? 1545 Tk.tk_call_without_enc('trace', 'remove', 'variable', 1546 @id, @trace_opts, 'rb_var ' << @id) 1547 @trace_opts.replace(newopts) 1548 unless @trace_opts.empty? 1549 Tk.tk_call_without_enc('trace', 'add', 'variable', 1550 @id, @trace_opts, 'rb_var ' << @id) 1551 end 1552 end 1553 end 1554 1555 self 1556 end 1557 alias trace_delete trace_remove 1558 alias trace_vdelete trace_remove 1559 1560 def trace_remove_for_element(elem,opts,cmd) 1561 if @elem 1562 fail(RuntimeError, 1563 "invalid for a TkVariable which denotes an element of Tcl's array") 1564 end 1565 return self unless @trace_elem.kind_of? Hash 1566 return self unless @trace_elem[elem].kind_of? Array 1567 1568 opts = _check_trace_opt(opts) 1569 1570 idx = -1 1571 if USE_OLD_TRACE_OPTION_STYLE 1572 @trace_elem[elem].each_with_index{|e, i| 1573 if idx < 0 && e[1] == cmd 1574 diff = false 1575 ['a', 'r', 'w', 'u'].each{|c| 1576 break if (diff = e[0].index(c) ^ opts.index(c)) 1577 } 1578 unless diff 1579 #find 1580 idx = i 1581 next 1582 end 1583 end 1584 } 1585 else 1586 @trace_elem[elem].each_with_index{|e, i| 1587 if idx < 0 && e[1] == cmd && 1588 e[0].size == opts.size && (e[0] - opts).empty? 1589 # find 1590 idx = i 1591 next 1592 end 1593 } 1594 end 1595 1596 if idx >= 0 1597 @trace_elem[elem].delete_at(idx) 1598 else 1599 return self 1600 end 1601 1602 if USE_OLD_TRACE_OPTION_STYLE 1603 newopts = '' 1604 @trace_var.each{|e| 1605 e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} 1606 } 1607 @trace_elem.each{|elem| 1608 @trace_elem[elem].each{|e| 1609 e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} 1610 } 1611 } 1612 else 1613 newopts = [] 1614 @trace_var.each{|e| 1615 newopts |= e[0] 1616 } 1617 @trace_elem.each{|elem| 1618 @trace_elem[elem].each{|e| 1619 e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)} 1620 } 1621 } 1622 end 1623 1624 if USE_OLD_TRACE_OPTION_STYLE 1625 diff = false 1626 @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))} 1627 if diff 1628 Tk.tk_call_without_enc('trace', 'vdelete', 1629 @id, @trace_opts, 'rb_var ' << @id) 1630 @trace_opts.replace(newopts) 1631 unless @trace_opts.empty? 1632 Tk.tk_call_without_enc('trace', 'variable', 1633 @id, @trace_opts, 'rb_var ' << @id) 1634 end 1635 end 1636 else 1637 unless (@trace_opts - newopts).empty? 1638 Tk.tk_call_without_enc('trace', 'remove', 'variable', 1639 @id, @trace_opts, 'rb_var ' << @id) 1640 @trace_opts.replace(newopts) 1641 unless @trace_opts.empty? 1642 Tk.tk_call_without_enc('trace', 'add', 'variable', 1643 @id, @trace_opts, 'rb_var ' << @id) 1644 end 1645 end 1646 end 1647 1648 self 1649 end 1650 alias trace_delete_for_element trace_remove_for_element 1651 alias trace_vdelete_for_element trace_remove_for_element 1652end 1653 1654class TkVarAccess<TkVariable 1655 def self.new(name, *args) 1656 if name.kind_of?(TkVariable) 1657 name.value = args[0] unless args.empty? 1658 return name 1659 end 1660 1661 name = name.to_s 1662 v = nil 1663 TkVar_ID_TBL.mutex.synchronize{ 1664 if v = TkVar_ID_TBL[name] 1665 v.value = args[0] unless args.empty? 1666 return v 1667 else 1668 (v = self.allocate).instance_eval{ 1669 @id = name 1670 TkVar_ID_TBL[@id] = self 1671 @var = @id 1672 } 1673 end 1674 } 1675 1676 v.instance_eval{ initialize(name, *args) } 1677 v 1678 end 1679 1680 def self.new_hash(name, *args) 1681 if name.kind_of?(TkVariable) 1682 unless name.is_hash? 1683 fail ArgumentError, "already exist as a scalar variable" 1684 end 1685 name.value = args[0] unless args.empty? 1686 return name 1687 end 1688 1689 name = name.to_s 1690 v = nil 1691 TkVar_ID_TBL.mutex.synchronize{ 1692 if v = TkVar_ID_TBL[name] 1693 unless v.is_hash? 1694 fail ArgumentError, "already exist as a scalar variable" 1695 end 1696 v.value = args[0] unless args.empty? 1697 return v 1698 else 1699 (v = self.allocate).instance_eval{ 1700 @id = name 1701 TkVar_ID_TBL[@id] = self 1702 @var = @id 1703 } 1704 end 1705 } 1706 1707 INTERP._invoke_without_enc('global', name) 1708 if args.empty? && INTERP._invoke_without_enc('array', 'exist', name) == '0' 1709 v.instance_eval{ initialize(name, {}) } # force creating 1710 else 1711 v.instance_eval{ initialize(name, *args) } 1712 end 1713 v 1714 end 1715 1716 def initialize(varname, val=nil) 1717 # @id = varname 1718 # TkVar_ID_TBL[@id] = self 1719 1720 # @var = @id 1721 @elem = nil 1722 1723 @def_default = false 1724 @default_val = nil 1725 1726 @trace_var = nil 1727 @trace_elem = nil 1728 @trace_opts = nil 1729 1730 @type = nil 1731 var = self 1732 @element_type = Hash.new{|k,v| var.default_value_type } 1733 1734 # is an element? 1735 if @id =~ /^([^(]+)\((.+)\)$/ 1736 # is an element --> var == $1, elem == $2 1737 @var = $1 1738 @elem = $2 1739 end 1740 1741 # teach Tk-ip that @id is global var 1742 INTERP._invoke_without_enc('global', @var) 1743=begin 1744 begin 1745 INTERP._invoke_without_enc('global', @id) 1746 rescue => e 1747 if @id =~ /^(.+)\([^()]+\)$/ 1748 # is an element --> varname == $1 1749 INTERP._invoke_without_enc('global', $1) 1750 else 1751 fail e 1752 end 1753 end 1754=end 1755 1756 if val 1757 if val.kind_of?(Hash) 1758 # assoc-array variable 1759 self[''] = 0 1760 self.clear 1761 end 1762 #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' #" 1763 #s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' #" 1764 #INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s)) 1765 #INTERP._set_global_var(@id, _toUTF8(_get_eval_string(val))) 1766 self.value = val 1767 end 1768 end 1769end 1770 1771module Tk 1772 begin 1773 INTERP._invoke_without_enc('global', 'auto_path') 1774 auto_path = INTERP._invoke('set', 'auto_path') 1775 rescue => e 1776 begin 1777 INTERP._invoke_without_enc('global', 'env') 1778 auto_path = INTERP._invoke('set', 'env(TCLLIBPATH)') 1779 rescue => e 1780 auto_path = Tk::LIBRARY 1781 end 1782 end 1783 1784 AUTO_PATH = TkVarAccess.new('auto_path', auto_path) 1785 1786=begin 1787 AUTO_OLDPATH = tk_split_simplelist(INTERP._invoke('set', 'auto_oldpath')) 1788 AUTO_OLDPATH.each{|s| s.freeze} 1789 AUTO_OLDPATH.freeze 1790=end 1791 1792 TCL_PACKAGE_PATH = TkVarAccess.new('tcl_pkgPath') 1793 PACKAGE_PATH = TCL_PACKAGE_PATH 1794 1795 TCL_LIBRARY_PATH = TkVarAccess.new('tcl_libPath') 1796 LIBRARY_PATH = TCL_LIBRARY_PATH 1797 1798 TCL_PRECISION = TkVarAccess.new('tcl_precision') 1799end 1800