123
 123

Mon 06 August, 2007

Click here to bookmark this link.Channel Image14:50 本を読んでない» 青木日記
最近、(真面目な) 本を読んでないなあ。 では何をしているかというと…… かというと…… 酒? (01:29)
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image14:50 リファレンスマニュアル進捗 (5)» 青木日記
詳細版 ARGF 7/ 28 ( 25.00%) ArgumentError 0/ 0 ( 0.00%) Array 0/ 66 ( 0.00%) Bignum 0/ 0 ( 0.00%) Binding 0/ 1 ( 0.00%) Class 0/ 6 ( 0.00%) Comparable 0/ 6 ( 0.00%) constants 0/ 18 ( 0.00%) Continuation 0/ 1 ( 0.00%) Data 0/ 0 ( 0.00%) Dir 3/ 19 ( 15.79%) Enumerable 0/ 26 ( 0.00%) Enumerable__Enumerator 0/ 4 ( 0.00%) ENV 28/ 29 ( 96.55%) EOFError 0/ 0 ( 0.00%) Exception 0/ 5 ( 0.00%) FalseClass 3/ 3 (100.00%) fatal 0/ 0 ( 0.00%) File 0/ 66 ( 0.00%) File__Constants 0/ 21 ( 0.00%) File__Stat 0/ 42..
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image14:50 リファレンスマニュアルの進捗確認 (4)» 青木日記
驚きの結果が出ました。 ~/c/bitclust % ruby -I./lib tools/stattodo.rb ../rubydoc/refm/api/src/_builtin.rd 73 / 1104 (6.61%) ろく……ぱーせんと……ッ! こ れ は ヤ バ い (02:50)
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image14:50 LL 魂……だった» 青木日記
LL 魂なんてみんなのブログで見るまで存在すら忘れてたよウワァァアン (00:19)
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image14:50 NY77 - The Coolest Year in Hell» James Britt - Code, Content, Caffiene

What’s now commonly called “punk rock” arguably started in New York City around 1974, when bands such as The Ramones and Television took up residence at CBGB’s. However, it was still pretty far underground, and t wasn’t until a few years later that the NYC music scene hit its stride (sparking similar eruptions of audio angst across the States and in the U.K.).

VH1 (oddly enough) is scheduled to show a documentary of those times, NY77:The Coolest Year in Hell

I’m stoked to see this, partly because I was there at the time (so I’m waxing nostalgic), but mostly because my good friend Patty has some film footage included.

This two-part, two-hour documentary tells the story of one of the most astonishing pop culture years in American history. New York City had fallen in decay and chaos. There were not enough jobs, not enough money, not enough police, not enough schools, and not enough social services. There was a city wide black out with major looting, there was a serial killer on the loose, and the Bronx was burning.

Yet out of the chaos, emerged one of the most creative times any city has ever encountered. Hip Hop was emerging from the South Bronx, punk music was emerging from the Lower Eastside, and disco was emerging from Queens and midtown Manhattan. Elaborate, finely crafted graffiti art decorated the subway cars. Break-dancers danced in the streets. There was a huge sexual liberation with sex clubs and a burgeoning porn industry. In the beginning of the year, the world was not paying attention, and most of this activity existed in its own underground bubble. Yet by the end of 1977 all of this artistic expression was about to become part of mainstream America and would remain popular for generations to come. Maybe it would never again be this independent expression, not invented for money or fame, but the need to rebel against the mayhem around them. Maybe it would go on to be commercialized and sterilized for massive consumption. Maybe it would never again be this unique.

I’m trying to be optimistic that it won’t suck too much, and hopefully it will capture the spirit of the day and get the story straight.


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image13:48 Grad school & Caprice» Projectionist

Grad school & Caprice

Lisa - i totally think about applying for a PhD in history, theory and criticism
Lisa - but then I'll be stuck in school forever doing nothing but bullshitting
Marcel - well it will be interesting what you decide when after several years of thinking loads of different things off and on a ton of times over and over again you finally reach a point when it's time to make a decision and something pops out of the swirl
Lisa - caprice pops out, my daughter
Marcel - double lol. Caprice is a really nice name when pronounced the Italian way (Cah pree cheh)

add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image13:16 All Through The Night» Projectionist
Click here to bookmark this link.Channel Image12:55 glabella: The smooth area b...» Projectionist
gla•bel•la
[gluh-bel-uh]noun, plural
The smooth area between the eyebrows just above the nose.

add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image12:55 Christina before the wedding» Projectionist
Christina-before-the-wedding

Christina before the wedding


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:59 Tweets on 2007-08-05» halostatue
I need to follow Lesson #5, just like @ntalbott did. # @ntalbott I did it once before, sort of, when Francis took over Net::LDAP and wrote all the code. still, it’s beyond time. # Powered by Twitter Tools.
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image10:55 Prolog» Ruby Object Oriented
link(1,2). link(2,3). path(X,Z):-link(X,Z);link(X,Y),link(Y,Z). 下载 Prolog SWI-Prolog/XPCE for MS-Windows
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image10:51 Rails Hackfest:Rails核心贡献竞赛» LetRails
为了鼓励更多的开发者参与到Rails的开发中来,Rails核心团队通过WorkingWithRails举办了一个Rails核心贡献竞赛(Rails Hackfest),对那些为Rails核心开发作出突出贡献的开发者进行奖励,竞赛每月举行...
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image09:07 嵌套量词» Ruby Object Oriented
class Array  def all?    each do |n|     unless  yield(n)       return false     end    end    return true   end    def any?    !all?{|n|!yield(n)}  end  end    A=[1,2,0] B=[3,4]   p A.all?{|x| B.all?{|y| x+y>0 } } p A.all?{|x| B.all?{|y| x-y>0 } } p A.all?{|x| B.any?{|y| x+y>0 } } p A.all?{|x| B.any?{|y| y-x>1 } } p A.any?{|x| B.all?{|y| x+y==y } } p A.any?{|x| B.all?{|y| x+y>=6 } } p A.any?{|x| B.any?{|y| x+y==6 } }
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image03:12 exaptation: Biology The uti...» Projectionist
ex•ap•ta•tion
[eg-zap-tey-shuhn]noun
Biology The utilization of a structure or feature for a function other than that for which it was developed through natural selection.

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

Sun 05 August, 2007

Click here to bookmark this link.Channel Image21:05 リファレンスマニュアルの進捗確認 (2)» 青木日記
…… tools/ を見たらすでに書いてあった。頼りになるな過去の俺。 でもこれじゃ全体の To Do 比率しかわからないな。 さすがに未来は予見できなかったか過去の俺。 まあ、とりあえず組み込みに限定するってのが決まったのは 6月だからしかたない (このスクリプトを書いたのはたぶん 3 月)。 (18:45)
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image21:05 リファレンスマニュアルの進捗状況確認 (3)» 青木日記
うーん、プリプロセッサがからむと本来の #@todo の数を数えるのが異様に大変だ。 このへんはプリプロセッサを使う場合の弱点だよな。 でもプリプロセッサ方式でないと処理系が異様に大変になるしなあ。 よし、力押しで解決しよう。 あらかじめライブラリ (クラス) ごとのエントリ総数を数えておき、リストとして持っておく。 でもって現存する #@todo を毎日数えて、全体に対する割合を計算する。 どうせ #@todo の数のヒストリは取っとかないといけないんだから、 そのヒストリの最初のエントリを全体と考えればよかろう。 それにしても..
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image21:05 リファレンスの進捗確認 (1)» 青木日記
って、最近ルータのトラブルのことしか書いてないので別のことも書こうと思う。 放置ぎみのリファレンスマニュアルについて。 よくよく思い出すと「とりあえず 8 月にリリースね」 とかそんなことを言った記憶がある。 これはマズイ。非常にマズイ。 そもそもどれくらいマズイのかどうかわかってないよ俺。 そんなわけで、まずどれくらいマズイのか確認するために ツールを書くことにしよう。 (18:22)
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image21:05 もう OMRON のルータなんて買わねえよウァーン» 青木日記
いまのところルータは快調のようだ。 早く代えればよかったな。 しかし、とあるところから HTTP な Subversion につないだら REPORT が通らなかったんだよなあ。 でもリファレンスにコミットできている人がたくさんいるから、 こっちのファイアウォールで止められてるわけじゃなさそうだ。 向こうで止められてるのか……。ちっ。 (18:09)
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image15:39 A Big Dev House Thanks to Derek» James Britt - Code, Content, Caffiene

