Welcome to our site!
<%= print_information %>

Capistrano 2.0 is real. (What is Capistrano?)
Install it thus:
gem install capistrano
It’s been through four preview releases, and has seen significant changes since 1.4.1. If you’re currently using 1.4.1, be sure to check out the upgrade documentation at http://www.capify.org. If you’re altogether new to Capistrano, you might like to read about getting started.
Since the last preview release (number four, version 1.99.3), the changes are primarily bug fixes, but the following featureish modifications snuck in, too:
Also, some people reported SFTP uploads were hanging for them. If this happens to you, try adding the following line to the top of your recipe file:
set :synchronous_connect, true
That will cause connections to the servers to be established serially, rather than in parallel, so if you’ve got a lot of servers that you are connecting to, it might make things a bit time-consuming. However, this appeared to work around the hanging SFTP issue.
You can read the complete changelog here. If you are using Capistrano at all, please also consider joining the mailing list, it’s a great place to share tips and report issues.
KNOWN ISSUES
Yes, there are a few of these. Two are of immediate significance:
add to del.icio.us. look up in del.icio.us.
add to furl
周末,跨越了大半个北京城和几个老朋友聚到了一起,由于有一段时间没有见到,自然一个个都变成了话痨。一个朋友的精神状态对比于之前见到的他来说,明显好了许多,生活显然也丰富多彩了一些。聊到原因,他从之前一个很糟糕的情况逐渐摆脱了出来,心情好了,自然而然人的状态也随之好转了。当然,朋友们也看到了我类似的变化。加入到ThoughtWorks后,我整个人的状态变得明显不同了,更活泼了。按照一个朋友的说法,明显是被释放的结果。
曾经和老妈聊天,我说找工作的标准是“钱多和心情好” 至少有一样。其实,虽然我也知道金钱的重要性,但我一直没有树立了一个良好的追逐金钱的观念,所以,我真正看重的是心情。工作最初的部门给我留下了一些很美好的回忆,其中一个重要的原因就是那里给了我一个良好的心情,周围的环境让我感到很舒服,所以,在那里我的表现也得到了大家的认可。虽然后来我离开了那里,但原因也与环境无关。反而,每次我回到沈阳,都会回到那个部门与一些老朋友叙旧。在我正式离职之前,我还曾经到那个部门与大家分享了一些Ruby的东西。
之后工作的那个部门,虽然我从中也学到了不少的东西,但自己整体评价我那两年的表现,很糟糕。自我分析的结果是,我一直没有找一个让自己心情愉快的理由。虽然大家也经常在一起玩,但那个部门的整体氛围一直不是我很喜欢的,人和人之间表现得也不是那么友善。正所谓祸不单行,有一段时间,我觉得自己很“背”,把该倒的霉在那一段时间都倒了。所以,在这种氛围中工作了一段时间之后,我感觉很压抑。我知道自己肯定会离开,只是不知道什么时候,下一个落脚点会在哪里,直到我找到了ThoughtWorks。
一个朋友看到我写的那篇《一月思想工作者》给出的评价是如鱼得水。经过长时间的压抑之后,我感觉自己一下子解脱了。我很快就融入了这样的环境中,以至于一些新来的同事误以为我已经在这里工作了很长的时间。ThoughtWorks给了我一个我喜欢的环境。我不会为了那些没有意义的东西,消磨自己锐气。
在ThoughtWorks的招聘流程中,有一条原则,如果应聘者让你感觉不舒服,你就完全有理由拒绝这个应聘者。这是一条看似不合理的原则,但对于维护一个良好的企业文化却至关重要。因为招进来的人是要和我们一起工作的。如果这个人在应聘过程中让人不舒服,那么在日后的工作过程中,他可能也同样会表现得让不舒服,让人不舒服的结果就会是影响工作效率,精力被浪费在一些无谓的地方。事实上,正是有这样一条原则,所以,几乎与所有ThoughtWorker在一起都会让人感觉很舒服。不管这个人来自哪里,即便是刚刚认识,也会很快就会熟悉起来。
你的工作环境给了你怎样的心情呢?
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
“ I used to tell my senior staff to get me poets as managers. ”
Sidney Harman
add to del.icio.us. look up in del.icio.us.
add to furl
Just days after Microsoft announced spending a billion dollars on extending the Xbox 360 warranty, my own console surrended to the dreaded three flashing red lights.
Now you'd think a billion dollars would buy Microsoft some premium, grade-A service and expedition to make short order of such a widespread problem, no? Think again.
It took three separate tries to even get through on their support line. The final attempt required about an hour on the line. All that to get a paper box shipped as the return package using UPS 3-day service (unlike, say, Apple's overnight delivery).
But much worse, expected service time is 4-6 weeks! Between the attempts at calling support and shipping boxes back and forth with snail service, I'm looking at a two-month turn-around from problem to resolution. Yikes.
How am I supposed to cope with no Forza Motorsports for that along!? It's inhuman, I tell you.
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
The MySQL-dump blog posted on some observed rubyisms while evaluating a large ruby application. He highlights some potential problems with ActiveRecord that may come up, such as using “SELECT *”, character sets, unsigned integers, and constraints.
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
things = Thing.find(:all)
random_things = []
3.times do
random_things << things[rand(things.size)]
end
上面这个方法是可以的,但是有个缺点,它把整个表都查询出来,再随机的取三个,缺点很明显,如果数据库表太大,效率很差(内存等消耗很大);且可能取出两条相同的记录(尽管概率不大),第二个问题比较好修复,如下代码即可解决:
things = Thing.find(:all)
random_things = []
while random_things.size < 3
random_things |= things[rand(things.size)]
end
*2.Ruby查询两次*
thing_ids = Thing.find(:all, :select => 'id').map(&:id)
random_ids = []
while random_ids.size < 3
random_things |= things[rand(things.size)]
end
random_things = Thing.find(:all, :conditions => ['id IN (?)', random_ids])
这个方法只是先随机取出ids较,然后再取ids对应的记录,比前面说的那个有个好处就是不会消耗太多的系统资源,比起第一种方法会快很多。
*3.在数据库层面上做*
random_things = Thing.find(:all, :limit => 3, :order => 'random()')
是不是神奇呢,我们直接把:random(如果是MySQL则需要使用 rand()) 传给Find方法就可以了,这个方法看似比较好,其实不然,其构造出来的SQL比较变形,且对于不同的数据库不能通用。且类似与order by rand() limit 1这样的语句是很畸形的。
*4.使用offset进一步改进*
Thing.find :first, :offset => rand(Thing.count)
上面这个方法好多了,但是只能取一条,你可以按照第一种办法构造一个取多条的,页很简单,不是么?
以上四个方法,请按照自己的实际情况使用,对于不同的需求,效率是不一样的,如果你有更好的方法,欢迎留言讨论。
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
<%= link_to image_tag("search.gif", :border=>0), :action => 'show', :id => user %>
注意里面的:border=>0是为了去掉图片四周那个无聊的框框的,需要加上哦~
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
def stripped_html(html)
# this is a copynpaste of the routine in article.rb
# so the one in article.rb can change w/o breaking this.
self.html.gsub(/<[^>]*>/,'').to_url
end
对于HTML标签的过滤和清除,你有什么好的方法么?欢迎分享!
add to del.icio.us. look up in del.icio.us.
add to furl
def manage_ducks(ducks)
if ducks == nil
ducks = fetch_some_champions
else
unless ducks.won_stanley_cup?
ducks = fetch_some_champions
end
end
ducks.beat_random_opponent
end
如果是刚刚解除Ruby的话,上面这段代码可能就是你写出来的,她虽然可行,但是一点都不符合ruby的风格,你将怎么改呢~请留言分享~
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
<% Business.find(@know.business_id).know_tags.each do |t| %>
<%= check_box_tag('know[know_tags_ids][]',t.know_tag_id,@know.know_tags.include?(t))%> <%= t.name %>
<%end %>
--------------
<% @know_tags.each do |t| %>
<%= check_box_tag('know[know_tags_ids][]',t.know_tag_id,@know.know_tags.include?(t))%> <%= t.name %>
<%end %>
---------------
<% @tags.each do |tag|%>
<%= check_box_tag ("topic[tags_ids][]",tag.id)%><%= tag.name %>
<% end %>
我想上面几个例子,大家应该明白了吧?
add to del.icio.us. look up in del.icio.us.
add to furl
def url=(addr)
super (addr.blank? || addr.starts_with?('http')) ? addr : "http://#{addr}"
end
当然,你也可以按照这个思路在你接收数据的时候处理。
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
class ApplicationController < ActionController::Base
before_filter :add_to_history
before_filter :page_title
###
def add_to_history
session[:history] ||= []
##
if File.exists?("#{RAILS_ROOT}/app/views/#{self.controller_name}/#{self.action_name}.rhtml") && session[:history].empty? || session[:history].first['uri'] != @request.request_uri
session[:history].unshift({ 'uri' => @request.request_uri, 'name' => page_title })
session[:history].pop while session[:history].length > 11
end
end
###
####
# This bit came from Peter Cooper's snippets source and was moved into the application controller:
###
def page_title
case self.controller_name
when 'tag'
title = "Tags » " + @params[:tags].join(" > ")
when 'user'
title = "Users » #{@params[:user]}"
when 'features'
case self.action_name
when 'show' then title = "Feature » #{Feature.find(@params[:id]).title}"
else title = APP_CONFIG["default_title"]
end
else
title = APP_CONFIG["default_title"] + self.controller_name + ":" + self.action_name
end
end
helper_method :page_title
###
...
end
然后在页面上就可以这样显示了:
User History
<% for cur in session[:history][0..9] -%>
<% end -%>
add to del.icio.us. look up in del.icio.us.
add to furl
#!/usr/bin/env ruby
require 'net/pop'
require File.dirname(__FILE__) + '/../config/environment'
logger = RAILS_DEFAULT_LOGGER
logger.info "Running Mail Importer..."
Net::POP3.start("localhost", nil, "username", "password") do |pop|
if pop.mails.empty?
logger.info "NO MAIL"
else
pop.mails.each do |email|
begin
logger.info "receiving mail..."
Notifier.receive(email.pop)
email.delete
rescue Exception => e
logger.error "Error receiving email at " + Time.now.to_s + "::: " + e.message
end
end
end
end
logger.info "Finished Mail Importer."
做些说明:你需要在*Net::POP3.start*这行写上你要接收的邮箱的服务器地址以及你的用户名密码,如上配置好了,你就可以在cron中配置调度这个任务了,至于调度的频度你可以按照自己的需求来设定了。
如何,还算简单吧。
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
ActionMailer::Base.server_settings = {
:address => "smtp.gmail.com",
:port => "587",
:domain => "localhost.localdomain",
:authentication => :plain,
:user_name => "someusername",
:password => "somepassword"
}
需要注意的是,该版本只支持ruby1.8.4及其以上版本。
参考:http://blog.pomozov.info/posts/how-to-send-actionmailer-mails-to-gmailcom.html
add to del.icio.us. look up in del.icio.us.
add to furl
class NoisyImage
require 'RMagick'
include Magick
注意这个*require 'RMagick'*是放在class里面的,如果放在外面,就会报我上面说的那个错误。
PS:刚刚给1stlog加上了验证码,也是最后一个功能点了。明天找时间整理下文档就可以开源了。真开心~
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
Welcome to our site!
<%= print_information %>
<%= render :partial => "sidebar" %>
*這是HAML*
#content
.left.column
%h2 Welcome to our site!
%p= print_information
.right.column= render :partial => "sidebar"
看!少了多少行?
可以讓開發速度變快耶= v =...
最主要的是,看起來也比較美觀了!
--------------------------
说说偶的看法:(基本上是不推荐的)
1、多了一次解析反解析,效果难道不受影响(除非是直接解析成html)
2、难道要Designer也學Ruby嗎?同问?
3、我把RHTML分成 局部模板,单个文件就不会很大,也很简单。
4、美观么?ruby本来是不强制缩进的,这个东西还要求缩进~=_=~
有谁再给出一些理由呢?
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
david = User.find(1)
david.to_json # {id: 1, name: "David", awesome: true, created_at: "07/01/2007"}
david.to_json(:only => :name) # {name: "David"}
david.to_json(:only => [:id, :name]) # {id: 1, name: "David"}
david.to_json(:except => :created_at) # {id: 1, name: "David", awesome: true}
david.to_json(:except => [:id, :created_at]) # {name: "David", awesome: true}
很简单吧~
add to del.icio.us. look up in del.icio.us.
add to furl
ActionMailer::Base.delivery_method = :smtp
#以简单邮件传送协议发送邮件
ActionMailer::Base.default_charset = "GBK"
#设置邮件的默认编码为国标码否则发送的邮件主题可能会乱码
ActionMailer::Base.server_settings = {
:address => "192.168.1.110",
:port => 25,
:domain => "xxx.com",
:authentication => :login,
:user_name => "xxx",
:password => "xxx",
}
1、:address => and :port => 决定你将使用的SMTP的地址和端口。这些缺省值分别为localhost和25。
2、:domain => 当识别自己是服务器时 mailer应该使用的域名。这是对HELO(因为HELO是命令客户端发送服务来启动一个连接)域的调用。你通常应该使用顶级域名机制来发送e-mail,但这依赖于你的SMTP服务的设置(some don’t check, and some check to try to reduce spam and socalled open-relay issues)
3、:user_name => and :password => 如果:authentication被设置则要求有此。
4、:authentication => :plain,:login,或:cram_md中的一个。你的服务器管理员将帮助选择正确的选项。当前没使用TLS(SSL)来从Rails连接邮件服务器的方式。这个参数应该被忽略,如果你的服务器不要求确认。
创建一个mailer的models
class OrderMailer < ActionMailer::Base
def signup(domain, sent_at = Time.now)
@subject = 'Welcome to Beast'
@body = "hello world"
@recipients = "yyy@yyy.com"
@from = 'yyy@yyy.com'
@sent_on = sent_at
@headers = {}
end
end
@subject:邮件标题
@body:邮件正文可以使用html标签但需要设置参考下面
@recipients:收件人可以接收数组进行群发
多人发送:@recipients = [ "1@a.com","2@b.com"]
@from:发件人
@sent_on:用于设置邮件 Date: header的Time 对象
@headers:一个header name/value 对的哈希望表,用于添加任意header行给邮件
如:@headers["Organization"] = "Pragmatic Programmers, LLC"
既要使用HTML格式发送邮件又要增加附件的话,需要在model里就对content-type进行设置 @content-type=”text/html”
*创建一个controller 用于发送邮件*
def send_mailer
email = OrderMailer.deliver_signup(request.host_with_port)
Puts email.encoded #邮件内容打印
#email = OrderMailer.create_signup(request.host_with_port)
#email.set_content_type("text/html") 可在模型中设置
#OrderMailer.deliver(email)
#发送HTML格式的邮件的设置
end
*发送HTML模板邮件*
在views中创建一个模板:_mail_content.rhtml
……
model中的mailer类改成如下:
def signup(domain,content,sent_at = Time.now)
@subject = "xxx"
@body = content
@recipients = "xxx@xxx.com"
@from = 'xxx@xxx.com'
@sent_on = sent_at
@headers = {}
end
controller中更改发送方法:
def send_mail
content =
render_to_string :partial=>" mail_content "
email = OrderMailer.create_signup(request.host_with_port,content)
email.set_content_type("text/html")
OrderMailer.deliver(email)
render :text=>"发送成功"
end
render_to_string方法返回的是String 与render不同的是它返回后不会发送给客户端。
*发送附件*
修改model中的mailer类,如下:
def signup(domain,content,sent_at = Time.now)
@subject = "xxx"
@body = content
@recipients = "xxx@xxx.com"
@from = 'xxx@xxx.com'
@sent_on = sent_at
@headers = {}
@data = ""
File.open("D:\\Tools\\FastAIT.rar", "rb") { |fp|
@data<
}
#参数的含义rb表示只读并且以二进制方式创建一个file对象
#不写r会出现丢失数据的问题,发送的附件也就被破坏了
``r''
Read-only, starts at beginning of file (default mode).
只读,清除原有内容(默认方式)
``r+''
Read-write, starts at beginning of file.
读写,清除原有内容
``w''
Write-only, truncates existing file to zero length or creates a new file for writing.
只写,创建一个新的文件覆盖旧的
``w+''
Read-write, truncates existing file to zero length or creates a new file for reading and writing.
读写,创建一个新的文件覆盖旧的
``a''
Write-only, starts at end of file if file exists, otherwise creates a new file for writing.
只写,追加
``a+''
Read-write, starts at end of file if file exists, otherwise creates a new file for reading and writing.
读写,追加
``b''
(DOS/Windows only) Binary file mode (may appear with any of the key letters listed above).
*二进制模式*
attachment :content_type => "application/rar",
:filename => "FastAIT.rar" ,
:body => @data
end
邮件附件的content_type(内容类型表)
".asf" ContentType = "video/x-ms-asf"
".avi" ContentType = "video/avi"
".doc" ContentType = "application/msword"
".zip" ContentType = "application/zip"
".xls" ContentType = "application/vnd.ms-excel"
".gif" ContentType = "image/gif"
".jpg", "jpeg" ContentType = "image/jpeg"
".wav" ContentType = "audio/wav"
".mp3" ContentType = "audio/mpeg3"
".mpg", "mpeg" ContentType = "video/mpeg"
".rtf" ContentType = "application/rtf"
".htm", "html" ContentType = "text/html"
".txt" ContentType = "text/plain"
".pdf" ContentType = "application/pdf"
其他 ContentType = "application/octet-stream"
add to del.icio.us. look up in del.icio.us.
add to furl
def self.up
create_table :priorities do |t|
t.column :name, :string, :default => ""
t.column :desc, :string, :default => ""
end
Priority.new(:name=>"一级",:desc=>"很紧急,4-8小时完成").save
Priority.new(:name=>"二级",:desc=>"紧急,8-24小时完成").save
Priority.new(:name=>"三级",:desc=>"一般,24-48小时完成").save
Priority.new(:name=>"四级",:desc=>"不紧急,48小时以上").save
Priority.new(:name=>"不详",:desc=>"不详").save
end
遇到下列错误
bq. ./db/migrate//003_create_priorities.rb:10: Invalid char `\274' in expression
./db/migrate//003_create_priorities.rb:10: Invalid char `\266' in expression
./db/migrate//003_create_priorities.rb:10: Invalid char `\262' in expression
./db/migrate//003_create_priorities.rb:10: Invalid char `\273' in expression
./db/migrate//003_create_priorities.rb:10: Invalid char `\275' in expression
./db/migrate//003_create_priorities.rb:10: syntax error, unexpected tIDENTIFIER,
expecting kEND
Priority.new(:name=>"四级",:desc=>"不紧急,48小时以上").save
真是ft,感觉是编码的问题,我数据库用的是UTF-8呀,我在environment.rb也加了$KCODE = 'u' require 'jcode'了呀,我在application.rb也写了:configure_charsets了下,我在数据库配置文件也加了encoding: utf8了呀。
这个问题搞得我一肚子火,最后想到了,还有一处编码需要注意,那就是文件的编码,也就是把radrails的editor默认字符集改成utf-8。
寒~真是ft,大家遇到类似问题千万记住呀,需要检查下面几个地方~
# 数据库编码
# application.rb
# environment.rb
# database.yml
add to del.icio.us. look up in del.icio.us.
add to furl
Contact.find(:all, :select => "id, name")
Contact.find_by_sql("SELECT id, name FROM `contacts`")
这两种写法效果是一样的,怎么样,是不是比较棒呀?可能你还要问这个写法有什么好处呀?写过rails的朋友应该对它的Find方法很熟悉,但是Find是一次吧所有字段都取出来,如果字段内容比较多,会耗费很多的内存的哦,这样的话,我们只取需要的字段就OK了。
你还有什么想法,欢迎留言讨论~
add to del.icio.us. look up in del.icio.us.
add to furl
@topic.body = '引言:' + @topic.body + '
'
feed = RSS::Parser.parse(open(params[:uri]).read, false)
@topic.body += '
*来源:*' + feed.channel.title
@topic.body += '
*地址:*' + feed.channel.link
feed.items.each do |item|
@topic.body += '
*标题:*' + item.title
@topic.body += '
*内容摘要:*
' + item.description
end
对了,你还需要在前面加上对库的引用,如下:
require 'rss/2.0'
require 'open-uri'
另外,刚刚看到Javaeye上一个老兄写了一个差不多的,我就不多写了,大家可以参考下,地址如下:http://www.javaeye.com/blog/57538
add to del.icio.us. look up in del.icio.us.
add to furl
def varargs(arg1, *rest)
“Received #{arg1} and #{rest.join(', ')}”
end
varargs("one") #=>"Received one and "
varargs("one","two") #=>"Received one and two"
varargs("one","two","three") #=>"Received one and two, three"
以上代码出自《programming ruby 中文版》p80 class TaxCalculator
def initialize(name,&block)
@name,@block = name, block
end
def get_tax(amount)
"#{@name} on #{amount} = #{@block.call(amount)}"
end
end
tc = TaxCalculator.new("Sales tax"){|amt| amt * 0.075}
tc.get_tax(100) #=>"Sales tax on 100 = 7.5"
tc.get_tax(200) #=>"Sales tax on 250 = 18.75"
以上代码出自《programming ruby 中文版》p81 def method(id,option={})
...
end method(5,key1=>value1,key2=>value2,...)
add to del.icio.us. look up in del.icio.us.
add to furl
def a_method_to_insult_innocent_people
error = compute_error
if error == :stupid
return false, "You made a stupid error"
elsif error == :ridiculous
return false, "You made a ridiculous error"
elsif error == :worst_of_all_time
return false, "You made the most idiot error in history. Way to go…"
else
return true, "You made no error, you are still an idiot"
end
end
success, msg = a_method_to_insult_innocent_people
do_something_with_success(success)
destroy_hateful_words!(msg)
但是这段代码还是只能返回一个结果,如何实现返回多个值呢,很简单,使用数组来实现,只要把上面这段代码中的- return false, "you made a stupid error"- 修改为 *return [false, "you made a stupid error"]*就可以了。
记录记录以备不时之需。
add to del.icio.us. look up in del.icio.us.
add to furl
send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'
这里只是一个例子,真实的使用中,你可以把一个文件的信息存放在数据库里面,然后下载的时候就可以根据每个文件来指定上述的值了,如下:
def attachment
@attachment = Attachment.find(params[:id])
@attachment.update_attribute(:downloads,@attachment.downloads+1)
send_file @attachment.filepath, :type => @attachment.filetype, :disposition => 'inline'
end
很棒,不是么~
add to del.icio.us. look up in del.icio.us.
add to furl
Magick::read("image.jpg") do |f|
f.write("manipulated.jpg")
end
*mini_magick*是把ImageMagick进行的一次封装,使得可以很方便的使用MiniMagick的commandline,可以在http://www.imagemagick.org/script/mogrify.php 查看可耕多的ImageMagick has 信息。
*mini_magick*1.2.2包含如下更新:
# 1.) all image commands return the image object (The output of the last command is saved in @output)
# 2.) identify doesn't trip over strangley named files
# 3.) TempFile uses file extention now (Thanks http://marsorange.com/archives/of-mogrify-ruby-tempfile-dynamic-class-definitions)
# 4.) identify commands escape output path correctly
add to del.icio.us. look up in del.icio.us.
add to furl
1. >> Time.days_in_month(4) => 30
2. >> Time.days_in_month(4,2006) => 30
3. >> Time.days_in_month(2,2006) => 28
4. >> Time.days_in_month(2) => 28
5. >> Time.days_in_month(2,2008) => 29
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
require 'rubygems'
require 'youtube'
youtube = YouTube::Client.new 'DEVELOPER_ID'
profile = youtube.profile('br0wnpunk')
puts "age: " + profile.age.to_s
favorites = youtube.favorite_videos('br0wnpunk')
puts "number of favorite videos: " + favorites.size.to_s
friends = youtube.friends('paolodona')
puts "number of friends: " + friends.size.to_s
puts "friend name: " + friends[0].user
videos = youtube.videos_by_tag('iron maiden')
puts "number of videos by tag iron maiden: " + videos.size.to_s
videos = youtube.videos_by_user('whytheluckystiff')
puts "number of videos by why: " + videos.size.to_s
puts "title: " + videos[0].title
videos = youtube.featured_videos
puts "number of featured videos: " + videos.size.to_s
puts "title: " + videos[0].title
puts "url: " + videos[0].url
puts "embed url: " + videos[0].embed_url
puts "embed html: \n" + videos[0].embed_html
details = youtube.video_details(videos[0])
puts "detailed description: " + details.description
puts "thumbnail url: " + details.thumbnail_url
附件是这个lib包。
更多信息请参考:
RDOC : http://youtube.shanesbrain.net/
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
class ExampleController < AppplicationController
def index
render :layout => ‘my_layout’
end
def list
end
end
*2. controller级别的控制*。很多情况下,需要对同一个controller中的所有或者大多数method应用一个layout。那么我们可以在controller级别上来定义layout
class ExampleController < AppplicationController
layout 'my_layout', :except => rss
# layout :my_def_layout
# layout proc{|c| …}
def index
end
def list
end
end
我们可以使用layout函数的三种方式来处理对应的情况。
*3. application级别的控制*。因为所有的controller都是继承于ApplicationController, 所以要在application的级别控制layout, 我们只要把2中的layout定义上升到ApplicationController class。比如对于应用程序而言,XMLHttpRequest不需要layout, 那么
class ApplicationController < ActionController::Base
layout proc{ |c| c.request.xhr? ? false : "application" }
end
在以后我们将说说在layout中怎么插入多部分内容。
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
themes_root = "D:/gem"
glob = "#{themes_root}/[a-zA-Z0-9]*"
@theme_cache = Dir.glob(glob).select do |file|
File.readable?("#{file}/readme.txt")
end.compact
p @theme_cache
还有一系列的延伸,请参考ruby手册。
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
The Ruby.NET project has been relocated to Google code, under a BSD license.
The Ruby.NET project’s goal is to create a compiler for the Ruby language that targets the Microsoft .NET CLR. There is currently support (at various stages of maturity) for the core language, including the built-in Ruby classes such as Class, Object, Array, String and the built-in Ruby modules such as Math and Kernel. However other Ruby libraries that commonly ship with the Ruby distribution, such as CGI and DBM are yet to be implemented.
There is also a mailing list , where a recent thread explored some of the differences between this project and Microsoft’s IronRuby. Perhaps the most notable is that you, dear coder, can contribute to Ruby.NET.
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
Two years ago today, Scott Barron published the first episode of the Ruby on Rails Podcast. —Geoffrey Grosenbach
Wow, has it been two years already? Geoffrey’s been a major positive force in the Rails community even longer then that, starting with the humble Pluralizer, which helped us all figure out what table names our ActiveRecord models were supposed to be using. For his next podcast, he’s turning the tables and letting himself be interviewed by Dan Benjamin. Be sure to send in some challenging questions (see Geoffrey’s blog post for details).
Congrats on the milestone, Geoffrey, Scott, and everyone else that’s been involved with the Rails Podcast!
add to del.icio.us. look up in del.icio.us.
add to furl
The hackfest is back! In sleek new form, the ‘fest runs monthly, starting now.
Without further ado: it’s on. Two weeks to go. Sprint!
Thanks to Working With Rails for making this an integral part of their site; thanks to O’Reilly for signing on as the first sponsor (first prize is a free pass to RailsConf Europe); and thanks to you for contributing the patches and bugfixes that keep Rails at the top of its game.
Go, go!
add to del.icio.us. look up in del.icio.us.
add to furl
ActiveReload has just released Warehouse, a simple subversion browser written using Rails. It sports a beautiful UI and can handle the mundane task of user and permission management for you. It’s also being distributed in a unique fashion for most Rails applications. Instead of being hosted, it is sold and downloaded to be installed on your own server.
If you’re interested, check us out at the Warehouse site.
add to del.icio.us. look up in del.icio.us.
add to furl
Michel Barbosa has completed his bachelor thesis Delivery of the Key Adoption Factors and Key Characteristics of Companies Using Ruby on Rails. It presents research he has done and conclusions the why and who of switchers.
I’m happy to see that “Joy in Development” was a key adoption factor for 92% of the people interviewed.
add to del.icio.us. look up in del.icio.us.
add to furl
Jason Perry has started a survey at http://railsforge.com/, asking for community feedback on whether a Rails-specific forge-site would be useful or not. What are your thoughts? Head on over and let him know!
add to del.icio.us. look up in del.icio.us.
add to furl
Registration for RailsConf Europe 2007 has opened up. It’s all going down in Berlin, Germany from September 17th through 19th. There’s a ton of great speakers lined up, so we’ll undoubtedly have one heck of a party there. Really hope to see as many as possible there.
add to del.icio.us. look up in del.icio.us.
add to furl
Rails to Italy is gathering the Italian Rails community in Pisa from October 26th through 27th. They’re open for registration and are still looking for speakers. The price to participate is €89 for registrations done before August 1st.
add to del.icio.us. look up in del.icio.us.
add to furl
Zilia Iskoujina is a PhD student from the UK who’s doing research on Knowledge management and innovation in virtual organisations. As part of that, a questionaire for people working in open source has been created. If you have 15 minutes, consider filling it out.
add to del.icio.us. look up in del.icio.us.
add to furl
The Haml team recently announced the release of Haml 1.7, which is an alternative markup system that you can use in Rails, instead of the default ERb-based markup. Version 1.7 is significantly faster than previous releases (and is almost as fast as Rails’ default system, now!). There are a few other new features, too: read all about it in the release notes. Great work!
add to del.icio.us. look up in del.icio.us.
add to furl
I am such a chicken. I very much wanted the next release of Capistrano to be the official “Capistrano 2.0” release. But as I watched the changelog grow, I started to get cold feet.
Thus, tonight I announce the fourth (and final, hopefully!) preview release of Capistrano 2.0. As before, you can grab it from the Rails beta gems server:
gem install -s http://gems.rubyonrails.com capistrano
(What is Capistrano, you ask? Allow me to direct your attention to http://www.capify.org...)
The following items are just some of the changes new in preview #4:
You can see the entire list of changes in the CHANGELOG.
So, give it a go. Try it out. Post your feedback to the Capistrano mailing list. I’d love to release cap2 final next week!
P.S. If you are on a Windows machine, and you get Zlib errors trying to install the Capistrano gem, try this. Find the rubygems/package.rb file (wherever it happens to be in your Ruby installation), open it up, and find the zipped_stream method. Then, replace it, wholesale, with the following:
def zipped_stream(entry)
entry.read(10) # skip the gzip header
zis = Zlib::Inflate.new(-Zlib::MAX_WBITS)
is = StringIO.new(zis.inflate(entry.read))
ensure
zis.finish if zis
end
That seems to do the trick for me; let me know if it doesn’t work for you.
add to del.icio.us. look up in del.icio.us.
add to furl
Alright, we’re nearing the finish line! Capistrano 2.0 Preview Release #3 is now available.
Capistrano is a utility for automating the execution of tasks on one or more remote machines. You can read all about it at www.capify.org.
To install Preview #3, you’ll need to grab it from the Rails beta gem server:
gem install -s http://gems.rubyonrails.org capistrano
Accompanying PR3 is a new page of documentation on the capify.org site: Capistrano Basics. This walks you through the major features of Capistrano, but does not touch on deployment. This makes it a great introduction for those wanting to use Capistrano in non-deployment scenarios.
Preview #3 includes the following changes and enchancements:
Feature: Mercurial and CVS are now supported out of the box. Just set your :scm variable to :mercurial or :cvs, like so:
set :scm, :mercurial # or set :scm, :cvs
Thanks to Tobias Luetke and Matthew Elder for the Mercurial module, and Brian Phillips for the CVS module.
Feature: There is now a :default_environment variable, which is a hash that can be used to set environment variables that should be present for all commands that are executed. For instance:
default_environment["PATH"] = "/bin:/usr/bin:/usr/local/bin:/home/jamis/bin"
Feature: All commands are now explicitly invoked via “sh”, which means that even if your default user shell is non-POSIX (e.g., tcsh, csh, etc.), you can use Capistrano just fine. Note that if you were using tcsh or csh syntax in your Capistrano scripts, you now need to set the :default_shell variable to use your (non-POSIX) shell of choice:
set :default_shell, "/usr/bin/tcsh"
Feature: You can declare empty roles, and Capistrano won’t complain. This is useful for predeclaring roles that need to exist (because task definitions depend on them), but which might not have any servers in them (depending on runtime conditions).
Feature: A username and port specified with the server definition (e.g., “fred@some.server.com:1234”) now take precedence over the :username and :port settings in the ssh_options hash, rather than the other way around. This lets you set a general default via ssh_options, and override on a per-server basis in the server definitions themselves.
There are several other minor changes and fixes as well; you can read the CHANGELOG for all the gory details.
add to del.icio.us. look up in del.icio.us.
add to furl
The Berlin Ruby User Group is throwing a pre-RailsConf party under the banner of Bratwurst on Rails.
The Ruby User Group Berlin is one of the biggest in Germany and therefore we’re pleased to organize an event on the night before the RailsConf Europe. In the tradition of last year’s “Pizza on Rails” the event is called “Bratwurst On Rails.”
The event is an opportunity to socialize and meet the conference participants in a relaxed atmosphere, and to make your name or brand known amongst them. Tighten your knots with the community by becoming a sponsor.
The venue will be in the heart of Berlin, close to the conference venue. Entry will be free, as will the food. (If you’re interested in sponsoring, have a look at our sponsoring packages and feel free to contact the organisation board via sponsoring@bratwurst-on-rails.com).
add to del.icio.us. look up in del.icio.us.
add to furl
A million yen ($8,300) is the first price for a new application competition called Award on Rails that starts tomorrow. The competition is sponsored by DRECOM and will run from July 2nd until September 25th. While the show is based in Japan, they’ll be accepting entries from all over the world. Read all about the rules and the sponsors or sign up to participate. Good luck!
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
uncov is a consistent source of heavy mirth.
From today’s post:
Ikan claims that their product will revolutionize your grocery shopping. I have done this once before, but let’s talk one more time about the definition of “revolutionary”:
- Modern pesticides: revolutionary
- Automated crop irrigation systems: revolutionary
- Worldwide shipping networks that make all vegetables “in-season” regardless of where you are on the planet: revolutionary
- Making a grocery list by scanning barcodes and shit: NOT REVOLUTIONARY.
add to del.icio.us. look up in del.icio.us.
add to furl
I found this by way of the Haskell Cafe list: How to Help Mailing Lists Help Readers
Interesting observations on helping newbies in a programming community.
Shame he didn’t survey the ruby-talk list; he would have found a much higher level of newbie support
add to del.icio.us. look up in del.icio.us.
add to furl
I like a good amount of what Lennon did, but this quote from This idiocy is all John Lennon’s fault is dead on:
Lennon invented the pop star as conscientious rebel, a fog that has enveloped others in the years since. In fact, pop music, rock music, call it what you will, is essentially conservative. People conform to certain types, and one of those types is “the rebel”, who considers himself to be some sort of anti-establishment character because he wears a leather jacket, drops his Hs, and swears in interviews.
add to del.icio.us. look up in del.icio.us.
add to furl
IDC predicts the market for open-source software will reach some six billion dollars in 2011. No wonder the VCs are getting anxious to play on that roulette.
Which brings me to why there's no Rails Inc. It certainly isn't for lack of VCs wanting to fund. I've had more than a handful conversations with various outfits eager to pour big money into such an operation, but I'm just not interested.
There are many reasons not to be interested in VC money these days, but let's just give two specific ones for Rails.
First, Rails is not my job. I don't want it to be my job. The best frameworks are in my opinion extracted, not envisioned. And the best way to extract is first to actually do.
That's really hard if your full-time job is just the extraction part since you now have to come up with contrived examples or merely live off the short bursts of consulting. For some that might work, but I find that all my best ideas and APIs come from working on a real project for a sustained period of time.
Second, the growth of the Rails ecosystem has been staggering. There are so many shops out there offering Rails consulting and training. I believe part of that proliferation is due to the fact that there's no core-group monopoly that can dominate the market.
I believe a Rails Inc consisting of a large group of core committers would have an unfair advantage in the training and consulting space — easily siphoning off all the best juice and leaving little for anything else. There are plenty of examples in our industry of that happening around open source tools.
It's much more satisfying to see a broader pool of companies all competing on a level playing field.
add to del.icio.us. look up in del.icio.us.
add to furl
Loud Thinking is down for the count while the server that held it up for the past six years is in ICU. Hopefully it'll make it through and allow the archives to appear unscathed. But if not, we'll deal with that too. Currently I have from June '05 and backwards recovered..
Nothing like a little forced Spring cleaning to get the cruft moved out.
But if you sent me any email to the loudthinking address over the past 3-4 days, it might not have made it. So if it was important, please do shoot it over again.
add to del.icio.us. look up in del.icio.us.
add to furl
There are some "Christians" who give the rest of us a bad name. Some TV-preacher jack-ass called Bill Keller is one of them. He's going off on Mitt Romney for being a member of a "cult" and being evil and having a forked tongue, a bifurcated tail and carrying a hay-fork. Yeah, he doesn't like Mormons. I just love hearing so-called "Christians" joyously telling everyone who will listen how someone else is "going to hell."
add to del.icio.us. look up in del.icio.us.
add to furl
I’ve tried using the built-in IDE for DrScheme but my fingers want to viminate the code.
To do the vim thing (gvim, actually), I first wanted to know how to call my scheme code from the command line.
A short Google, and presto:
$ mzscheme -r foobar.scm
Next, because shifting from editor to terminal is suspiciously like work, I looked around for a nice way to map this to a keyboard command.
My first poke was something like this:
map ss <ESC>:! mzscheme -r %<CR>
That worked, but it wasn’t really making my day. I would prefer to have the results in a new buffer. I then found this on vim.org:
function! TabMessage(cmd)
redir => message
silent execute a:cmd
redir END
tabnew
silent put=message
set nomodified
endfunction
command! -nargs=+ -complete=command TabMessage call TabMessage(<q-args>)
I combined that with the previous mapping to create this:
map ss <ESC>:TabMessage ! mzscheme -r % <CR><ESC>: % s/\r//g<CR>
(I needed that last part because I was seeing ^M in the results.)
Very cool. However, while vim7 has tabs, I’ve not gotten used to using them. I tend to just have many instances of gvim floating around. I think that’s because I’m used to navigating tabs a certain way in Firefox. And my vim habits started with vim5.
Given the “bang output in a tab” macro, I decide to go figure out the proper tab navigation commands and just make myself learn them. But, no need: Kim Schulz wrote up mappings to do Firefox-style tab-nav in vim:
" tab navigation like firefox
:nmap <C-S-tab> :tabprevious<cr>
:nmap <C-tab> :tabnext<cr>
:map <C-S-tab> :tabprevious<cr>
:map <C-tab> :tabnext<cr>
:imap <C-S-tab> <ESC>:tabprevious<cr>i
:imap <C-tab> <ESC>:tabnext<cr>i
:nmap <C-t> :tabnew<cr>
:imap <C-t> <ESC>:tabnew<cr>
Quite the slickness.
add to del.icio.us. look up in del.icio.us.
add to furl
Fellow Zonie Robin Harris, who writes the excellant Storage MoJo blog, has posted links for the videos from the recent Seattle Conference on Scalability .
I’ve read good things about what was presented there and look forward to watching these (though it seems that not all the presentations are up on Google video).
add to del.icio.us. look up in del.icio.us.
add to furl
I never thought I'd be cheering for Barney Frank, but the Congressman has introduced legislation that would make the UIGEA unenforceable. For those of you who haven't been following this, the UIGEA is a law that was passed last year that effectively killed online poker in the US. The august Bill Frist snuck the UIGEA on the tail-end of a must-pass "port security" bill and thus it was passed without any discussion. What an ass-clown. So now Frank has introduced legislation that, if passed, would bring online poker back to the US.
Let's hope it passes. I'm not sure how much of a chance it has, but it's at least forward progress.
add to del.icio.us. look up in del.icio.us.
add to furl
Being at the end of a UPS route is hard. Tuesday morning I saw from the UPS website that my third set of RAM from Crucial was "out for delivery" from the local hub. What this means is that it's on a truck, heading for my house. Unfortunately, we're at the tail-end of said route, and I have yet to receive a UPS delivery before 4:00 PM. We were going to be leaving around 5:00 and since UPS is a "drop and run" courier, if it got there after we left, it would have been sitting on the porch for several hours until we got home. Fortunately, it arrived about 4:45. So it got inside the house, but wouldn't get inside the Mac until later.
When I got home Tuesday night, I installed the RAM. So far, it's working perfectly. Of course, the first set worked perfectly for a week or so, so I'll have to just keep an eye on it. Thus, once again, my Activity Monitor looks like this
add to del.icio.us. look up in del.icio.us.
add to furl
There's a little golf store near my house. I've now tried three times to patronize them, but each time I've been thwarted. The first time I tried to visit them, was on a Monday. When I got there, I discovered that they were closed on both Sunday and Monday. Strike 1. The second time, I went on a Wednesday. They closed at 6:00PM. Who closes that early any more? Strike 2. Today, I tried again. I got there at 12:30, only to find a hand-written sign taped to the glass: Bank + Lunch. Back 1:45 - 2:30.
Strike 3.
I guess I'll just have to keep schlepping over to the PGA Tour Superstore for my golfing needs.
The lesson here is this: if you have a business you need to be open when your customers try to visit. I don't care how good the store is, I'm not going to try a 4th time to visit them.
add to del.icio.us. look up in del.icio.us.
add to furl
Great news! According to this story the Amnesty Bill is dead. Ted Kennedy said the defeat was "enormously disappointing for Congress and for the country." I have to say that anything that is disappointing for Kennedy is good for the rest of us.
Kennedy then added "We will be back. This issue is not going away." We need to remember this threat. Bush and Kennedy will not be happy until this monstrosity is law, and the hordes of illegal Mexicans are welcomed as citizens.
add to del.icio.us. look up in del.icio.us.
add to furl
Remember that point about Rails lacking an easy-to-use way of dealing with multiple read/write databases? Strike that. Nic Williams has released Magic Multi-Connections. It makes it dead easy to use a cluster of databases to scale read and write speeds higher than a single connection would ever allow.
That in itself is wonderful. Williams let code be his reply to the discussion of Twitter's woes on scaling the database. I would of course rather have seen this work come out of Twitter, but I'm happy that they got a free offering handed to them regardless. They didn't even have to pass step 1 in Brian McCallister's road map for getting stuff fixed in open source. And the turn-around time was within the same day of this whole thing blowing up.
Now how could this be. How could Nic fix such an apparent "critical flaw", as others have billed the lack of this facility in Rails, in such a short time? Simple, he did it in less than 75 lines of Ruby as a plugin for Rails. Less than 75 lines.
In my mind, that's the crux of the story. That extending Rails to do what you want is often much simpler than you think. That you can't compare extending a high-level framework written in a language like Ruby to, say, patching Apache or MySQL. The barriers of entry are simply not in the same sport.
So let's use this occasion to celebrate the wonders of open source ("some times you can just ask and you will receive"), but at the same time keep the effort involved in this example as a guidance for the future ("maybe next time, I could just have a look at how hard it would be to fix myself"). And of course, a big thanks to Nic Williams to making a big fuss a non-issue.
add to del.icio.us. look up in del.icio.us.
add to furl
If you don't like things that mix religion and humor, then don't watch the video below. If you do have a sense of humor, then press on. It's hilarious.
add to del.icio.us. look up in del.icio.us.
add to furl
I’ve mentioned it to some people in the Phoenix tech crowd, but thought I should mention it here, too.
I’m quite pleased to say that I’ve joined Rising Tide Software.
If you’re curious, you can get an idea of the culture behind the company from David’s recent post.
We’re a wicked cool team of skilled, smart people, so keep an eye on future announcements.
add to del.icio.us. look up in del.icio.us.
add to furl
I've actually never been to Berlin before, so I'm excited to get the chance to not only see one of the great cities of Europe, but at the same time share in a meeting with the Rails community in Europe and around for RailsConf Europe 2007. The doors for registration have just been opened and until August 6th, the price is €645 (after that, it jumps to €795).
I really had a smashing time last year in London. There was somehow more time to get into more discussions with people than the more hectic version in the US. And I got to premiere a bunch of new Rails features I had been working on over the Summer.
So I hope to see a lot of the familiar faces from last year and new ones too when we convene from September 17th through 19th in Germany.
add to del.icio.us. look up in del.icio.us.
add to furl
Some well-done vids at Cannes Lions Live
(found via Reddit)
add to del.icio.us. look up in del.icio.us.
add to furl
Super happy Phoenix Dev House has arrived.

Sweet logo. ;)
Saturday August 4th, 2pm – 1am
21469 East Lords Way, Queen Creek AZ
Only an hour drive from my home.
Phoenix Dev House hopes to become the greater metro Phoenix premier hackathon event mimicking the now famous Bay Area SuperHappyDevHouse.We’re about rapid development, ad-hoc collaboration, and cross pollination. Whether you’re a l33t hax0r, hardcore coder, or passionate designer, if you enjoy software and technology development, Phoenix Dev House is for you. Code in Ruby? PHP? Java? .NET? Perl? It doesn’t matter.
Phoenix Dev House is not a marketing event. It’s a non-exclusive event intended for passionate and creative technical people that want to have some fun, learn new things, and meet new people. In this way, we’re trying to resurrect the spirit of the Homebrew Computer Club. We also draw inspiration from the demoscene as one of the only intentional getting-things-done computer events in the world.add to del.icio.us. look up in del.icio.us.
add to furl

Three friends and I went up to the Chateau Elan, Par 3 yesterday for my second golf outing. While my score didn't improve that much (a 51, down from 53), I felt like I played better, in terms of mechanics. I had just as much fun as the first time, even though it was about 8 degrees hotter.
Also of note is that I was playing with new grips on my irons. As I mentioned before I took my clubs to the PGA Tour Superstore and got some pretty, red Lamkin Crossline grips put on, which made a nice change. It was almost like getting a new set of clubs, at a fraction of the cost. Here's what it looks like
I'm playing this same course again tomorrow (Tuesday), so maybe I'll shave a few more strokes off my score.
add to del.icio.us. look up in del.icio.us.
add to furl
I said before that my Mac Pro was fast. But lately it's been bogging down a bit when I have lots of apps open. Especially if I am using Parallels.
But UPS just arrived with a little shipment from Crucial: another 2GB of RAM. O, glorious day! Notice the screenshot of my activity meter:
add to del.icio.us. look up in del.icio.us.
add to furl
I played golf last Sunday for the first time in many years. We went to the 9 Hole, Par 3 course up at Chateau Elan and had a great time. I shot nearly 2x par, but for not having played in so long, I think that qualifies as "not that bad." Here's the score card:
The 9th hole was the fun one. You have to hit over a lake to get to the green. The first shot each of us took, we put the ball straight into the water. My second shot, with a 3 wood, was beautiful: straight, high and long. The ball landed on the green, about 20 feet from the hole. Putting was another story, but it was fun to make such a nice tee shot.
The hardest hole was 5. You have to skirt a lake, and that wasn't easy. I lost three balls in that lake.
I went to the PGA Tour Superstore in Duluth on Saturday and bought a new golf bag. It's quite nice, with lots of pockets and dividers and such, and these auto-retracting legs for standing it up. It was on sale, which makes it even better. I also looked at grips and talked to the guy in the club-building department about getting mine regripped. I'm going to take them up there this week to get some new grips put on them, since mine are old, wrapped leather that have slipped and turned.
I can't wait to play again.
add to del.icio.us. look up in del.icio.us.
add to furl
New CPUs are growing in cores and not in GHz. That's a tough problem for applications that have been traditionally single-threaded, like games. They have to learn all new techniques and rework their thinking to get the most out of the next-generation platforms.
But the fear of that transition has bled into places where it's largely not relevant, like web-application development. Which has caused quite a few folks to pontificate that the sky is falling for Rails because we're not big on using threads. It isn't.
Multiple cores are laughably easy to utilize for web applications because our problems are rarely in the speed of serving 1 request. The problem is in serving thousands or tens or hundreds of thousands of requests. Preferably per second.
Threads are not the only way to do that. Processes do the job nearly as well with a drop of the complexity. And that's exactly how Rails is scaling to use all the cores you can throw at it.
The 37signals suite is currently using some ~25 cores for the application servers that all the applications have dips on. We'd welcome a 64-core chip any day.
Read more: A good summary of a discussion on multi-core programming in general.
add to del.icio.us. look up in del.icio.us.
add to furl
You may remember how excited I was about a month ago when I got the 2GB RAM upgrade from Crucial for my Mac Pro. Well, about two weeks ago I happened to notice in Activity Monitor that I only had 3GB of RAM. That wasn't right; I had 4GB. I started testing, and discovered a problem with the RAM. System Profiler was reporting 6 512MB sticks of RAM, instead of 4 512MB and 2 1GB sticks. I tried moving the sticks around to various banks, but never got it to see more than 3GB. Also, there are four LED's on each of the risers that correspond to the four RAM banks. When you boot the system, these lights come on for about 2 seconds, then go out. There was one Crucial stick whose LED stayed on. No matter which bank I put that stick in, its light stayed on.
Saddened by this, I called Crucial. I spent just a few minutes on the phone with them before they agreed that there was clearly a problem, and that they would replace them. They have excellent customer and technical support. I shipped the two sticks back to them and waited.
Two days ago UPS arrived with my replacement sticks. I shut down my Mac and put the two new sticks in banks 3 and 4 of riser A, leaving the 512MB sticks in banks 1 and 2 of risers A and B, and booted. I logged-in, brought up Activity Monitor, only to see 3GB reported. System Profiler says 6 512MB sticks, just like before. The new RAM is doing exactly what the first set of RAM did. I tried every combination of placement of the sticks I could think of, including removing ALL the Apple RAM, and just putting the Crucial sticks into banks 1 and 2 of riser A. In that case, the Mac only saw 1G of RAM.
So it was back to Crucial tech support. They agreed it sounded like a bad stick (again) and are going to replace them again. I just shipped back the two latest sticks, and am once again waiting on a shipment from Crucial. I hope this one works. If it doesn't, I'm just going to pony up the 2x extra and buy direct from Apple.
The Crucial guy said it was "hard to believe" that I got two bad sticks in a row, and I agree. But what else could it be? If I only had two banks for RAM in the computer, then you could blame it on the computer itself. But I've got eight banks to play with, and have tried them all. I don't think it's a problem with the Mac itself. I could be wrong, but I don't think so.
add to del.icio.us. look up in del.icio.us.
add to furl
Last night I saw a link to a clip of Ann Coulter apparently saying very nasty things about John Edwards. After watching it, I was fully prepared to write her off as having gone from being edgy, to going over the edge. The Internet is aflame today with liberals in shock and amazement at what Ann "said." According to the, in this case, apt-named Crooks and Liars
And Coulter herself said, "if I'm going to say anything about John Edwards in the future, I'll just wish he had been killed in a terrorist assassination plot."Based on that statement, it sure sounds like Ann has gone over the edge and should be denounced by everyone. I had my pitchfork ready to go.
But not so fast. Today, I found the full interview that provides the context for her apparently-insensitive statement. Go watch both and come back. I'll wait.
[Time passes.]
Notice the really important line of context leading up to the "slur?" The full quote is
... but at the same time, you know Bill Maher was not joking and saying he wished Dick Cheney had been killed in a terrorist attack. So I've learned my lesson, if I'm going to say anything about John Edwards in the future, I'll just wish he had been killed in a terrorist assassination plot.That context changes things, doesn't it? It always does.
add to del.icio.us. look up in del.icio.us.
add to furl
I was at Borders the other day, and I happened to see a book called Learn the Bible in 24 Hours. Yeah, I'm sure that's possible.
Anyway, I was discussing it with my friend Fred and we started coming up with other funny "learn the Bible" book titles, such as
add to del.icio.us. look up in del.icio.us.
add to furl
It's just after midnight on June 26. Kelly Willis' new album, Translated From Love was just made available on the iTMS, and since I pre-ordered it, it was a-waiting for me to download it. Oh, yeah. I'm four songs into it, and it's really good. I have all of Kelly's stuff, but the last two, Easy and What I Deserve, have been my favorites. Based on what I've heard so far, they may have some competition with this album.
Kelly's voice is just as smooth and luscious as always. She has that Austin twang, and her music is about as far as you can get from the "pop country" that passes for C&W these days. Kelly, Mindy Smith and Neko Case are my favorite ladies. You should check them out.
Kelly is coming to Atlanta on July 7! I went ahead and bought my ticket the other day, after I got hosed on the Mindy Smith show selling out. I was not pleased about that. I love both these ladies' music, and I really wanted to see Mindy. Oh well, at least I'm assured of seeing Kelly.
add to del.icio.us. look up in del.icio.us.
add to furl
Today's my birthday, and now I can truthfully quote Dennis from Holy Grail
I'm thirty-seven; I'm not old!That should make for hours of entertainment.
I last played golf about 20 years ago. For some reason, about six weeks ago, I started having the urge to play again. So, using money given for my birthday, I'm going to get me some golf schoolin'. My first lesson with the local golf pro is Saturday. I am supposed to play with some friends later in the month at Chateau Elan and I'd rather not look like a complete idiot. Hopefully the lessons will prevent that. :-)
add to del.icio.us. look up in del.icio.us.
add to furl
George Orwell would be so proud of this. HBO's CTO recently said he no longer wants to use the term DRM, Digital Rights Management, for how they copy-protect their content. Instead, he prefers the term DCE, Digital Consumer Enablement (emphasis mine). Referring to a technology that limits what I can do with content as something that "enables" my use... well... that's just double-plus good, isn't it?
add to del.icio.us. look up in del.icio.us.
add to furl
I had my first golf lesson on Saturday. It was fun, and I wasn't starting out as terrible as I had imagined. We started out working on swing mechanics without a ball present, but once we moved up to using a ball, only once did I swing and completely miss the ball. Every other swing made contact; it was just the quality of the hit that changed. There were a few rollers and a few "D'oh!" moments, but for the most part, I got some good hits.
My right biceps is still sore from Saturday, too. I need to stretch out before-hand next time more. Bob showed me some stretching exercises to do, I just didn't take the time to actually do them so they could stretch me out. I'll know better next time.
The clubs I have are a mixture of ancient and not-quite-so-ancient. The two woods I have are from a set my parents gave me back in the mid-eighties. The irons are some that my wife bought from a neighbor's yard sale a few years ago. Bob said that the irons (Ram) were quite good, but the woods were "going to put you [me] at a disadvantage." The problem, he said, was that the faces on them were so small that you get no margin for error. He said that modern woods are three to four times as large, and he would recommend getting something else. We did hit some with the driver, but he was right about margin for error. So yesterday I went to my local Play It Again Sports store and picked up a new 1 and 3 "wood" that had enormous faces and heads that are far, far larger than my old ones. I'll give them a try tonight. And I put "wood" in quotes because there's not a scrap of anything resembling wood on them. It's all aluminum and carbon and such. Or something. I don't know what they really are made of, but it's definitely not wood.
I've got a second lesson scheduled for this Saturday and I need to practice some this week. I'm going to try to get to the driving range tonight and at least one more time before Saturday.
add to del.icio.us. look up in del.icio.us.
add to furl
Reading about the carbon footprint of those participating in the Live Earth concerts makes me think that it’s a bit like PETA holding a promotional barbecue.
add to del.icio.us. look up in del.icio.us.
add to furl
I used to fence in high school. It's such an elegant sport. Yes, stamina, agility, and even strength are elements, but fencing foil is so much more about technique. A small rotation of the wrist is all it takes to parry an attack and you're all set for riposte.
I relearned that last Wednesday when I went my first fencing class in more than a decade. Most of the footwork was still imprinted in my memory, but that was the easy part. The hard part was realizing just how much technique I had lost as I was getting schooled by a 7 year-old girl.
Which is of course also one of the wonders of fencing. It allows for such a wide range of physical attributes to enjoy it together. In the small group that was at the session that night, it ranged from Alexa, 7 to a 50-something Argentinean. With a few teenagers and me in between.
So lots of fun, but I'm also grateful that there's a full week between sessions on the beginner's team. It's taken at least half that to be able to walk without pain again. Nothing like exercising muscles that have laid dormant since Jurassic Park was a box office hit.
add to del.icio.us. look up in del.icio.us.
add to furl
A few days ago I went by the grocery store. One of the things I picked up were some 12-packs of soda. I had three 12-packs in my cart when I went to check-out, and the clerk said that they had a special running: 4 12-packs for $10, and you got three 2-liters for free. It made sense for me to go get some more soda, so I did.
When I got home, I was able to get everything except two of the 12-packs in one trip, with the intention of coming back out for the other two. But something happened, and I never made it back out. The 2 12-packs in question were in the back floorboard, out of direct sunlight, so I didn't see a problem.
The next day, Thomas and I were going somewhere. I opened his door for him, and noticed that the 2 12-packs were obstructing his leg-room. I moved one of the 12-packs to the back seat, behind the passenger seat, and off we went.
On Friday morning, I needed to run an errand. I went out to my car, got in and started it up. I noticed a strange smell, but couldn't quite place it. I then turned around and saw a 12-pack of Pepsi One on the back seat. Actually, I should say I noticed the remnants of a 12-pack of Pepsi One on the back seat. Remnants, because the whole bloody thing had exploded all over the inside of my car. It was then that I noticed the brown spots all over the car: the ceiling, the sunroof, the back window, the side windows, the windshield, the back seat, the backs of the front seats. Yes, pretty much everywhere that could have gotten splattered did.
I got out, went back in the house and got Thomas to come out and see the carnage. He was amused. I have to say, I was, too. I just couldn't help but laugh at this absurd occurrence. I got the remnants out, and as I gently dropped it down onto the driveway, another can exploded. It missed me, but barely. There were three others that looked like they were near the bursting point, so I carefully knocked the side of each one against the edge of the driveway to puncture it in a "controlled" fashion.
So, of a 12-pack, 8 exploded in the car, one on its own, and three via "controlled detonation."
The lesson to be learned: if you live in the South, don't leave sodas in your car on hot Summer days.
add to del.icio.us. look up in del.icio.us.
add to furl
Going from five to sixteen hundred people is a big risk for a conference. There's so much to lose: The atmosphere, the coherence of content, and the interestingness of the people. But in my mind we didn't, RailsConf 2007 was a roaring success.
There were so many great debates going on, so much fascinating work happening, and so extraordinary tales of adoption. It was wonderful to meet up with people like Martin Fowler,
Ward Cunningham, Tim Bray, Dave Thomas, Robert Martin, and other industry leaders.
But in many ways, even more wonderful was the level of involvement from everyone else. I remember RubyConf '03 when we just had a couple of people doing professional Ruby work. This year at RailsConf more than half the room raised their hand when I asked how many were working professionally with Rails. What a leap.
So many people doing applications in all niches and of all shades. Plenty of startups, naturally, but also plenty of so-called enterprise operations. From banks to insurance companies. ThoughtWorks announcing that 40% of all new business in the US is Ruby on Rails projects. Wow.
I loved the fact that it wasn't all about the nitty gritty stuff either. We had an Extra Action marching band that pushed the comfort level of many on the fun side of things.
And on the more serious side, Alan Francis explored the similarities between the Rails and XP movements on a higher plane of approach, angry teenager-tendencies, and peaks.
I also much enjoyed the fact that it was broader than just Ruby and Rails circle. That we had Avi Bryant talk to us about this magical parallel universe of Smalltalk. And that we attracted people like Scott Hanselman from the .NET world (and that he posed plenty of opposing opinion that we sorta captured in a podcast with Martin Fowler and me).
All in all, a spectacular extended weekend. It made me all the more excited for turning another chapter in the conference book in Berlin come late September with RailsConf Europe.
All photos by the always awesome James Duncan Davidson
add to del.icio.us. look up in del.icio.us.
add to furl
Planning is underway for Desert CodeCamp 2007. It will be held Saturday, September 15th, 2007, at the University of Advancing Technology in Tempe. Presentation proposals are being accepted now (see previous link).
I’d like to give talk, but I’m not sure what I want to talk about.
Here’s what’s running through my mind:
Comments and suggestions invited.
add to del.icio.us. look up in del.icio.us.
add to furl
So I finally had a few spare moments to work on the Loud Thinking machine again. Instead of going with one of the million packages out there, I decided to eat some dog food and just roll my own.
Yes, yes, terribly inefficient from a productivity perspective, but I indulged myself with a learning experience on how it feels to setup a small Rails application from scratch using Ubuntu Fiesty, nginx, Mongrel, and SQLite3.
As a side-effect, I haven't bothered implementing comments for my little machine just yet. And I'm thinking that's actually a blessing in part disguise. I think I'll be happy with the tranquillity for a while.
add to del.icio.us. look up in del.icio.us.
add to furl
Saturday, July 7, 2007.
Show time: 9:00pm. Or so they say.
Well worth your time and trouble to party hearty with the desert rock masters.
Really, how could you pass on this:
Another booty-rockin’, smack-talkin’, party-like-you’re-Christopher-Walken good time from your favorite degenerates at Cold Turkey. Playing with us also is our friends in rock from Rudy’s Arcade. Funkmaster Avedog will be flying all the way from Dallas to ensure the jam is properly funkified.
Nothing beats funkified jam.
Nothing.
July 7, 9pm, Trax, NW corner of 1st St. & Farmer in Tempe (right down the block form the secret liar of the mysterious Dr. Jumpbox), and NO COVER.
add to del.icio.us. look up in del.icio.us.
add to furl
I have been a consistent user of the nightly builds of the WebKit project for some time now. For those of you who don't know, WebKit is essentially the work-in-progress that will be the next production version of Safari. I like the nightlies because they are extremely fast, and while they occasionally have problems, that's OK.
The point of that discussion was to say that I have stopped using Firefox on my Mac, because the nightly builds of WebKit are so much faster. But there's one problem. In Firefox I could click a tab with my middle-mouse button, and it would close. Safari doesn't have that feature, and that's the one feature from Firefox that I really miss.
So, I've been trying to solve this problem using SIMBL. What SIMBL does is let you write a standard Cocoa bundle and have it load into another program, like Safari. Once loaded, you can replace methods in the application with your own versions, in a way known as "method swizzling." I have successfully written a Cocoa bundle, made the approrpriate changes to make it loadable by SIMBL, and have loaded it into Safari/WebKit. I have logging statements at various points in the bundle, and I can see these on the system console, thus I know it's loading.
Once the bundle was loading, I needed to pick the objects and their methods that I thought would be most likely to let me do what I needed, and then swizzle in my changes. Using F-Script Anywhere I was able to identify a single tab as an instance of TabButton. Using class-dump I was able to generate header files for Safari that would let me see the methods on TabButton and it's parents. My first thought was to override mouseUp:. This works, and I can now trap mouse events when you click on any tab. According to the Apple docs, once I get a mouse event, I should be able to call [theEvent buttonNumber] to figure out which button was pressed. Well, maybe. No matter if I clicked with the left- or middle-mouse button, [theEvent buttonNumber] always returned 0. Further digging in the docs turned up an event called NSOtherMouseUp that is sent when a button "other" than left- or right-mouse is clicked. Supposedly, I should be able to override otherMouseUp: to get those events. I have successfully swizzled this method, but it never gets called. I know that TabButton had a version of this method, because when I swizzle, I can tell if there was already a method there, and there was. I'm just not sure why it isn't being called.
So what did I get working? Well, after working a long time trying to get the middle-mouse detection working, I decided to punt for the moment. I added some code to the mouseUp method to check the event for modifiers and if the user held down Command while clicking, then I will close the tab. This is close to what I want, but nearly as sexy as just middle-mouse clicking. In case you're interested, my TabButton.m looks like this:
1 #import "TabButton.h"
2 #import "WebKit/WebKit.h"
3
4 @implementation TabButton (MCCSwizzle)
5 - (void)_mcc_mouseUp:(NSEvent *) theEvent
6 {
7 NSLog(@"_mcc_mouseDown");
8 int buttonNumber = [theEvent buttonNumber];
9
10 NSLog(@"buttonNumber: %d", buttonNumber);
11 NSLog(@"type: %d", [theEvent type]);
12 NSLog(@"modifierFlags: %d", [theEvent modifierFlags]);
13
14 if ([theEvent modifierFlags] & NSCommandKeyMask) {
15 NSLog(@"Cmd-Click!");
16 [self closeTab: theEvent];
17 } else {
18 [self _safari_mouseUp: theEvent];
19 }
20 }
21 @end
and then the swizzling looks like this:
1 #import <WebKit/WebKit.h>
2 #import "AppController.h"
3 #import "MiddleClickClose.h"
4
5 typedef struct objc_method *Method;
6
7 struct objc_method {
8 SEL method_name;
9 char *method_types;
10 IMP method_imp;
11 };
12
13 BOOL MCCRenameSelector(Class _class, SEL _oldSelector, SEL _newSelector)
14 {
15 NSLog(@"OLD: %s", _oldSelector);
16 NSLog(@"NEW: %s", _newSelector);
17
18 Method method = nil;
19
20 // Look for the methods
21 method = (Method)class_getInstanceMethod(_class, _oldSelector);
22 if (method == nil)
23 return NO;
24
25 // Point the method to a new function
26 method->method_name = _newSelector;
27 return YES;
28 }
29
30 @implementation MiddleClickClose
31 + (void) load
32 {
33 int rc;
34
35 rc = MCCRenameSelector([TabButton class], @selector(mouseUp:),
36 @selector (_safari_mouseUp:));
37 NSLog(@"RC: %d", rc);
38
39 rc = MCCRenameSelector([TabButton class], @selector(_mcc_mouseUp:),
40 @selector(mouseUp:));
41 NSLog(@"RC: %d", rc);
42
43 rc = MCCRenameSelector([TabButton class], @selector(rightMouseUp:),
44 @selector (_safari_rightMouseUp:));
45 NSLog(@"RC: %d", rc);
46
47 rc = MCCRenameSelector([TabButton class], @selector(_mcc_rightMouseUp:),
48 @selector(rightMouseUp:));
49 NSLog(@"RC: %d", rc);
50
51 NSLog(@"MiddleClickClose loaded");
52 }
53
54 + (MiddleClickClose*) sharedInstance
55 {
56 static MiddleClickClose* plugin = nil;
57
58 if (plugin == nil)
59 {
60 plugin = [[MiddleClickClose alloc] init];
61 }
62
63 return plugin;
64 }
65 @end
Line 35 renames Safari's original mouseUp: method to _safari_mouseUp: and then line 39
renames my _mcc_mouseUp: method to mouseUp:. The otherMouseUp: method is handled
on lines 43 and 47, but as I said otherMouseUp never gets called.
What's especially frustrating about this is that I know Safari knows how to bag a middle-click, because I frequently will middle-click on a link in a web page, and Safari will open that link in a new tab. So, why can't I get a middle-click in the TabButton instance? Does anyone have any ideas on this? I'd appreciate any pointers. I feel like I'm thiiiiiiiiiiis close to getting this working, but there's some small piece of info that is eluding me.
add to del.icio.us. look up in del.icio.us.
add to furl
In case you've missed me, I'm back. The site has been down for a week and a half due to server problems. I host this site in the same rack as my company, on one of the spare machines, but last monday we lost a drive in our database server. I started moving the data to the spare machine, but while doing so, that drive also failed, taking with it my blog. Today I upgraded my test machine from an older copy of SuSE Linux to Ubuntu Fiesty (which is what all the machines are now running), and now the blog is back. Hooray!
For good, I hope.
add to del.icio.us. look up in del.icio.us.
add to furl
I use iTerm for all my command-line needs. I really like it, especially the tabbed interface. I typically have two to three terminals open for my local box, plus two to three for various systems in the company rack. iTerm has a nice bookmark feature that lets you save commands (like ssh me@foo) to open these various windows, but it's not exactly what I want. The reason for this is that I either have to leave the bookmark drawer open all the time, or I have to click to open it, then double-click the bookmark I want to launch, then close the bookmark drawer. And that's a real drag for me, because I'm not really a mouse guy.
So yesterday I started thinking that it had to be possible to do this using
AppleScript, and indeed it is. My solution is not optimal, as I
had to use two files, but it's close to optimal. It's approaching optimal. Here's the AppleScript file, which is called
it.scpt:
1 on run argv 2 9 end runNext is a regular shell script, called it that calls it.scpt:
1 #!/bin/bash 2 3 if 4 then 5 echo "Usage: it <session_name>" 6 exit 7 fi 8 9 osascript ~/bin/it.scpt $*You can see that the shell script checks to see if you've specified a bookmark name to launch. If you haven't, it tells you how to run it. Once it's established that you have specified a name, it calls the AppleScript file it.scpt, which I've placed in ~/bin for convenience. (Both files are in ~/bin on my system.) The AppleScript tells the currently-running iTerm to activate (probably not needed) and then tells it to launch the requested bookmark in a new tab. I don't need to worry about the case where iTerm isn't running, because I would execute this script from within iTerm. If you specify a non-existent bookmark, it just opens a new shell on your local system, which is OK, I guess.
So, to run it, I would type something like
it web1to open the bookmark called "web1." And that's what I wanted.
I was a bit surprised that I was unable to just have one file. I should have been able to put a she-bang line in it.scpt and have it work. In other words, I should have been able to have
1 #!/usr/bin/osascriptand then the rest of the script, but I got an error when I tried that.
If anyone knows an easier way to do this, please let me know.
04/11/2007 14:20 Update: A reader sent in how you can combine the two scripts into one, using osascript's
-e switch. I knew about this switch, which let's you specify the program on the command line, but I've seen so many
horrible (ab)uses of the same option in Perl that I didn't even try it. What I didn't know was that you can have embedded line feeds
inside the quotes, so you can still have a nicely formatted script. Here's the new and improved, single-file version of it:
1 #!/bin/bash 2 3 if ; then 4 echo "Usage: $0 <session_name>" >&2 5 exit 1 6 fi 7 8 osascript -e 'on run argv 9 tell application "iTerm" 10 activate 11 12 tell the first terminal 13 launch session (item 1 of argv) 14 end tell 15 end tell 16 end run' $@
04/12/2007 11:46 Update: This tip got posted over at MacOSXHints.com
and has gotten some comments. Based on those comments, below is the latest version, which includes the ability to get a list of available
bookmarks to launch by typing it list. Here it is:
1 #!/bin/bash 2 3 if ; then 4 echo "Usage: 'it bookmarkname' or 'it list'" && exit 1 5 elif ; then 6 defaults read ~/Library/Preferences/iTerm|grep Name |grep -v NSColorPicker|awk '{$1="";$2=""; print $0}'|tr -d ';' 7 else 8 osascript <<ENDSCRIPT 9 on run argv 10 tell application "iTerm" 11 activate 12 tell the current terminal 13 launch session "$1" 14 end tell 15 end tell 16 end run 17 ENDSCRIPT 18 fi
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
Bruce Williams asked this question at RailsConf, and I am soliciting feedback.
First, a little background. There are two possibilities when calling flexmock(). First, you are creating a full mock object:
# Example 1
mock = flexmock("description")
mock.should_receive(...)
A full mock fulfills two roles: (1) it is a target for should_receive to define expectations, and (2) it is a target for normal domain messages when testing.
The other possibility is that you are creating a partial mock (i.e. a regular Ruby object with just a few mocked methods):
# Example 2 real_obj = RealObject.new proxy_mock = flexmock(real_obj, "description") proxy_mock.should_receive(...)
The object returned from the flexmock() method is actually a proxy object that can accept should_receive() messages to define the expectations, but does not handle normal domain messages. After all, we have a real object that that handles domain messages.
It is clear that when creating a partial mock using the non-block form of flexmock(real_obj), we must return the proxy, else there would be no way to add expectations. But the return value for the block form of flexmock is not so clear.
Consider the following code:
# Example 3 real_obj = RealObject.new result = flexmock(real_obj) do |mock| mock.should_receive(...) end
Here the proxy object is passed as the block argument. All the expectation setup is done within the block. It is very tempting to write this code as:
# Example 4 result = flexmock(RealObject.new) do |mock| mock.should_receive(...) end
But here is the problem: in example 4 we no longer have a reference to the RealObject instance. The flexmock() method returns the proxy object, not the real object; just as it does in the non-block form.
Bruce suggested changing the block version of flexmock() to go ahead and return the real object. Since the proxy is used in the block, there is no real need for it outside the function. And, I will admit, example 4 is short and relatively clear, especially with those familiar with the returning idiom used in Rails.
So here is my dilemma. Changing FlexMock so that example 4 works properly is attractive. And I suspect that the return value of flexmock(real_obj) is not ever used in a significant way in existing code, so backwards compatibility should be be only a minor concern. However, changing the return object based on whether or not the method has a block just seems … wrong.
There is precedent for this. In the standard Ruby libraries open(fn) and open(fn) { ... } return different things (an open file for the former and the value of the block for the latter). I’ve never had problems with this behavior in open, so perhaps I am just being over sensitive here.
I told Bruce I would blog the issue and consider the feedback received. So let me know what you think. Should flexmock() be modified to return the real_object when defining partial mocks using the block form?
You can email me (jim@weirichhouse.org) or add a comment using the comments link below.
add to del.icio.us. look up in del.icio.us.
add to furl
This happened to me just this past week.
If you are having problem installing packages with the macports port command, double check that you have the latest version of Xcode installed (version 2.4.1 at this point in time). A number of packages install with much less hassle when you are up to date.
Just speaking from experience.
add to del.icio.us. look up in del.icio.us.
add to furl
user_pref("network.protocol-handler.app.http", "/usr/local/bin/konqueror");
user_pref("network.protocol-handler.app.ftp", "/usr/local/bin/konqueror");
add to del.icio.us. look up in del.icio.us.
add to furl
With the erubycon quickly approaching, I have sent a list of 5 questions to several of the erubycon speakers. As their responses come back to me, I’ll publish them here.
Enjoy!
—Jim Weirich
Zak Mandhro is a Senior Manager of Information Management Solutions for BearingPoint (http://www.bearingpoint.com). He is the first of our erubycon speaker interviews.
I am a Senior Manager at BearingPoint, a global consulting company. My background is custom Enterprise Solutions that utilize JavaEE, .NET, SOA, Portals and Business Intelligence. I came across Ruby while exploring dynamic languages in 2004. I started using Ruby actively after Rails 1.0 release (outside of BearingPoint). We are currently using Ruby for a requirements DSL (http://rubyforge.org/projects/rdil) at a major federal client.
Short answer: The bottom-line is richer application at lower cost with faster time-to-market. At the moment, I see two areas where Ruby and Ruby on Rails are particularly attractive. (1) Building departmental database-driven applications, the type that are being serviced by VB, Access and ColdFusion today, and (2) Web services and SOA glue code.
The long answer is here: http://www.sdtimes.com/printArticle/column-20070101-01.html
We need to have a better deployment and infrastructure story for Rails. Unlike the shared hosting and VPS market, terms like monit, lighty, mongrel and fastcgi are alien to Enterprise data centers. There’s isn’t much in the “Enterprise”-press that would give these products credibility, let alone coverage. Lack of management tools is another area of improvement. We need to get to a point where systems integrators and IT infrastructure staff are familiar and comfortable with Rails deployment. JRuby WAR deployments is one way to get there.
I think we are already in the midst of the next big thing. “Simplification of Enterprise Software”. Complex and high-priced proprietary Enterprise software will slowly but surely start to lose market share to simpler open-source alternatives. We are seeing a move to openness and simplicity with JavaEE. We are witnessing endorsement of dynamic languages (less code). Over the next 12 to 24 months, we’ll see more simpler alternatives pop-up, mature and become pervasive; hopefully without ending up becoming just as complex.
Must I choose? Here are three quick picks (in no order):
- Security (CAS and OpenID)
- Mingle: Full-scale JRuby
- Keeping Tests Dry
Thanks Zak. Folks can get more information about erubycon at erubycon.com.
add to del.icio.us. look up in del.icio.us.
add to furl
Today we are publishing Stuart Halloway’s answers to our erubycon interview questions.
Stuart Dabbs Halloway is a co-founder of Relevance, LLC. Stuart is the author of Component Development for the Java Platform. He regularly speaks at industry events including the No Fluff, Just Stuff Java Symposiums and the Pragmatic Studio.
Here are Stuart’s answers:
I have been doing enterprise software development since 1989. Four years ago Justin and I founded Relevance with a goal of raising the bar for how software is written. Ruby has been a great tool. In March 2005, we ported a project to Ruby and haven’t looked back.
Ruby is compelling for enterprises that embrace agility. Agile teams don’t aim to limit failure, they aim to enable success. Thus, they are willing to embrace open languages that give developers maximum power to get things done.
We need more knowledge transfer. Ruby embodies a ton of good ideas, and it will take people (and organizations) a while to explore them all.
We’re already there: Agile development methods and open languages.
I’m looking forward to Muness’s report from the field on large Ruby projects.
Thanks Stu.
For more information on the conference, see erubycon.com.
add to del.icio.us. look up in del.icio.us.
add to furl
Continuing with the erubycon speaker interviews, next we have Muness Alrubaie.
Muness has over 10 years of experience in software development and teaching computer science. His development background has included working with various languages including Java, C#, Python, VB.Net, Perl and Javascript. Now, he is thrilled to be coding in Ruby. Muness is currently a software developer at ThoughtWorks.
Here are Muness’s answers:
I’ve been doing software development since ‘97. I am currently an architect with ThoughtWorks. I first came across Ruby three years ago thanks to all the Rails hype.
I love Ruby for system with fast changing requirements. Its succinctness and readability make it especially attractive, for those properties make programs written in Ruby easier to write, maintain, and most importantly for me, evolve.
Half hearted attempts at Ruby. Let me explain: whenever a company tries something new and it fails, they blame the technology. This is a problem all new tools/languages face, but I think it’s especially relevant for Ruby.
To be harnessed properly, one has to approach Ruby with respect. In my opinion, using Ruby for large systems without the feedback supplied by an agile process, for example, is a recipe for disaster. Another example of the respect due Ruby is that it is drastically different than Java or C#. Writing Ruby without TDD or taking advantage of its features (dynamic typing and extensive metaprogramming support stand out) will ultimately disapoint both managers and developers.
Language oriented programming, aka, making better use of DSLs.
I am looking forward to all the talks, and especially to Keeping Tests Dry and The Beauty of Ruby.
Thanks Muness.
For more information on the conference, see erubycon.com.
add to del.icio.us. look up in del.icio.us.
add to furl
Glenn Vanderburg is featured in today’s erubycon interview.
Glenn Vanderburg has over 20 years of experience as a software developer, working in diverse environments using a wide variety of languages and tools, including Java, C and C++, Perl, Tcl, and more. His career spans large enterprises, universities, and startups. He caught the Ruby bug in 2000, and has never enjoyed programming so much.
Here are Glenn’s answers:
I’ve been a programmer for 20 years now, and I’ve worked in a wide variety of enterprises, with many different technologies. I’ve just hung up my independent consultant hat to join Relevance, LLC (where I’m be a semi-independent consultant).
In late 2000 I was a regular at a Dallas-area lunch discussion group focused on “Extreme Programming and related topics” (i.e., what we would now call agile software development). Dave Thomas was also a regular there, and he mentioned to us that he and Andy were working on a book about Ruby. I was able to go to the OOPSLA conference that year, where the first edition of the PickAxe was released, and bought a copy on release day. I was hooked immediately.
I blogged recently that I think Ruby and Rails help good programmers to become better—partly through just being well-designed and powerful, partly through providing good examples and assistance in doing the right thing, and partly through having a community and culture that values good design and clean, expressive code. I think good, solid design and code are crucial for enterprise software. Enterprises, however, have historically undervalued those things, largely because it’s been so tempting to believe that tools and technologies will solve all the problems. I think we in the Ruby community have a chance to bring much-needed simplicity back to enterprise systems, and remind enterprises that there’s no substitute for skilled people with good tools.
Large enterprises have a pretty solid division of labor between those whose job it is to get work done and those who are supposed to prevent mistakes. Those in the first group will be drawn to Ruby as a powerful tool that helps them work faster, but those in the second group always try to resist change. And to some degree they’re right to resist. But because they aren’t accountable for the work getting done, they might hold out much longer than they should, hurting the organization in the process. The best strategy against such resistance is for all of us to go public with our Ruby success stories (and there are a lot of them already).
There are a lot of people these days wondering whether Apollo or Silverlight will mean the end of web applications, but I don’t think that will happen. My prediction is that new kinds of devices (including smartphones, pads, multitouch screens, and even large- scale displays) will require revising our assumptions about user interfaces, and that will require developers (yes, even enterprise developers) to learn some new techniques. Two-handed input, pervasive animation, and other innovations will cause a lot of upheaval among application developers.
I can’t wait to hear Neal Ford discuss Mingle.
Thanks Glenn.
For more information on the conference, see erubycon.com.
add to del.icio.us. look up in del.icio.us.
add to furl
Bruce Tate is the second featured speaker to provided feedback on our erubycon speaker interviews.
Bruce Tate is a kayaker, mountain biker, and father of two from Austin, Texas. An international speaker and respected author, Bruce’s primary focus through the years has remained steady: rapid application development of web applications. He specializes on putting highly effective teams on the most productive and most appropriate technologies.
I have been programming for about 30 years, and programming for money for the last 25. I worked at IBM for a number of years, got bored, and left to work for a startup which immediately blew up. Then, I was an independent consultant, which was a little like saying “Unemployed, but with business cards.” I did Java development, training, mentoring, and consulting for five years or so, and began to think that things were getting too bloated, too complicated, and unsustainable. Dave Thomas challenged me to give Ruby a try, and I did, and loved it, and hated that I loved it. All of my reputation, my books, and my customers were all wrapped up in Java, but I knew it was not the right language for the types of problems I was trying to solve. I interviewed a bunch of people to understand what was happening, and then decided to write a book about the learning experience. That book, Beyond Java, caused a lot of controversy, but the stuff seems pretty tame these days.
Eventually, I shifted my consulting practice to Ruby full time. I later turned a consulting gig into a full time CTO position at http://ChangingThePresent.org, We’re building a charitable contributions portal. At ChaningThePresent, you don’t just make a donation. You get an hour of a cancer researcher’s time, you make a blind person see, and if you like, you can make that tangible donation in the name of another, and get a customized card to announce your donation. We hope to be the de facto resource for nonprofits on the web. We think we’re well on the way.
I do everything in Ruby. As computing power gets less expensive, we need to use more of that power, and let the base programming language do more of the work. Our infrastructure is just about all in Ruby these days.
We don’t see insurmountable obstacles. We do think tools have room to grow, especially in the area of refactoring development environments. The dependence on so many C libraries, like ImageMagic, is a pain for deployment. And we use Rails, which has its share of warts. Caching in the persistence layer is harder than it needs to be. Migrations don’t scale beyond small teams. But none of these things even dent the long term productivity that we experience. Any framework will lead to its share of technical debt. Rails is no exception. All in all, it’s a fantastic framework.
I always get in trouble for doing this, but I’ll bite. From a language perspective, we seem to be getting closer and closer to a functional language. Ruby is just one step in that direction. We won’t see major movement in the core language for another 10 years, though… we’re locked pretty hard into a 10 year programming language cycle. I think we’ll continue to converge on a set of frameworks that is over HTML and JavaScript. You can easily imagine one of the HAML-like languages putting a dent in HTML, and one of the AJAX frameworks, either in JavaScript or a langauge that composes it, providing a layer over the browser. It’s becoming clearer that HTML isn’t enough, and JavaScript needs layers on top to be everything we need.
Domain specific languages will be unleashed, and driven from things like IDEA’s language workbench and programming languages and concepts in Ruby. This will take us closer to functional programming languages than we’ve ever been.
From a language and feature standpoint, we’ll see continuations play a bigger role. AJAX is complicating web development again, and we’re going to have to make some simplifying assumptions. AJAX tripped up continuation based models for a little while, but I can easily see an abstraction with better encapsulation that lets AJAX play.
So those are three things that I see in the 5-10 year window. In the more immediate timeframe, we’ll see Ruby continue to push Java on the applications end. No single language will dominate, but a bunch of us have already moved beyond Java. There’s still a place for Java, and C++ or COBOL for that matter. But mind share is moving on. It’s inevitable.
It’s an incredible docket. I can’t pick just one.
Thank you Bruce. Folks can get more information about erubycon at erubycon.com.
add to del.icio.us. look up in del.icio.us.
add to furl
Anthony Eden’s answers to the erubycon interview questions make up the third installment in this series.
Anthony Eden has more than 10 years of experience developing web applications, first with Perl, then Java and now Ruby on Rails. Anthony has developed numerous open source projects over the last 5 years in both Java and now in Ruby. Anthony is currently a project manager and technical lead with Camber Corporation, a government contractor and runs his own company, Aetrion LLC, a data warehouse development company.
Here are Anthony’s answers:
I am a software developer/project manager with Camber Corporation, a 1400-employee consulting company that services the military and US Government as well as other nations. I also run my own business on the side developing Ruby-based data warehouse solutions for small businesses. I began with Perl in ‘95, started using Java in ‘96, used Python along the way and am now doing Ruby almost exclusively (except for some interest in Erlang). I came to Ruby via Rails and I was skeptical at first, but within a couple of months of using Ruby I became convinced that it could greatly improve my productivity, my team’s productivity and the overall joy of developing software.
The prime opportunity is to reduce the amount of code and amount of effort that goes into operating and maintaining various systems used to support Enterprise organizations. The larger an application is the harder it is to maintain. My hope is that the elegance of the Ruby language is seen as an enabler for smaller, easier to maintain enterprise applications that work together, rather than monolithic beasts that can’t be integrated.
Lack of quality documentation about Ruby and its associated libraries, that is easy to find, for one. Development tools are still an issue, but I actually see Ruby as a catalyst for new development tools that can take advantage of the dynamic nature of scripting languages, rather than something which is seen as an obstacle.
Distributed parallel processing. A few days with Erlang opened my eyes to the potential of direct support for parallel processing in a language and made me realize that parallel processing is going to be the only way to process the huge amount of data that is becoming available thanks to the “opening up” of a lot of web sites. Google and Amazon are really leading the way here and are representative of where we can go with applications and data integration on a large scale.
- Ruby on Rails with Large Teams
- Stretching ActiveRecord
Thanks Anthony.
For more information on the conference, see erubycon.com.
add to del.icio.us. look up in del.icio.us.
add to furl
Some days ago, I wrote an OgScaffolder component. It’s damn easy to use. Just pass an Og domain class to OgScaffolder.new, and what you get is a regular Wee component. Look at the screenshot below.
Below I’d like to show some Nemo screenshots, to show it’s potential. Note that the whole generic editor component (the first screenshot) is less than 200 lines very clean Ruby code! Thanks Kevin ;-)
add to del.icio.us. look up in del.icio.us.
add to furl
…If you aim to dispense with method, learn method
…If you aim at facility, work hard
…If you aim for simplicity, master complexity
— Lu Ch’ai (Wang Kai), [chinese painter, ca 17 century]
The economy and simplicity of traditional oriental painting is not arrived at by squinting at the subject in order to blur or filter out the complexity — subjects are studied in detail (with both eye and mind). The simplicity and elegance are distilled from the far side of that process.
Consider the tale/fable of the gentleman who entered a well known chinese painter’s shop and described a painting he would like to have painted. The painter talked the painting over with him over a cup of tea, thought for a few minutes and said he could do such a painting but he wouldn’t have it ready for a year. The gentleman frowned at such a delay, but this painter came highly recommended, so he paid a downpayment and left the shop.
A year passed and the gentleman returns and asks the painter if his painting is ready. Without a word, the painter rolls out a new length of rice paper, grinds some fresh ink, and proceeds to paint the picture before the gentleman’s very eyes. In a few minutes he is finished. The gentleman is stunned, and quite impressed that this picture, painted in just a few minutes, captured exactly what he had wanted. "Don’t get me wrong", the gentleman spoke, "the painting is exquisite. But it took you less time to paint than we spent drinking tea a year ago, could you not have found the few minutes needed to paint it any sooner?"
The painter went to a cupboard and retrieved a large box full of hundreds of discarded versions of the masterpiece now drying on the table. "Which of these", the painter replied, "would you have wished to have sooner?"
Well, there may be as many versions of this fable as there were discarded paintings in the box, and, Damn, could that painter estimate a project or what!? But project estimation isn’t my point. Try this one:
I would not give a fig for the simplicity this side of complexity,
but I would give my life for the simplicity on the other side of
complexity. — Justice Oliver Wendell Holmes (1809-1894)
I think we can all recognize a certain Truth in these quotes that applies to any human activity — and certainly to software development. Getting over the complexity divide takes work. You can’t just skirt around it, and you shouldn’t fear it.
Behind complexity, there is always simplicity to be revealed. Inside simplicity, there is always complexity to be discovered. — Gang Yu
__END__
add to del.icio.us. look up in del.icio.us.
add to furl
cd directory/to/copy
pax -w -x sv4crc . |
ssh root@remotehost "cd directory/to/copy/into && pax -r -p e"
You should use "root", to maintain correct ownership of files. Use format sv4crc, as most other formats are limited to a path-length of 255.
To double-check that all files were transfered correctly, make use of mtree:
cd directory/to/copy
mtree -c -k md5digest -p . |
ssh root@remotehost "cd directory/to/copy/into && mtree -k md5digest -p ."
If there’s no output, everything is OKAY!
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
Oniguruma is a regular expression C library you can use in your own projects under the BSD license, or you can install it as Ruby’s regular expression engine (in which case it falls under the Ruby license). Oniguruma may be translated to English as Demon Wheel (or something along those lines).
Oniguruma is slated to become Ruby’s default regular expression engine, and Ruby 1.9 already has it included. But you don’t have to wait to try it out — it is easily incorporated into 1.8* ruby builds and basically just involves:
The only danger in doing this is forgetting that oniguruma is not yet standard Ruby and shouldn’t be a dependency in released code. You might want to build both a standard ruby and an oni-ruby (or perhaps guru-ruby).
Oniguruma brings several features to Ruby’s regexen, notably:
Look-behind and callable backreferences are probably the main reasons you’d want to install oniguruma.
Look-ahead assertions have been around for some time, in many regular expression flavors. Look-behind assertions are less prevalent. Oniguruma brings positive and negative look-behind assertions ((?<=…) and (?<!…) respectively) to Ruby. Just like look-ahead assertions, these are zero-width assertions — they match the current position if the assertion about what follows (look-aheads) or precedes (look-behinds) is true. They do not consume any part of the string.
Unlike look-ahead assertions, look-behinds must contain fixed-width patterns which means: no indeterminate quantifiers. However, alternation is allowed at the top level of the look-behind, and the alternations need not be of the same fixed width. Capturing is allowed within positive look-behinds, but not in negative look-behinds (which makes sense).
Callable backreferences give us recursively defined regular expressions, which allow one to match/extract arbitrarily nested balanced parentheses (or other delimiters).
# to match a group of nested unescaped parentheses:
re = %r/((?<pg>\((?:\\[()]|[^()]|\g<pg>)*\)))/
s = 'some(stri\)\((()x)(((c)d)e)\))ng'
mt = s.match re
puts mt[1]
==> (stri\)\((()x)(((c)d)e)\))
The main behavioral difference I’ve noted between the two regular expression engines involves capturing with zero-length subexpression matches. In the following, sruby is standard ruby, and oruby is compiled with oniguruma:
$ sruby -e '"abax" =~ /((a)*(b)*)*/; print "#{$&}:#{$1}:#{$2}:#{$3}\n"'
aba::a:b
$ oruby -e '"abax" =~ /((a)*(b)*)*/; print "#{$&}:#{$1}:#{$2}:#{$3}\n"'
aba::a:b
No difference there, but note that Perl handles this differently (and, IMHO more correctly):
$ perl -e '"abax" =~ /((a)*(b)*)*/; print "#{$&}:#{$1}:#{$2}:#{$3}\n"'
#{aba}:#{}:#{}:#{}
In my mind, with nested capturing such as this I would expect that the contents of $2 and $3 would be substrings (even if only empty strings) of $1 — like Perl handles it. However, Ruby isn’t alone in that Python and the pcre both handle it as Ruby does.
If this behavior doesn’t seem strange, consider this more obvious example:
$ sruby -e '"ba" =~ /((a)*(b)*)*/; print "#{$&}:#{$1}:#{$2}:#{$3}\n"'
ba::a:b
$ oruby -e '"ba" =~ /((a)*(b)*)*/; print "#{$&}:#{$1}:#{$2}:#{$3}\n"'
ba::a:b
I understand the interpretation, I just don’t think it is the most correct interpretation to follow.
The difference between Oniguruma and Ruby becomes apparent in the following example, when the subexpressions themselves may be zero-length:
$ sruby -e '"abax" =~ /((a*)*(b*)*)*/; print "#{$&}:#{$1}:#{$2}:#{$3}\n"'
aba::a:b
$ oruby -e '"abax" =~ /((a*)*(b*)*)*/; print "#{$&}:#{$1}:#{$2}:#{$3}\n"'
aba:::
$ perl -e '"abax" =~ /((a*)*(b*)*)*/; print "#{$&}:#{$1}:#{$2}:#{$3}\n"'
#{aba}:#{}:#{}:#{}
Here, Oniguruma sides with Perl instead of Ruby, and all the captured subexpressions are the empty string. However, pcre agrees with standard Ruby on this one, and Python won’t even compile the regular expression.
Versions used in testing:
sruby => Ruby 1.8.4 (2006-01-21)
oruby => Ruby 1.8.4 (2006-01-21) with Oniguruma 2.5.2
Perl 5.8.7
Python 2.4
pcre 6.3
__END__
add to del.icio.us. look up in del.icio.us.
add to furl
I like simple, so when I heard that darcs is a simple (but rich) distributed version control system, I had to take a look.
darcs is a relatively new entry on the version control landscape, officially announced in April of 2003 it passed the 1.0.0 milestone in November of 2004 and now sits at 1.0.1. It is written in Haskell, and you’ll need the Glasgow Haskell Compiler (GHC) to build it from source, but there are binaries available for many platforms. The linux static binary worked out of the box.
What makes darcs different is that you don’t check out working directories, but rather fully functional repositories — essentially branches — without any of the fuss or administrative overhead of setting up local branches / repositories that some other version control systems require.
So, if I do
darcs get http://www.abridgegame.org/repos/darcs
I wind up with a full repository of the darcs sources — in which I can make changes, record, unrecord, revert, pull down new patches, or create patches to apply back to the "main" repository (using darcs push if I had write access to the that repository, or darcs send to send via email where they might either be manually or automatically applied). Of course, I could share my patches directly with another developer equally as easily if we both working on some fix or feature.
(Note: darcs get —partial … is recommended if you don’t really need the entire patch history of the project — it will just fetch the patches since the last ‘tagged’ version and build your repository based on that. Currently with darcs, that’s the difference between getting some 2500+ patches or just getting and applying few hundred).
This tutorial illustrates how easy using darcs is, and the manual itself is a well written guide and reference (which also discusses the underlying Theory of patches of darcs). So I won’t duplicate that material here.
I will mention one experience I had with darcs itself. I decided I’d rather build darcs from source rather than rely on a binary, so I downloaded a binary install of GHC, used my binary of darcs to get the darcs repository, and built my own version. Unfortunately, the GHC I installed was broken on my system, and any system() calls failed (and darcs uses system() calls in a few places such as bringing up your editor to write long log messages, or for running automated test commands). My first attempt to build my own GHC from source also failed.
So I dove into the darcs sources (without ever having looked at Haskell code before) and was able to come up with a workaround patch that replaced any system() calls in darcs with an execvp based alternative — this solved my immediate problem, and everything worked fine.
Now I wouldn’t expect a patch for my isolated case to be incorporated into darcs, especially since my real problem was the GHC compiler and not darcs. But then, I do have my own fully functioning branch right here which I can still keep up to date by pulling down new patches from the main repository (resolving any conflicts if they arise). In fact, a couple of new patches were added to the repository, and I just did:
darcs pull
within my own repository and it interactively asked me about applying each patch in turn (I could have had it not ask), applied them, and I recompiled — no problem, no headache.
That was quite nice to know. Fortunately, I did manage to get a working version of GHC compiled on my machine (with a little baby-sitting during the compile), thereby solving my real problem and allowing me to unpull my specialized patch from my repository. Cool.
In reworking the code section of this site, I decided to make the few small Ruby and Perl projects currently there available as darcs repositories (along with tarballs).
A couple of other darcs features:
But the number one feature I like is that it is damn easy to use without sacrificing power.
However, it’s not all roses and there are a couple of caveats:
Work is being done to address the above issues, and in the meantime, darcs is cetainly capable of handling small to medium projects (say perhaps, into the 10’s of thousands of LOS[1] range). Darcs is self-hosting and runs some 28,000+ LOS.
__END__
[1] LOS = Lines Of Stuff
add to del.icio.us. look up in del.icio.us.
add to furl
Browsers can display webpages, and now webpages can display browsers (which can display …).
For a quick demo, I created a Ruby mashup of a different sort (javascript required) — one webpage displaying four embedded bitty browsers, each an independent, functional browser. Each is initialized with a different Ruby feed. Kind of cool, really … and its even possible to have a bitty browser in a bitty browser (though the recursion isn’t infinite).
I was thinking this would be a dead simple way to add a "Recent Posts" sidebar, just slot in a bitty browser with my site’s rss feed. I’ve even got a couple different layouts that work pretty well — but the bitty browsers themselves are, imho, ugly; so for now, those layouts are staying in my development pool.
__END__
add to del.icio.us. look up in del.icio.us.
add to furl
Socket.do_not_reverse_lookup = true
I’ve now enabled this by default for my Wee::WEBrickAdaptor class, which results in a huge difference in performance.
add to del.icio.us. look up in del.icio.us.
add to furl
Disclaimer: This is my understanding of how Rails work. I might be wrong.
Rails model is very simple compared to that of Wee. The controller class and the method to invoke is extracted directly from the URL. For example:
/blog/show
would invoke BlogController#show. Now imaging the following URL:
/blog/show/4
This would invoke BlogController#show with @params = {‘id’ => 4}. I don’t know how Rails knows that 4 maps to the ‘id’ key, but that’s another story.
So you have these parts of a URL:
/controller/action/arguments
In Rails, there’s also no (conceptual) distinction between performing an action and rendering, as is the case in Wee. Both are inseparable from each other (in Rails).
Another difference to Wee is, that the controller classes are stateless, and instances of it might be reused (pooling). On the other hand this implicates that you can’t store information inside a controller instance across requests.
In Wee, we differenciate between an action phase, where callbacks are invoked and as such possibly modify the state of components, and a render phase, which ideally is side-effect free and whose sole purpose is to render the component to HTML (or whatever format you like).
Imagine you look at a simple Wee application which displays an HTML anchor tag. If you click on that anchor, you’ll trigger an action phase, which eventually will find the registered callback associated with the anchor you have clicked on and invokes it. At the end of the action phase, Wee will forward you to a new (automatically generated) URL, which when requested by your browser, will trigger the render phase. This in turn renders the whole component tree. "Why redirect", you might ask. Well, this simply avoids that the same callback will be invoked again if you hit your browsers reload button. Whenever you hit on reload, this will only trigger a render phase event.
Additionally, at the end of each action phase, a snapshot of the component tree is taken, so that you can go back to older states (called back-tracking). The information about which state of the component tree we refer to, is stored as page_id inside the URL. This page_id increases whenever an action phase is performed.
So, an URL in Wee basically consists of the following parts:
session_id page_id [callback_id]
where callback_id is optional. If it is given, the URL triggers an action phase. Otherwise, a render phase.
Compared to Rails controllers, Wee’s components are composites, meaning that they may contain sub-components which itself might contain sub-components and so on. And in Wee there’s only ever one root component, whereas in Rails there are usually multiple controllers. All this makes it nearly impossible to have REST-like URLs in Wee. Also due to the reason that a sub-component cannot be rendered on it’s own, whereas a controller in Rails builds a whole page. So it does not make sense to have URLs in Wee like:
/1.2.3 # == @root_component.children[1].children[2].children[3]
The concept of multiple top-level controllers can be easily added onto Wee by using the following RootComponent class:
# NOTE: not fully functional code!
class RootComponent < Wee::Component
def initialize
super()
@controllers = {
'blog' => add_child(BlogComponent.new),
'list' => add_child(ListComponent.new)
}
end
def render
controller = # extract information from URL
r.render @controllers[controller]
end
end
This RootComponent merely acts as a dispatcher. It looks at the URL and extracts the desired controller out of it and then forwards to it.
Likewise, we could map the Rails action part (the "show" in "/blog/show"), to invoke render_xxx (e.g. render_show) of the controller-component (I use this term now, to distinguish it from a "regular" Wee component and to mark the similarity with a Rails controller):
def render
controller = # extract information from URL
action = # extract Rails action part from URL
component = @controllers[controller]
component.with_renderer {
component.send("render_" + action)
}
end
And even further, we could also extract the additional arguments of the URL for use inside the called render method. We could use a custom parse_arguments method here in each controller-component.
Now lets look at a simple example:
class BlogController < Wee::Component
def parse_arguments(str)
# for /blog/show/5, str would be "5"
@params = ... # e.g. {'id' => 5}
end
def render_show
entry = BlogEntry.get(@params['id'])
# render it
end
def render_list
BlogEntry.find_all do |entry|
# render it
end
end
end
What else would be needed is to tell which controller/action pair should be used. This could for example be specified each time when generating an anchor or form tag:
r.anchor.controller('blog/show/5').callback { .... }.with('show')
Note that this would first invoke the callback and then render ‘blog/show/5’. Of course you could ommit in this case the callback. But specifying the controller/action pair each time is tedious, as this would have to be done in each sub-component, too, which completely breaks the concept of a component. So the second approach is much better:
r.anchor.callback {
... do something
request.controller = 'blog/show/5'
}
where the request.controller setting is carried inside the URL as long as you assign a new value to it.
Note that you can still use sub-components with this approach, but they would no longer be subject of REST-like URLs.
add to del.icio.us. look up in del.icio.us.
add to furl
I’ve been meaning to post about this for a couple of weeks, but with everything going on, there just didn’t seem to be time.
Here’s the news. Registration is open for the next RailsEdge conference in Chicago (August 23-25). Mike and Nicole have posted the session list for Chicago and there are some really great talks lined up for this time around, including a number of new talks that we haven’t done before.
Chad Fowler will be speaking on ”Quick and Clean: Well-Factored Rails”. I really like the emphasis in the Rails community on keeping your code clean (and still beating everyone to market).
Stuart Halloway is adding a talk on Domain Driven Design. Good design is critical to producing a system that flexible and maintainable. Looks like Stu is going to give us the goods on how to do just that.
Justin Gehtland will be talking about JRuby. I was in the JRuby tutorial at RailsConf and the JRuby guys are doing a bang up job of bring JRuby up to speed as a solid platform for rails. If you are in a place that already has Java deployed, then deploying a Rails app has suddenly become as easy as dropping a WAR file on the server. Cool stuff.
And it looks like I will be able to reprise my ”DSL: Speaking the Lingo” talk from RubyConf a couple years ago. If anything, the DSL story in Ruby has gotten even stronger than before. And in addition to juggling and Rubiks Cube from the original talk, I have a little extra surprise just for the Chicago crowd.
In addition to all the new talks, we have several new speakers featured at the Chicago venue.
Ezra Zygmuntowicz will be speaking on ”Mongrel: Learning how to walk the dog” and ”Xen and the Art of Rails Deployment”. Deployment issues seemed to be at the top of the list of concerns at RailsConf and Ezra will help set us straight.
At past RailsEdge conferences, the feedback was strong about having more coverage on the topic of testing. So as not to disappoint, we will have David Chelimsky talk about ”RSpec: Behavior Driven Rails” and Mike Mangino will cover ”Testing in the Real World”.
That’s just the new stuff for Chicago. We still have a great selection of topics from previous RailsEdge conferences. See the current schedule for a complete list of topics.
All in all, it looks like a really great lineup of speakers and topics. I hope to see you there.
add to del.icio.us. look up in del.icio.us.
add to furl
Welcome to my blog, dear reader. I can only assume that you are going back over the archives, searching desperately for something interesting, or you are some poor bastard who had the site foisted upon them by me personally. Either way, well met. Hopefully one day this will be an interesting place.
But first, thanks and acknowledgements. The blog is, at this time, powered by the unfortunately named diaria, by ozten. Its powered by Ruby, which is a language that will probably get some airtime on this blog. The site design was a homage of glish.com's css site. By homage, I mean direct ripoff, of course.
Diaria is convenient for me, as I have nothing active that I can play with on the server, so client-side generation is a must. Its a very pragmatic little program - spartan, even. I tried to write my own several times, but kept on coming back to diaria as the simplest thing that could possibly work. And I need something to get me writing, even if there is no audience. Here it is. Hopefully, there'll be more coming.
add to del.icio.us. look up in del.icio.us.
add to furl
And voila, it boots from the root partition of the first slice of da0. Note that the kernel will be loaded from the CD-ROM and not from the USB harddisk.
add to del.icio.us. look up in del.icio.us.
add to furl
I was recently looking up something in Knuth’s TAOCP vol. III, 2nd ed. and I came across mention of Burton H. Bloom and his data structure for set membership queries that now carries his name: Bloom filters. This structure has seen something of resurgence in the past few years, so I thought I’d contribute my own explanation and implementation.
Superimposed encoding techniques on secondary keys (attributes) had been around for quite some (manual card filing systems for example) when Bloom, in 1970, published an article that basically turned the idea on its side by considering an entire dataset as one record and the primary keys as the attributes. This provides the basis of a relatively compact structure (an m-bit field) that allows for fast membership queries on the primary with a probabilistically controlled rate of false positives.
What does that mean? Let’s start with something a little more concrete. We can simulate the stucture with a hole-punch, a strip of paper, and a Ruby irb shell open (to calculate a few numbers for us).
Let’s assume I want to make a set consisting of the names of myself and my three brothers: Andrew, Bradford, Gregory, and John. I can take a strip of paper with 12 small circles drawn on it numbered from 0 to 11 (this is a 12-bit field).
For each name, we will calculate two identifying numbers between 0 and 11 — for the purposes of this little simulation it will suffice to use Ruby’s String#sum and String#hash methods and use the modulo operator to reduce these to numbers between 0 and 11. For example, the two identifying numbers for my name in this situation are:
"Andrew".sum % 12 # => 9 "Andrew".hash % 12 # => 7
We generally refer to such operations as hashing operations or functions — so our example is using two hashing functions. To add my name to the set, I just use my hole punch to punch out those two circles in the strip of paper:
And continuing by hashing Gregory, Bradford, and John we get
"Bradford".sum % 12 # => 0 "Bradford".hash % 12 # => 5 "Gregory".sum % 12 # => 3 "Gregory".hash % 12 # => 9 "John".sum % 12 # => 3 "John".hash % 12 # => 4
And after a bit of hole-punching (some holes will have already been punched and that’s expected) we arrive at this strip of paper which represents our loaded Bloom filter:
Now, if I want to see if any old Tom, Dick, or Harry is in the Johnson Gang, I just calculate the 2 hashes for that name, punch out those two holes in a new strip of paper, then line it up with my master strip (the Bloom filter) and see if both holes align with existing holes in the master strip.
As we can see, neither Tom nor Harry are in the gang because at least one hole in each person’s strip doesn’t match up with a corresponding hole in the Bloom filter strip. However, Dick’s name just happens to hash to two holes in my Bloom filter. This is the false-positive problem mentioned earlier. In fact, using a 12-bit field to store 4 items by setting two bits per item results in a false positive rate of approximately 25%. Reducing this false positive rate is accomplished by increasing the size of the bit-field and utilizing more bits per item. For example, to get the false positive rate down to 10% we could use a 20-bit field with 3 hashes, and to reach 1% we’d use a 39-bit field and 7 hashes.
The way the math falls out for optimum performance with a given set size n and an acceptable rate err of false positives is to calculate the size of the bit-field and number of hashing functions as follows:
m = (n * log(err) / log(1.0 / 2**log(2))).ceil k = (log(2) * m / n).round
Where m is the size of the bit-field and k is the number of hashes to use. So, for example, given n = 1000 here are a few data points for various error rates just to get a general idea of the relationships:
err m k
0.25 2886 2
0.10 4793 3
0.01 9586 7
0.001 14378 10
0.0001 19171 13
One of the assumptions is a good set of hashing functions — and MD5 or SHA1 (with various salts) are common choices — for a good random distribtion of the k-bits per key. However, a recent paper demonstrates that distributing k-bits using only 2 hashes and a simple cycling algorithm can achieve results comparable to using k high-quality hashing functions. This can lead to definite speedups as k grows and numerous keys are checked against the filter.
My Ruby implementation utilizes the above mentioned algorithm — the core of the implementation resides in the private bits_on method which takes a key and computes two hashes (aka MD5 digests) and then cycles through k bit positions yielding each position in turn. The add and has? methods call bits_on and supply blocks to set or test the bit positions respectively:
def add(*keys)
keys.flatten.each do |key|
raise RangeError, "Too many keys" if (self.nkeys += 1) > capacity
bits_on(key) {|pos| self.bv[pos] = 1}
end
end
alias :insert :add
def has?(key)
bits_on(key){|pos| self.bv[pos] == 1 or return false}
true
end
# yields each bit-position for a given key
def bits_on(key)
pos1, pos2 = salts.map{|s|Digest[s + key.to_s].hex % bits}
hashes.times do |i|
yield pos1
pos1 = (pos1 + pos2) % bits
pos2 = (pos2 + i) % bits
end
end
private :bits_on
On a simple test using a smallish dictionary of n = 38619 words and a false-positive rate of err = 0.0001, this implementation was better than an order of magnitude faster than the pre-existing Ruby version or the Perl version from which it was derived. I’ve run a number of ad-hoc tests and confirmed that the false positive rate does not appear to be affected by the dependency introduced in the k-bit positions.
Traditionally, Bloom filters were used in memory constrained applications, such as a spell-checker when available RAM couldn’t hold a dictionary of appreciable size. More recently, Bloom filters have found uses in network routing, cache-summary, and peer-peer applications (see this survey article, or read about loaf for a more specific example).
Here are a few further resources — my implementation drew heavily from the C# version given in the literate programming example at the end of the following links:
__END__
add to del.icio.us. look up in del.icio.us.
add to furl
Greg Pollack has written a Rake Tutorial.
Remember this (and this, this, and this)?
Gregg Pollack (the “Rails” guy in the above videos) has written a delightful little rake tutuorial that you might enjoy. You can find the tutorial at http://railsenvy.com/2007/6/11/ruby-on-rails-rake-tutorial.
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
http://hexane.org/slider/artwork-old.htmlLast night I pulled this work together using dHTML:
http://hexane.org/slider/artwork.htmlThe programming is nothing too exciting: script.aculo.us is cool, browsers are still annoying, but all it takes is a few hours of fiddling.
add to del.icio.us. look up in del.icio.us.
add to furl
gem install plist
gem install iphoto2
iphoto = IPhoto2.new # path to AlbumData.xml is optional
iphoto.albums.each do |album|
album.each do |image|
puts image.path
end
end
add to del.icio.us. look up in del.icio.us.
add to furl
{
"Application Version" = "5.0.4 (263)";
"Archive Path" = "/Users/username/Pictures/iPhoto Library";
"List of Albums" = (
{
AlbumId = 999000;
AlbumName = Library;
KeyList = (7);
Master = 1;
PhotoCount = 1;
PlayMusic = YES;
RepeatSlideShow = YES;
SecondsPerSlide = 3;
SlideShowUseTitles = 0;
SongPath = "";
TransitionDirection = 0;
TransitionName = Dissolve;
TransitionSpeed = 1;
},
{
"Album Type" = "Special Roll";
AlbumId = 999001;
AlbumName = "Last Roll";
"Filter Mode" = All;
Filters = ({Count = 1; Operation = "In Last"; Type = Roll; });
KeyList = (7);
PhotoCount = 1;
PlayMusic = YES;
RepeatSlideShow = YES;
SecondsPerSlide = 3;
SlideShowUseTitles = 0;
SongPath = "";
TransitionDirection = 0;
TransitionName = Dissolve;
TransitionSpeed = 1;
},
{
"Album Type" = "Special Month";
AlbumId = 999002;
AlbumName = "Last 12 Months";
"Filter Mode" = All;
Filters = ();
KeyList = (7);
PhotoCount = 1;
PlayMusic = YES;
RepeatSlideShow = YES;
SecondsPerSlide = 3;
SlideShowUseTitles = 0;
SongPath = "";
TransitionDirection = 0;
TransitionName = Dissolve;
TransitionSpeed = 1;
},
{
"Album Type" = Regular;
AlbumId = 9;
AlbumName = "An Album";
KeyList = (7);
PhotoCount = 1;
PlayMusic = YES;
RepeatSlideShow = YES;
SecondsPerSlide = 3;
SlideShowUseTitles = 0;
SongPath = "";
TransitionDirection = 0;
TransitionName = Dissolve;
TransitionSpeed = 1;
}
);
"List of Keywords" = {};
"List of Rolls" = (
{
"Album Type" = Regular;
AlbumId = 6;
AlbumName = "Roll 1";
KeyList = (7);
Parent = 999000;
PhotoCount = 1;
}
);
"Major Version" = 2;
"Master Image List" = {
7 = {
"Aspect Ratio" = 1;
Caption = "fallow_keep.png.450x450.2005-12-04";
Comment = "";
DateAsTimerInterval = 158341389;
ImagePath = "/Users/username/Pictures/iPhoto Library/2006/01/07/fallow_keep.png.450x450.2005-12-04.jpg";
MediaType = Image;
MetaModDateAsTimerInterval = 158341439.728129;
ModDateAsTimerInterval = 158341389;
Rating = 0;
Roll = 6;
ThumbPath = "/Users/username/Pictures/iPhoto Library/2006/01/07/Thumbs/7.jpg";
};
};
"Minor Version" = 0;
}
add to del.icio.us. look up in del.icio.us.
add to furl
state = "label 1"
continuation = callcc { |c| c }
puts "state: #{state}"
state = "label 2"
continuation.call if continuation
state: label 1
state: label 2
state = "label 1"
continuation = nil
callcc { |c| continuation = c }
puts "state: #{state}"
state = "label 2"
continuation.call if continuation
state: label 1
state: label 2
state: label 2
state: label 2
... (ad nauseam)
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
Flying over the Atlantic, I wondered about the reliability of the flight progress indicators. It's so hard to integrate software. How did the engineers pass the location of the plane to one critical system (autopilot) and one trivial system (cabin TVs) while ensuring that a short or other problem with the cabin TVs didn't knock out the autopilot. My memory of the East Coast blackout lingers.
def fullname; firstname + ' ' + lastname; end
Having 2 copies of the above code doesn't hurt anyone.
add to del.icio.us. look up in del.icio.us.
add to furl
In an article posted entitled What’s Wrong With Ruby?, the author cites me as one of the main problems:
If I was put off Ruby by the hype, I was put off more by the many cutesy introductory tutorials I encountered when trying to get into it. Why’s (Poignant) Guide is a particular horrid example… I don’t want someone chatting away to me and telling me how “cool” it all is (I’ve lived long enough as a computer programmer to know it’ll never really be “cool” to be one). I just want the straight facts, plainly put.
These are such great points and so well-put. See, actually, I’ve known since birth that I’m a problem, so this is no surprise to me. As a child, I caused a giant meadow fire that all the dads had to go fix! Also, I broke a statue! And now I’ve ruined Ruby. Uh. Oh.
If I may build on his argument for just a sec.
The problem here is: the author of the article is trying to do academics, to gain knowledge, to build a career. And my cartoons and stories have patronized him, belittled him, by treating him as if he wasn’t a real professional. This is a terrible breach of conduct. He has accolades innumerable. He has done no small deed. His peers are all gathered around him, wishing him the best and swelling with nothing but respect and esteem for him. NOW WHAT IS THIS CARTOON BOOK DOING HERE??
Programming is for world commerce. It is like agriculture or fossil fuels. It is lot a like baling hay. I’ll give you an example: You wouldn’t write a cartoon book with a plot and running narrative just to show a guy how to bale hay! That would frustrate the guy! He would throw that book in the pig’s pen! He just wants to get straight to the nitty-gritty and, for once in his life, just bale hay, straightway!
Fortunately, as I’ve mentioned before, I have a strong feeling that I will die young without artifact. That I will make no lasting impression. This will be my avenue. So hold your horses, I just have a few more things to do in life and I’m sure I’ll be out of your hair.
add to del.icio.us. look up in del.icio.us.
add to furl
Being intentionally provocative to knock people out of old assumptions is all well and good … but even though I love Ruby, and am so glad to be working in it now after 11 years of Java, my perspective is more pragmatic.
There is no perfect world. You gain a lot by giving up static typing for dynamic typing, but you also give up some things. It’s six of one, a half-dozen of the other. Or maybe 9 and 3. Whatever. Whether the tradeoff works in your favor depends on a lot of things — the kinds of systems you’re building, the process and practices you use, how well you understand your domain, and other things. And folks like Tom Ball make great points when they point out some of those tradeoffs.
(Furthermore, "static typing" doesn’t necessarily mean "Java-style static typing." It’s just that the industry right now is all wrapped up in static typing done the wrong way, while ignoring static typing done the right way.)
In spite of all that, though, I do agree (mostly) with Neal and Stu. I, too, would rather write Ruby in vi (er … that is, emacs) than Java in IDEA.
If you’re still on the fence about this, or even downright skeptical, here’s my advice. Having been a static typing bigot for a very long time, I know all of the arguments from that side. I used them myself. And what I’ve learned is that you can’t figure this out by thinking about it. There are things about dynamic programming languages — and about how programmers work in those languages, and how systems are designed in those languages — that you don’t really understand until you’ve gained some real experience. It’s the Blub paradox at work. Knowing about the flaws in the language isn’t enough either. What’s important is knowing when they bite you, and how badly, and what you have to do to stay clear of them. Primitive types in Java represent one of that language’s worst flaws, but in my many years of Java programming I was impressed by how rarely they really got in my way. (They did get in my way, but not as much as I expected them to when I first learned Java.)
So just give Ruby (or Groovy, or Python) a try. Find a way to build a system of some reasonable size (a few thousand lines or so) in it. Give yourself time to get over the learning curve of syntax and names, and learn to think in the language. Decide based on experience, not fear or doubt.
Our field is at its worst when we act (when we teach, design, manage, plan, argue) as if we’ve got it all figured out, as if we’ve got it down to a science. Nothing could be further from the truth. Our field is one of creativity, experimentation, guesswork, hunches, and feedback. Above all, feedback.
Nothing blinds us and deafens us to feedback like being convinced we’ve found the one true way.
add to del.icio.us. look up in del.icio.us.
add to furl

Over the last two months, I have met a small group of friends online who helped me out with a new program. The fifty people in that group have made my life soooo wonderful!!
Brian DeLacey, who started teaching 3 of his kids to program and kept detailed notes on their good and bad times.
Leslie Wu, who has been all over FFSandbox and Hpricot. I am amazed by how she can look in any direction and then do exactly what she wants in that direction. I repeat: she’s been hacking the sandbox for me!!
RSL, who’s been a regular around here, was one of the 50 and I really like his Hacky Mouse kaleidoscope.
Harold Hausman, who started LittleCoder and hung out in the group to offer encouragement and ideas—we’re going to team up soon, Harold!
And I still gotta dig up some links for the rest of these folks. (Eli?)
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
I know a lot of you have questions about how to use Hpricot. And I’d like to start helping with that a lot more. For example, did you know that XML files should be loaded with the Hpricot::XML() method? Oh, hey, that’s handy, right? That skips Hpricot’s HTML clean-up stuff.
So, I’ve started lists for both Hpricot and Sandbox, since both have had lots of good activity over the last little while.
To join:
For sandbox, the e-mail address is sandbox@code.whytheluckystiff.net. Please come along!
add to del.icio.us. look up in del.icio.us.
add to furl
For a while now I've been using Duane Johnson's TextMate Footnotes plugin with my Rails development. It's been the biggest boost to my productivity since I started using Rails. I kind of assumed that most Rails developers were using it, but apparently it's not as widely known as it should be.
I first learned about footnotes from Geoff Grosenbach, when he interviewed me last year for the Ruby on Rails Podcast. Geoff mentioned that it links lines from a Rails stack trace (displayed in the browser in development mode) so that clicking will open the appropriate file in TextMate, positioned to the correct line. Nice!
But it does more than that. When there is no error and your page renders correctly, the plugin adds "footnotes" to it: a little div at the bottom of the page with useful features for development and diagnosis:
You can show the contents of the current session, current cookies, the parameters passed to the controller, and the last 200 lines of the Rails log. But the most useful things are the links that ask TextMate to open the controller, view, layout, and other important files that Rails used to build that page. (It only does all this when the app is running in development mode, of course.)
If you're doing Rails development on OS X, install it this way:
$ script/plugin install -x http://macromates.com/svn/Bundles/trunk/Bundles/Rails.tmbundle/Support/plugins/footnotes
If you aren't on OS X, I know there are ways to define URL schemes like the "txmt" scheme TextMate defines on OS X. What are you waiting for? Arrange for "txmt:" URLs to open your favorite editor appropriately, install footnotes, modify it (to remove the "only on OS X" code), and have fun!
add to del.icio.us. look up in del.icio.us.
add to furl
class Symbol def hash; to_s.hash; end end
Someone explain why not.
add to del.icio.us. look up in del.icio.us.
add to furl
Whoa, the rubini.us site is all fleshed out with forums and a wiki and the like.
What is Dev’il? The excellent Beast forum extended with tickets, pages, and source code changes.
What a fantastic little spook. Here’s Brian’s list of upcoming features.
add to del.icio.us. look up in del.icio.us.
add to furl
Scope management is as important as dynamic typing in the development of general purpose scripting languages.Because I would really like to ruby online, but the architecture insists that I write fire breathing applications rather than the simple pet scripts that I prefer.
add to del.icio.us. look up in del.icio.us.
add to furl
aparrish: How can you find fault in a programming tutorial that teaches you how to make a blog before it teaches you how to do arithmetic?
AtDuskGreg: So many people drone on boringly about how important it is for kids to learn computers, only to come up with curricula that focus on using a spreadsheet or writing a resume.
Paul Robinson: The first book I ever read on programming was on BBC Basic and was illustrated with pictures of robots in factories pretending to be FOR loops.
I have a solid four years of work ahead of me on Hackety Hack, which is in my mind a very primitive tool, but hey the discussion is igniting. And among people who I haven’t encountered before, yeahhh!! One common theme is: where do you start teaching someone? (Brian D. pointed out Constructivism on the HH mailing list.)
I’m not really sure, actually. Who really knows if H-ety H goes about things in a sensible way. I was a very bad student myself and am often occupied with ideas which are widely acknowledged as ill-conceived. So, today, I’m surprised at the feelings of goodwill pouring in for Hackety Hack, but I suspect waves of criticism are forthcoming, which will be quite stimulating indeed.
I designed HH with two of my very good friends in mind, Oliver Mooradian and A. Woolsey. The second friend, A., was taking a university beginning Java class. The culminating exercise of his class was to read a comma-separated address book into memory. His program was nearly one-hundred lines long. And he wrote it knowing that he would never use it again. As a reminder: it is the year 2007.
I didn’t think I had many strong opinions about the way things should be. But this infuriated me!! This is not programming!! It should not be acceptable in 2007 for students to write a program which isn’t somehow useful to them. Not when we all use computers and are already employing micro-hacks (emoticons, bbcode, email addresses, etc.) everyday.
A. was also subject to a lot of mathematical programs: drawing circles, computing distances, a lot of spreadsheet-style activity. This sounds like academic drilling. Surely this can wait until after you’ve tinkered with RSS feeds and written a blog.
I can’t say, though. I personally only really use math for pagination and pointer arithmetic. Tell me: are math and programming intertwined much these days??
add to del.icio.us. look up in del.icio.us.
add to furl
#!/usr/bin/env ruby-web
puts "Hello World"
Web::filter do |content|
"#{content}
"
end
Web::filter do |content|
"#{content}
"
end
Web::filter do |content|
content.gsub(/Hello World/, "Hallo Welt")
end
add to del.icio.us. look up in del.icio.us.
add to furl
I’m always interested in the things that other fields can teach us about my own field of programming. My blog on bridge building from a few weeks ago is one example; I also recall when Dave Thomas pointed out some relevant phrases from the U.S. Marine Corps’ document on Warfighting, and of course Dave and Andy learned about the Dreyfus Model of Skill Acquisition from reading about the nursing profession.
Now Greg’s found a delightful example from the world of woodworking. Read Greg's blog, and the short article it links to.
"So in your leisure or in your active moments, if you wish to advance, you must be alert."
add to del.icio.us. look up in del.icio.us.
add to furl
I started a new Rails project last week. The customer had done an unusually good job of working out the site look-and-feel ahead of time, so my first day on the project I grabbed the HTML mockup of the first page we were going to implement and turned it into a Rails app. It was still static HTML -- there was no code at all in the application, and no database yet -- but the page was being rendered by the new Rails application. I carved the page up into a layout, main template, and appropriate partials, and got ready to start implementing features the next day.
But before I called it a day, I had an idea that seemed promising. I spent about 10 minutes (certainly not more than 15) going through that HTML looking for anything representing a feature that needed to be implemented. That meant links and buttons, plus anything that needed to be generated dynamically. Whenever I found something like that, I added a CSS class to the markup: "unimpl".
Then, using Chris Pederick's Web Developer Toolbar extension in Firefox, it became a simple matter to quickly highlight all of the not-yet-implemented features in the application:
Just use CSS selector syntax in the dialog to select all elements with class "unimpl":
Here's what the result looks like (demonstrated with the Streamlined sample application rather than my current project):
(By the way, those features are really implemented in Streamlined; I just marked that application up as an example.)
This provides a great, easy way of keeping track of things that remain to be done. As I implement those features, I replace static HTML with generated HTML, and I just delete the "unimpl" class as I go. Sometimes I partially implement a large part of the page; in that case, I move "unimpl" from the surrounding element to the individual pieces inside that I haven't completed yet.
This is no substitute for requirements, or an issue tracking system, or anything like that. But it's already proven very convenient as I implement features, trying to decide what's next. It's particularly nice when I have just a few minutes available … maybe not enough time to tackle a big feature, but I can quickly scan to see if there are any small things I could fix.
It takes just a little bit of discipline and consistency on the part of the development team, but it was really easy to annotate that first mockup, and now that the layout and commonly used partials are done, doing subsequent mockups will be even easier.
This morning I became annoyed by the three-click process to highlight those elements using the toolbar (how lazy is that?) so I hacked TextMate Footnotes to add a quick toggle link in the footnotes div at the bottom of the page:
If you're interested in that, let me know. If it's useful to people, I'll polish it up and submit it for inclusion in footnotes.
add to del.icio.us. look up in del.icio.us.
add to furl
Hot on the heels of that, Chad strumming on his ukelele while Rich Kilmer gamely tried to deadpan through his introduction of David Heinemeier Hansson.
From David’s RailsConf keynote: "What we want to manipulate … is people." (With a little careful editing, you can turn a harmless quote into just about anything!)
Seeing Uncle Bob speak. He’s a master, and I haven’t seen him speak for about three years. The talk was about clean code, and I already understood about 48 out of the 50 minutes of material he presented—but as a speaker, watching the way he presents and works the audience is always fantastic and educational. (James' photo captures the magic perfectly.)
After being online friends since sometime in 1999 (when we met on Ward's wiki), Alan Francis and I finally got to meet in person.
Another quotable moment from David (this time with no editing required) during Alan’s talk: "People don’t stop doing stupid things because you make fun of them once."
Being blocked out of Adam Keys' standing-room-only talk. (Not a highlight for me, but I was thrilled for Adam, and it was great to see so many people interested in such an important but underemphasized topic.)
The accordion and ukelele duet.
Avi Bryant's wondefully articulated challenge for Ruby over the next few years to work toward turtles all the way down.
Ze Frank. ‘Nuff said.
My audience cheering wildly. I always thought you had to deserve something like that, but apparently you can just ask! I’ll try that again sometime. (But even though I got the cheers by cheating, it was nice to know everyone was on my side. :-)
James Adam is a great speaker, and his talk on "The Dark Art of Developing Plugins" was loads of fun.
Jeff Barczewski and Deb Lewis demonstrating MasterView at the lightning talks session. Deb told me about MasterView last year at OSCON when she and Jeff had just begun working on it. MasterView is an alternative templating system for Rails that’s HTML-centric, designed to allow page designers to use HTML editors like Dreamweaver within a Rails project. I was a bit skeptical of MasterView, because I’m most comfortable when the programmers are in control of HTML generation. But Deb and Jeff get it; MasterView works just like a Rails templating engine should. Reopen the page in Dreamweaver, edit things, save, and when you click refresh in the browser the changes are there. Great stuff.
The personal page editor demonstrated by the guys from Revolution Health. Impressive!
French programmer Fernand Galiana's "Pardon my French!" after he got a bit frustrated during his demo of the Mole plugin.
Rich and Marcel finally believing I wasn’t a werewolf.
Charles Nutter and Tom Enebo giving some really boring demos of JRuby. Boring is great for JRuby. It’s supposed to be just Ruby, on a different platform, and with Java integration that just seems natural. And it is! That was the challenge for them, to make JRuby boring, and they’ve done a great job.
Erik Hatcher’s fantastic talk about Solr on Rails, with demos of very cool things he’s doing with full-text search at the University of Virginia.
All of James' photos. He keeps getting better.
Beginning with many attendees at the Pragmatic Studio’s introductory Guidebook tutorial (but continuing throughout the week), the Ruby community raised (at last count) $26,000 for some excellent causes. (Update: over $33,000!)
Finally, Dave Thomas’ closing keynote was the perfect finish. Thanks so much, Dave.
But of course, at all of the really good conferences the best things happen in the halls and over lunch and dinner. I had the pleasant privilege of chatting with loads of great people—some old friends, and some new. I’m already looking forward to next year.
add to del.icio.us. look up in del.icio.us.
add to furl

Thankyou for enjoying The RedHanded Adventure Show. We have had the nth batmans galore!! I adore you. I will never forget you. I will especially not forget you if you follow me to Hackety Org.
Is this the first time a Ruby blog has closed?? No matter. There will three more by supper. I will enjoy those blogs as a plainclothes civilian. Tallyho.
add to del.icio.us. look up in del.icio.us.
add to furl
A few other H-ety H items you may be interested to hear of:

add to del.icio.us. look up in del.icio.us.
add to furl
It’s absolutely certain that the biggest factor in their early maturity as programmers is that they’re just very smart guys. I’m also sure they started programming at a younger age than I did.
But Alan and I think there’s a third factor: Ruby itself. Ruby helps to teach those good programming skills, and makes them easier to learn. I got the chance later to talk to Koz about it, and he enthusiastically agreed.
The first thing I said in my talk on Saturday was that Rails is like an instructional laboratory for how to build good software. I think that’s the thing I like most about Rails. A big part of that is Ruby itself. Ruby, its libraries, and its documentation are filled with examples of clean, well designed code, and Ruby makes it easier than most other languages to create clean code yourself. The community values and encourages it. Ruby teaches good programming by setting the goal, lowering the barrier, and providing a lot of assistance and encouragement.
I was thrilled last year when Chris Pine’s Learn to Program was published, and now _why has taken up the flag with his brilliant Hackety Hack. We should support efforts that are focused on using Ruby to teach children to program. I think it’s the best way available right now to grow a generation of great programmers.
add to del.icio.us. look up in del.icio.us.
add to furl
swish-e -S prog -i ./output_documents.rb
The output_documents.rb dumps out a series of html documents:Swish-e is FAST , in every way that matters:#!/usr/bin/ruby
require 'dbi'
require 'pp'
dbh = DBI.connect("dbi:Mysql:test:localhost", "user", "pass")
# get server version string and display it
artbase = dbh.select_all("SELECT * from objects")
artbase.each do |object|
path = '/object/' + object['object_id'].to_s
mtime = object['modified'].to_time.to_i
html = <#{object['title']}
#{object['body']}
HTML
print "Path-Name: #{path}\r\n"
print "Last-Mtime: #{mtime}\r\n"
print "Content-Length: #{html.length}\r\n"
print "\r\n"
print html
end
add to del.icio.us. look up in del.icio.us.
add to furl
I’m not sure if there’s any fixing the arcane parse errors of Ruby, but here’s a stab at it. I need to do some examination of other IDEs to see what else is being done to fix this.
Anyway, some screen captures from H-ety H 0.4.
This release has a lot of fixes to the bundled Try Ruby. (Problems with the cursor, browser crashes, tutorial loading time.) But the main feature is the new friendly and condensed error messages.

These same error messages are expanded into HTML in the program editor:

The next release will work on highlighting the line which threw the error and some links in the exception to help pages for any involved classes or error messages.
Here’s another nice feature. The bundled Try Ruby has a progress bar for page fetching. I want this console to be irresistible to you lot!!

add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
From John Joyce in [ruby-talk:245343]:
I’m a little surprised at this. In irb, I tried
puts gets gets. Why? I don’t know. But basically,gets gets, seems to almost act like a heredoc!
Such a simple and unintended thing: the double-gets. Do you see how it works?
add to del.icio.us. look up in del.icio.us.
add to furl
It’s so rare to find video of talks in English by our friends from Nihon Ruby-no Kai, but here is a lightning talk by Masayoshi Takahashi at last weekend’s OSDC in Taiwan. In case you haven’t had the pleasure. (Spotted on matz’ blog.)
add to del.icio.us. look up in del.icio.us.
add to furl
Every now and then I hear someone compare software development to bridge building. (Bridge building, of course, is just a placeholder here for "real engineering," which in the speaker’s mind is much cleaner and more manageable than the current messy state of software development.) Sometimes it’s "software development isn’t like building bridges," while on other occasions it’s "software development should be more like building bridges." In either case, though, the implication is clear: bridge building is predictable, rote, unexciting, very manageable work, and software development is not. The only difference is whether the speaker likes software development the way it is, or wishes it could be different.
I think both positions are misinformed. And no, I’m not about to pull out my magic prescription for how to solve all the software industry’s problems by making it more like bridge building. In my experience, software developers tend to have an idealized, unrealistic view of what "real engineering" is like. Sure, some kinds of bridges are so well understood by now that there’s very little risk involved; freeway overpasses and the like are churned out regularly and routinely (in much the same way that simple CRUD applications, whether web- or desktop-based, are usually safe bets for even inexperienced development teams). But from what I’ve learned, bridge building in general is a lot more like modern software development than most people realize. And I think the software industry can learn some lessons from the history of bridge building.
Take, for example, the bridges of Swiss engineer Robert Maillart. His best known bridge, Salginatobel, was just featured in a really nice piece about some of the best man-made structures.
Maillart was seeking new designs that would take advantage of the properties of a new material: reinforced concrete. It had been in use for some time, and builders had figured out how to work with it, but Maillart realized that reinforced concrete had unique properties that would permit the use of new forms, resulting in significant savings (due to reduced material costs).
The formal methods used by civil engineers at the time weren’t up to the challenge of analyzing these structures (known today as "hollow box arches" and "deck-stiffened arches"). Maillart verified the designs empirically, by building models, rolling barrels full of concrete over them, etc. etc. The civil engineering establishment of the day vilified him as a charlatan who was endangering lives and cheating his customers by building bridges that would fall down. But he got customers anyway, because his designs were much, much cheaper to build. (The fact that they were strikingly beautiful didn’t hurt.)
Another engineer of the time was Leon Moisseiff, a strong proponent of formal methods and the developer of "deflection theory," at the time the state of the art in mathematical analysis of suspension bridges. Moisseiff designed a bridge intended to be a showpiece for the power of deflection theory. It was the Tacoma Narrows bridge. After its famous collapse, other bridges that had been designed with Moisseiff’s assistance (such as the Golden Gate) were retrofitted with stiffening trusses. It turned out that deflection theory was deeply flawed in a way that nobody had yet realized.
One of Maillart’s bridges did fall down … after being buried under an avalanche. One was demolished because more capacity was required. The rest are still in use, and the forms he pioneered are now standard design taught to civil engineers. The math eventually caught up with Maillart’s methods. As the story I linked to above notes, Maillart is an inspiration to the current superstar of bridge design, Santiago Calatrava.
I think there are some important lessons here for the software profession. The lesson is definitely not that "real engineering" is a mechanistic, purely construction-oriented process, which is the lesson that is usually assumed when software is compared to bridges.
Note: I have at best an interested layman’s knowledge of the history of bridge engineering. Sources include Henry Petroski’s wonderful Engineers of Dreams: Great Bridge Builders and the Spanning of America for information about Moisseiff, and David P. Billington’s article "The Revolutionary Bridges of Robert Maillart" (from the July 2000 edition of Scientific American). For what I believe to be the best description of the true relationship between software development and other engineering disciplines, I encourage you to read "What is Software Design?", Jack Reeves’ brilliant essay.
add to del.icio.us. look up in del.icio.us.
add to furl
Mark Pilgrim: The UNSELECTABLE attribute is implemented as an expando. Setting the expando property of the document object to false precludes the functionality of all expandos.
Kxxxx, oh when the jargon on MSDN hits stride and blossoms into complete psychedelia.

Someone please assemble a Wikipedia page for this rare bird. I want creators’ bios. I want the original legal pads. I want pronunciation mp3s. GO!!
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
# reading elements
data = Plist::parse_xml("example.plist");
data['image'].read
# changing elements
bin = File.open("example.jpg"){ |f| f.read }
data['image'] = StringIO.new( bin )
data.save_plist("example_data-v2.plist")
add to del.icio.us. look up in del.icio.us.
add to furl
Tim Bray, as he so often does, nails it.
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
def xwill_paginate entries = @entries
will_paginate entries,
:prev_label => "No TRANSLATION: Previous"[:Previous],
:next_label => "No TRANSLATION: Next"[:Next]
end

add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
“ Subject: 3 days of video storage left. ”
Recent internal email at YouTube
add to del.icio.us. look up in del.icio.us.
add to furl
Das Biberacher Schützenlied ist für mich auch nach längerem Nachdenken das einzige christliche deutsche Lied, das ich inbrünstig singen kann.
Meist werden nur drei Strophen gesungen was eigentlich schade ist, da auch die anderen schön sind.
Du, den die Felder uns entdeckten,
du den der Blumen Flor erhob,
auch die unscheinbaren Insekten,
o Schöpfer, predigen dein Lob.
Hier sammeln wirtschaftliche Bienen,
sie pflücken emsig, uns zu dienen,
die beste Kraft der Blumen ab.
Du lehrst die Seidenwürmer weben:
sie sterben, edler aufzuleben,
und spinnen sich ihr kostbar Grab.
Oder auch:
Die Felsen, die so traurig scheinen,
sind dir, o Mensch, zum Dienst geweiht.
Die Quelle tröpfelt aus den Steinen,
und mit der Quelle Fruchtbarkeit.
Wie? Werd ich auf den heitren Auen,
auf die des Himmels Schätze tauen,
den frommen Lenz nicht selbst gewahr?
Seht, mich umringen laue Weste.
Dort winken mir die schwanken Äste,
der Baum beut seine Frucht mir dar.—Christian Sturm, 1775
Scheene Schütza
NP: Funny van Dannen—Eurythmieschuhe
add to del.icio.us. look up in del.icio.us.
add to furl
“ It’s a shame this poor little usage gets such a bum rap. ”
Jennifer Dailey-O’Cain on the quotative like
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
Die WG-Trommler gingen dieses Jahr beim Bunten Umzug als Hawaiianerinnen, die anderen gingen alle als Bauarbeiter. Zumindest schien es so.
Wagen, die man gerne hätte:
Sonst fällt mir dazu nichts ein,
Scheene Schütza
NP: Funny van Dannen—Kunden der Zeit
add to del.icio.us. look up in del.icio.us.
add to furl
Last year, UPS cut 28 million miles from truck routes, saving roughly three million gallons of fuel, in good part by mapping routes that minimize left turns.
(source: http://tinyurl.com/2d6uy6)
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl

add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl