Mac OS X下让ruby支持tcl/tk

               

    我记得在老早在OS X10.8下使用ruby1.9.x的时候只要到下载安装ActiveTcl8.5,没怎么配置就运行tk好好的。但是近日想重新执行下tk代码,发现在require 'tk'的时候就报错鸟!现在用的是ruby2.1.3版本。上网搜了一下,1.9.x之后的版本默认不再将tcl/tk支持编译到ruby里面,so如果你想用则必须重新编译ruby!我勒个去!就不能做成个gem吗?但在多种外围尝试无果的的情况下只有一条路,就是重新编译ruby了...

    到ruby官网下载最新的ruby2.1.5的源代码15MB左右,解压后257MB,console进入解压目录,输入:

./configure -prefix=/Users/apple/src/ruby_src/ruby2.1.5_installed --with-arch=x86_64,i386 --enable-pthread --enable-shared --with-tk --with-tcl

注意-prefix必须要绝对路径,否则不让过;这是你要最后安装ruby2.1.5的路径,一旦固定下来,就不可以再动了。因为我后来用rvm也安装了ruby2.1.5版,所以这里换了个临时位置,只是测试用的。接着可以输入make命令编译ruby,大概要等一会,最后执行make install就将ruby2.1.5安装到了我前面设定的位置上。下面测试一下对tk的支持如何:

[email protected]: bin$ls

erb    gem    irb    rake   rdoc   ri     ruby   testrb

[email protected]: bin$./ruby -e "require 'tk'"

可以看到是ok的,然后运行一下我的tk.rb看一下效果(代码节选):