I want to thank Derek Neighbors and Integrum for yesterday’s Phoenix Super Happy Dev House . It was a blast.

I also want to thank those who attended; I’m know it was a bit of a drive for many (40 miles for me. Each away. :) ) but supporting these kinds of gatherings is important in bolstering the local developer community.

The demos were outstanding, as were the ad hoc discussions and hacking sessions. I especially want to thank Brian Shaler (yes, THE Brian Shaler) for showing off his Google Gears work and helping me sort out a Gears + Greasemonkey issue I had.


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image14:18 That was the heaviest slam ...» Projectionist
That was the heaviest slam we’ve ever seen.

Commentator’s response to Jake Brown’s fall


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:59 Tweets on 2007-08-04» halostatue
watching StarGate (the movie); liking that the BOSE system is finally fully configured. Sounds good. # took the car in for service; biked home (~4km). feels good. it’ll be too hot to bike back to pick it up, though. :/ # done with tennis. need to get the car back; can’t be fixed for a couple [...]
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:57 estivate: 1. To spe…» Projectionist
es•ti•vate
[es-tuh-veyt]intransitive verb
1. To spend the summer, as at a special place.
2. Zoology To pass the summer in a dormant or torpid state.

add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image10:26 Beyond time» halostatue
In Twitteriffic today, I hit the wrong button on a message sent by Nathaniel Talbott and it took me to his blog, which had his entry about handing off test/unit to Ryan Davis. It has taken me a long time to reach this point, but it has to happen: I no longer have time [...]
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image09:16 Experience of object orient...» Projectionist
Experience of object oriented programming languages is not considered a merit.

From the qualifications section of an Erlang job listing


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image07:34 图灵机» Ruby Object Oriented
http://baike.baidu.com/view/117065.htm
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl

Sat 04 August, 2007

Click here to bookmark this link.Channel Image21:43 WG Abi 2007 auf SuprGlu» chris blogs

In der Stufe haben wir ja einige recht aktive Blogger, und man kommt kaum nach mit lesen. Statt alles in mein NetNewsWire zu importieren suchte ich nach einem öffentlichen Feedaggregator und bin dann bei SuprGlu gelandet.

Sämtliche Blogs der Stufe kann man jetzt also gesammelt auf

http://wgabi2007.suprglu.com/

lesen.

Wer noch andere stufenrelevante Blogs hat, bitte bei mir melden.

NP: Bob Dylan—Let Me Die in My Footsteps


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image20:25 处理含有多个提交按钮的表单» LetRails
有时候,我们可能需要在一个表单中包含多个提交按钮(比如我写这篇帖子使用的Wordpress就为我提供了3个按钮:Save, Save and Continue Editing, Publish),但是HTML不支持将一个表单提交给不同的Action...
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image14:33 I just gave myself commit r...» Projectionist
I just gave myself commit rights to the English language.

Patrick Ewing


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:59 Tweets on 2007-08-03» halostatue
cleaning up my blog. anyone know why I can’t get a 410 result even though I’ve got the right mod_rewrite rule? # twitter-tools considers a changed slug a new blog post. interesting, and not good. # Ugh. Using CruiseControl.NET and MSBuild and Perforce is an ugly combination. # @nathaniel I actually like perforce a lot. It’s extremely [...]
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image08:38 priapism: Persistent, usual...» Projectionist
pri•a•pism
[prahy-uh-piz-uhm]noun
Persistent, usually painful erection of the penis, especially as a consequence of disease and not related to sexual arousal.

add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image08:28 Ray Charles — Ring of...» Projectionist

Ray Charles — Ring of Fire on the Johnny Cash Show


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image08:25 Wild card matching Google q...» Projectionist

Tip Wild card matching Google queries

An asterisk can be used in a Google query as a wild card placeholder in a search phrase.

For example, if you forgot how to spell “Dwemthy”, a search for:

”*’s array” why the lucky stiff

finds results for “Dwemthy’s Array”.

Or, for example, you could try:

“Yukihiro Matsumoto was born in *“

(Though “Yukihiro Matsumoto was born in” might actually be better depending on what you are looking for…)


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image06:21 一些小事» Ruby Object Oriented
1.周末网吧不关机 这样在6点到8点之间,有一些机器是可以免费上的。因为某些上通宵的人回去睡觉去了 ,没有关机。 这些人遵循“如果少做就能完成,多做就是徒劳。若无必要,务增加实体”的奥卡姆剃刀法则。睡觉去了,没有必要关机。 2.谷歌拼音安装后,其自动弹出的页面会替换当前页面,造成当前输入文档的丢失。 这是谷歌拼音程序作者没有想到的一个细节问题,这个问题说大不大,说小也不小。呵呵
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image00:17 Good feeling of oneness wit...» Projectionist
Good feeling of oneness with cup rubber.

HHKB Pro 2 box


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image00:11 Using FlexMock to Test Computational Fluid Dynamics Code» { | one, step, back | }

This is a fun example of using FlexMock

Andrew Sweeney Asks:

Andrew Sweeney emailed me with the following question:

I am currently working on a ruby project in which I think flexmock would be a good fit for unit testing. I have read the documentation and gone over the examples however fail to wrap my head around how to apply flexmock to my own app. I was hoping that you could give me some guidence and get me started or point me in the right direction.

You can find his original source code here.

I thought his problem was interesting enough to write it up as an example of using FlexMock. Andrew and his mentor, Bil Kleb gave permission for me to reproduce the code in my blog. The F3DQueue class is part of a Computational Fluid Dynamics project (http://fun3d.larc.nasa.gov) at NASA.

Quick Code Review

The F3DQueue class is small, so there’s not a lot of code we need to wade through. We see it uses a second class named AutoF3D, but the only clues we have to what AutoF3D might do are the four method calls on the “job” object in the run method.

It looks like the main interface to the queue object is the add_to_queue method. There is a thread started that pulls jobs (i.e. AutoF3D objects) from the queue and processes them in turn. There is some server delays built into the system. I presume that Computational Fluid Dynamics is, ummm, computationally complex and the delays are just there to make sure the workload does eat up all the CPU time on the server.

Starting Testing

When writing new code, I always like to approach it in a Test-First manner. Because I won’t write solution code without a test that forces me to write it, I have a high confidence that the code is well covered with tests.

Unfortunately, dealing with legacy code means that the code is already written and the test-first approach won’t work. That’s ok, I have a little trick that I use. Just comment out the bodies of all the methods in the class you are about to test. Then write the tests that force you to uncomment the code. Just uncomment only enought to get the tests to pass, don’t uncomment anything you don’t have to. You have enough tests when all the code has been uncommented. The technique is almost as good as doing real test-first.

The Commented Out Version

Here is the code base as I started the test.

An Existence Test

I almost always start out with an existence test. Existence tests basically prove the proper files are included and the object can be created. Normally I delete these after a few tests have been written. But I left this one in for an example.

   def test_initial_conditions
    q = F3DQueue.new
    assert_not_nil q
  end

Nothing really exciting here. Let’s move on …

Proving FIFO Queue Order

The first thing I want to prove is that items put into the queue are removed in FIFO order. Since add_to_queue creates a AutoF3D object, I mock out the new method on the class object and tell FlexMock to expect new to be called twice. Once with :a, :b, and :c as parameters, then again with :x, :y, :z paramters. Each invocation of new will return a different symbol (:first and :second) so we can easily test the items are pulled off the queue in FIFO order.

Notice that I pass in simple symbols for the arguments to add_to_queue. Our code doesn’t interpret the values of the arguments, they are merely passed directly to the AutoF3D constructor. All we do is verify that the AutoF3D (mocked) constructor does indeed receive the arguments we pass in.

Here’s the test:

  def test_adding_to_queue_is_removed_in_fifo_order
    flexmock(AutoF3D).should_receive(:new).once.with(:a, :b, :c).and_return(:first).ordered
    flexmock(AutoF3D).should_receive(:new).once.with(:x, :y, :z).and_return(:second).ordered
    q = F3DQueue.new

    q.add_to_queue(:a, :b, :c)
    q.add_to_queue(:x, :y, :z)

    assert_equal :first, q.remove_from_queue
    assert_equal :second, q.remove_from_queue
  end

This test caused three changes. First, the add_to_queue method needed lines uncommented:

  def add_to_queue(modelLoc, params, gridFile)
     autoF3D = AutoF3D.new(modelLoc, params, gridFile)
     @queue.push autoF3D
#     $log.info 'Request added to queue'
  end

(Notice I didn’t uncomment the log. The logger is not needed to pass the test, and doesn’t contribute to the actual functionality of the method. I will not be testing the logger in the for the purposes of this article.)

Also the remove_from_queue needed its body uncommented:

  def remove_from_queue
    @queue.pop
  end

And finally, the initializer code needed to create the queue array:

  def initialize  
     @queue = []
#     Thread.new{ process }
  end

Notice that the Thread.new line is left commented. We will deal with that in a bit.

So now we run the test:

$ ruby test_f3dqueue.rb
Started
F.
Finished in 0.010184 seconds.

  1) Failure:
