Filed under Rails

hotcocoa上手

1. 这是什么?

这是macruby的一个Gem,用来快速开发mac GUI应用。

2. 安装

首先安装macruby,我装的是0.11版本。然后运行sudo macgem install hotcocoa,这个package默认是没有安装的。

3. 运行命令hotcocoa w3,具体参考官方的指南。这里会产生一个和Rails类似的目录。

4.build。 直接编译的话会有问题:Undefined symbols for architecture i386,产生的代码都不能用,很无语。修改gem,在这里/Library/Frameworks/MacRuby.framework/Versions/0.11/usr/lib/ruby/Gems/1.9.2/gems/hotcocoa-0.5.1/lib/hotcocoa/application_builder.rb里面的 archs = RUBY_ARCH.include?('ppc') ? '-arch ppc' : '-arch x86_64',把-arch i386去掉,现在的macruby都已经只有64bit的了。

5. 编译没问题的话就可以看到界面了。不过还没完,试试ruby的closure语法,不然妄走一趟。

def start
  application :name => "W3" do |app|
  app.delegate = self
  window :frame => [100, 100, 500, 500], :title => "W3" do |win|
    title = label(:text => "Hello from HotCocoa.", :layout => {:start => false})
    win << title
    name = text_field(:text => 'you name please')
    win << name
    win << button(:title => 'go') do |b|
       b.on_action do
          title.text = "hi," + name.stringValue
       end
    end
    win.will_close { exit }
end