require 'dbm'#require 'tempfile'#require 'zip/zip'#require 'win32api'#PATH = '/Users/apple/src/c_src/ruby-1.9.3-p362/ext/tk/lib/'require 'tk'#require PATH+'tk'require 'tkextlib/tkimg/bmp'require 'tkextlib/tkimg/jpeg'require 'tkextlib/tkimg/png'require 'tkextlib/iwidgets'require 'tkextlib/bwidget'SM_CXSCREEN = 0SM_CYSCREEN = 1def get_screen_size #get_screen_size_nv = Win32API.new('user32','GetSystemMetrics',['L'],'L') #x = get_screen_size_nv.Call(SM_CXSCREEN) #y = get_screen_size_nv.Call(SM_CYSCREEN) `./s`.split.map {|x| x.to_i} #[x,y]enddef zip(path) zip_path = path + '.zip' File.delete(zip_path) if File.exist? zip_path  Zip::ZipFile.open(zip_path,Zip::ZipFile::CREATE) {|f| f.add(File.split(path)[1],path)}enddef unzip(path) unzip_path = path[0..-5] Zip::ZipFile.open(path) {|f| f.extract(f.entries[0],unzip_path) {true}}endDB_PATH = File.expand_path(".") + '/movies.dbm'#zip(DB_PATH + '.dir')#zip(DB_PATH + '.pag')#unzip(DB_PATH + '.dir.zip')#unzip(DB_PATH + '.pag.zip')db = DBM.new(DB_PATH)#db.clearat_exit { db.close #压缩数据库 #zip(DB_PATH + '.dir') #zip(DB_PATH + '.pag') #File.delete(DB_PATH + '.dir');File.delete(DB_PATH + '.pag')}ROOT_W = 1000ROOT_H = 610x,y = get_screen_size#计算屏幕居中显示时需要移动到的坐标mov_x = (x - ROOT_W)/2mov_y = (y - ROOT_H)/2root = TkRoot.new(:title=>"movie query v1.2")Tk::Wm.geometry(root,"+#{mov_x}+#{mov_y}")#Tk::Wm.attributes(root,:toolwindow=>true)Tk::Wm.geometry(root,"#{ROOT_W}x#{ROOT_H}")Tk::Wm.minsize(root,ROOT_W,ROOT_H)Tk::Wm.maxsize(root,ROOT_W,ROOT_H)img_love = TkPhotoImage.new(:file=>File.expand_path(".") + '/logo.gif')Tk::Wm.iconphoto(root,img_love)def dlgbox_input_name(in_name) #puts Tk::Wm.state dlg #Tk::Wm.deiconify dlg  dlg = Tk::Toplevel.new(:title=>"输入演员名"#Tk::Wm.attributes(dlg,:toolwindow=>true) Tk::Wm.attributes(dlg,:notify=>true#隐藏窗口 #Tk::Wm.withdraw dlg  out_name = nil  txt_input_name = Tk::Tile::Entry.new(dlg,:width=>40) do  grid :row=>0,:column=>0 end txt_input_name.value = in_name  btn_add_name = Tk::Tile::Button.new(dlg) do  text "添 加"  command do   out_name = txt_input_name.value   dlg.destroy  end  grid :row=>1,:column=>0 end  txt_input_name.bind("Return") do  btn_add_name.invoke end  txt_input_name.focus  #将toplevel窗口(对话框窗口)设为主窗口的"瞬时窗口" Tk::Wm.transient dlg #模式对话框 Tk::BWidget.grab :set,dlg #暂时挂起主窗口线程 #TkTimer.new.tkwait dlg dlg.wait_window out_nameend#(r0,c0)lab_app = Tk::Tile::Label.new do text "大熊猫最爱电影查询工具" font "新宋体 14 bold" foreground "blue" grid :row=>0,:column=>0,:columnspan=>8,:padx=>10,:pady=>10end#(r1,c0)lab_names = Tk::Tile::Label.new do text "电影名称" font "新宋体 12 bold" grid :row=>1,:column=>0,:padx=>10,:pady=>10end#(r1,c1)txt_names = TkText.new(:width=>35,:height=>2) do font "新宋体 12 bold" grid :row=>1,:column=>1end#(r2,c0)lab_stars = Tk::Tile::Label.new do text "熊猫星级" font "新宋体 12 bold" grid :row=>2,:column=>0,:padx=>10,:pady=>40,:sticky=>:nendimg_file = File.open(File.expand_path(".") + '/star.jpg','r+b')img_data = img_file.read#img_star = TkPhotoImage.new(:data=>img_data,:gamma=>0.01)img_star = TkPhotoImage.new(:data=>img_data,:palette=>10)img_star_chk = TkPhotoImage.new(:data=>img_data)img_file.closestar = 0btn_stars = []btn_chks = [false,false,false,false,false]clr_all_chk = proc do btn_chks = [false]*5 btn_stars.each do |btn|  btn.configure(:image=>img_starendend#(r2,c1)frm_stars = TkFrame.new do grid :row=>2,:column=>1,:padx=>10,:pady=>10,:sticky=>:n 5.times do |i|  btn_stars << TkButton.new(self,:width=>45,:height=>50) do   text i.to_s   image img_star   relief :flat   grid :row=>0,:column=>i+1   command do    idx = self.cget(:text).to_i    unless btn_chks[idx]     btn_chks[0..idx] = [true]*(idx+1)    else     if btn_chks[idx+1]      btn_chks[(idx+1)..-1] = [false]*(5-idx-1)     else      btn_chks[0..idx] = [false]*(idx+1)     end    end        5.times do |j|     img = if btn_chks[j];img_star_chk else img_star end     btn_stars[j].configure(:image=>img)    end    star = btn_chks.count(true)   end  end endend#(r3,c0)lab_direct = Tk::Tile::Label.new do text "导 演" font "新宋体 12 bold" grid :row=>3,:column=>0end#(r3,c1)txt_direct = Tk::Tile::Entry.new(:width=>35) do font "新宋体 12 bold" grid :row=>3,:column=>1end#(r4,c0)lab_nil = Tk::Tile::Label.new do grid :row=>4,:column=>0end#(r5,c0)lab_artist = Tk::Tile::Label.new do text "演 员" font "新宋体 12 bold" grid :row=>5,:column=>0,:padx=>10,:pady=>10,:sticky=>:nendlst_artist = lst_xroll = lst_yroll = nil#(r5,c2)lst_yroll = Tk::Tile::Scrollbar.new do command proc{|*idx|lst_artist.yview *idx} grid(:row=>5,:column=>2,:sticky=>:ns)end#(r11,c4)btn_del = Tk::Tile::Button.new(frm_btns) do text "删 除 command do  if db.each_key.select {|k|a = k.split(" ")[0].force_encoding("gbk");  b = txt_names.value.split(" ")[0]  a =~ /#{b}/}.count == 0   Tk.messageBox(:icon=>:error,:type=>:ok,:title=>"error",\   :message=>"该主电影名不在数据库中!");break  end  db.delete(txt_names.value)  txt_names.value = "" end grid :row=>11,:column=>4,:padx=>10,:sticky=>:nendbtn_exit = Tk::Tile::Button.new(frm_btns) do text "退 出" command do  exit end grid :row=>11,:column=>5,:padx=>10,:sticky=>:nend#TkGrid.grid(btn_add,"-","x",btn_del,:sticky=>:nsew)#(r0,c5)cvs_line = TkCanvas.new(:width=>"0.1c") do create :line,"0.1c","1c","0.1c","30c",:dash=>"10",:width=>4,:fill=>"blue" grid :row=>0,:column=>5,:rowspan=>12,:sticky=>:wnsendyrl_lst_find = nil#(r1,c6)lst_find = TkListbox.new(:width=>20,:height=>20) do font "新宋体 12 bold" yscrollcommand proc {|*idx|yrl_lst_find.set *idx} grid :row=>1,:column=>6,:rowspan=>13,:sticky=>:wnend#(r1,c7)yrl_lst_find = Tk::Tile::Scrollbar.new do command proc{|*idx|lst_find.yview *idx} grid(:row=>1,:column=>7,:rowspan=>5,:sticky=>:wns)endflash_movie_info = proc do |name| vals = eval(db[name].force_encoding("gbk")) #先按一下btn[0],以防上一个star>0 #btn_stars[0].invoke idx = vals[:star].to_i  #idx -= 1 if idx > 0 clr_all_chk[] btn_stars[idx-1].invoke if idx > 0  txt_names.value = name  txt_direct.value = vals[:direct] list.value = vals[:artist]  scl_clarity.value = vals[:scl].to_i  txt_size.value = vals[:size] txt_len.value = vals[:len] txt_locate.value = vals[:locate] txt_mark.value = vals[:mark] txt_note.value = vals[:note] pic = TkPhotoImage.new(:data=>vals[:pic].force_encoding("ASCII-8BIT")) if vals[:pic]  lab_pic.configure(:image=>pic)endflash_vals = proc do |vals| idx = vals[:star].to_i clr_all_chk[] btn_stars[idx-1].invoke if idx > 0  txt_names.value = vals[:name]  txt_direct.value = vals[:direct] list.value = vals[:artist]  scl_clarity.value = vals[:scl].to_i  txt_size.value = vals[:size] txt_len.value = vals[:len] txt_locate.value = vals[:locate] txt_mark.value = vals[:mark] txt_note.value = vals[:note] pic = TkPhotoImage.new(:data=>vals[:pic].force_encoding("ASCII-8BIT")) if vals[:pic] lab_pic.configure(:image=>pic)endlst_find.bind("<ListboxSelect>") do i = lst_find.curselection[0] if i.to_s != ""  name = lst_find.get(i)  flash_movie_info[name] endendlst_find.bind("ButtonRelease-1") do i = lst_find.curselection[0] if i.to_s != ""  name = lst_find.get(i)  flash_movie_info[name] endend#(r10,c6)txt_find = Tk::Tile::Entry.new(:width=>20) do font "新宋体 12 bold" grid :row=>10,:column=>6endbtn_find = niltxt_find.bind("Return") do btn_find.invokeend#(r11,c6)btn_find = Tk::Tile::Button.new do text "查 找" command do  name_to_find = txt_find.value  next if name_to_find == ""    lst_find.clear  if name_to_find == "*"   db.each_key.select do |k|    lst_find.insert(:end,k.force_encoding("gbk"))   end   next  end    db.each_key.select do |k|   names = k.force_encoding("gbk").split(" ")   for n in names    (lst_find.insert(:end,k.force_encoding("gbk"));break) if n =~ /#{name_to_find}/   end  end end grid :row=>11,:column=>6endmenu = TkMenu.new(:parent=>root,:tearoff=>0)root.configure(:menu=>menu)menu_file = TkMenu.new(:parent=>root,:tearoff=>0)cmd_import = proc do imp_path = Tk.getOpenFile next if imp_path == ""  data = nil File.open(imp_path,"r+") do |f|  data = f.read end vals = eval(data.force_encoding("gbk")) flash_vals[vals]endmenu_file_import = menu_file.add_command(:label=>"Import movie",:underline=>1,:command=>cmd_import)cmd_export = proc do unless chk_vals[]  Tk.messageBox(:icon=>:error,:type=>:ok,:title=>"error",\   :message=>"请选择一部电影!");next end exp_path = Tk.getSaveFile next if exp_path == ""  m = get_vals[] m[:name] = txt_names.value File.open(exp_path,"w+") do |f|  f.write m.to_s endendmenu_file_export = menu_file.add_command(:label=>"Export movie",:underline=>1,:command=>cmd_export)menu_file.add_separatorcmd_exit = proc do exitendmenu_file_exit = menu_file.add_command(:label=>"Exit",:underline=>2,:command=>cmd_exit)menu.add_cascade(:menu=>menu_file,:label=>"File",:underline=>1)#menu_file = menu.add(:cascade,:label=>"File",:underline=>0)Tk.mainloop