test_adding_to_queue_is_removed_in_fifo_order(TestF3DQueue) [test_f3dqueue.rb:23]:
<:first> expected but was
<:second>.

2 tests, 2 assertions, 1 failures, 0 errors

Oops! This test uncovered the first bug. The code as written has stack behavior (i.e. LIFO). The naming seems to indicate that we want FIFO.

No problem. That’s an easy fix.

  def remove_from_queue
    @queue.shift
  end

Now the tests run clean:

$ ruby test_f3dqueue.rb
Started
..
Finished in 0.001925 seconds.

2 tests, 3 assertions, 0 failures, 0 errors

Proving that Running a Job Works

Now when I run a job, I need to show that the proper four methods are called once each and in the proper order. This is very straight forward using FlexMock.

  def test_running_a_job_will_call_the_right_stuff_in_the_right_order
    job = flexmock("job")
    job.should_receive(:generate_geometry_and_grid).once.ordered
    job.should_receive(:partition_grid_and_initialize_flow).once.ordered
    job.should_receive(:run_flow_solver).once.ordered
    job.should_receive(:post_process_solution).once.ordered
    q = F3DQueue.new

    q.run(job)
  end

Uncommenting the body of run is all that is needed here:

  def run( job )
#     $log.info 'Request being processed'
     job.generate_geometry_and_grid
#     $log.info 'Created Geometry'
     job.partition_grid_and_initialize_flow
#     $log.info 'Partitioned Grid'
     job.run_flow_solver
#     $log.info 'Flow Solver Completed'
     job.post_process_solution
#     $log.info 'Post process Completed'
#     $log.info 'Request completed'
  end

Test are now showing:

3 tests, 3 assertions, 0 failures, 0 errors

Processing an Empty Queue

Ok, now it gets interesting. I want to show that attempting to process a job when the queue is empty will cause the process to sleep for the check queue interval.

This is one spot where I changed the code to make it easier to test. It is difficult to test endless loops in unit tests (it tends to make the tests run a bit long), so I broke out the logic for a single pass through the loop into a method called process_one_job. We can then test this logic without dealing with the looping at the same time.

Note: It is possible to test endless loops and an example will be given below. But it is slightly tricky and this allows us to concentrate on proving the logic.

If there are no jobs to be processed, then all the code should do is sleep for a particular amount of time. We will locally mock out the sleep method on the queue object and insist that it will be called exactly once with the expected interval.

  def test_processing_with_no_jobs_will_sleep_the_check_interval
    q = F3DQueue.new
    flexmock(q).should_receive(:sleep).once.with(F3DQueue::CHECK_QUEUE_INTERVAL)

    q.process_one_job
  end

Here is process_one_job with just two lines uncommented so that the test will pass.

  def process_one_job
#       execution_attempts = 0
    job = remove_from_queue
#       begin
#         if job
#       run job
#           execution_attempts = 0
#           sleep SERVER_RECOVERY_TIME
#         else
    sleep CHECK_QUEUE_INTERVAL
#         end
#       rescue
#         $log.warn 'An error occurred during execution'
#         $log.warn $ERROR_INFO
#         $log.debug $ERROR_POSITION
#         sleep SERVER_RECOVERY_TIME
#         if execution_attempts > MAX_EXECUTION_ATTEMPTS
#           $log.error 'Too many failed execution_attempts: aborting'
#           raise
#         else
#           execution_attempts += 1
#           retry
#         end
#       end
   end

There’s a lot of code still left commented in that method. Now we need a test to force us to uncomment more code.

Handling a Single Job

Ok, now what happens when a single job is in the queue. We will assume the happy path (i.e. no exceptions) so we expect run to be called with the queued object, and then a sleep with the recovery interval.

A couple of things to note. First, we mock out AutoF3D again so that when we request something added to the queue, we control what kind of object is returned. We could return a mock object and then mock out the four methods that run will be calling.

However, I chose a slightly different approach. AutoF3D is mocked so that it returns a simple symbol. Then I mock out the run method to do nothing (but it is expected to be called once). This is slightly controversial because I am actually mocking a method on the object under test. But the run method is fairly simple, and we know that run works because of our previous test, so in the end we get clearer and simpler code.

Also note that the run and sleep methods mocks are ordered. This means run will be called first, then sleep.

  def test_processing_with_a_single_job_will_run_the_job_and_pause_for_recovery
    q = F3DQueue.new
    flexmock(AutoF3D).should_receive(:new).once.and_return(:job)
    flexmock(q).should_receive(:run).once.with(:job).ordered
    flexmock(q).should_receive(:sleep).once.with(F3DQueue::SERVER_RECOVERY_TIME).ordered
    q.add_to_queue(:a, :b, :c)

    q.process_one_job
  end

Now we get to uncomment even more lines in process_one_job.

  def process_one_job
#       execution_attempts = 0
    job = remove_from_queue
#       begin
    if job
      run job
#           execution_attempts = 0
      sleep SERVER_RECOVERY_TIME
    else
      sleep CHECK_QUEUE_INTERVAL
    end
#       rescue
#         $log.warn 'An error occurred during execution'
#         $log.warn $ERROR_INFO
#         $log.debug $ERROR_POSITION
#         sleep SERVER_RECOVERY_TIME
#         if execution_attempts > MAX_EXECUTION_ATTEMPTS
#           $log.error 'Too many failed execution_attempts: aborting'
#           raise
#         else
#           execution_attempts += 1
#           retry
#         end
#       end
   end

That just leaves the error handling code to be uncommented. So that will be next.

Handling a Job With Errors

Now we want to test the case where processing a job will return an exception. This test exercise the exception recovery code in the original code base. The technique is similar to the last test, but this time we specify two mock calls for run. The first time run will return an exception. The second time it is called, it will complete normally.

Notice that we have ordered run and sleep so that they interleave execution with each other.

  def test_if_a_job_fails_retry_after_recovery_time
    q = F3DQueue.new
    flexmock(AutoF3D).should_receive(:new).once.and_return(:job)
    flexmock(q).should_receive(:run).once.with(:job).and_raise(RuntimeError).ordered
    flexmock(q).should_receive(:sleep).once.with(F3DQueue::SERVER_RECOVERY_TIME).ordered
    flexmock(q).should_receive(:run).once.with(:job).ordered
    flexmock(q).should_receive(:sleep).once.with(F3DQueue::SERVER_RECOVERY_TIME).ordered
    q.add_to_queue(:a, :b, :c)

    q.process_one_job
  end

I was showing this test code to one of my coworkers and they were a little surprised that the second expectation on run didn’t override the first expectation. FlexMock is explicitly designed to allow you to stack expectations like this. When searching for an expectation during mocking, FlexMock will use the first one matching one if finds. When an expectation has been used its designated number of times (in the above test, the once method designates that the expectation should only be used once), FlexMock will begin to use matching expectations that are defined later.

The upshot is this is that it is easy to define mock behavior for multiple calls to the same method.

Here’s the latest process_one_job method with some more lines uncommented. We are getting close to the end with this one.

  def process_one_job
#       execution_attempts = 0
    job = remove_from_queue
    begin
      if job
        run job
#           execution_attempts = 0
        sleep SERVER_RECOVERY_TIME
      else
        sleep CHECK_QUEUE_INTERVAL
      end
    rescue
