File: tk/variable.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Tk#1737
extends
  Encoding ( Unknown-Module )
  Tk   
includes
  TkCore   
has properties
constant: AUTO_PATH #1750
constant: TCL_PACKAGE_PATH #1758
constant: PACKAGE_PATH #1759
constant: TCL_LIBRARY_PATH #1761
constant: LIBRARY_PATH #1762
constant: TCL_PRECISION #1764
  class: TkVariable#6
extends
  TkCore   
includes
  Comparable ( Builtin-Module )
  Tk   
inherits from
  Object ( Builtin-Module )
has properties
constant: TkCommandNames #13
constant: TkVar_CB_TBL #17
constant: TkVar_ID_TBL #18
constant: Tk_VARIABLE_ID #19
method: mutex #21
constant: USE_OLD_TRACE_OPTION_STYLE #30
class method: callback / 4 #55
class method: new_hash / 1 #106
method: default_value / 2 #117
method: set_default_value / 1 #127
alias: default_value= set_default_value #132
method: default_proc / 1 #133
method: undef_default #139
method: default_value_type #145
method: default_element_value_type / 1 #148
method: _set_default_value_type_core / 2 #157
method: set_default_value_type / 1 #220
alias: default_value_type= set_default_value_type #224
method: set_default_element_value_type / 2 #226
method: _to_default_type / 2 #231
method: _to_default_element_type / 2 #277
method: initialize / 2 #282
method: wait / 2 #362
method: eventloop_wait / 1 #381
method: thread_wait / 1 #384
method: tkwait / 1 #387
method: eventloop_tkwait #390
method: thread_tkwait #393
method: id #397
method: ref / 1 #401
method: is_hash? #406
method: is_scalar? #413
method: exist? / 1 #417
method: keys #429
method: size #440
method: clear #445
method: update / 1 #453
constant: USE_TCLs_SET_VARIABLE_FUNCTIONS #462
method: _value (1/2) #470
method: value= (1/2) / 1 #482
method: _element_value (1/2) / 1 #513
method: []= (1/2) / 1 #532
method: unset (1/2) / 1 #544
alias: remove (1/2) unset #552
method: _value (2/E) #559
method: value= (2/E) / 1 #577
method: _element_value (2/E) / 1 #628
method: []= (2/E) / 1 #649
method: unset (2/E) / 1 #664
alias: remove (2/E) unset #678
method: value #684
method: [] / 1 #688
method: set_value / 1 #692
method: set_element_value / 2 #697
method: set_value_type / 1 #706
alias: value_type= set_value_type #712
method: set_element_value_type / 2 #714
method: numeric #724
method: numeric_element / 1 #727
method: set_numeric / 1 #730
alias: numeric= set_numeric #741
method: set_numeric_element / 2 #742
method: set_numeric_type / 1 #758
alias: numeric_type= set_numeric_type #763
method: set_numeric_element_type / 2 #764
method: bool #769
method: bool_element / 1 #781
method: set_bool / 1 #784
alias: bool= set_bool #797
method: set_bool_element / 2 #798
method: set_bool_type / 1 #816
alias: bool_type= set_bool_type #821
method: set_bool_element_type / 2 #822
method: variable #827
method: variable_element / 1 #831
method: set_variable / 1 #834
alias: variable= set_variable #839
method: set_variable_element / 2 #840
method: set_variable_type / 1 #849
alias: variable_type= set_variable_type #855
method: set_variable_element_type / 2 #856
method: window #861
method: window_element / 1 #864
method: set_window / 1 #867
alias: window= set_window #872
method: set_window_element / 2 #873
method: set_window_type / 1 #882
alias: window_type= set_window_type #887
method: set_window_element_type / 2 #888
method: procedure #893
method: procedure_element / 1 #896
method: set_procedure / 1 #899
alias: procedure= set_procedure #903
method: set_procedure_element / 2 #904
method: set_procedure_type / 1 #913
alias: procedure_type= set_procedure_type #918
method: set_procedure_element_type / 2 #919
method: to_i #924
method: element_to_i / 1 #927
method: to_f #931
method: element_to_f / 1 #934
method: to_s #938
alias: string to_s #942
method: element_to_s / 1 #943
method: string_element / 1 #946
method: set_string / 1 #949
alias: string= set_string #954
method: set_string_element / 2 #955
method: set_string_type / 1 #964
alias: string_type= set_string_type #969
method: set_string_element_type / 2 #970
method: to_sym #975
alias: symbol to_sym #978
method: element_to_sym / 1 #979
alias: symbol_element element_to_sym #982
method: set_symbol / 1 #983
alias: symbol= set_symbol #988
method: set_symbol_element / 2 #989
method: set_symbol_type / 1 #998
alias: symbol_type= set_symbol_type #1003
method: set_symbol_element_type / 2 #1004
method: list #1009
alias: to_a list #1013
method: list_element / 1 #1014
alias: element_to_a list_element #1017
method: numlist #1019
method: numlist_element / 1 #1022
method: set_list / 1 #1026
alias: list= set_list #1037
alias: set_numlist set_list #1039
alias: numlist= set_numlist #1040
method: set_list_element / 2 #1042
alias: set_numlist_element set_list_element #1058
method: set_list_type / 1 #1060
alias: list_type= set_list_type #1065
method: set_list_element_type / 2 #1066
method: set_numlist_type / 1 #1070
alias: numlist_type= set_numlist_type #1075
method: set_numlist_element_type / 2 #1076
method: lappend / 1 #1081
method: element_lappend / 2 #1085
method: lindex / 1 #1093
alias: lget lindex #1096
method: element_lindex / 2 #1097
alias: element_lget element_lindex #1105
method: lget_i / 1 #1107
method: element_lget_i / 2 #1110
method: lget_f / 1 #1114
method: element_lget_f / 2 #1117
method: lset / 2 #1121
method: element_lset / 3 #1125
method: inspect #1133
method: coerce / 1 #1138
method: & / 1 #1157
method: | / 1 #1164
method: + / 1 #1171
method: - / 1 #1185
method: * / 1 #1192
method: / / 1 #1200
method: % / 1 #1203
method: ** / 1 #1211
method: =~ / 1 #1214
method: == / 1 #1218
method: zero? #1242
method: nonzero? #1245
method: <=> / 1 #1249
method: to_eval #1270
method: trace_callback / 2 #1274
method: _check_trace_opt / 1 #1285
method: trace / 2 #1343
method: trace_element / 3 #1383
method: trace_info #1429
alias: trace_vinfo trace_info #1433
method: trace_info_for_element / 1 #1435
alias: trace_vinfo_for_element trace_info_for_element #1444
method: trace_remove / 2 #1446
alias: trace_delete trace_remove #1523
alias: trace_vdelete trace_remove #1524
method: trace_remove_for_element / 3 #1526
alias: trace_delete_for_element trace_remove_for_element #1616
alias: trace_vdelete_for_element trace_remove_for_element #1617
  class: TkVarAccess#1620