界面丑是丑了点,不过后期可以再调整哦Mac OS X下让ruby支持tcl/tk,关键是这段代码windows,linux,OS X下跑都没问题啊,轻松跨平台鸟:

Mac OS X下让ruby支持tcl/tk

还有一种办法是用rvm重新安装支持tcl/tk的版本:

rvm reinstall 2.1.5 --enable-shared --enable-pthread --with-tk --with-tcl

不过我试了一下,在brew update无限卡住了,所以才有了开篇的那一坨文章...Mac OS X下让ruby支持tcl/tk

不过本猫觉得这样用不太爽,尤其是自己编译的irb用不了,因为其还是调用了rvm的路径。要替换也很容易,做软连接吧:

[email protected]: rubies$ls -lh

total 16

lrwxr-xr-x  1 apple  staff    35B 12 10 13:03 default -> /Users/apple/.rvm/rubies/ruby-2.1.5

drwxr-xr-x  8 apple  staff   272B  7 27 19:47 ruby-2.1.2

lrwxr-xr-x  1 apple  staff    45B 12 10 16:08 ruby-2.1.5 -> /Users/apple/src/ruby_Src/ruby2.1.5_installed

drwxr-xr-x  8 apple  staff   272B 12 10 13:02 tmp_ruby-2.1.5

先把原来的ruby目录改名,然后将编译的路径加入即可,可以看到其版本号显示略有不同:

[email protected]: rubies$ruby -v

ruby 2.1.5p273 (2014-11-13 revision 48405) [universal.x86_64-darwin14.0]

[email protected]: rubies$./tmp_ruby-2.1.5/bin/ruby -v

ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]

不过irb开头的版本号和方法名自动补全都没有鸟,咋回事呢?原来是.irbrc没有拷贝过来,而且里面没有加上require 'irb/completion'这句啊!最后看一下自己编译支持tcl/tk的ruby和rvm安装的ruby体积哪个大啊:

[email protected]: ruby-2.1.5$du -sh 

113M .

[email protected]: tmp_ruby-2.1.5$du -sh

 95M .


           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.****.net/jiangjunshow