1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/ext/tk/lib/tk/optiondb.rb
nagai ed6ce8b43b * ext/tk/extconf.rb: New strategy for searching Tcl/Tk libraries.
* ext/tk/*: Support new features of Tcl/Tk8.6b1 and minor bug fixes.
     ( [KNOWN BUG] Ruby/Tk on Ruby 1.9 will not work on Cygwin. )
* ext/tk/*: Unify sources between Ruby 1.8 & 1.9.
            Improve default_widget_set handling.
* ext/tk/*: Multi-TkInterpreter (multi-tk.rb) works on Ruby 1.8 & 1.9.
     ( [KNOWN BUG] On Ruby 1.8, join to a long term Thread on Tk
       callbacks may freeze. On Ruby 1.9, cannot create a second 
       master interpreter (creating slaves are OK); supported master
       interpreter is the default master interpreter only. )
* ext/tk/lib/tkextlib/*: Update supported versions of Tk extensions.
         Tcllib 1.8/Tklib 0.4.1  ==>  Tcllib 1.11.1/Tklib 0.5
         BWidgets 1.7            ==>  BWidgets 1.8
         TkTable 2.9             ==>  TkTable 2.10
         TkTreeCtrl 2005-12-02   ==>  TkTreeCtrl 2.2.9
         Tile 0.8.0/8.5.1        ==>  Tile 0.8.3/8.6b1
         IncrTcl 2005-02-14      ==>  IncrTcl 2008-12-15
         TclX 2005-02-07         ==>  TclX 2008-12-15
         Trofs 0.4.3             ==>  Trofs 0.4.4


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@24063 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-07-12 23:08:32 +00:00

377 lines
11 KiB
Ruby

#
# tk/optiondb.rb : treat option database
#
require 'tk'
module TkOptionDB
include Tk
extend Tk
TkCommandNames = ['option'.freeze].freeze
(CmdClassID = ['CMD_CLASS'.freeze, TkUtil.untrust('00000')]).instance_eval{
@mutex = Mutex.new
def mutex; @mutex; end
freeze
}
module Priority
WidgetDefault = 20
StartupFile = 40
UserDefault = 60
Interactive = 80
end
def add(pat, value, pri=None)
# if $SAFE >= 4
# fail SecurityError, "can't call 'TkOptionDB.add' at $SAFE >= 4"
# end
tk_call('option', 'add', pat, value, pri)
end
def clear
# if $SAFE >= 4
# fail SecurityError, "can't call 'TkOptionDB.crear' at $SAFE >= 4"
# end
tk_call_without_enc('option', 'clear')
end
def get(win, name, klass)
tk_call('option', 'get', win ,name, klass)
end
def readfile(file, pri=None)
tk_call('option', 'readfile', file, pri)
end
alias read_file readfile
module_function :add, :clear, :get, :readfile, :read_file
def read_entries(file, f_enc=nil)
if TkCore::INTERP.safe?
fail SecurityError,
"can't call 'TkOptionDB.read_entries' on a safe interpreter"
end
i_enc = ((Tk.encoding)? Tk.encoding : Tk.encoding_system)
unless f_enc
f_enc = i_enc
end
ent = []
cline = ''
open(file, 'r') {|f|
while line = f.gets
#cline += line.chomp!
cline.concat(line.chomp!)
case cline
when /\\$/ # continue
cline.chop!
next
when /^\s*(!|#)/ # coment
cline = ''
next
when /^([^:]+):(.*)$/
pat = $1.strip
val = $2.lstrip
p "ResourceDB: #{[pat, val].inspect}" if $DEBUG
pat = TkCore::INTERP._toUTF8(pat, f_enc)
pat = TkCore::INTERP._fromUTF8(pat, i_enc)
val = TkCore::INTERP._toUTF8(val, f_enc)
val = TkCore::INTERP._fromUTF8(val, i_enc)
ent << [pat, val]
cline = ''
else # unknown --> ignore
cline = ''
next
end
end
}
ent
end
module_function :read_entries
def read_with_encoding(file, f_enc=nil, pri=None)
# try to read the file as an OptionDB file
read_entries(file, f_enc).each{|pat, val|
add(pat, val, pri)
}
=begin
i_enc = Tk.encoding()
unless f_enc
f_enc = i_enc
end
cline = ''
open(file, 'r') {|f|
while line = f.gets
cline += line.chomp!
case cline
when /\\$/ # continue
cline.chop!
next
when /^\s*!/ # coment
cline = ''
next
when /^([^:]+):\s(.*)$/
pat = $1
val = $2
p "ResourceDB: #{[pat, val].inspect}" if $DEBUG
pat = TkCore::INTERP._toUTF8(pat, f_enc)
pat = TkCore::INTERP._fromUTF8(pat, i_enc)
val = TkCore::INTERP._toUTF8(val, f_enc)
val = TkCore::INTERP._fromUTF8(val, i_enc)
add(pat, val, pri)
cline = ''
else # unknown --> ignore
cline = ''
next
end
end
}
=end
end
module_function :read_with_encoding
# support procs on the resource database
@@resource_proc_class = Class.new
@@resource_proc_class.const_set(:CARRIER, '.'.freeze)
@@resource_proc_class.instance_variable_set('@method_tbl',
TkCore::INTERP.create_table)
@@resource_proc_class.instance_variable_set('@add_method', false)
@@resource_proc_class.instance_variable_set('@safe_mode', 4)
class << @@resource_proc_class
private :new
=begin
CARRIER = '.'.freeze
METHOD_TBL = TkCore::INTERP.create_table
ADD_METHOD = false
SAFE_MODE = 4
=end
=begin
def __closed_block_check__(str)
depth = 0
str.scan(/[{}]/){|x|
if x == "{"
depth += 1
elsif x == "}"
depth -= 1
end
if depth <= 0 && !($' =~ /\A\s*\Z/)
fail RuntimeError, "bad string for procedure : #{str.inspect}"
end
}
str
end
private :__closed_block_check__
=end
def __check_proc_string__(str)
# If you want to check the proc_string, do it in this method.
# Please define this in the block given to 'new_proc_class' method.
str
end
def method_missing(id, *args)
#res_proc, proc_str = self::METHOD_TBL[id]
res_proc, proc_str = @method_tbl[id]
proc_source = TkOptionDB.get(self::CARRIER, id.id2name, '').strip
res_proc = nil if proc_str != proc_source # resource is changed
# unless res_proc.kind_of?(Proc)
unless TkComm._callback_entry?(res_proc)
#if id == :new || !(self::METHOD_TBL.has_key?(id) || self::ADD_METHOD)
if id == :new || !(@method_tbl.has_key?(id) || @add_method)
raise NoMethodError,
"not support resource-proc '#{id.id2name}' for #{self.name}"
end
proc_str = proc_source
proc_str = '{' + proc_str + '}' unless /\A\{.*\}\Z/ =~ proc_str
#proc_str = __closed_block_check__(proc_str)
proc_str = __check_proc_string__(proc_str)
res_proc = proc{
begin
#eval("$SAFE = #{self::SAFE_MODE};\nProc.new" + proc_str)
eval("$SAFE = #{@safe_mode};\nProc.new" + proc_str)
rescue SyntaxError=>err
raise SyntaxError,
TkCore::INTERP._toUTF8(err.message.gsub(/\(eval\):\d:/,
"(#{id.id2name}):"))
end
}.call
#self::METHOD_TBL[id] = [res_proc, proc_source]
@method_tbl[id] = [res_proc, proc_source]
end
res_proc.call(*args)
end
private :__check_proc_string__, :method_missing
end
@@resource_proc_class.freeze
=begin
def __create_new_class(klass, func, safe = 4, add = false, parent = nil)
klass = klass.to_s if klass.kind_of? Symbol
unless (?A..?Z) === klass[0]
fail ArgumentError, "bad string '#{klass}' for class name"
end
unless func.kind_of? Array
fail ArgumentError, "method-list must be Array"
end
func_str = func.join(' ')
if parent == nil
install_win(parent)
elsif parent <= @@resource_proc_class
install_win(parent::CARRIER)
else
fail ArgumentError, "parent must be Resource-Proc class"
end
carrier = Tk.tk_call_without_enc('frame', @path, '-class', klass)
body = <<-"EOD"
class #{klass} < TkOptionDB.module_eval('@@resource_proc_class')
CARRIER = '#{carrier}'.freeze
METHOD_TBL = TkCore::INTERP.create_table
ADD_METHOD = #{add}
SAFE_MODE = #{safe}
%w(#{func_str}).each{|f| METHOD_TBL[f.intern] = nil }
end
EOD
if parent.kind_of?(Class) && parent <= @@resource_proc_class
parent.class_eval(body)
eval(parent.name + '::' + klass)
else
eval(body)
eval('TkOptionDB::' + klass)
end
end
=end
def __create_new_class(klass, func, safe = 4, add = false, parent = nil)
if klass.kind_of?(TkWindow)
carrier = klass.path
CmdClassID.mutex.synchronize{
klass = CmdClassID.join(TkCore::INTERP._ip_id_)
CmdClassID[1].succ!
}
parent = nil # ignore parent
else
klass = klass.to_s if klass.kind_of?(Symbol)
unless (?A..?Z) === klass[0]
fail ArgumentError, "bad string '#{klass}' for class name"
end
if parent == nil
install_win(nil)
elsif parent.kind_of?(TkWindow)
install_win(parent.path)
elsif parent <= @@resource_proc_class
install_win(parent::CARRIER)
else
fail ArgumentError, "parent must be Resource-Proc class"
end
carrier = Tk.tk_call_without_enc('frame', @path, '-class', klass)
end
unless func.kind_of?(Array)
fail ArgumentError, "method-list must be Array"
end
func_str = func.join(' ')
if parent.kind_of?(Class) && parent <= @@resource_proc_class
cmd_klass = Class.new(parent)
else
cmd_klass = Class.new(TkOptionDB.module_eval('@@resource_proc_class'))
end
cmd_klass.const_set(:CARRIER, carrier.dup.freeze)
cmd_klass.instance_variable_set('@method_tbl', TkCore::INTERP.create_table)
cmd_klass.instance_variable_set('@add_method', add)
cmd_klass.instance_variable_set('@safe_mode', safe)
func.each{|f|
cmd_klass.instance_variable_get('@method_tbl')[f.to_s.intern] = nil
}
=begin
cmd_klass.const_set(:METHOD_TBL, TkCore::INTERP.create_table)
cmd_klass.const_set(:ADD_METHOD, add)
cmd_klass.const_set(:SAFE_MODE, safe)
func.each{|f| cmd_klass::METHOD_TBL[f.to_s.intern] = nil }
=end
cmd_klass
end
module_function :__create_new_class
private_class_method :__create_new_class
def __remove_methods_of_proc_class(klass)
# for security, make these methods invalid
class << klass
def __null_method(*args); nil; end
[ :class_eval, :name, :superclass, :clone, :dup, :autoload, :autoload?,
:ancestors, :const_defined?, :const_get, :const_set, :const_missing,
:class_variables, :constants, :included_modules, :instance_methods,
:method_defined?, :module_eval, :private_instance_methods,
:protected_instance_methods, :public_instance_methods,
:singleton_methods, :remove_const, :remove_method, :undef_method,
:to_s, :inspect, :display, :method, :methods, :respond_to?,
:instance_variable_get, :instance_variable_set, :instance_method,
:instance_eval, :instance_exec, :instance_variables, :kind_of?, :is_a?,
:private_methods, :protected_methods, :public_methods ].each{|m|
alias_method(m, :__null_method)
}
end
end
module_function :__remove_methods_of_proc_class
private_class_method :__remove_methods_of_proc_class
RAND_BASE_CNT = [0]
RAND_BASE_HEAD = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
RAND_BASE_CHAR = RAND_BASE_HEAD + 'abcdefghijklmnopqrstuvwxyz0123456789_'
def __get_random_basename
name = '%s%03d' % [RAND_BASE_HEAD[rand(RAND_BASE_HEAD.size),1],
RAND_BASE_CNT[0]]
len = RAND_BASE_CHAR.size
(6+rand(10)).times{
name << RAND_BASE_CHAR[rand(len),1]
}
RAND_BASE_CNT[0] = RAND_BASE_CNT[0] + 1
name
end
module_function :__get_random_basename
private_class_method :__get_random_basename
# define new proc class :
# If you want to modify the new class or create a new subclass,
# you must do such operation in the block parameter.
# Because the created class is flozen after evaluating the block.
def new_proc_class(klass, func, safe = 4, add = false, parent = nil, &b)
new_klass = __create_new_class(klass, func, safe, add, parent)
new_klass.class_eval(&b) if block_given?
__remove_methods_of_proc_class(new_klass)
new_klass.freeze
new_klass
end
module_function :new_proc_class
def eval_under_random_base(parent = nil, &b)
new_klass = __create_new_class(__get_random_basename(),
[], 4, false, parent)
ret = new_klass.class_eval(&b) if block_given?
__remove_methods_of_proc_class(new_klass)
new_klass.freeze
ret
end
module_function :eval_under_random_base
def new_proc_class_random(klass, func, safe = 4, add = false, &b)
eval_under_random_base(){
TkOptionDB.new_proc_class(klass, func, safe, add, self, &b)
}
end
module_function :new_proc_class_random
end
TkOption = TkOptionDB
TkResourceDB = TkOptionDB