#         $log.warn 'An error occurred during execution'
#         $log.warn $ERROR_INFO
#         $log.debug $ERROR_POSITION
      sleep SERVER_RECOVERY_TIME
#         if execution_attempts > MAX_EXECUTION_ATTEMPTS
#           $log.error 'Too many failed execution_attempts: aborting'
#           raise
#         else
#           execution_attempts += 1
      retry
#         end
    end
  end

Processing Jobs that Continually Fail

Finally we test the case where the job will continually raise an exception until the error recovery code gives up and passes the exception on to the caller. I didn’t bother ordering the run/sleep calls here, making it easy to just specify that each are called four times. I believe that the previous test adequately specified interleaving.

I used a RuntimeError for my testing. If you have a specific error in mind, you might want to test explicitly for it. Generally raising the most general error you intend to handle is a good way of testing the boundry conditions on your rescue clause.

  def test_too_many_failures_will_pass_along_exception
    q = F3DQueue.new
    flexmock(AutoF3D).should_receive(:new).once.and_return(:job)
    flexmock(q).should_receive(:run).with(:job).and_raise(RuntimeError.new("XYZZY")).times(4)
    flexmock(q).should_receive(:sleep).with(F3DQueue::SERVER_RECOVERY_TIME).times(4)
    q.add_to_queue(:a, :b, :c)

    ex = assert_raise RuntimeError do
      q.process_one_job
    end
    assert_equal "XYZZY", ex.message
  end

Note that the exception needs to be raised four times. I suspect this is a bug in the error handling logic. I left the logic as is and just made sure the test will pass. The code base specifies a retry count of “2”. This seems to imply that we try run twice, or perhaps three times (if the initail attempt doesn’t count as a retry). In any case, four times seems too much.

So, here is the code for process_one_job with most of its lines uncommented.

  def process_one_job
    execution_attempts = 0
    job = remove_from_queue
    begin
      if job
        run job
#           execution_attempts = 0
        sleep SERVER_RECOVERY_TIME
      else
        sleep CHECK_QUEUE_INTERVAL
      end
    rescue
#         $log.warn 'An error occurred during execution'
#         $log.warn $ERROR_INFO
#         $log.debug $ERROR_POSITION
      sleep SERVER_RECOVERY_TIME
      if execution_attempts > MAX_EXECUTION_ATTEMPTS
#           $log.error 'Too many failed execution_attempts: aborting'
        raise
      else
        execution_attempts += 1
        retry
      end
    end
  end

Again note that this test surfaced a (rather minor) bug. There is an extra assignment that clears the execution attempt counter after a successful run of job. Since a successful run will exit the loop, clearing it has no effect (unless it is the sleep command that fails, that would be an interesting test scenario).

Since we haven’t shown the test results for a while, here’s how we stand at this point:

7 tests, 5 assertions, 0 failures, 0 errors

Processing Multiple Jobs

Now we know that we can handle a single job successfully. Now let’s make sure that we can handle multiple jobs. Remember that we broke process into two methods: process_one_job and a much shorter process that will call process_one_job in a loop.

Here’s what the original process method is looking like at the moment:

  def process
#     loop do
#     end
  end

We pulled out its guts and left the still commented loop there. We haven’t even bothered to have it call process_one_job yet. So let’s write a test that will force us to fix that.

We will just mock out process_one_job so that it must be called 10 times. On the eleventh call it throws a symbol that we catch in the test. Throwing a symbol is the trick that breaks us out of the infinite loop. By throwing a symbol (rather than raising an error), we don’t interact with the error handling logic of the code under test.

This is actually the trick refereced earlier. By breaking the body of the loop into a separate method, we only have to use this trick once rather than on each of the process job tests.

  def test_process_calls_process_one_job_in_a_loop
    q = F3DQueue.new
    flexmock(q).should_receive(:process_one_job).times(10)
    flexmock(q).should_receive(:process_one_job).and_return { throw :done }

    assert_throws(:done) do 
      q.process
    end
  end

To get this to pass, we implement the process method as follows:

  def process
    loop do
      process_one_job
    end
  end

Threading Issues

Finally we need to make sure a thread is started. Here is another place I changed the code to make testing easier. The original code base started a thread in the initializer of the object. This means that every F3DQueue object ran in its own thread. This would means every test would have to deal with multithread issues. Yuck!

I changed the code so that a thread is started only when explicitly calling the start method. I like this better for real object anyways. Although it is an extra step, it gives you more control about when the threads are started. If you really want to start a thread at object creation, you can just say:

queue = F3DQueue.new.start

Since I really don’t want to start a Thread in the test (I just want to make sure that the Thread.new method is called), I mock out Thread.new so that it must be called once and when called will execute the given block.

I then mock out the process method to that it must be called once. The combination of these two mocks will ensure that start will start a new thread that calls process.

And finally, I ensure that the return value of start will be the queue object. This makes sure that the F3DQueue.new.start idiom works.

  def test_start_will_start_a_process_thread
    q = F3DQueue.new
    flexmock("thread", Thread).should_receive(:new).with(Proc).once.and_return { |block| block.call }
    flexmock(q).should_receive(:process).once

    return_value = q.start
    assert_equal q, return_value
  end

And is is the little start method that needed to be written for the test. The Thread.new line is moved from the initialize method to here.

  def start
    Thread.new do process end
    self
  end

Here’s our final test run:

9 tests, 7 assertions, 0 failures, 0 errors

Code Coverage

We know that TDD gives pretty code code coverage stats out of the box. How did our “Comment-out First” approach do with regards to code coverage?

Here is the RCov report:

+----------------------------------------------------+-------+-------+--------+
|                  File                              | Lines |  LOC  |  COV   |
+----------------------------------------------------+-------+-------+--------+
|AutoF3D.rb                                          |     5 |     2 | 100.0% |
|f3dqueue.rb                                         |    82 |    53 | 100.0% |
|test_f3dqueue.rb                                    |   100 |    76 | 100.0% |
+----------------------------------------------------+-------+-------+--------+
|Total                                               |   187 |   131 | 100.0% |
+----------------------------------------------------+-------+-------+--------+
100.0%   3 file(s)   187 Lines   131 LOC

Wow! 100% on the first try.

Final Code Samples

You can find the final versions of the F3DQueue object and its tests here:

Future Directions

Now that the F3DQueue object is well testing, it is time to take a step back and think about the overall design of the class. There are a couple of things that stick out in my mind about this code.

(1) First Item

We did a lot of mocking on the F3DQueue object itself while it was being testing. Although a valid technique, you must be careful so that you don’t end up just testing your own mocks. What it does indicate is that the object you are testing might be trying to do too many things. Perhaps the class needs to be broken up into small classes, or perhaps some functionality needs to move into other classes.

With this in mind, the run method seems to know an awful lot about the workings of an Auto3D job object. It seems a bit out of place. Why don’t we move the run method to the job itself. Moving run into the Auto3D job object would allow us to write the following code fragment (in the process_one_job method):

...
  job = remove_from_queue
    begin
      if job
        job.run                       # was: run job
        sleep SERVER_RECOVERY_TIME
...

Now, our queue class is one method shorter and is just concerned with the scheduling of the jobs and not the details of running the job itself. This is good …

Except for the following little piece of code, which leads us into the second thing that bothered me:

  def add_to_queue(modelLoc, params, gridFile)
    autoF3D = AutoF3D.new(modelLoc, params, gridFile)
    @queue.push autoF3D
  end

(2) Second Item

Here we have direct knowledge of the AutoF3D class. If we remove the reference to AutoF3D, then our queue will suddenly become much more general, and usable in situations where we might want to process a different kind of job.

I would recommend changing the above code to:

  def add_to_queue(job)
    @queue.push job
  end

This does mean that adding a job to the queue would now have to create the job object explicitly. So, instead of:

   queue.add_to_queue(loc, param, grid)        

you would have to write:

   queue.add_to_queue(new AutoF3D.new(loc, param, grid))

If you don’t like to manually create an AutoF3D object all the time (and I don’t), then the following solution is an easy fix to that:

  queue = F3DQueue.new
  def queue.add_job(loc, params, grid)
    add_to_queue(AutoF3D.new(loc, params, grid))
  end