可以看到,比起objective-c来直观多了,想想看objective-c是怎么操作array的,痛苦。而且这里用closure的方法比用Interface Builder来建立button的事件响应要直观、简单的多,不过就要自己手工组织layout了。能否用HTML中的event bind呢?比如这样dojo.connect(‘buttonId’, “onclick”, function(){…}

这里如果把name.stringValue写成name.text,运行时会有异常:in `’: undefined method `value’ for you name please:NSTextField (NoMethodError),可以看到这里是直接访问cocoa的foundation的。macruby是基于cocoa的运行库的,比如NSString,但是当运行macrake时有个build的过程,时间有点长,难道macruby直接把ruby代码编译成二进制?打开打包好的app文件(这里为W3.app),

可以看到这里即有二进制,也有rb的源代码。可能这里的二进制文件是编译出来的,所以需要一段时间,二进制文件大概作为程序运行的入口,比如运行ruby加载rb文件,这个和有些exe结尾的可执行java程序相像。只是这样打包后coding-build-test的周期就长了,还是“刷新浏览器”的方式爽啊,当然有firebug这种工具就更爽了。

Ruby method cache

场景是这样的:我写的手机客户端要从豆瓣上取出当天最受欢迎的书评和影评,这些数据我是到douban.com相关页面上抓取的,大概有20条数据;然后我在这20条数据中随机取出6条显示到手机客户端

Rails内置几种cache机制:1.Page Cache – Fastest, 2.Action Cache – Next Fastest, 3.Fragment Cache – Least Fastest, 4.ActiveRecord Cache – Only available in Edge Rails 。从前端到后端,这几种cache机制粒度都不同,但是都不能满足我的需求。page cache会使每次返回同样的页面,这样达不到“随机”的效果。我希望是这样的:

def get_pop_list
  fetch_reviews.random
  render...
end

def fetch_reviews
  {1...20}
end

我只希望get_reviews这个方法返回的结果是cache的,Action cache好像符合,实验一番后无果,这里的action是指rails中的controller而不是一般的method。

google了下找到了这里,刚好满足我的需求:对method的cache。参考这里例 子:

require 'caches.rb'
  class Spider extend Caches
	def self.fetch_reviews
        	puts "---fetch_reviews"
	        Time.now
	end

	class_caches :fetch_reviews, :timeout => 10.minutes
  end

这里只是一个测试的类,当我们调用Spider.fetch_reviews时,得到的时间每次都是一样的,10分钟后值会刷新,有了timeout我也不用写cron程序来刷新cache了。这个method cache可以对参数cache:不同的参数值会有不同的cache,这个倒是很方便,因为这是一个静态方法,不可避免的要传参数。这点和Page Cache的分页处理倒类似。一个要注意的是在development模式下,controller用load “spider”或者不显示引用(默认为load)不能达到cache的测试效果。

用Java的单例模式来完成这个任务也不太难,这里的self.fetch_reviews也是类的静态方法。不同的是ruby的做法让cache更加透明:加上或者去掉class_caches :fetch_reviews即可改变cache模式,客户端代码不用改变。

Tagged ,

why Ruby over Java

这个帖子很不错,可以参照来学习Ruby。总结来说Ruby的优点在于:
* closures
* multiple implementation inheritance via mixins (simplifies a lot designs where we would use decorators and factories in java)
* messages to objects as if they were first class methods (natural way of doing AOP, used a lot in ActiveRecord). This actually also counts for the famous java properties support planned for java 7…
缺点在于没有了Java的类型检查,而这是提高Java开发效率的关键:通过编译就可以排除大部分的错误,也提高了系统的安全性。但是在开发一个完整的 Java应用时,经常会遇到DSL语言的地方,比如jsp, sql,这些都是没有办法进行类型检查的地方(DSL的特点吗?)。再比如对Session的处理不可避免的会用到类型cast。
在RJS里面,html, rjs, rb这些文件之间存在的变量type和name的合约(或契约)更多,而只能手工检查。
疑问:Ruby里面method的参数的类型会在运行时进行类型检查?
那JRuby会起到一个粘合剂的作用吗?这会提高系统的复杂性,而且一个系统中使用两种语言也少见,除非是一个遗留系统。

小试Rails RJS

    RJS是Rails1.1的一个ajax的功能点。这里是一个简单明了的turturail。
    这个framework引入了一个rjs类型的文件,当control的function执行后,同名的rjs文件会被执行来动态产生出(或者说是被翻译为)javascript文件。
    rjs可以为如下的形式:
a = “fkp”
page.insert_html :bottom, ‘list’,
                 content_tag(“li”, “Fox2″)
page.visual_effect :highlight, ‘list’, :duration => 3
page.replace_html ‘header’,
                  a + “b”
利用工具(for example:charles)可以得到其产生的response为:
try {
new Insertion.Bottom(“list”, “<li>Fox2</li>”);
new Effect.Highlight(“list”,{duration:3});
Element.update(“header2″, “fkpb”);
} catch (e) ……
    让人惊奇!我原来以为返回的是xml形式的(ajax必须返回xml吗?)。
    这样的做法产生一个问题就是js的代码量可能过大,当然这里是因为直接调用而显得很简短(application.js就可以放自定义的js function的地方)。这些js基本上是没有变化的,那么能不能直接传参数呢?这样产生出来的js可以cache(google web tools好像是这样做的)。而rjs的做法感觉是对于page.methodxx的返回值每次来个字符串的相加?
    rjs不仅提供了ruby语法的api来简化js的开发,更重要的是将ajax从view曾剥离出来,而且可以访问server端同名function的导出变量(@开头的?这湮没了xml在B/S间的传递)。
    跟其它的ajax框架不一样(大多可以用js直接访问后台的java function),这种方式去掉了访问的接口的定义(method的返回值没有定义),灵活性更强,因为view可能改变频繁。
    用这种模式后,契约存在两个地方:1)rjs和html。rjs用id来对html element控制,一般的ajax模式是把js和html混合写,由于id粒度过低,分开加大了耦合度;2)ruby和rjs之间的context。显然,google web tools解决了这些问题,但是需要讨厌的compile的过程。
    如果用java来实现,rjs模板可以用java写,也可以为脚本语言(jdk6有更好的支持),而主要不同可能是java代码和模板之间的contex的共享:java可能没有ruby实现的优雅。
    模板产生出来的javascriptbroswer端用如下的形式引用:
<script src=”/javascripts/prototype.js?1159875410″ type=”text/javascript”></script>
<script src=”/javascripts/effects.js?1159875410″ type=”text/javascript”></script>
还不知这些number是做何用处。