inherits from
  TkVariable   
has properties
class method: new / 2 #1621
class method: new_hash / 2 #1646
method: initialize / 2 #1682

Class Hierarchy

Object ( Builtin-Module )
TkVariable#6
  TkVarAccess    #1620

Code

   1  #
   2  # tk/variable.rb : treat Tk variable object
   3  #
   4  require 'tk'
   5 
   6  class 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, "00000".taint]).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, type_name, 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 
 461  unless const_defined?(:USE_TCLs_SET_VARIABLE_FUNCTIONS)
 462    USE_TCLs_SET_VARIABLE_FUNCTIONS = true
 463  end
 464 
 465  if 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 
 554  else
 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 
 680  end
 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 set_element_value(idxs, val)
 698      if idxs.kind_of?(Array)
 699        self[*idxs]=val
 700      else
 701        self[idxs]=val
 702      end
 703      self
 704    end
 705 
 706    def set_value_type(val)
 707      self.default_value_type = val.class
 708      self.value = val
 709      self
 710    end
 711 
 712    alias value_type= set_value_type
 713 
 714    def set_element_value_type(idxs, val)
 715      self.set_default_element_value_type(idxs, val.class)
 716      if idxs.kind_of?(Array)
 717        self[*idxs]=val
 718      else
 719        self[idxs]=val
 720      end
 721      self
 722    end
 723 
 724    def numeric
 725      number(_value)
 726    end
 727    def numeric_element(*idxs)
 728      number(_element_value(*idxs))
 729    end
 730    def set_numeric(val)
 731      case val
 732      when Numeric
 733        self.value=(val)
 734      when TkVariable
 735        self.value=(val.numeric)
 736      else
 737        raise ArgumentError, "Numeric is expected"
 738      end
 739      self
 740    end
 741    alias numeric= set_numeric
 742    def set_numeric_element(idxs, val)
 743      case val
 744      when Numeric
 745        val
 746      when TkVariable
 747        val = val.numeric
 748      else
 749        raise ArgumentError, "Numeric is expected"
 750      end
 751      if idxs.kind_of?(Array)
 752        self[*idxs]=val
 753      else
 754        self[idxs]=val
 755      end
 756      self
 757    end
 758    def set_numeric_type(val)
 759      @type = :numeric
 760      self.numeric=(val)
 761      self
 762    end
 763    alias numeric_type= set_numeric_type
 764    def set_numeric_element_type(idxs, val)
 765      self.set_default_element_value_type(idxs, :numeric)
 766      self.set_numeric_element(idxs, val)
 767    end
 768 
 769    def bool
 770      TkComm.bool(_value)
 771  =begin
 772      # see Tcl_GetBoolean man-page
 773      case _value.downcase
 774      when '0', 'false', 'no', 'off'
 775        false
 776      else
 777        true
 778      end
 779  =end
 780    end
 781    def bool_element(*idxs)
 782      TkComm.bool(_element_value(*idxs))
 783    end
 784    def set_bool(val)
 785      if ! val
 786        self.value = '0'
 787      else
 788        case val.to_s.downcase
 789        when 'false', '0', 'no', 'off'
 790          self.value = '0'
 791        else
 792          self.value = '1'
 793        end
 794      end
 795      self
 796    end
 797    alias bool= set_bool
 798    def set_bool_element(idxs, val)
 799      if ! val
 800        val = '0'
 801      else
 802        case val.to_s.downcase
 803        when 'false', '0', 'no', 'off'
 804          val = '0'
 805        else
 806          val = '1'
 807        end
 808      end
 809      if idxs.kind_of?(Array)
 810        self[*idxs]=val
 811      else
 812        self[idxs]=val
 813      end
 814      self
 815    end
 816    def set_bool_type(val)
 817      @type = :bool
 818      self.bool=(val)
 819      self
 820    end
 821    alias bool_type= set_bool_type
 822    def set_bool_element_type(idxs, val)
 823      self.set_default_element_value_type(idxs, :bool)
 824      self.set_bool_element(idxs, val)
 825    end
 826 
 827    def variable
 828      # keeps a Tcl's variable name
 829      TkVarAccess.new(self._value)
 830    end
 831    def variable_element(*idxs)
 832      TkVarAccess.new(_element_value(*idxs))
 833    end
 834    def set_variable(var)
 835      var = var.id if var.kind_of?(TkVariable)
 836      self.value = var
 837      self
 838    end
 839    alias variable= set_variable
 840    def set_variable_element(idxs, var)
 841      var = var.id if var.kind_of?(TkVariable)
 842      if idxs.kind_of?(Array)
 843        self[*idxs]=var
 844      else
 845        self[idxs]=var
 846      end
 847      self
 848    end
 849    def set_variable_type(var)
 850      @type = :variable
 851      var = var.id if var.kind_of?(TkVariable)
 852      self.value = var
 853      self
 854    end
 855    alias variable_type= set_variable_type
 856    def set_variable_element_type(idxs, var)
 857      self.set_default_element_value_type(idxs, :variable)
 858      self.set_variable_element(idxs, var)
 859    end
 860 
 861    def window
 862      TkComm.window(self._value)
 863    end
 864    def window_element(*idxs)
 865      TkComm.window(_element_value(*idxs))
 866    end
 867    def set_window(win)
 868      win = win._value if win.kind_of?(TkVariable)
 869      self.value = win
 870      self
 871    end
 872    alias window= set_window
 873    def set_window_element(idxs, win)
 874      win = win._value if win.kind_of?(TkVariable)
 875      if idxs.kind_of?(Array)
 876        self[*idxs]=win
 877      else
 878        self[idxs]=win
 879      end
 880      self
 881    end
 882    def set_window_type(win)
 883      @type = :window
 884      self.window=(win)
 885      self
 886    end
 887    alias window_type= set_window_type
 888    def set_window_element_type(idxs, win)
 889      self.set_default_element_value_type(idxs, :window)
 890      self.set_window_element(idxs, win)
 891    end
 892 
 893    def procedure
 894      TkComm.procedure(self._value)
 895    end
 896    def procedure_element(*idxs)
 897      TkComm.procedure(_element_value(*idxs))
 898    end
 899    def set_procedure(cmd)
 900      self.value = cmd
 901      self
 902    end
 903    alias procedure= set_procedure
 904    def set_procedure_element(idxs, cmd)
 905      cmd = cmd._value if cmd.kind_of?(TkVariable)
 906      if idxs.kind_of?(Array)
 907        self[*idxs]=cmd
 908      else
 909        self[idxs]=cmd
 910      end
 911      self
 912    end
 913    def set_procedure_type(cmd)
 914      @type = :procedure
 915      self.procedure=(cmd)
 916      self
 917    end
 918    alias procedure_type= set_procedure_type
 919    def set_procedure_element_type(idxs, cmd)
 920      self.set_default_element_value_type(idxs, :procedure)
 921      self.set_proceure_element(idxs, cmd)
 922    end
 923 
 924    def to_i
 925      number(_value).to_i
 926    end
 927    def element_to_i(*idxs)
 928      number(_element_value(*idxs)).to_i
 929    end
 930 
 931    def to_f
 932      number(_value).to_f
 933    end
 934    def element_to_f(*idxs)
 935      number(_element_value(*idxs)).to_f
 936    end
 937 
 938    def to_s
 939      #string(value).to_s
 940      _value
 941    end
 942    alias string to_s
 943    def element_to_s(*idxs)
 944      _element_value(*idxs)
 945    end
 946    def string_element(*idxs)
 947      _element_value(*idxs)
 948    end
 949    def set_string(val)
 950      val = val._value if val.kind_of?(TkVariable)
 951      self.value=val
 952      self
 953    end
 954    alias string= set_string
 955    def set_string_element(idxs, val)
 956      val = val._value if val.kind_of?(TkVariable)
 957      if idxs.kind_of?(Array)
 958        self[*idxs]=val
 959      else
 960        self[idxs]=val
 961      end
 962      self
 963    end
 964    def set_string_type(val)
 965      @type = :string
 966      self.string=(val)
 967      self
 968    end
 969    alias string_type= set_string_type
 970    def set_string_element_type(idxs, val)
 971      self.set_default_element_value_type(idxs, :string)
 972      self.set_string_element(idxs, val)
 973    end
 974 
 975    def to_sym
 976      _value.intern
 977    end
 978    alias symbol to_sym
 979    def element_to_sym(*idxs)
 980      _element_value(*idxs).intern
 981    end
 982    alias symbol_element element_to_sym
 983    def set_symbol(val)
 984      val = val._value if val.kind_of?(TkVariable)
 985      self.value=val
 986      self
 987    end
 988    alias symbol= set_symbol
 989    def set_symbol_element(idxs, val)
 990      val = val._value if val.kind_of?(TkVariable)
 991      if idxs.kind_of?(Array)
 992        self[*idxs]=val
 993      else
 994        self[idxs]=val
 995      end
 996      self
 997    end
 998    def set_symbol_type(val)
 999      @type = :symbol