The more traditionally minded of us might want to just subclass the F3DQueue class and add the add_job method in the subclass rather than in the singleton class. That works too. Either way, it is easy to do.

Recap

I hope this was useful for you. Here is a recap of some of the important ideas from this exercise:

  • Comment-First is not a bad way to handle legacy code.
  • Test scenarios, not methods. Note that I didn’t just pick a method in F3DQueue and write a single test for it. I choose scenarios that would exercise different sections of the code base. Start with the simple (e.g. a Job that Doesn’t Fail). Then pick increasing harder scenarios (e.g. “a Job that Fails Once”, “a Job that Fails Multiple Times”).
  • Don’t be afraid to refactor to make testing easier. Breaking out process_one_job was a great idea that not only made testing much easier, but made the code easier to read.
  • The “Use Symbols as Cheap Mocks” is an idea I stole from Stu Halloway in his “Refactoring of the Week” presentation. If a method takes arguments that you don’t want to deal with, try passing in symbols. If the arguments aren’t used, the symbols work great. If an argument is actually used, the error message will identify the symbol at fault. At that point, just replace the symbol with the appropriate mock. This technique save you lots of time and makes the tests easier to read.
  • If you want to break out of an infinite loop in the code under test, throw a symbol from your mocks and catch it in your test. This generally doesn’t interfere with any exception handling code in your code under test.
  • Always take a step back and look for ways of improving the code. A well tested module is fairly easy to change with confidence. Don’t be afraid to improve things.

More Samples

Do you have a bit of code that you are having trouble testing? If so, go ahead and send it to me. If your code is interesting enough, I’ll take a look at it and post the results here (so don’t send anything you aren’t willing to see published in this blog). I can’t look at everything, but I’ll try to find some interesting examples.


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image00:11 採用面接» Matzにっき
普段なら採用面接を担当してる前田くんが 外せない用事があったということで、私ともう一人で採用の技術者面接を受け持つ。 で、FizzBuzzにヒントを得て紙の上に簡単なプログラムを書くという問題を 2問ほどやってもらう。緊張したのかちょっと的外れな解答もあったけど、 さすがに全然プログラムができないってことはなさそう。 っていうか、日本での面接で全然プログラムできないプログラマ候補に出会ったことないんだけど、 それはやっぱりエンジニアの地位が高いアメリカ固有の事情なのだろうか。 日本でのエンジニアの地位なら、でき..
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image00:11 UTN #27: Known anomalies in Unicode Character Names» Matzにっき
Unicodeに間違いがあるって知ってた? まあ、9万以上も文字があれば間違いがあるのも無理はないかもしれない。 しかし、どのような経緯でこんな間違いがまぎれ込んだのか、 むしろ、その辺が知りたい気もする。
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image00:11 ITpro Challenge!» Matzにっき
というイベントが開催されるそうだ。 プログラマーの挑戦が世界を変える ハッカーの流儀がメインストリームになる のだそうだ。本当かな。 まあ、いずれにしても著名人たちの話が聞けるのは貴重な機会であろう。 定員が限られてるみたいだけど。70名は少なすぎるなあ。 江島健太郎 鵜飼文敏 伊藤直也 戀塚昭彦 小飼弾 私はちょうど同じ日にX-Devに呼ばれてるから 顔を出すくらいはできるかもしれない。
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl

Fri 03 August, 2007

Click here to bookmark this link.Channel Image21:08 小试capistrano» 动态感觉 静观其变
最近几天抽时间试验一下capistrano,大概走通了一下,它的文档简而又简,只给出了一点大框架的说明,并没有透露出一些细节,不过总体上还是能了解到大概的一个做法和思路。主要还是给ssh的处理上碰到了一些麻烦,我对ssh不是很了解,这次总算了解了一下,win/ubuntu下的都使用了一下,win下使用putty,pageant来处理,ubuntu server端需要openssh,ssh-agent等,有时间我把一些细节再整理一下。...
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image17:49 人是有局限性的» Ruby Object Oriented
视力再好的人,好不过望远镜. 耳朵再灵的人,敌不过电话 跳得再高的人,高不过飞机. 算得再快的人,快不过计算机. … 这不是说人始终都不如工具,而是说,人是有局限性的,可以用工具弥补之. 不重视工具的舆论,不利于工具的发明.
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image17:14 情報科学類案内» Matzにっき
私の母校、筑波大学の情報科学類のパンフレット。 いつの間にか学類の名前が変わっている(情報学類→情報科学類)。 「先輩からのメッセージ」というところに、観たような顔の人が...。
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image17:14 InfoQ: Rubinius Internals: Threading, ObjectSpace, Debugging» Matzにっき
Rubiniusについてのインタビュー、続き。 最近、JRuby界隈でも話題になっているThreadingやObjectSpaceについて。 Rubiniusにはそれらについての問題はあまりない、とのこと。 完全に独立したmachine(MultiVMのこと)を作るのは簡単だし、 それらを独立したnative threadに割り当てたり、channelを通じて相互通信したりできる。 また、メモリ管理は自前でやっているのでObjectSpaceの問題もない。 あと、バイトコード置き換えのテクニックを使ってパフォーマンスの劣化なしに、 ブレークポイントが使えるというのも魅力的である。 もちろん、..
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:59 Tweets on 2007-08-02» halostatue
managing perforce users at work # Setting up more VMs. # Powered by Twitter Tools.
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:49 Changes Coming» halostatue
So far, I’ve had two abortive attempts at personal blogging; I still want to blog, but I have to figure out what I want it to be about, and how much I want to talk about work (if at all). I’m going to be playing with some new themes for WordPress and some new plug-ins [...]
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:29 オープンソースで「永く使える安心」を守るために:ITpro» Matzにっき
製品ベンダーによって狙いは様々だろうが,OSSの開発企業やコミュニティを取り込もうとする動きが活発化するのは必至だ。その中で,いかに開発コミュニティを維持していくか。OSSも属人的な人のつながりに依存したままでなく,組織運用力が問われる時代になったと言えそうだ。 古くからオープンソース/フリーソフトウェア開発に関ってきたものとしては ビジネス論理はちょっと「イヤな感じ」がするのが正直なところだが、 企業の論理も理解できる。 Rubyアソシエーションの設立は まさにそこを埋めるためのものだ。
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:29 The Broken Metric of Intuitive to the Uneducated Language Syntax - O'Reilly ONLamp Blog» Matzにっき
初心者に理解しやすいため、プログラミング言語の文法は プログラミング経験のない人にも分かりやすいものでなければならない、 という指標は間違っている。なぜなら文法(シンタックス)は意味(セマンティクス)ほど 重要ではないからだ、という話。 が、セマンティクスの違いというのは、 「普通の言語」とProlog、HaskellやErlangのような場合であって、 「普通の言語」の間では、文法の違いはそれなりに重要だと思う。 もっとも、「初心者向けである必要はない」という点では同意するのだが。
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:29 Rubyをビジネスに活用へ、40超の企業が集まり新団体:ITpro» Matzにっき
Rubyビジネスコモンズの設立。 Rubyアソシエーションの設立と時期が前後するため、 ややわかりにくいが、対象が結構異なるため、 「中の人」の眼からは競合しないと思ってる。 ビジネス分野における「Rubyの安心感」の達成を目指し、 (開発)コミュニティとビジネス界(とそこからのお金)の関係構築を目指す Rubyアソシエーション ビジネス分野におけるRubyコミュニティ構築を目指すRubyビジネスコモンズ という感じか。 共通するのは「Rubyビジネスはじまったな」という点くらいだと。 ま、競合するくらいならRA理事長たる私がRubyビジネス..
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:29 Open Tech Press | Nintendo DS(Lite)でオープンソース系ソフトウェアを使用する» Matzにっき
Nintendo DSをコンピュータとして考えると、 めちゃめちゃ低価格でそれなりのパフォーマンスがある。 バッテリーも長持ちだし。 とりあえず息子のDSを借りて試してみるかな。 このサイズと価格ならPDAの代わりになる、かも。いや、やっぱ難しいか。 最初にメモリカードリーダを買わないといけないのかな。
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image09:01 无重力平展树» Ruby Object Oriented
昨天看到一本”算法设计”的书,里面提到”重力倒挂树”的说法. 事实上,树是一种典型的连通图. 而”无重力平展树”的形象,更能体现树的图本质—-树是一种连通图.
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image06:39 Otis Redding — I’ve b...» Projectionist

Otis Redding — I’ve been loving you


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image00:52 Facebook API debugging» Projectionist

Facebook API debugging

Chad - wow debugging facebook API problems is a PAIN
Chad - parameter error: here are the parameters you posted
Chad - but not
Chad - parameter error: this particular parameter is wrong or missing
Marcel - You've been PHPeed on

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

Thu 02 August, 2007

Click here to bookmark this link.Channel Image21:57 crepuscular: 1. Of or like ...» Projectionist
cre•pus•cu•lar
[kri-puhs-kyuh-ler]adjective
1. Of or like twilight; dim.
2. Becoming active at twilight or before sunrise, as do bats and certain insects and birds.

add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image21:08 path @ vim» nonocast ! 真诚原是一种需要坚强不屈的品质
#include <stdio.h>

int main(){
    pri

在edit mode下直接^p就应该提示printf,
如果cur在stdio.h中,则gf(goto file)应该直接跳转到stdio.h

but E447 在路径中找不到文件
然后在system path中加入D:/Program Files/Microsoft Visual Studio 8/VC/include
没用

重启
没反应

然后google,在.vimrc中加入
"set path+="D:\Program Files\Microsoft Visual Studio 8\VC\include"
还是不行

最后老老实实:help path
...(老老实实help)

最后如下,
set path+=D:/Program\\\ Files/Microsoft\\\ Visual\\\ Studio\\\ 8/VC/include/
set suffixesadd=.java,.py,.pyw,.h,.hpp

ok.
最后不忘:help!
别慌我!
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image16:12 PHP’s DSL?» Ruby Object Oriented
<?php function ∑() {     return array_sum(func_get_args()); } echo ∑(1,2,3); ?>
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image15:17 Ruby Association Launches, With Bad-ass Logo» James Britt - Code, Content, Caffiene

From the home page :

The Ruby Association LLC is an organization to help development of the programming language Ruby. The goals of the Ruby Association are to improve relationship between Ruby-related projects, communities and businesses, to address issues connected with using Ruby in an enterprise environment.

Seems to be Ruby Central, but for Japan.

It’s a bit hard to tell, so maybe I’m mistaken, but the logo looks like a Penrose Triangle .

And if it isn’t, then it should be.


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image15:17 erubycon Summary» { | one, step, back | }

Better late than never, here are some thoughts from the erubycon conference in Columbus Ohio.

erubycon Themes

First of all, what a great conference. The talks were great and the hallway interactions were excellent. Glenn Vanderburg’s talk on “Enterprise, Schmenterprise” hit the nail on the head. (paraphrased soundbite: “The Enterprise it not ready for Ruby, it is desperate for it).

Testing, Testing, Testing

But the theme that kept coming back to me over and over again from the conference was testing: unit testing, integration testing, UI testing, all of them. Stu Halloway’s talk on the “Refactoring of the Week” emphasized the importance of tests to enable refactoring. In addition, Stu made a strong pitch for getting 100% code coverage in the projects you are working on. In selecting code to be refactored for his talks, he would just zero in on any code reported not covered by RCov and start looking there for fruitful refactoring possibilities.

So, the moral of the story is that if you have 100% code coverage, then Stu has to work a bit harder to find examples for his refacting talks.

I was inspired by Stu’s talk so I went back and checked all my open source projects to see how well they were covered by tests. I’m happy to say that both flexmock and builder are now at 100% and only needed a little tweeking to get that last percent or two. (Except for the CSS builder … we really need to finish that class or dump it).

The main library file of Rake is now at 100%. It was in the mid 90s when I check and needed some attention to get it the rest of the way. So that is good.

The unfortunate part is that there are some pieces of Rake that are not well covered. First there are a number of deprecated libraries that aren’t at 100%, and since people shouldn’t be using them, I’m more likely to remove them entirely than to write tests for them.

Second, the are some Rakefile tasks that are not adequately covered. I’m not sure how to address this for Rake tasks tend to be very involved in the environment you are working in, making it tedious to mock. I’d love to make the testing of Rake tasks easier, so fee free to make suggestions.

As for RubyGems … I’d rather not talk about the code coverage stats on that one.

So, I’m making RCov a part of my standard Rakefile setup and will start running it more religiously to keep those code coverage numbers up.

Emacs … We’re not dead yet!

I can’t really call it a “theme” of the conference, more like a strong undercurrent. There was certainly a number of programmers attending who use Emacs for their day to day editting, even when programs like TextMate are available. While emacs is a strong editor for a wide number of programming languages, its support for Ruby and Rails is lagging behind some of the more recent editors that are targetting Ruby specifically (e.g. the aforementioned TextMate). A group of us holdouts got together and shared some tips and tricks on bringing Emacs closer to the state of the art in Ruby support. I’ll share some of those tips here in the near future.

Next Time

Going into this conference, I heard the organizers swear they were never doing this again, but the the end everyone was enthusiastic about next year. So, who knows, if you’ve missed this year’s erubycon, you might get a chance to join us next year.


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:59 Tweets on 2007-08-01» halostatue
FB and twitter aren’t working too well together… # Powered by Twitter Tools.
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image11:22 星级统计» Ruby Object Oriented
某星级的个数,以及该星级包含半星级的个数统计: SELECT star,count(star),sum(half) FROM `stars` group by star 其中可以体现count函数和sum函数在group by时候的作用与不同. CREATE TABLE `stars` (   `id` int(11) NOT NULL auto_increment,   `name` varchar(200) NOT NULL,   `star` int(11) NOT NULL,   `half` int(11) NOT NULL default '0',   PRIMARY KEY  (`id`) )ENGINE=InnoDB; INSERT INTO `stars` (`id`, `name`, `star`, `half`) VALUES  (1, 'a', 1, 0), (2, 'a', 2, 0), (3, 'a', 1, 0), (4, 'a', 3, 0), (5, 'a', 4, 0), (6, 'a', 1, 1), (7, 'a', 2, 1), (8, 'a', 2, [...]
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image09:29 有序对访问» Ruby Object Oriented
假设有序对[a,b,f(a,b)],对于任意a和b,存在映射f,使得第三个元素等于f(a,b).那么可以有两种方法访问已经形成的一组有序对: $data=[ [1,1,"a"], [1,2,"b"], [1,3,"c"],   [2,1,"d"], [2,3,"e"] ]   def get_row(*keys)   a,b = keys   $data.find{|row|row[0]==a and row[1]==b} end   p get_row(1,2) p get_row(2,1)     class Array   def pkey     inject({}) do |h,e|       h[yield(e)]=e       h     end    end  end      p gdata = $data.pkey{|e|[e[0],e[1]]}   p gdata[[1,2]] 如何从关系数据库里查询得到一组有序对?举例入下: SELECT * FROM `contracts` WHERE  (sale_id between 20 and 50 ) and  (signed_time between '2006-2-1' and '2006-9-1') 逻辑依据:(a or b) and (c or d)等效于(a and c) or (a and d) or (b and [...]
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl

Wed 01 August, 2007

Click here to bookmark this link.Channel Image13:27 XRAY Your Site» James Britt - Code, Content, Caffiene

From westciv :

XRAY is a bookmarklet for Safari, Firefox, Camino or Mozilla. Use it to see the box model for any element.

And it is. When loaded, it will allow you to click on any element in the current page and show you all sorts of creamy CSS goodness.

Very groovy


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image13:27 Why Are We So Scared of Offending Muslims?» Joey Gibson's Blog

If you can get past Hitchens' polemic against all religion, this commentary is excellent.


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image13:27 New Ruby Profiler Released: Supports Rails, threads, IRB, and more» Matzにっき
新しいruby-profでは 再帰的メソッド Rails スレッドアプリケーション IRBからの呼び出し 64ビットCPU をサポートしているという話。Railsアプリのプロファイルとかは嬉しい気がする。
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image04:02 Rails框架技术讲座:数据库后台管理插件RailsMyAdmin» 道喜技术日记
Rails框架技术讲座:数据库后台管理插件RailsMyAdmin

目录
 (一)系统环境:

  1. Ruby 语言 1.8.4版本, 点击这里Ruby1.8.4。要想安装多个Ruby语言运行环境请看这里
  2. Rails 框架 1.2.1版本,安装方法请看这里,最简单方法是第一种方法即可。
  3. Windows XP 或者 Windows 2000操作系统 或者 Linux操作系统
  4. 需要一个浏览器,如FireFox1.5.0.1以上版本。
  5. 开发编辑工具 Notepad2 ,安装方法请单击这里,复制一个notepad2.exe,并且更名为vi.exe。
  6. 在Windows XP上安装Linux核心命令,点击这里
  7. 如何在Windows Console下使用命令svn(下载软件),点击这里

 (二)前提条件:

  1. 在本机Winodw操作系统上,我们的工作目录为d:\works_rails。
  2. 你的电脑必须在线。

 (三)目的:

  1.  RailsMyAdmin是一个Rails框架软件的插件,它可以管理你的Rails框架软件数据库,注意不仅仅可以是MySQL数据库,也可以是其它的数据库。
  2. 本讲座的完整代码请您在Google Code Hosting上查看:
    https://cnruby.googlecode.com/svn/trunk/rails-projects/use_railsmyadmin
    或者下载
    svn co https://cnruby.googlecode.com/svn/trunk/rails-projects/use_railsmyadmin

 (四)解决方案:

  1. 创建一个Rails框架的应用软件,切换到软件的根目录。
    rails use_railsmyadmin
    cd use_railsmyadmin
  2. 修改数据库配置文件
    vi config/database.yml
    【具体内容如下:用下面的代码替换原文件的所有内容】
    development:
      adapter: mysql
      database: myadmin
      username: root
      password: root
      host: localhost

    test:
      development

    production:
      development
  3. 创建一个MySQL数据库myadmin
    mysqladmin -u root -proot create myadmin
  4. 自动生成一个基于模型Admin的相关代码,增加表admins的字段username和password,最后执行生成数据库表的命令。
    ruby script/generate scaffold_resource admin

    vi db/migrate/001_create_admins.rb
    【具体内容如下:放在create_table一行下面】
          t.column :username, :string
          t.column :password, :string

    rake db:migrate
  5. 第一步:安装RailsMyAdmin插件;第二步:生成应用于我们软件的代码;第三步:修改我们软件的环境配置文件。
    ruby script/plugin install http://railsmyadmin.googlecode.com/svn/trunk/my_admin/

    要是第一次安装失败,再使用下面命令执行。
    ruby script/plugin install --force http://railsmyadmin.googlecode.com/svn/trunk/my_admin/

    ruby script/generate my_admin

    vi config/environment.rb
    【具体内容如下:放在该文件最后】
    ## MY ADMIN CONFIG  BEGIN
    require 'my_admin/my_admin_tool'

    # If you only want certain models to be available to RailsMyAdmin,
    # set :all_models to false and specify the desired models in MY_ADMIN_MODELS
    MY_ADMIN_GLOBALS  = {:all_models => true, :confirm_destroy => false}

    # Uncomment the following line if you set :all_models to false above.
    #MY_ADMIN_MODELS = [User, Content]
    # Replace [User, Content] with your desired array of model classes that
    # RailsMyAdmin should be restricted to.

    # MY_ADMIN_AUTH must define a Proc object that takes as a paramater
    #   an ApplicationController instance variable (c - in the example below).
    # If you have a method defined in your ApplicationController,
    #   'admin_logged_in?' for example, the following sample code will
    #    authenticate against that method and only allow visitors to
    #    view RailsMyAdmin if the 'admin_logged_in?' method returns true.

    MY_ADMIN_AUTH     = Proc.new { |c| c.send('admin_logged_in?') }
    ## MY ADMIN CONFIG  END
  6. 启动网络服务器
    ruby script/server
  7. 再打开一个Shell,执行下面命令
    start http://localhost:3000/my_admin/main
  8. 我们看到该插件结果图:

 (五)视听教学:




 (六)必须注意的问题:




 (七)参考资料:




 (八)命令清单:

rails use_railsmyadmin
cd use_railsmyadmin

vi config/database.yml
development:
adapter: mysql
database: myadmin
username: root
password: root
host: localhost

test:
development

production:
development

mysqladmin -u root -proot create myadmin

ruby script/generate scaffold_resource admin
vi db/migrate/001_create_admins.rb
t.column :username, :string
t.column :password, :string
rake db:migrate

ruby script/plugin install http://railsmyadmin.googlecode.com/svn/trunk/my_admin/
ruby script/plugin install --force http://railsmyadmin.googlecode.com/svn/trunk/my_admin/
ruby script/generate my_admin
vi config/environment.rb
## MY ADMIN CONFIG BEGIN
require 'my_admin/my_admin_tool'

# If you only want certain models to be available to RailsMyAdmin,
# set :all_models to false and specify the desired models in MY_ADMIN_MODELS
MY_ADMIN_GLOBALS = {:all_models => true, :confirm_destroy => false}

# Uncomment the following line if you set :all_models to false above.
#MY_ADMIN_MODELS = [User, Content]
# Replace [User, Content] with your desired array of model classes that
# RailsMyAdmin should be restricted to.

# MY_ADMIN_AUTH must define a Proc object that takes as a paramater
# an ApplicationController instance variable (c - in the example below).
# If you have a method defined in your ApplicationController,
# 'admin_logged_in?' for example, the following sample code will
# authenticate against that method and only allow visitors to
# view RailsMyAdmin if the 'admin_logged_in?' method returns true.

MY_ADMIN_AUTH = Proc.new { |c| c.send('admin_logged_in?') }
## MY ADMIN CONFIG END

ruby script/server
start http://localhost:3000/my_admin/main


 (九)下载文件pdf:


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

Tue 31 July, 2007

Click here to bookmark this link.Channel Image23:21 God: Monit的Ruby实现» LetRails
God是一个使用Ruby写成的用于监视任务运行状态的可扩展框架,它的配置脚本同样采用Ruby来编写。因此,比起它的前辈Monit,God更为简单,灵活且易于扩展(尤其对于Ruby使用者),你可以很轻易...
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image18:38 解决ubuntu下的rails开发时mysql的问题!» Ruby On Rails Techlogs --1ster..!
今天开电脑的时候没有注意选择,直接重启到前几天装的ubuntu下,于是懒得重新启动了,于是就在 ubuntu下继续开发好了,rails环境前几天就搭建好了,也测试过了,于是把源代码copy过来,重启后,初始化数据库,页面显示乱码,进数据库看看也是乱码,看来是有点问题。 于是google了一把,抓住关键点,很快就解决了,以前在win下出现过乱码都解决了,所以这里针对ubuntu上的问题: 1、配置sock地址 另外还可能会出现一个错误 No such file or directory - /tmp/mysql.sock 这个是因为在ubuntu下默认的mysql是如上位置,于是在database.ym里面需要重新设置一下就ok了,如下: SQL代码 1. development: 2. adapter: mysql 3. database: sdroad_development 4. username: root 5. password: 6. host: localhost 7. socket: /var/run/mysqld/mysqld.sock 2、改变mysql编码,如下: 1.) 修改mysql的配置文件 sudo gedit /etc/mysql/my.cnf 在[client]下面增加 default-character=utf8 2. )在mysql shell下建立数据库. create database 1ster default character set utf8; *同时发表:*http://weblog.1ster.cn/?action=show&id=153
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image18:38 用Magick操作数据库blog字段的图像!» Ruby On Rails Techlogs --1ster..!
一直不是很喜欢用一些插件,一来觉得没有必要使用那么复杂的,一些特色功能我们完全可以写代码完成,比如用Magick操作图片等等,就很方便和简单; 以前说过如何处理磁盘上的图片,今天看看如何用Magick操作数据库中blob字段的图片,看代码就明白咯,如果对你有用,记得谢谢我哈:) Ruby代码 1. #这个是用来生成用户图像的 2. def picture 3. @user = User.find(params[:id]) 4. image = Magick::Image::from_blob(@user.data).first 5. # clown = Magick::Image.read(.read).first 6. image.crop_resized!(60, 60, Magick::NorthGravity) 7. send_data(image.to_blob, 8. :filename => @user.nickname, 9. :type => @user.content_type, 10. :disposition => "inline") 11. end 有不明白的就留言问哈。 同时发表于:http://weblog.1ster.cn/?action=show&id=145
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image18:38 rails笔记 active controller» Ruby On Rails Techlogs --1ster..!
别人写的一篇文章,推荐整理下,如下地址: http://weblog.1ster.cn/?action=show&id=150
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image18:38 日記的な - multipart時のCGIライブラリの挙動» Matzにっき
Rubyのcgi.rbはリクエストボディのサイズが10Kを越えると パラメータとして文字列でなくStringIOかTempfileを渡す。 それが使いにくい(ので直してしまおう)という話。 正直、Rubyのcgi.rbは古めかしいし、この件をはじめとして あちこち使いにくいことが残っているので、 捨ててしまいたい。 問題は適切な移行パスが思いつかない点だ。 世の中はほとんどRailsだからcgi.rbはさほど使われていない(から、どう変えても問題なし) だとありがたいんだが、世の中そうは甘くないだろうな。
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image18:38 ITmedia +D LifeStyle:「1世代コピー9th」では誰も幸せになれない» Matzにっき
なんだか新しいアクションを取れば取るほど、墓穴を掘っているような気がする。 もう日本の(TV系)メディアの未来に関して希望は持てないな。 前から宣言しているように、4年後に地デジ完全移行になれば、 私はもう(放送受信装置としての)テレビを捨てるし、 HD画像も要らない。 正直、HD画像はきめ細かくて情報量は多いんだけど、 カメラがパンする時とかに、車に酔ったような気分になるので、 全然うれしくない。 ネットから情報を得るか、アナログにダウングレードしてから見るから、 こういう新しい(消費者不在の)テクノロジーたちは、..
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image18:38 IT Conservative: 10 Years of XML: Global Warming» Matzにっき
XMLは誕生以来ほぼ10年になるが、その結果は地球温暖化ではないか、という話。 つまり、XMLはシンプルではあるが非効率である。 CPUサイクルやネットワーク帯域を少しずつ無駄遣いしている。 そして、その消費されたエネルギーは地球温暖化(Global Warming)の原因の一つかもしれない。 アル・ゴアはこの件についてドキュメンタリーを書くべきではないか。 いや、CPUサイクルの無駄遣いに関しては、我らスクリプト言語も同罪だな。
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image18:38 Dr Nic >> Magic Wiggly Lines => GuessMethod, by Chris Shea» Matzにっき
特にirbの中で用いることを想定したスペルチェック付きメソッド呼び出し。 $ irb require 'rubygems' require 'guessmethod' class Object; include GuessMethod; end class Product; def name; "Some product"; end; end Prodct.nw.nae attention: replacing non-existant constant Prodct with Product for Object attention: sending new instead of nw to Product:Class attention: sending name instead of nae to #Product:0x144ff10:Product = “Some product” 以前からNameErrorでスペルチェックを行う「もしかして」機能付エラ..
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image18:38 CodeZine:L2Lisp in Ruby(インタープリタ)» Matzにっき
オリジナルはPascalで記述されたLispインタプリタを Rubyで再実装したもの。 手軽っぽくてLispの孝三構造を理解するのに良さそうだ。 でも、出自を考えると、どうしてPythonでないのかというのは疑問である。
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image13:44 Dependency Injection in One Sentence» { | one, step, back | }