1000      self.value=(val)
1001      self
1002    end
1003    alias symbol_type= set_symbol_type
1004    def set_symbol_element_type(idxs, val)
1005      self.set_default_element_value_type(idxs, :symbol)
1006      self.set_symbol_element(idxs, val)
1007    end
1008 
1009    def list
1010      #tk_split_list(value)
1011      tk_split_simplelist(_value)
1012    end
1013    alias to_a list
1014    def list_element(*idxs)
1015      tk_split_simplelist(_element_value(*idxs))
1016    end
1017    alias element_to_a list_element
1018 
1019    def numlist
1020      list.collect!{|val| number(val)}
1021    end
1022    def numlist_element(*idxs)
1023      list_element(*idxs).collect!{|val| number(val)}
1024    end
1025 
1026    def set_list(val)
1027      case val
1028      when Array
1029        self.value=(val)
1030      when TkVariable
1031        self.value=(val.list)
1032      else
1033        raise ArgumentError, "Array is expected"
1034      end
1035      self
1036    end
1037    alias list= set_list
1038 
1039    alias set_numlist set_list
1040    alias numlist= set_numlist
1041 
1042    def set_list_element(idxs, val)
1043      case val
1044      when Array
1045        val
1046      when TkVariable
1047        val = val.list
1048      else
1049        raise ArgumentError, "Array is expected"
1050      end
1051      if idxs.kind_of?(Array)
1052        self[*idxs]=val
1053      else
1054        self[idxs]=val
1055      end
1056      self
1057    end
1058    alias set_numlist_element set_list_element
1059 
1060    def set_list_type(val)
1061      @type = :list
1062      self.list=(val)
1063      self
1064    end
1065    alias list_type= set_list_type
1066    def set_list_element_type(idxs, val)
1067      self.set_default_element_value_type(idxs, :list)
1068      self.set_list_element(idxs, val)
1069    end
1070    def set_numlist_type(val)
1071      @type = :numlist
1072      self.numlist=(val)
1073      self
1074    end
1075    alias numlist_type= set_numlist_type
1076    def set_numlist_element_type(idxs, val)
1077      self.set_default_element_value_type(idxs, :numlist)
1078      self.set_numlist_element(idxs, val)
1079    end
1080 
1081    def lappend(*elems)
1082      tk_call('lappend', @id, *elems)
1083      self
1084    end
1085    def element_lappend(idxs, *elems)
1086      if idxs.kind_of?(Array)
1087        idxs = idxs.collect{|idx| _get_eval_string(idx, true)}.join(',')
1088      end
1089      tk_call('lappend', "#{@id}(#{idxs})", *elems)
1090      self
1091    end
1092 
1093    def lindex(idx)
1094      tk_call('lindex', self._value, idx)
1095    end
1096    alias lget lindex
1097    def element_lindex(elem_idxs, idx)
1098      if elem_idxs.kind_of?(Array)
1099        val = _element_value(*elem_idxs)
1100      else
1101        val = _element_value(elem_idxs)
1102      end
1103      tk_call('lindex', val, idx)
1104    end
1105    alias element_lget element_lindex
1106 
1107    def lget_i(idx)
1108      number(lget(idx)).to_i
1109    end
1110    def element_lget_i(elem_idxs, idx)
1111      number(element_lget(elem_idxs, idx)).to_i
1112    end
1113 
1114    def lget_f(idx)
1115      number(lget(idx)).to_f
1116    end
1117    def element_lget_f(elem_idxs, idx)
1118      number(element_lget(elem_idxs, idx)).to_f
1119    end
1120 
1121    def lset(idx, val)
1122      tk_call('lset', @id, idx, val)
1123      self
1124    end
1125    def element_lset(elem_idxs, idx, val)
1126      if elem_idxs.kind_of?(Array)
1127        idxs = elem_idxs.collect{|i| _get_eval_string(i, true)}.join(',')
1128      end
1129      tk_call('lset', "#{@id}(#{idxs})", idx, val)
1130      self
1131    end
1132 
1133    def inspect
1134      #Kernel.format "#<TkVariable: %s>", @id
1135      '#<TkVariable: ' + @id + '>'
1136    end
1137 
1138    def coerce(other)
1139      case other
1140      when TkVariable
1141        [other._value, self._value]
1142      when String
1143        [other, self.to_s]
1144      when Symbol
1145        [other, self.to_sym]
1146      when Integer
1147        [other, self.to_i]
1148      when Float
1149        [other, self.to_f]
1150      when Array
1151        [other, self.to_a]
1152      else
1153        [other, self._value]
1154      end
1155    end
1156 
1157    def &(other)
1158      if other.kind_of?(Array)
1159        self.to_a & other.to_a
1160      else
1161        self.to_i & other.to_i
1162      end
1163    end
1164    def |(other)
1165      if other.kind_of?(Array)
1166        self.to_a | other.to_a
1167      else
1168        self.to_i | other.to_i
1169      end
1170    end
1171    def +(other)
1172      case other
1173      when Array
1174        self.to_a + other
1175      when String
1176        self._value + other
1177      else
1178        begin
1179          number(self._value) + other
1180        rescue
1181          self._value + other.to_s
1182        end
1183      end
1184    end
1185    def -(other)
1186      if other.kind_of?(Array)
1187        self.to_a - other
1188      else
1189        number(self._value) - other
1190      end
1191    end
1192    def *(other)
1193      num_or_str(self._value) * other.to_i
1194      #begin
1195      #  number(self._value) * other
1196      #rescue
1197      #  self._value * other
1198      #end
1199    end
1200    def /(other)
1201      number(self._value) / other
1202    end
1203    def %(other)
1204      num_or_str(self._value) % other.to_i
1205      #begin
1206      #  number(self._value) % other
1207      #rescue
1208      #  self._value % other
1209      #end
1210    end
1211    def **(other)
1212      number(self._value) ** other
1213    end
1214    def =~(other)
1215      self._value =~ other
1216    end
1217 
1218    def ==(other)
1219      case other
1220      when TkVariable
1221        #self.equal?(other)
1222        self._value == other._value
1223      when String
1224        self.to_s == other
1225      when Symbol
1226        self.to_sym == other
1227      when Integer
1228        self.to_i == other
1229      when Float
1230        self.to_f == other
1231      when Array
1232        self.to_a == other
1233      when Hash
1234        # false if self is not an assoc array
1235        self._value == other
1236      else
1237        # false
1238        self._value == _get_eval_string(other)
1239      end
1240    end
1241 
1242    def zero?
1243      numeric.zero?
1244    end
1245    def nonzero?
1246      !(numeric.zero?)
1247    end
1248 
1249    def <=>(other)
1250      if other.kind_of?(TkVariable)
1251        begin
1252          val = other.numeric
1253          other = val
1254        rescue
1255          other = other._value
1256        end
1257      elsif other.kind_of?(Numeric)
1258        begin
1259          return self.numeric <=> other
1260        rescue
1261          return self._value <=> other.to_s
1262        end
1263      elsif other.kind_of?(Array)
1264        return self.list <=> other
1265      else
1266        return self._value <=> other
1267      end
1268    end
1269 
1270    def to_eval
1271      @id
1272    end
1273 
1274    def trace_callback(elem, op)
1275      if @trace_var.kind_of? Array
1276        @trace_var.each{|m,e| e.call(self,elem,op) if m.index(op)}
1277      end
1278      if elem.kind_of?(String) && elem != ''
1279        if @trace_elem.kind_of?(Hash) && @trace_elem[elem].kind_of?(Array)
1280          @trace_elem[elem].each{|m,e| e.call(self,elem,op) if m.index(op)}
1281        end
1282      end
1283    end
1284 
1285    def _check_trace_opt(opts)
1286      if opts.kind_of?(Array)
1287        opt_str = opts.map{|s| s.to_s}.join(' ')
1288      else
1289        opt_str = opts.to_s
1290      end
1291 
1292      fail ArgumentError, 'null trace option' if opt_str.empty?
1293 
1294      if opt_str =~ /[^arwu\s]/
1295        # new format (Tcl/Tk8.4+?)
1296        if opts.kind_of?(Array)
1297          opt_ary = opts.map{|opt| opt.to_s.strip}
1298        else
1299          opt_ary = opt_str.split(/\s+|\|/)
1300          opt_ary.delete('')
1301        end
1302        if USE_OLD_TRACE_OPTION_STYLE
1303          opt_ary.uniq.map{|opt|
1304            case opt
1305            when 'array'
1306              'a'
1307            when 'read'
1308              'r'
1309            when 'write'
1310              'w'
1311            when 'unset'
1312              'u'
1313            else
1314              fail ArgumentError, "unsupported trace option '#{opt}' on Tcl/Tk#{Tk::TCL_PATCHLEVEL}"
1315            end
1316          }.join
1317        else
1318          opt_ary
1319        end
1320      else
1321        # old format
1322        opt_ary = opt_str.delete('^arwu').split(//).uniq
1323        if USE_OLD_TRACE_OPTION_STYLE
1324          opt_ary.join
1325        else
1326          opt_ary.map{|c|
1327            case c
1328            when 'a'
1329              'array'
1330            when 'r'
1331              'read'
1332            when 'w'
1333              'write'
1334            when 'u'
1335              'unset'
1336            end
1337          }
1338        end
1339      end
1340    end
1341    private :_check_trace_opt
1342 
1343    def trace(opts, cmd = Proc.new)
1344      opts = _check_trace_opt(opts)
1345      (@trace_var ||= []).unshift([opts,cmd])
1346 
1347      if @trace_opts == nil
1348        TkVar_CB_TBL[@id] = self
1349        @trace_opts = opts
1350        if USE_OLD_TRACE_OPTION_STYLE
1351          Tk.tk_call_without_enc('trace', 'variable', 
1352                                 @id, @trace_opts, 'rb_var ' << @id)
1353        else
1354          Tk.tk_call_without_enc('trace', 'add', 'variable', 
1355                                 @id, @trace_opts, 'rb_var ' << @id)
1356        end
1357      else
1358        newopts = @trace_opts.dup
1359        if USE_OLD_TRACE_OPTION_STYLE
1360          opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
1361          if newopts != @trace_opts
1362            Tk.tk_call_without_enc('trace', 'vdelete', 
1363                                   @id, @trace_opts, 'rb_var ' << @id)
1364            @trace_opts.replace(newopts)
1365            Tk.tk_call_without_enc('trace', 'variable', 
1366                                   @id, @trace_opts, 'rb_var ' << @id)
1367          end
1368        else
1369          newopts |= opts
1370          unless (newopts - @trace_opts).empty?
1371            Tk.tk_call_without_enc('trace', 'remove', 'variable', 
1372                                   @id, @trace_opts, 'rb_var ' << @id)
1373            @trace_opts.replace(newopts)
1374            Tk.tk_call_without_enc('trace', 'add', 'variable', 
1375                                   @id, @trace_opts, 'rb_var ' << @id)
1376          end
1377        end
1378      end
1379 
1380      self
1381    end
1382 
1383    def trace_element(elem, opts, cmd = Proc.new)
1384      if @elem
1385        fail(RuntimeError, 
1386             "invalid for a TkVariable which denotes an element of Tcl's array")
1387      end
1388 
1389      opts = _check_trace_opt(opts)
1390 
1391      ((@trace_elem ||= {})[elem] ||= []).unshift([opts,cmd])
1392 
1393      if @trace_opts == nil
1394        TkVar_CB_TBL[@id] = self
1395        @trace_opts = opts
1396        if USE_OLD_TRACE_OPTION_STYLE
1397          Tk.tk_call_without_enc('trace', 'add', 'variable', 
1398                                 @id, @trace_opts, 'rb_var ' << @id)
1399        else
1400          Tk.tk_call_without_enc('trace', 'variable', 
1401                                 @id, @trace_opts, 'rb_var ' << @id)
1402        end
1403      else
1404        newopts = @trace_opts.dup
1405        if USE_OLD_TRACE_OPTION_STYLE
1406          opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
1407          if newopts != @trace_opts
1408            Tk.tk_call_without_enc('trace', 'vdelete', 
1409                                   @id, @trace_opts, 'rb_var ' << @id)
1410            @trace_opts.replace(newopts)
1411            Tk.tk_call_without_enc('trace', 'variable', 
1412                                   @id, @trace_opts, 'rb_var ' << @id)
1413          end
1414        else
1415          newopts |= opts
1416          unless (newopts - @trace_opts).empty?
1417            Tk.tk_call_without_enc('trace', 'remove', 'variable', 
1418                                   @id, @trace_opts, 'rb_var ' << @id)
1419            @trace_opts.replace(newopts)
1420            Tk.tk_call_without_enc('trace', 'add', 'variable', 
1421                                   @id, @trace_opts, 'rb_var ' << @id)
1422          end
1423        end
1424      end
1425 
1426      self
1427    end
1428 
1429    def trace_info
1430      return [] unless @trace_var
1431      @trace_var.dup
1432    end
1433    alias trace_vinfo trace_info
1434 
1435    def trace_info_for_element(elem)
1436      if @elem
1437        fail(RuntimeError, 
1438             "invalid for a TkVariable which denotes an element of Tcl's array")
1439      end
1440      return [] unless @trace_elem
1441      return [] unless @trace_elem[elem]
1442      @trace_elem[elem].dup
1443    end
1444    alias trace_vinfo_for_element trace_info_for_element
1445 
1446    def trace_remove(opts,cmd)
1447      return self unless @trace_var.kind_of? Array
1448 
1449      opts = _check_trace_opt(opts)
1450 
1451      idx = -1
1452      if USE_OLD_TRACE_OPTION_STYLE
1453        newopts = ''
1454        @trace_var.each_with_index{|e, i|
1455          if idx < 0 && e[1] == cmd
1456            diff = false
1457            ['a', 'r', 'w', 'u'].each{|c|
1458              break if (diff = e[0].index(c) ^ opts.index(c))
1459            }
1460            unless diff
1461              #find
1462              idx = i
1463              next
1464            end
1465          end
1466          e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
1467        }
1468      else
1469        newopts = []
1470        @trace_var.each_with_index{|e, i|
1471          if idx < 0 && e[1] == cmd && 
1472              e[0].size == opts.size && (e[0] - opts).empty?
1473            # find
1474            idx = i
1475            next
1476          end
1477          newopts |= e[0]
1478        }
1479      end
1480 
1481      if idx >= 0
1482        @trace_var.delete_at(idx) 
1483      else
1484        return self
1485      end
1486 
1487      (@trace_elem ||= {}).each{|elem|
1488        @trace_elem[elem].each{|e|
1489          if USE_OLD_TRACE_OPTION_STYLE
1490            e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
1491          else
1492            newopts |= e[0]
1493          end
1494        }
1495      }
1496 
1497      if USE_OLD_TRACE_OPTION_STYLE
1498        diff = false
1499        @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))}
1500        if diff
1501          Tk.tk_call_without_enc('trace', 'vdelete', 
1502                                 @id, @trace_opts, 'rb_var ' << @id)
1503          @trace_opts.replace(newopts)
1504          unless @trace_opts.empty?
1505            Tk.tk_call_without_enc('trace', 'variable', 
1506                                   @id, @trace_opts, 'rb_var ' << @id)
1507          end
1508        end
1509      else
1510        unless (@trace_opts - newopts).empty?
1511          Tk.tk_call_without_enc('trace', 'remove', 'variable', 
1512                                 @id, @trace_opts, 'rb_var ' << @id)
1513          @trace_opts.replace(newopts)
1514          unless @trace_opts.empty?
1515            Tk.tk_call_without_enc('trace', 'add', 'variable', 
1516                                   @id, @trace_opts, 'rb_var ' << @id)
1517          end
1518        end
1519      end
1520 
1521      self
1522    end
1523    alias trace_delete  trace_remove
1524    alias trace_vdelete trace_remove
1525 
1526    def trace_remove_for_element(elem,opts,cmd)
1527      if @elem
1528        fail(RuntimeError, 
1529             "invalid for a TkVariable which denotes an element of Tcl's array")
1530      end
1531      return self unless @trace_elem.kind_of? Hash
1532      return self unless @trace_elem[elem].kind_of? Array
1533 
1534      opts = _check_trace_opt(opts)
1535 
1536      idx = -1
1537      if USE_OLD_TRACE_OPTION_STYLE
1538        @trace_elem[elem].each_with_index{|e, i|
1539          if idx < 0 && e[1] == cmd
1540            diff = false
1541            ['a', 'r', 'w', 'u'].each{|c|
1542              break if (diff = e[0].index(c) ^ opts.index(c))
1543            }
1544            unless diff
1545              #find
1546              idx = i
1547              next
1548            end
1549          end
1550        }
1551      else
1552        @trace_elem[elem].each_with_index{|e, i|
1553          if idx < 0 && e[1] == cmd && 
1554              e[0].size == opts.size && (e[0] - opts).empty?
1555            # find
1556            idx = i
1557            next
1558          end
1559        }
1560      end
1561 
1562      if idx >= 0
1563        @trace_elem[elem].delete_at(idx)
1564      else
1565        return self
1566      end
1567 
1568      if USE_OLD_TRACE_OPTION_STYLE
1569        newopts = ''
1570        @trace_var.each{|e| 
1571          e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
1572        }
1573        @trace_elem.each{|elem|
1574          @trace_elem[elem].each{|e|
1575            e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
1576          }
1577        }
1578      else
1579        newopts = []
1580        @trace_var.each{|e|
1581          newopts |= e[0]
1582        }
1583        @trace_elem.each{|elem|
1584          @trace_elem[elem].each{|e|
1585            e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
1586          }
1587        }
1588      end
1589 
1590      if USE_OLD_TRACE_OPTION_STYLE
1591        diff = false
1592        @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))}
1593        if diff
1594          Tk.tk_call_without_enc('trace', 'vdelete', 
1595                                 @id, @trace_opts, 'rb_var ' << @id)
1596          @trace_opts.replace(newopts)
1597          unless @trace_opts.empty?
1598            Tk.tk_call_without_enc('trace', 'variable', 
1599                                   @id, @trace_opts, 'rb_var ' << @id)
1600          end
1601        end
1602      else
1603        unless (@trace_opts - newopts).empty?
1604          Tk.tk_call_without_enc('trace', 'remove', 'variable', 
1605                                 @id, @trace_opts, 'rb_var ' << @id)
1606          @trace_opts.replace(newopts)
1607          unless @trace_opts.empty?
1608            Tk.tk_call_without_enc('trace', 'add', 'variable', 
1609                                   @id, @trace_opts, 'rb_var ' << @id)
1610          end
1611        end
1612      end
1613 
1614      self
1615    end
1616    alias trace_delete_for_element  trace_remove_for_element
1617    alias trace_vdelete_for_element trace_remove_for_element
1618  end
1619 
1620  class TkVarAccess<TkVariable
1621    def self.new(name, *args)
1622      if name.kind_of?(TkVariable)
1623        name.value = args[0] unless args.empty?
1624        return name 
1625      end
1626 
1627      name = name.to_s
1628      v = nil
1629      TkVar_ID_TBL.mutex.synchronize{
1630        if v = TkVar_ID_TBL[name]
1631          v.value = args[0] unless args.empty?
1632          return v
1633        else
1634          (v = self.allocate).instance_eval{
1635            @id = name
1636            TkVar_ID_TBL[@id] = self
1637            @var = @id
1638          }
1639        end
1640      }
1641 
1642      v.instance_eval{ initialize(name, *args) }
1643      v
1644    end
1645 
1646    def self.new_hash(name, *args)
1647      if name.kind_of?(TkVariable)
1648        unless name.is_hash?
1649          fail ArgumentError, "already exist as a scalar variable"
1650        end
1651        name.value = args[0] unless args.empty?
1652        return name 
1653      end
1654 
1655      name = name.to_s
1656      v = nil
1657      TkVar_ID_TBL.mutex.synchronize{
1658        if v = TkVar_ID_TBL[name]
1659          unless v.is_hash?
1660            fail ArgumentError, "already exist as a scalar variable"
1661          end
1662          v.value = args[0] unless args.empty?
1663          return v
1664        else
1665          (v = self.allocate).instance_eval{
1666            @id = name
1667            TkVar_ID_TBL[@id] = self
1668            @var = @id
1669          }
1670        end
1671      }
1672 
1673      INTERP._invoke_without_enc('global', name)
1674      if args.empty? && INTERP._invoke_without_enc('array', 'exist', name) == '0'
1675        v.instance_eval{ initialize(name, {}) }  # force creating
1676      else
1677        v.instance_eval{ initialize(name, *args) }
1678      end
1679      v
1680    end
1681 
1682    def initialize(varname, val=nil)
1683      # @id = varname
1684      # TkVar_ID_TBL[@id] = self
1685 
1686      # @var  = @id
1687      @elem = nil
1688 
1689      @def_default = false
1690      @default_val = nil
1691 
1692      @trace_var  = nil
1693      @trace_elem = nil
1694      @trace_opts = nil
1695 
1696      @type = nil
1697      var = self
1698      @element_type = Hash.new{|k,v| var.default_value_type }
1699 
1700      # is an element?
1701      if @id =~ /^([^(]+)\((.+)\)$/
1702        # is an element --> var == $1, elem == $2
1703        @var  = $1
1704        @elem = $2
1705      end
1706 
1707      # teach Tk-ip that @id is global var
1708      INTERP._invoke_without_enc('global', @var)
1709  =begin
1710      begin
1711        INTERP._invoke_without_enc('global', @id)
1712      rescue => e
1713        if @id =~ /^(.+)\([^()]+\)$/
1714          # is an element --> varname == $1
1715          INTERP._invoke_without_enc('global', $1)
1716        else
1717          fail e
1718        end
1719      end
1720  =end
1721 
1722      if val
1723        if val.kind_of?(Hash)
1724          # assoc-array variable
1725          self[''] = 0
1726          self.clear
1727        end
1728        #s = '"' + _get_eval_string(val).gsub(/[\[\]$"]/, '\\\\\&') + '"' #"
1729        #s = '"' + _get_eval_string(val).gsub(/[\[\]$"\\]/, '\\\\\&') + '"' #"
1730        #INTERP._eval(Kernel.format('global %s; set %s %s', @id, @id, s))
1731        #INTERP._set_global_var(@id, _toUTF8(_get_eval_string(val)))
1732        self.value = val
1733      end
1734    end
1735  end
1736 
1737  module Tk
1738    begin
1739      INTERP._invoke_without_enc('global', 'auto_path')
1740      auto_path = INTERP._invoke('set', 'auto_path')
1741    rescue => e
1742      begin
1743        INTERP._invoke_without_enc('global', 'env')
1744        auto_path = INTERP._invoke('set', 'env(TCLLIBPATH)')
1745      rescue => e
1746        auto_path = Tk::LIBRARY
1747      end
1748    end
1749 
1750    AUTO_PATH = TkVarAccess.new('auto_path', auto_path)
1751 
1752  =begin
1753    AUTO_OLDPATH = tk_split_simplelist(INTERP._invoke('set', 'auto_oldpath'))
1754    AUTO_OLDPATH.each{|s| s.freeze}
1755    AUTO_OLDPATH.freeze
1756  =end
1757 
1758    TCL_PACKAGE_PATH = TkVarAccess.new('tcl_pkgPath')
1759    PACKAGE_PATH = TCL_PACKAGE_PATH
1760 
1761    TCL_LIBRARY_PATH = TkVarAccess.new('tcl_libPath')
1762    LIBRARY_PATH = TCL_LIBRARY_PATH
1763 
1764    TCL_PRECISION = TkVarAccess.new('tcl_precision')
1765  end