Condensing thoughts down to one sentence …

In One Sentence …

So I was asked this question in IM today:

If you had one sentence to explain to a Java programmer why Dependency Injection is rarely necessary in Ruby, what would it be?

Wow, one sentence! After some thought, here’s what I sent back:

Dependency injection provides vital flexibility in Java and unneeded overhead in Ruby.

Anyone have other suggestions?


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image05:44 Last week of early-bird price for RailsConf Europe» Riding Rails - home

RailsConf Europe is approaching fast. It’s going down September 17-19 in Berlin, as most of you know, but this very week is actually the last if you want to take advantage of the 150 euro-discount for early-bird registrations.

I can’t wait to see everyone in Berlin. We had such a great conference in London last year and so much has happened since then. Have a look at the program and hopefully we’ll get a chance to meet up and talk.


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image05:44 Happy 3-year anniversary, Rails» Riding Rails - home

We’ve passed the 3-year mark for when Rails first saw the light of day as a public release. It’s been an amazing ride, don’t you think?


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image05:44 Three years with Ruby on Rails» Loud Thinking by David Heinemeier Hansson

We've just passed the three year anniversary of Ruby on Rails' first release to the public. Which in turn means that I've been working on the framework for more than four years. Wild.

It's been an incredibly rewarding experience. I've met so many great people. Worked with so many talented programmers. Seen so many amazing sites and applications be launched off Rails.

To image that this whirlwind tour all started because I wasn't happy working with the mainstream environments and decided to give Ruby a try. And to image the impact Ruby on Rails have had on the industry with none of the big-company backing that traditionally is needed to make waves there.

What's even more rewarding is knowing that we're not done. That the work to make web-application development ever more pleasant continues every day.

We might have taken the pace of radical changes in the core framework down a few notches (remember when we did multiple releases per month?), but the steady stream of improvement and refinement continues relentlessly.

So cheers, Rails.


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image03:49 There is abundant evidence ...» Projectionist
There is abundant evidence to show that high buildings make people crazy.

Christopher Alexander in A Pattern Language


add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image01:11 Simpsonize Me» Lovable Lyle
I spent last weekend down in Auburn, for the Auburn Knights Reunion, and since I had some time to kill on Saturday afternoon, I thought about going to see The Simpsons Movie. Luckily, I decided not to, since Denise now tells me that she wants to see it too. This is even though she gets [...]
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl

Mon 30 July, 2007

Click here to bookmark this link.Channel Image20:45 用Annotation标记Ruby方法» 梦想风暴
JRuby最近在讨论是否要支持Java 5。

JRuby邮件列表的讨论
http://www.nabble.com/Moving-to-Java-5--tf4131923.html

InfoQ报道
http://www.infoq.com/news/2007/07/jruby-java5-move
http://www.infoq.com/cn/news/2007/07/jruby-java5-move

XRuby起步就是从Java 5开始的,所以,不存在这个问题。在他们还在为此争论的时候,受到Charles Nutter最开始那封邮件的启发,我已经完成了Annotation标记Java代码和Ruby代码绑定的第一个版本。

下面是一个例子:
@RubyLevelClass(name="ClassFactory")
public class ClassFactoryValue extends RubyValue {
    ...        
    @RubyLevelMethod(name="test", type=MethodType.NO_ARG)
    public RubyValue test() {
        return RubyConstant.QNIL;
    }
}

首先,用@RubyLevelClass标记出这个Java类对应着一个Ruby层次上的类,其名称为ClassFactory。然后,用@RubyLevelMethod标记出一个Java方法是对应着Ruby的方法,它的Ruby名称为test,而且它是无参数的。

我们可以这样利用这段代码:
RubyClass klass = RubyTypeFactory.getClass(ClassFactoryValue.class);

通过RubyTypeFactory,我们可以生成ClassFactoryValue将Java层次和Ruby层次对应起来的代码,生成代码大致如下:
public class ClassFactoryValue$ClassBuilder implements RubyClassBuilder {
    public RubyClass createRubyClass() {
        RubyClass rubyclass = RubyAPI.defineClass("ClassFactory", RubyRuntime.ObjectClass);
        MethodFactory methodfactory = MethodFactory.createMethodFactory(ClassFactoryValue.class);
        rubyclass.defineMethod("test", methodfactory.getMethod("test", MethodType.NO_ARG));

        return rubyclass;
    }
}

这里用之前介绍过的生成方法Wrapper的MethodFactory去辅助代码生成,简化了编写。

XRuby本身为了生成bytecode已经做了大量的代码生成,这里只是把代码生成更多的用在了其他的部分。把这里的Annotation更广泛的用在XRuby中,会让代码看上去更干净。
add to del.icio.us add to del.icio.us. look up in del.icio.us.   add to furl.net add to furl
Click here to bookmark this link.Channel Image15:06 看到它,我笑了» nonocast ! 真诚原是一种需要坚强不屈的品质
也许是对生活的无奈, 
我知道我要的笑很简单,很单纯
 
WinDirStat
 
当然你可以先去他们家看看
 

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