Ruby Planet

Advertisements


ToC

  1. Call for developers: Alexandria project
  2. Links for 2007-01-19 [del.icio.us]
  3. Links for 2007-01-19 [del.icio.us]
  4. Fixturease 0.2.3 Released
  5. Digging Deep: Mixing it up (or in) with Modules
  6. Converting to Mephisto - Almost Done
  7. Bad Design Case Study: Lush
  8. OOPS! I released again!
  9. I've Read Your Horoscope and You're No Hacker
  10. Presentation tip from Steve Jobs
  11. March on Washington
  12. script.aculo.us 1.7
  13. Blocks rock
  14. Wrapping a C Function as a Block
  15. Lots of Rubies, All Playing Nicely Together
  16. Bringing Rails to the Enterprise
  17. Rails 1.2 Released
  18. Method Auto Completion (#110)
  19. Rails Cookbook Released (w/ Rails 1.2 Content)
  20. O'Reilly's "Rails Cookbook"
  21. Number Spiral (#109)
  22. Extend Your ActiveRecord Association Methods
  23. FamilyLearn Interview
  24. rubypodder:Initial version released
  25. Getopt::Declare 1.20
  26. Duby turns 0.6
  27. RubyRoom is just for you!
  28. rcodetools: TDD, completion, browsing...:rcodetools 0.4.1
  29. RDIL (DSL for requirements) files imported
  30. Seattle.rb Projects:ruby2ruby 1.1.4
  31. Links for 2007-01-18 [del.icio.us]
  32. Dependency checking with Capistrano
  33. Concerns in ActiveRecord
  34. Merb 0.1.0
  35. Qtodo 0.2
  36. Prototype 1.5 and the Documentation is Here
  37. Haml 1.0
  38. Managing Rails versions with Capistrano
  39. Prototype 1.5: Now with a manual!
  40. Rails 1.2: REST admiration, HTTP lovefest, and UTF-8 celebrations
  41. Kchhhk (Small Implosion)
  42. Prototype 1.5 Released and Documentation Site Live
  43. Want to work on a cool project?
  44. OMG, Prototype Docs!
  45. Prototype 1.5 out now, with complete API docs
  46. Infected with the 5 Things Meme
  47. ActiveRecord association scoping pitfalls
  48. RubyGems 0.9.1
  49. Camping's Youthfulness Wins Annual Award
  50. Using Rake as a Library -- Update
  51. Using Rake as a Library
  52. Tuning Performance
  53. Announcing the RailsEdge Conference
  54. Updates to Ruse Wiki Software
  55. Fireworks on the Fourth of July
  56. Delete Your RubyGems Cache
  57. Write a Proposal for RubyConf
  58. Multicasting in Ruby
  59. Some More Ruse Related News Items
  60. Debugging with Ruby
  61. Rails and the Legacy World
  62. Migrations Outside Rails
  63. Decimal Support in Rails
  64. Pluvo
  65. Prices in Cents
  66. Rails Guidebook
  67. Glue That Doesn't Set
  68. The Rails Edge
  69. Capistrano-Standing Room Only
  70. While I Was Sleeping...
  71. rela.tv open-sourced
  72. minor note
  73. Lookup fields plugin:LookupFields Rails Plugin
  74. Rounded Corners - 95
  75. Rubinius Serial Interview: Episode III
  76. rubinius Serial Interview: Episode IV
  77. Serial rubinius Interview: Episode V
  78. RubyCAS-Client 0.11.0 Released
  79. Links for 2007-01-17 [del.icio.us]
  80. Links for 2007-01-17 [del.icio.us]
  81. Easy Family Portal 0.6 Alpha is released
  82. Handoff: readable assertions for simple delegation
  83. So You Want to Learn ActiveResource...
  84. JRuby Serial Interview 3
  85. hardware hacks
  86. Mailing list for Ruby/Informix
  87. 5 Things, That's The Meme, That Meme Again, It's 5 Things
  88. Copenhagen Ruby Brigade on the Rails Podcast
  89. s33r Amazon S3 library version 0.5
  90. a declaration of independence
  91. PHP vs. Ruby on Rails. An evolutionary story of a Web Developer and his tools.
  92. New Gem Generator:newgem 0.7.1 - deployed gems not dependent on hoe
  93. Basic Rails association cardinality
  94. uncertain 0.1.0 Released
  95. Ruby Units:ruby-units 1.0.1 Released
  96. Extending render
  97. Gr.egario.us Done Right
  98. Button, Button, Who's Got The Button?
  99. URL rewriting with WEBrick
  100. Every Second Counts with a Piston in your Trunk
  101. Web Developer Makeover - It Finally Happened
  102. Refactoring RJS
  103. Five things
  104. Merb 0.0.9 released
  105. Railsbench gem updated
  106. Drop That Design! 6 Things You Need to Know About Color
  107. RSS Updates for my Subversion Repositories
  108. SQLite3/Ruby 1.2.0
  109. Taking ARes Out For a Test Drive
  110. rcodetools: TDD/BDD++, automagic assertions, 100% accurate completion, doc/code browsing...
  111. Returned from India
  112. Rounded Corners - 94
  113. Solid State Disk Changes The Game
  114. More inline RJS
  115. CoderPath Screencasts
  116. The Big Rewrite
  117. Ruby on Rails training off the beaten track
  118. Will rubinius Be An Acceptable Lisp
  119. Scripting Essentials
  120. Don't make a new one on my account
  121. Links for 2007-01-11 [del.icio.us]
  122. Links for 2007-01-11 [del.icio.us]
  123. Self-cloning JRuby and RubyGems in a Jar
  124. must be what it feels like to get old
  125. Word Blender (#108)
  126. Connecting First and Second Life
  127. Moving associated creations to the model
  128. Rounded Corners - 93
  129. How Rails Helped Me Level Up
  130. Refactoring Ruby
  131. Advance Directives For Hosted Projects
  132. JRuby Serial Interview 2
  133. Rela.tv and Gr.egario.us Taken Down
  134. How to Turn Deprecation Warnings Off in Rails
  135. eigenclass.org "Happy 2007!" Ruby mini-contest started
  136. Inline RJS
  137. Event Wax Is The First Production UJS Application
  138. Meet the Cheat
  139. The Zen of Auto Rspec
  140. Tattle Host OS
  141. How Rails made me a better programmer
  142. Large merge, tiny automation
  143. XML and J2EE: Commodity Skills
  144. Links for 2007-01-09 [del.icio.us]
  145. Gemtacular Gone Be Bona Fide
  146. Rounded Corners - 92
  147. Extending ActiveRecord associations
  148. Rails blogging contest
  149. Advanced Rails Studio
  150. Don't Follow the Lemmings
  151. Apple listens to Robby and releases an iPhone
  152. Discovering Capistrano
  153. FreeImage on OSX
  154. What's New in Edge Rails: Get Your RSS & Atom Feeds for Free
  155. What's New in Edge Rails: Around Filters are Here
  156. What's New in Edge Rails: Prettier Error Pages!
  157. What's New in Edge Rails: I Smell Version 1.2...
  158. What's New in Edge Rails: ActiveResource Pulled from v1.2, World Weeps
  159. What's New in Edge Rails: New Http Authentication Plugin - And a Plea to Contribute
  160. Tattle: The Ruby Census
  161. Tattle: The Ruby Census
  162. Watching ActiveRecord Do Its Thing
  163. Dabble Plugin API
  164. Debugging Ruby -RubyOSA continued
  165. Hackfest 2007 and CD Baby sprint
  166. CD Baby awards free RailsConf registrations+hotel to top 20 contributors to Rails
  167. RailsConf 2007 in style
  168. The Five Things Meme
  169. Six tips for building better Web apps with Rails
  170. RSpec and Unit Tests: Localizing Problems or Reducing Coupling
  171. Eigenclass Considered... Considered!
  172. Move to Mephisto
  173. eBay API Client for Ruby
  174. Ninjistix - 1st Place, Most Creative, Rails Day 2006
  175. PeepCode Rails Screencast Series
  176. RJS Templates for Rails - Updated
  177. RJS Templates for Rails
  178. Testing RJS with ARTS
  179. Canada on Rails Ticket For Sale - SOLD
  180. RJS Element and Collection Proxies
  181. The Pixel Box
  182. Using with_scope to refactor Rails finder methods.
  183. RJS Templates Plugin Subversion Repository
  184. Rails RJS Templates Plugin
  185. Rails RJS Templates
  186. Shopify is Live!
  187. RubyGems Beta 0.9.0.9
  188. Your own Mac OS XP with Parallels
  189. On Bush's Sacrifice
  190. Es jährt sich...
  191. Rounded Corners - 91
  192. rbayes 1.0.0 Released
  193. Tagged
  194. Copenhagen Rails Podcast
  195. My New Year's Resolution: Out With The Old...
  196. Annals of fashion, January 2007
  197. Working in Portland Coffee Shops and Cafes Reviews, part 2
  198. JRuby Serial Interview 1
  199. Continuous Integration Goodness(TM) for Your Ruby Project
  200. identifiers and authority records
  201. 5 things you didn't know yet about me
  202. Links for 2007-01-05 [del.icio.us]
  203. Capistrano 1.3.1
  204. DemoCampDC
  205. PeepCode: Capistrano Concepts and a Free Rails + Ubuntu Screencast
  206. Custom maintenance pages
  207. STI and Abstract Classes Driving You Nuts?
  208. Brevity vs. Clarity
  209. MenTaLguY on Concurrency
  210. NubyGems: Don't Use Class Variables!
  211. Rails 1.2 coming soon
  212. Firebug reloaded
  213. eigenclass.org 'Happy 2007!' Ruby contest, Sat 2007-01-06 20H UTC
  214. image_science 1.1.0 Released
  215. been quiet lately
  216. DailyKos considers Ruby on Rails
  217. Links for 2007-01-04 [del.icio.us]
  218. Rails 1.2: Release Candidate 2
  219. Instiki to Junebug
  220. Rounded Corners - 90
  221. Those that Tend the Store need Dialogue
  222. Christoffer's Hpricot Goodies
  223. Ruby declared TIOBE's Programming Language of the Year 2006!
  224. #9
  225. The joy of 'rolling your own' with Camping.
  226. (Poignant) Guide Earlies
  227. assert_xml_select
  228. Who's Tending the Store?
  229. From The Archives: Cleaner Callbacks With Partial Application
  230. Word Search (#107)
  231. Abandoned Projects, Bus Proofing, and a Draft Directive
  232. 2006 in Review
  233. ActiveMessaging: New home and new maintainer
  234. Links for 2007-01-03 [del.icio.us]
  235. Links for 2007-01-03 [del.icio.us]
  236. Rounded Corners - 89
  237. Simple AJAX and Inline Javascript with Rails
  238. New Nginx.conf with optimizations
  239. rcov
  240. A Hodel 3000 Compliant Logger for the Rest of Us
  241. Ruby 1.9 with YARV - Ruby is getting faster
  242. Soundboard Beta released
  243. Justifications and Lies
  244. The Big Bang
  245. Testing with my new Theme
  246. Representing Ruby Objects
  247. rubinius Internals Guide
  248. Rounded Corners - 88
  249. Author Interview: Christian Hellsten
  250. Links for 2007-01-02 [del.icio.us]

January 20, 2007

RubyForge image

Call for developers: Alexandria project

The Alexandria project (http://alexandria.rubyforge.org/), a project
to develop a book-and-other-media management application written in
Ruby for Gnome, is undergoing a minor renaissance after going dormant
for a while. Halted at version 6.1 since mid-2005, the project is
seeking to take the currently unstable repository code and release a
stable version 6.2 suitable for inclusion in major distributions. After
this release, the assembled development team will pursue ambitious plans
to increase the utility and visibility of Alexandria, with the ultimate
goal of default inclusion in major distributions. Some ideas that have
been discussed:

* integration with deskbar-applet/beagle.
* integration with OpenOffice for bibliography management.
* network-shareable book libraries (similar to iTunes DAAP)
* ability to access public library borrowing systems.
* new client/server architecture
* social/collaborative book rating/suggestion

Alexandria is an excellent example of a well-designed, fully-conceived
Ruby-Gnome2 application (thanks to the great work of Laurent Sansonetti and
others) that has the potential to match and surpass other closed-source
applications in this application niche, and to become a showcase product
for Linux/Gnome and Ruby-Gnome2.

The project currently needs Ruby developers of all shapes and stripes.
We welcome any short-term assistance to help us bugfix for the 6.2 release,
and any assistance and design input for the future.

In addition, there is a sub-project leadership position for anyone who
would like to resurrect the (already mostly implemented) RubyCocoa MacOS port
of Alexandria.

A first step if you are interested in helping is to introduce yourself on the mailing list:
http://rubyforge.org/mailman/listinfo/alexandria-list

January 20, 2007 06:41 AM

Michael Koziarski image

Links for 2007-01-19 [del.icio.us]

January 20, 2007 06:00 AM

Obie Fernandez image

Links for 2007-01-19 [del.icio.us]

January 20, 2007 06:00 AM

RubyForge image

Fixturease 0.2.3 Released

Fixturease is a console-based Rails fixtures design tool which simplifies fixtures creation process greatly.
Gem installable
http://rashkovskii.com/articles/2007/1/17/easy-fixtures
http://rashkovskii.com/articles/2007/1/18/better-fixturease

January 20, 2007 05:53 AM

O'Reilly Ruby image

Digging Deep: Mixing it up (or in) with Modules

Yet another series attempt

I think my NubyGems series has gone over pretty well, so I figured I’d try my luck with something else.

This new series, digging deep, will be targeted towards the more experienced developer, or at least folks who want to know a little more about some deeper concepts in Ruby. I’m going to do what I can to make these as clear as possible, but I’m relying on input from gurus and skeptics to help improve these posts and make them a good resource for folks.

So this post will focus on a recent topic on RubyTalk, the merit of using Mixins as a suitable replacement for multiple inheritance.

Overview

If you haven’t worked with multiple inheritence before, or aren’t familiar with object oriented programming, this article isn’t going to be super helpful. However, as a quick review, the core concept of multiple inheritance is that an object can have more than one parent class. For example, perhaps you have a Student class, and you want to say Joe is a student, but he’s also a musician and a rubyist. Single inheritence would not let you have this kind of structure without awkward hackery, so multiple inheritence would make life easier.

Though I’m sure there are folks out there who can explain why Java’s interfaces help simplify things in some cases, this sort of thing is a notorious source of annoyance in Java. A lot of times single inheritance just doesn’t do the trick. So often when folks hear that Ruby is single inheritance, they get sort of nervous.

On the gripping hand, there are plenty of languages in which incorrect use of MI can really bite you. C++ and Perl would be common culprits, and I have to be honest, a ten foot pole isn’t long enough to keep me away from object oriented Perl 5.

Ruby I suppose is lucky enough to be able to happily steal good ideas and throw away the bad ones. With this in mind, I think the Mix-in idea really fits the language.

But isn’t a Module just a container / a crippled Class ?

A short definition of a Module would likely be ‘a ruby class that cannot be instantiated and does not live within the class hierarchy’. It wouldn’t be 100% complete, but it’s enough to work with.

This at first sounds inconsequential. But the semantic power that such a construct provides is rather vast. David Black mentioned that he likes the idea of having both a noun like construct as well as an adjective like construct available for modeling.

That’s is a pretty good way to put it. This object is an Array. It is Enumerable.

If you look closely, you’ll see the distinction. The relationship is not really an ‘is a’ for the latter, but more describes some behavior the object has. It’s noun vs. adjective, when it all boils down.

For a quick example of modules in action, have a look at this use of Comparable. To get all your usual comparision operators(,==,>,=,>=,!=) in ruby, you just need to implement one method, the comparison operator(or spaceship).

>> class A
>> attr_accessor :data
>> def =>(other)
>> data => other.data
>> end
>> include Comparable
>> end
=> A
>> a = A.new
=> #
>> a.data = 78
=> 78
>> b = A.new
=> #
>> b.data = 10
=> 10
>> a b
=> false
>> a > b
=> true
>> b.data = 78
=> 78
>> a > b
=> false
>> a == b
=> true

Since Fixnums are Comparable, i can just delegate on down to get the right behavior. By including the Comparable module into my class, I get all those methods for free as promised.

This should be sufficient to show that we can avoid that interface problem. But it’s not going to tell you much about how mixins might save some headaches that MI introduce, so let’s get on to that, and luckily, this gives me an excuse to play with OmniGraffle.

But isn’t that just MI under a different name?

It might be tempting to just box off the idea of mix-ins as a direct comparison to multiple inheritance, but that’d be a misconception. The core difference between multiple inheritance and single inheritance is the former turns your hierarchy into a digraph where the latter preserves a tree structure. Since Ruby is single inheritance, the use of mix-ins prevents the issues associated with a more loosely arranged network of paths.

Python 2.3 has a very good implementation of multiple inheritance, and this is mostly due to the fact that if a cycle forms in the graph, it is considered illegal. (Which helps make method resolution sane). Please refer to this paper if you’re interested in the details, as they’re a little beyond the scope of this article.

However, this might be best explained graphically. I’m not a particularly graphical person, so bear with me :)

So the graphs on the left are meant to represent a situation where the leftmost path from D to A is the ‘main path’, and the other paths represent orthogonal concerns. (Think of them of doing things similar to Ruby’s Comparable or Enumerable). On the right hand side, you see the same idea, but the overlapping orbs represent modules ‘mixed in’ to D.

One of these clearly has a single linear path back to the root. The other would depend on how your language implemented its method resolution. Hopefully you can look at this and abstract the idea that no matter what, even when we mix modules into other modules, the results are a single component with no hierarchy attached to it. In this way, introducing new modules is much less likely to cause conflicts than introducing new parent classes, considering that it is rare in complex systems to know the entire topology well enough to avoid problems. I’m pretty sure this is the biggest case for the mix-in model, and it’s tough to find many situations in which its capabilities fall short of multiple inheritance.

I see the point, but I still don’t get how to use these things in my modeling

Basically, if you’re already familiar with modeling multiple inheritance in a sane way, the leap to mix-ins will be relatively small. However, if you’re new to the concept, it might take a little extra leap. Going back to David’s analogy, classes are our Noun component and modules our adjective.

Perhaps we have a Record construct and we want to be able to add tags to these records( a la folksonomy ). This is an ideal time to say an object with the ability to be tagged is Taggable, which is a nice adjective, and makes a nice module.

The following example is from Ruport’s source, and shows an actual use of modules:

module Ruport::Data
module Taggable
def tag(tag_name)
tags tag_name unless has_tag? tag_name
end
def delete_tag(tag_name)
tags.delete tag_name
end
def has_tag?(tag_name)
tags.include? tag_name
end
def tags
@ruport_tags ||= []
end
def tags=(tags_list)
@ruport_tags = tags_list
end
end
end

Nothing really surprising or fancy. However, both our Records and Tables are taggable, and they're not related to each other directly. This is what modules let us do, and it sure can be handy.

The light at the end of the tunnel

Hopefully this will bring folks who haven't been really thinking much about what modules are for closer to understanding how they work. Also, it might provide some insight for folks who are missing multiple inheritance, or for people who have been looking for a construct like this but didn't quite find it yet.

I hope this explanation has been helpful, but if you have questions, please do ask them. Also, if you have some suggestions on how to make this more clear or notice any mistakes, let me know as well. Hopefully future articles in this series will help expose some of the deeper concepts within Ruby to those who are interested!

January 20, 2007 04:20 AM

Amy Hoy image

Converting to Mephisto - Almost Done

Dear readers,

As you can see, Slash7 is almost back to its former beautiful glory. Once I write some custom liquid plugins for Mephisto to handle the rest of the sidebar, and customize some section templates, it’ll be all the way better… and perhaps even better than before.

So you wanna be a convert…

If you’re curious about switching from Typo to Mephisto, there’s never been a better time....

Check out Slash7 for more -- and let me know what you think!
image imageimage

January 20, 2007 01:19 AM

Bad Design Case Study: Lush

What better way is there to learn than to look at what you shouldn’t do?

Lush isn’t just a nice word for “borderline alcoholic,” it’s the name of a global company. Lush makes its millions selling juicy bath-stuffs, shampoos, lovely soaps, and “bath bombs” which splutter bubbles and foam and tasty smells when dropped into water.

The Set Up

Let me start off by saying that the Lush stores and...

Check out Slash7 for more -- and let me know what you think!
image imageimage

January 20, 2007 01:16 AM

January 19, 2007

Zenspider image

OOPS! I released again!

I totally forgot to blog this!

ParseTree version 1.6.4 has been released!

http://rubyforge.org/projects/parsetree

ParseTree is a C extension (using RubyInline) that extracts the parse
tree for an entire class or a specific method and returns it as a
s-expression (aka sexp) using ruby's arrays, strings, symbols, and
integers.

  • 1 minor enhancement:
    • Switched short if/unless to 1 line expressions.
  • 2 bug fixes:
    • Fixed the nested case/when bug. YAY!
    • Added dasgncurr and defnrescue test cases.

ruby2ruby version 1.1.4 has been released!

http://rubyforge.org/projects/seattlerb

ruby2ruby provides a means of generating pure ruby code easily from
ParseTree's Sexps. This makes making dynamic language processors much
easier in ruby than ever before.

Changes:

  • 4 minor enhancements:
    • Added some extra rewriting code and tests for various bmethods.
      Ugh.
    • Added support for splatted block args.
    • Refactored class/module and dsym/dstr.
    • Short if/unless statements are now post-conditional expressions.
  • 4 bug fixes:
    • Finally fixed eric's nebulous proc code-in-goalposts bug.
    • Fixed dasgn_curr so block's dasgn vars decl goes away (bug 7420).
    • Fixed dmethod. I think the tests were bogus before.
    • Fixed improper end in method rescues (bug 7396).

heckle version 1.2.0 has been released!

http://www.rubyforge.org/projects/seattlerb by Ryan Davis and Kevin Clark

This one is huge. Heckle is turning into the test tool I always wanted for ruby.

Heckle is a mutation tester. It modifies your code and runs your
tests to make sure they fail. The idea is that if code can be changed
and your tests don't notice, either that code isn't being covered or
it doesn't do anything.

  • 2 major enhancements:
    • Timeout for tests set dynamically and overridable with -T
    • Class method support with "self.method_name"
  • 3 minor enhancements:
    • -b allows heckling of branches only
    • Restructured class heirarchy and got rid of Base and others.
    • Revamped the tests and reduced size by 60%.
  • 1 bug fix:
    • Fixed the infinite loop caused by syntax errors

Now that rubygems are open again:

sudo gem install heckle

or, because you're a good person:

sudo gem update

January 19, 2007 11:09 PM

Why TheLuckyStiff image

I've Read Your Horoscope and You're No Hacker

What’s up with this job posting which demands a Gemini, Leo, Libra, Sagittarius or Aquarius?

The most ambitious Ruby on Rails project calls for a Rail’s guru to lead team as Co-founder

This is a wonderful entrepreneurial position for the humanitarian keen on facilitating emotional fulfilment for humanity.

*Birthday must fall between;

January 20 and February 18
May 21 and June 20
July 23 and August 22

Sept. 23 and Oct. 22
November 23 and December 21

Is this a phenomenon common to Germany? I’m sorry, the stars just aren’t aligned for you to code for us today. (Seen on onslaught.)

January 19, 2007 10:51 PM

Tobias Luetke image

Presentation tip from Steve Jobs

A photographer took a picture of Steve Job’s booklet from his recent Macworld Keynote where he unveiled the iPhone.

Apart from the interesting way in which he organizes his thoughts, its also very interesting to see which parts of the presentation are scripted and which are not (ordering 4000 lattes is on the list). What strikes me is just how gorgeous the booklet looks however.

Luckily, a avid jobs fan over at digg took the opportunity to recreate a template for Apple’s Pages which makes it easy to create such booklets yourself.

January 19, 2007 10:20 PM

Edward Summers image

March on Washington

MARCH ON WASHINGTON TO END THE WAR

Begins: Sat, 27 Jan 2007 at 11:00 AM

Ends: Sat, 27 Jan 2007 at 2:00 PM

Location:

Mall between 3rd and 7th Streets

Washington, DC 20002

USA

Link: more info

Mark your calendars, and let me know if you need a place to stay...

January 19, 2007 09:01 PM

Thomas Fuchs image

script.aculo.us 1.7

On the heels of the recent release galore here’s one more:

script.aculo.us 1.7 is final!download away!

So what’s new? Basically, the new stuff is all about Effect.Morph and all the goodness you can read about here and here.

Of course, we’re on Prototype 1.5 final now.

As always, get the fine print from the CHANGELOG.

Now, if script.aculo.us only had an API documentation like the new one for Prototype. The wiki is great, but a more complete, up-to-date and coherent resource would be even better. Well, let’s see about that… ;)

Of course thanks to the contributors. And yeah, I know that there are quite a bunch of tickets and patches pending—let’s get this one out first and get all that love in the next version. :)

NOTE: This is not the version included in Rails 1.2.1.—. You can use this version with Rails 1.2.1, just download and overwrite the files provided by Rails! The next Rails release will include this, of course. :)

image image

January 19, 2007 08:35 PM

Jamis Buck image

Blocks rock

Blocks are one of Ruby’s greatest assets. Every newcomer to Ruby is immediately introduced to their power when they learn how to do basic iteration, but there is a more powerful aspect to blocks than that. They are invaluable in refactoring code to remove duplication. Consider the classic example of the difference assertions proposed by the Projectionists. You want to know whether a particular bit of code increases the number of rows in a particular table or not. The brute-force approach is not very DRY at all:

1
2
3
4
5
6
7

8
9
10
11
12
13
def test_create_user

count = User.count
User.create(...)
assert_equal count+1, User.count
end


def test_delete_user
count = User.count
users(:jamis).destroy
assert_equal count-1, User.count

end

# ad nauseam...

By recognizing that the inner code is all that changes significantly, you can write a helper method that executes the outer code, and yields at the appropriate place(s):

1

2
3
4
5
6
7
8
9
10

11
12
13
14
# from http://project.ioni.st/post/218#post-218
def assert_difference(object, method, difference=1)

initial_value = object.send(method)
yield
assert_equal initial_value + difference, object.send(method)
end

def test_create_user
assert_difference(User, :count) { User.create(...) }

end

def test_delete_user
assert_difference(User, :count, -1) { users(:jamis).destroy }

end

This can be handy in a variety of situations. I recently was working on a method that did a bunch of setup and teardown, and in the middle it invoked find.

1

2
3
4
5
6
def find_with_extra_stuff(*args)

# a bunch of setup code here
result = some_collection.find(*args)
# a bunch of teardown code here
return result
end

The problem was that I found myself wanting to do a variation on the find call, but with the exact same setup and teardown stuff. Rather than duplicate all the code, I refactored it into a separate method and used yield right there in the middle:

1

2
3
4
5
6
7
8
9
10

11
12
13
14
def find_with_extra_stuff(*args)
setup_with_extra_stuff { |collection| collection.find(*args) }

end

def setup_with_extra_stuff
# a bunch of setup code here
result = yield some_collection
# a bunch of teardown code here

return result
end

# this allows me to use that abstract method with any
# method of the collection I want:
setup_with_extra_stuff { |c| c.find_all_by_name("Joe") }

Blocks rock.

January 19, 2007 08:03 PM

Why TheLuckyStiff image

Wrapping a C Function as a Block

I had previously been using rb_iterate and a call to Proc.new to build a block in C. But that takes two function calls while the undocumented rb_proc_new is just one.

require 'rubygems'
require 'inline'
module Kernel
inline do |ext|
ext.prefix %{
static VALUE sum(VALUE args)
{
return rb_funcall(rb_ary_entry(args, 0), rb_intern("+"), 1,
rb_ary_entry(args, 1));
return Qnil;
}
}
ext.c %{
VALUE sum_block()
{
return rb_proc_new(sum, 0);
}
}
end
end
p sum_block[13, 2]
p (0..20).inject(0, &sum_block)

Most of the time rb_iterate is what you need. But, you know, in case you actually want a Proc object.

January 19, 2007 04:33 PM

O'Reilly Ruby image

Lots of Rubies, All Playing Nicely Together

I’ve written before about how cool it is to see the JRuby and rubinius guys working together (Nick Sieger also posted a piece about it). (It can be mind-bending to follow a discussion across multiple irc channels though.) I’m even more encouraged to see that Kevin Tew (the Cardinal hacker) and SASADA Koichi (the YARV hacker) have joined the fray.

In his recent post about tail call optimization for YARV on JRuby, Ola Bini wrote:

This work goes forward very fast, and it’s funny to see progress happen this quickly. Yesterday SASADA Koichi visited the #jruby and #rubinius IRC channels, and we had some very interesting discussions on further collaboration. The future looks bright indeed, and this weekend I’ll probably have time enough to take a first crack at a YARV compiler for JRuby.

What’s going to happen next? Maybe one of the big-name Perl folks will start answering questions on ruby-talk — naah, that’ll never happen.

January 19, 2007 04:10 PM

Bringing Rails to the Enterprise

(correction): fixed Upton Sinclair quote it is ’salary’ not ‘job’ (thanks for the correction)

Even with all the buzz, it is still a tough sell. If you’ve suggested Rails as an alternative to (Java|.NET) at work, you’ve probably experienced some reactionary pushback. Convincing a set of established “Enterprisy” engineers that Rails is worth paying attention to it is like convincing a Texas oil baron that he should purchase a Subcompact hybrid vehicle and become a Vegan. Why is convincing a highly paid (Java|.NET) programmer to look at Rails that difficult? I’ll steal a quote from Al Gore’s Inconvenient Truth that he, in turn, stole from Upton Sinclair:

“It is difficult to get a man to understand something when his salary depends on not understanding it.” - Upton Sinclair (1878 - 1968)

In an effort to convince, you may have sent people to some of the good Ruby on Rails blogs. This might have escalated the resistance. Asking your fellow enterprise developers to read DHH’s loudthinking.com, is like asking (the other) O’Reilly to sit down with Colbert - Mr. Enterprise isn’t going to appreciate the message because he’ll be focused on the ridicule. Rails, rightly so, is positioned as the challenger, and it makes good use of hyperbolic ridicule to gain converts. This works for most of us, but I’ve also seen it push some entrenched Java developers further away.

Common Responses

So, you are in “The Big Planning” meeting, and your boss says something like, “There is no time to finish this project, we’re going to have to tell the customer we won’t meet the deadline.” You wearily offer up the suggestion: “We might be able to deliver something on time if we used Rails to implement the web application”. And, an entire room full of Java programmers is now trying to tell you every reason from here to the North Pole why your suggestion is naïve. Here are some of the common responses:

  1. Freedom (Too Much) - “Our developers are not disciplined enough to use a scripting language.”
  2. Rigor / Formality - “Our systems are serious and require a much more rigorous approach.”
  3. Performance - Our systems need to perform, and Ruby (specifically Ruby on Rails) doesn’t perform to our standards.
  4. Flexibility (Not Enough) - (Rails) We can’t afford to follow the database standards that Rails would impose on us

Let’s take each one individually…read on…

Myth #1: Too Much Freedom

“My developers are not disciplined enough for a scripting language, we need the structure that a platform like .NET provides.”

Answer: If your developers really do lack discipline, then they should probably not be programming in something as complex as .NET. Or, Java, let’s take Java as an alternative, Java is a powerful language, but it is a language based on choice: you can create a web application using one of 30+ web frameworks, you can deal with persistence using Hibernate, iBatis, or just direct JDBC. And, if you are using the Spring Framework, you are really defining your own custom architecture as you go. If you need this level of flexibility, use Java, but, IMO, you have to be a bit more disciplined to create a good architecture in Java than you would to follow the bright lights in a Rails application.

The real answer to Myth #1: “If your developers are not very disciplined, you can’t afford to not be using a tool like Ruby on Rails. If your developers are disciplined enough to learn Struts + Spring + Hibernate + WebSphere, then I’m surprised you can’t expect them to learn ActiveRecord. Who are these people? I don’t believe you, what’s the real reason?”

Myth #2: Rails isn’t “Rigorous”.

Scripting languages do not provide an adequate level of “structure”.

“Our systems are serious and require a much more rigorous approach.”

Answer: Myth #2 is born of a belief that systems built-atop scripting languages can be difficult to maintain, and this Myth is closely related to Myth #1. The problem with this myth is that it has absolutely nothing to do with scripting languages and everything to do with a universal industry truth - Bad Code is Difficult to Maintain Regardless of the Language. Anyone who’s had an encounter with bad Perl code in the past is going to appeal to this myth, but the real truth is that, again, it is less a specific problem with Ruby and more a fear of the unknown. I’ve seen .NET systems designed with all the rigorous process-driven, test-first, pattern-inspired magic you will find, but they were still a quagmire of logic.

The other reason someone might offer this up is because they are frightened of not having compile-time type safety (or just frightened of not having a compiler at all). Compile-time type-safety isn’t so bad when we’re talking about the Solid Rocket Booster or a FIX gateway for the London Stock Exchange. But, with enough testing, this argument doesn’t make sense for something like a Web UI.

The real answer to Myth #2: “Right! Let’s go back to the customer and tell them that even though we could deliver something on time, we’re not going to because it’s not a rigorous technical solution and that our developers are not disciplined enough to program in Ruby on Rails. What makes Ruby less ’serious’ than Java? You guys could still draw UML diagrams of model objects to your heart’s content, and, if you really need me to, I could generate just as many gantt charts and word documents about the code we write in Ruby.”

Myth #3: Performance

“It just ain’t fast enough…”

Answer: What isn’t fast enough? Rails? Well optimize your deployment, figure out what a materialized view is. Think about the database a little bit, are you querying a table with 10 million rows? and do you know what an index is? Have you thought about database partitioning? Start using memcache, get faster hardware, use 40 instances of Mongrel. Don’t just stand there, fix it. You’d do the same for your .NET application. Myth #3 usually translates to, “I just don’t want to use Rails, and someone told me it isn’t fast enough.” In my experience Rails scales as long as you apply some brain power to your performance problems. If you just expect Rails to scale without taking any steps to achieve scaleability then you’ve really just staged a show trial for Rails. This myth is offered from people who want to Rails to break a leg out of the gate. If this is your reason, don’t tell me you didn’t have to go through a dog and pony show to optimize every other platform in your production network. Performance optimization is a black art regardless of the language or platform.

Compared to Java: From the perspective of real cost, the cost of scaling a Ruby application is on par with a similar Java application. It takes about the same hardware to scale a big J2EE application as it would take to scale a large Ruby on Rails deployment. We’re talking about a few commodity servers running Mongrel with lots of memory. IMO, it might be a lttle easier to setup Apache + mod_proxy + mongrel + Capistrano + memcached, than it is to go through the motions of installing JBoss or Tomcat and then dealing with the lack of OS integration that most Java servers suffer from. In other words, if you are creating an application and attempting to scale horizontally, you’ll probably end up paying just about the same $$ to scale a well designed Java app or a Ruby app (assuming your container is free). You may end up buying an extra one or two servers for your Ruby application, but you are going to make up the cost in development.

The real answer to Myth #3: “So, we’re not going to meet our deadline because you feel that Ruby on Rails just ‘isn’t fast enough’ in an abstract sense. You haven’t used it yet, we haven’t tested an application, or sized a real production deployment. No one has done an apples to apples comparison, all we’re going on now is your belief that Ruby doesn’t scale? Before you go on, let’s agree to at least study the issue, and the next time we talk let’s discuss specific numbers.”

Myth #4: Flexibility

“We can’t afford to follow the database naming conventions ActiveRecord demands”

Answer: You don’t have to use the ActiveRecord naming conventions. (I’ve heard this more than a few times, “we can’t use rails because of our database…”) Sure, it is marginally easier if your database tables follow the naming conventions, but let me assure you Rails can work with almost any database no matter how strange. To prove this I’ll use a Siebel database as an example. A Siebel database is definitely not designed for ActiveRecord. Every table has a MS_IDENT column which is the primary key….then every table has a ROW_ID column which happens to be the application specific identifier. Column names of the foreign keys do not match the names of the tables they references. Foreign keys don’t really reference the real primary key, they reference the application specific id which isn’t just a simple autoincrementing integer. There are hundreds of tables, and, my favorite, no define FK constraints. Did I mention that all of the table and column names are somewhat cryptic. It took a little bit of effort, a module and some before_create methods, but if I can get a Siebel database to work with Rails, you can use ActiveRecord with anything.

Compared to Java: …turn the tables on this one. EJB3 annotations in Java has the same “default naming assumption” behavior. If you don’t supply column names and table names, EJB3 will just assume them from the names of the columns and tables. If someone rules out Rails because of database naming conventions force them to hold Java (or .NET) to the same standard. Also, anyone who has been using Hibernate will tell you that Hibernate certainly has problems with oddly conceived databases - I’ve spent days trying to work with 3-way mapping tables in Hibernate only to find out that there’s some really mysterious bug with @MapKey.

The real answer to Myth#4: “You are mistaken. If you read more than the first 40-pages of the “Agile Web Development…” book, you would know this.”

Conclusion: When Reason Fails to Persuade…

Sneak it into the organization if your arguments fail. Eventually someone will notice, and there’s a good chance you’ll get in trouble. But, there’s always a chance that your transgression will go unnoticed and your boss can go on happily believing that he is using a “Real Platform”. J

But do us all a favor, if you are going to employ Rails behind hostile territory don’t turn into to one of those O’Reilly Radar-reading cool kids who is constantly throwing around references to Paul Graham and talking about how cool Web 2.0 is. Take your time, know your enemy, and work slowly. Use the language of your corporate masters

Wrong: “Ruby is a revolution, dude, it’s going to change the way you think about coding. Rails will run circles around your fancy SpringMVC or ASP.NET applications. Coding Rails is fun!”

Right: “Mr. Supervisor, sir, may I speak freely?”…..”I think we could leverage Ruby as a competitive advantage. For our next low-risk web application I propose that we engage in a feasibility study to assess the impact of a lightweight rapid application development framework. There is a real possibility that Ruby could encourage the productivity increase which will allow us to finish Q3 well under budget. It would be a great addition to our Enterprise’s ‘knowledge portfolio’.”

January 19, 2007 04:07 PM

fngtps.com image

Rails 1.2 Released

Today the Rails Core Team released Ruby on Rails 1.2. The long awaited new version is of course full of features and fixes. The thing we’re most excited about is the inclusion of ActiveSupport::Multibyte. But it doesn’t stop with multibyte support, Rails now ships with UTF-8 as a default in all parts of the framework, something we couldn’t have dreamed of a year ago.

January 19, 2007 03:49 PM

Ruby Quiz image

Method Auto Completion (#110)

by Robert Dober

Command Line Interfaces very often support command abbreviations The purpose of this quiz is to automatically dispatch to methods on unambiguous abbreviations, ask the user for clarification in case of ambiguous abbreviations and raise a NoMethodError in case of an abbreviation that cannot be matched to any command.

Behavior of other methods defined in a class shall not be altered.

Be creative about the interface and about behavior. I have OTOH defined a small test suite that makes assumptions about the interface and behavior. But the test suite is only there for your convenience.

What is said below applies to the test suite and shall in no way inhibit any alternative ideas.

ruby class Mine abbrev :step, :next, :stop abbrev :exit end Mine.new.e # should resolve to exit Mine.new.st # should prompt the user Mine.new.a # should still raise a NoMethodError

Abbreviation targets themselves are not expanded.

ruby class Nine abbrev :hash abbrev :has end Nine.new.ha # => [:hash, :has] Nine.new.has # => NoMethodError class Nine def has; 42; end end Nine.new.has # => 42

In order to allow for automated testing the test code shall not prompt the user in case of an ambiguous abbreviation but return an array containing all (and only all) possible completions as symbols. Note that the test suite sets the global variable $TESTING to a true value for your convenience.

Test Suite

January 19, 2007 01:45 PM

Ryan Daigle image

Rails Cookbook Released (w/ Rails 1.2 Content)

The aforementioned Rails Cookbook from O’Reilly, to which I made a minute contribution, has been released… including Rails 1.2 relevant content like ActiveResource and RESTful development.

Go getcha one.

(Here is a full TOC for the curious amongst you)

image

image image image image

January 19, 2007 01:24 PM

O'Reilly's "Rails Cookbook"


image

A few weeks ago I got a call from O’reilly publishing asking me to write the REST chapter introduction for their upcoming Rails Cookbook. Apparently, some people found my effusive soliloquy on Rails’ upcoming Active Resource and Simply RESTful support actually useful and thought I could reproduce my intellectual facade for them.

After the first stab, in which I found out that writing a blog entry does not an author one make, I think I got something useful to them. But beyond my meager contribution I got to take a look at the rest of the book. I’ve always been a fan of the cookbook format and this looks to be no different. A lot of tasty recipes including some great post-development stuff like performance, security and deployment.

You can check out the rough cuts version at O’Reilly now or wait a lil bit until it hits bookshelves – which Amazon says will be Dec. 1st. Look for the book that has some sort of stray feline with a killer rash on its stomach…

And don’t forget the original entrant in the Rails cookbook market, Chad Fowler’s Rails Recipes.

tags: rubyonrails, rails, rails cookbook, REST

image

image image image image

January 19, 2007 01:23 PM

Ruby Quiz image

Number Spiral (#109)

by Bob Showalter

(Taken from the puzzle by William Wu at http://www.ocf.berkeley.edu/~wwu/riddles/cs.shtml)

[Editor's Note: This was also a code golf problem a few months back: http://codegolf.com/oblongular-number-spirals --JEG2]

Write a Ruby program to print out a "spiral" of numbers that fill a NxN square. Your program will take a single argument to specify the dimensions of the square (1 or higher). The number zero represents the center of the spiral, and the succeeding integers spiral out in a clockwise (or counterclockwise; your choice) direction from the center until the square is filled.

Your program should write the output line by line, without using an array to build up the data first.

Here's the output for an 8x8 spiral:

56 57 58 59 60 61 62 6355 30 31 32 33 34 35 3654 29 12 13 14 15 16 3753 28 11 2 3 4 17 3852 27 10 1 0 5 18 3951 26 9 8 7 6 19 4050 25 24 23 22 21 20 4149 48 47 46 45 44 43 42

January 19, 2007 01:19 PM

Ryan Daigle image

Extend Your ActiveRecord Association Methods

Much of the beauty of ActiveRecord associations is in the collection methods that are provided for you when you define has_many relationships.

For instance, when we say:

class Organization < ActiveRecord::Base
has_many :people
end

We now have an organization.people method that returns the collection of associated people within the organization. Easy enough. We also get nice little methods on the collection of people like organization.people<<, organization.people.build, organization.people.create and organization.people.find (among others). Well what if you wanted to define your own method on this auto-magically provided collection method? You do this through Association Extensions which let you define methods to add to the collection. You can define an association extension either with a block or a module – we’ll use a block provided to the has_many call here as it’s the most common way to do so:


class Organization < ActiveRecord::Base
has_many :people do
def find_active
find(:all, :conditions => ["active = ?", true])
end
end
end

I’ve defined a find_active method which will retrieve all people in the organization that have the active column set to true. This can be invoked very intuitively with:

organization.people.find_active

This is a great way to provide convenience finder methods for common retrievals on the associated collection.

If you want to define an extension as a module just provide the :extend option in your has_many definition:


module FindActiveExtension
def find_active
find(:all, :conditions => ["active = ?", true])
end
end

class Organization < ActiveRecord::Base
has_many :people, :extend => FindActiveExtension
end

You can customize to your heart’s content – these are just some simplistic examples of how to plug into this nifty feature. I just recently stumbled upon it and thought it might be worth spreading the word since I found myself smitten by it.

Resources

tags: rails, activerecord, rubyonrails

image

image image image image

January 19, 2007 01:12 PM

Pat Eyler image

FamilyLearn Interview

Duane Johnson and Neal Harmon are a programmer at and the president of FamilyLearn, a small company using Ruby, Rails, and Amazon's S3 and EC2. They've ported their applications from PHP to Ruby on Rails, and have recently started a Public Beta of their iMemorybook tools. I've invited them to share some of their experiences in this interview.

To start things off, would you two please tell us

January 19, 2007 11:38 AM

RubyForge image

rubypodder:Initial version released

rubypodder is a very simple podcast aggregator in the spirit of bashpodder. Feedback welcome.

January 19, 2007 07:23 AM

Getopt::Declare 1.20

Added support for GNU style options.
Better docs (now on rubyforge).
Some minor bug fixes.

January 19, 2007 06:47 AM

Duby turns 0.6

Happy versionday to Duby! Today's menu: faster, faster, and prettier. I am starting to lack icing on the cake.

January 19, 2007 06:47 AM

RubyRoom is just for you!

RubyRoom is ready. Just You, Your Text, and Yourself. Perfect for concentration.

RubyRoom is a fullscreen text editor (using gtk2 for the interface) with as less distractions as possible.

January 19, 2007 06:47 AM

rcodetools: TDD, completion, browsing...:rcodetools 0.4.1

rcodetools is a collection of Ruby code manipulation tools for automagic Test::Unit(RSpec) assertion generation, code annotation, 100% accurate code completion, code and documentation browsing, precise method information (rcodetools is meta-programming aware)...

rcodetools can be used with any editor, but it ships with emacs and vim support.

More info at http://eigenclass.org/hiki.rb?rcodetools

January 19, 2007 06:47 AM

RDIL (DSL for requirements) files imported

RDIL is a Domain-Specific Language for Requirements Definition and Illustration. Initial source, tests and specs imported on RubyForge SVN.

January 19, 2007 06:47 AM

Seattle.rb Projects:ruby2ruby 1.1.4

ruby2ruby version 1.1.4 has been released!

ruby2ruby provides a means of generating pure ruby code easily from
ParseTree's Sexps. This makes making dynamic language processors much
easier in ruby than ever before.

Changes:

== 1.1.4 / 2007-01-15

* 4 minor enhancements:
* Added some extra rewriting code and tests for various bmethods. Ugh.
* Added support for splatted block args.
* Refactored class/module and dsym/dstr.
* Short if/unless statements are now post-conditional expressions.
* 4 bug fixes:
* Finally fixed eric's nebulous proc code-in-goalposts bug.
* Fixed dasgn_curr so block's dasgn vars decl goes away (bug 7420).
* Fixed dmethod. I think the tests were bogus before.
* Fixed improper end in method rescues (bug 7396).

January 19, 2007 06:47 AM

Michael Koziarski image

Links for 2007-01-18 [del.icio.us]

January 19, 2007 06:00 AM

Jamis Buck image

Dependency checking with Capistrano

Nathan de Vries recently posted a neat tip for using Capistrano to determine whether or not your remote machines have all your expected dependencies installed. We could have used something like this recently at work when we were having some strange issues that turned out to be due to some out-of-date dependencies on a few of our boxes. Good stuff! I love seeing the things people are doing with Capistrano.

January 19, 2007 05:39 AM

Concerns in ActiveRecord

Ruby does not support multiple-inheritance. Personally, I have mixed feelings about that, but the fact of the matter is, you can accomplish almost exactly the same thing using modules.

Consider this ActiveRecord scenario. In Basecamp, we allow files to be attached to both messages, and comments. One way to do this would be to have both messages and comments inherit from a common ancestor, via single-table inheritance. Alas, the two models (in our case) are different enough that STI is not a viable option here.

Instead, we employ “concerns” (as David has started calling them). A “concern” is simply a module that we mix in to both the message and comment models, which sets up the common “file attachment” functionality. We’ll call this module “Folder”, to denote that any of its clients essentially become a container for files. Observe:

1
2
3
4

5
6
7
8
9
10
11
module Folder

def self.included(base)
base.has_many :files, :as => :owner, :dependent => :destroy

end

# This returns the path where files are to be uploaded
# for this specific "folder".
def attachment_path

"/path/to/files/for/#{id}"
end
end

Then, we mix the Folder concern into whichever models we want to allow files to be attached to:

1
2
3
4
5
6
7

8
9
class Message < ActiveRecord::Base
include Folder

#...
end

class Comment < ActiveRecord::Base
include Folder

#...
end

Because of the included hook, defined in the module, each class that receives this module will automatically gain a “has_many :files” association. Also, because the module is mixed into the class, you can put as much or as little extra functionality there as you want to share between the classes.

This has proven to be a very powerful pattern. To accommodate it, we’ve recently taken to creating an “app/concerns” directory in our projects, and adding that to the load path in config/environment.rb:

1
config.load_paths += %W(#{RAILS_ROOT}/app/concerns)

Our modules then go in that directory.

January 19, 2007 05:33 AM

Ezra Zygmuntowicz image

Merb 0.1.0

This is mainly a big fix release. The 0.9.0 release had a bad app skeleton. I have fixed this problem.

I also added support for freezing the merb framework into your app for portability. Just deploy the entire app and no need to install the merb gem on your server.

A few refactors and updates go in as well. Gem install merb in a few hours when the gem propogates.

January 19, 2007 05:02 AM

RubyForge image

Qtodo 0.2

Qtodo version 0.2 has been released. It features nice color-coding to quickly see which tasks are late, postponing of a whole tree (don't abuse it ;-) !), several improvements in the text editor and in the way settings are stored from one session to another.

Enjoy !

January 19, 2007 03:34 AM

Prototype image

Prototype 1.5 and the Documentation is Here

Ever since the initial announcement of the documentation effort, we’ve been busy planning and preparing Prototype for its rebirth. Along with the official 1.5 release, we’d like to welcome you to the official home of Prototype. This site will serve as the center of our community and help developers everywhere become familiar with Prototype and its continued progress.

Prototype 1.5 release

We’ve been squashing some nasty bugs getting ready for the 1.5 release. You can get the full scoop on all the fixes and improvements in the CHANGELOG.

The API gets documentation

While there has always been some great documentation on Prototype, we’ve been the victim of a famous quote from *“The Man Who Shot Liberty Valance”:

When the legend becomes fact, print the legend.

We’re moving past those times, however. We’ve worked really hard to fully document the API. This is something we’ll be improving over time, but it’s a great start. Here are some of the features:

Guessable URLs

The documentation site has guessable URLs. For instance, if you’re looking for documentation on Element.show, then you can find that documentation at a url like: http://prototypejs.org/api/element/show. If you’re looking for Form.Element.focus you can find it at: http://prototypejs.org/api/form/element/focus.

Atom feeds

Each Object has its own atom feed. This opens the doors for integrated documentation. For instance, if you want the XML file for Form.Element, you can find it at: http://prototypejs.org/feed/api/form/element/atom.xml. This feed will always contain the most up-to-date documentation for Form.Element.

Tips and Tutorials

We’ve also added an article section where you can find tips, tutorials, and a variety of articles for Prototype. We plan on adding many more articles to this area over time, so keep your eyes peeled.

A special thanks

We’ve added three new core members to our team. Chris, Mislav, and Tobie were already avid contributors to Prototype, and they were the driving force behind the documentation effort. We all worked really hard on it, but these guys deserve most of the credit.

Rough around the edges

We’re not perfect, so if you catch any spots in the documentation that are incorrect, or if you’d like to improve parts of the documentation shoot one of us an email. We’ll try to get an official email posted later so you can send in improvements or additions to the documentation. Until then, please enjoy the site!

Update: Rails 1.2 has been announced and includes Prototype 1.5 with the release! Congrats to the Rails team.

image image

January 19, 2007 03:23 AM

Ruby on Rails image

Haml 1.0

Since we’re all celebrating new releases, it seems only fair to point out that Haml, an alternative markup format to Rails’ RHTML templates, has reached the lofty version of 1.0. It even comes with a plugin for seamless integration with Rails applications, so you really have no excuse not to give it a try. If you’re looking for an alternative to RHTML, Haml may just be you. Check it out!

January 19, 2007 02:16 AM

Jamis Buck image

Managing Rails versions with Capistrano

The simplest way to deploy your application and tie that release to a specific Rails version is to put Rails in your vendor directory as an svn:external dependency. That’s fine, but it’s not very efficient, and Mike Clark has posted an excellent writeup of the alternatives. If you’ve been wondering if there is a better way, you could do a lot worse than to read what he’s got to say.

Good stuff, Mike!

January 19, 2007 02:03 AM

Ruby on Rails image

Prototype 1.5: Now with a manual!

Prototype 1.5 shipped together with Rails 1.2 today. But that’s not all that’s been happening at the JavaScript sugar mill. Today also marks the official unveiling of prototypejs.org. A brand new site dedicated to promoting and teaching Prototype. It comes complete with API documentation, a blog, and a guide on how to contribute. Congratulations to Sam, Justin, and the rest of the team behind the site.

January 19, 2007 01:28 AM

Rails 1.2: REST admiration, HTTP lovefest, and UTF-8 celebrations

Get out your party balloons and funny hats because we’re there, baby. Yes, sire, Rails 1.2 is finally available in all it’s glory. It took a little longer than we initially anticipated to get everything lined up (and even then we had a tiny snag that bumped us straight from 1.2.0 to 1.2.1 before this announcement even had time to be written).

So hopefully it’s been worth the wait. Who am I kidding. Of course it’s been worth the wait. We got the RESTful flavor with a new encouragement for a resource-oriented architecture. We’re taking mime types, HTTP status codes, and multiple representations of the same resource deadly serious. And of course there’s the international pizzazz of multibyte-safe UTF-8 wrangling.

That’s just some of the headliner features. On top of that, there’s an absolutely staggering amount of polish being dished out. The CHANGELOG for Action Pack alone contains some two hundred entries. Active Record has another 170-something on top of that. All possible due to the amazing work of our wonderful and glorious community. People from all over the world doing their bit, however big or small, to increase the diameter of your smile. That’s love, people.

Get out your party balloons and funny hats because we’re there, baby. Yes, sire, Rails 1.2 is finally available in all it’s glory. It took a little longer than we initially anticipated to get everything lined up (and even then we had a tiny snag that bumped us straight from 1.2.0 to 1.2.1 before this announcement even had time to be written).

So hopefully it’s been worth the wait. Who am I kidding. Of course it’s been worth the wait. We got the RESTful flavor with new encouragement for resource-oriented architectures. We’re taking mime types, HTTP status codes, and multiple representations of the same resource serious. And of course there’s the international pizzazz of multibyte-safe UTF-8 wrangling.

That’s just some of the headliner features. On top of that, there’s an absolutely staggering amount of polish being dished out. The CHANGELOG for Action Pack alone contains some two hundred entries. Active Record has another 170-something on top of that.

All possible due to the amazing work of our wonderful and glorious community. People from all over the world doing their bit, however big or small, to increase the diameter of your smile. That’s love, people.

As always, you get a hold of the latest and greatest through gems:

gem install rails --include-dependencies

...or if you prefer to freeze it straight up, you can:

rake rails:freeze:edge TAG=rel_1-2-1

If you go with the gems, remember to change your version binding in config/environment.rb. Otherwise, you’ll still be tied to whatever old version you were using before.

Do note, though, that this is a massive upgrade. A few major components of Rails were left for scraps and entirely rewritten (routing and auto-loading included). We’ve tried our very best to remain backwards compatible. We’ve run multiple release candidate sessions to everyone help achieve that goal.

But it may not be perfect — heck, what is — so you’d be best advised to give your application a full and thorough work-out before contemplating a deployment. But of course, you’ve been such a good little tester bee that all what is needed is a single “rake” to see if everything passes, right?

How to get started learning all about Rails 1.2

With the fanfare out of the way, I point your attention to a rerun of the RC1 release notes on the new features. This rerun only contains the highlights, though. Real fans will want to peruse the CHANGELOGs themselves from the API.

For everyone else, there’s of course also the much easier path of just picking up the second edition of Agile Web Development with Rails. This edition was written to be spot on with 1.2 and contains a lot more elaborate guidance than you’ll find in the CHANGELOGs.

So it’s no wonder that the 2nd edition sold out the 15,000 copies of the first print run in a mere three weeks. Rest assured, though, the second run should already be available in stores. And for instant gratification, nothing beats picking up the PDF+Book combo off the Pragmatic book site.

REST and Resources

REST, and general HTTP appreciation, is the star of Rails 1.2. The bulk of these features were originally introduced to the general public in my RailsConf keynote on the subject. Give that a play to get into the mindset of why REST matters for Rails.

Then start thinking about how your application could become more RESTful. How you too can transform that 15-action controller into 2-3 new controllers each embracing a single resource with CRUDing love. This is where the biggest benefit is hidden: A clear approach to controller-design that’ll reduce complexity for the implementer and result in an application that behaves as a much better citizen on the general web.

To help the transition along, we have a scaffold generator that’ll create a stub CRUD interface, just like the original scaffolder, but in a RESTful manner. You can try it out with “script/generate scaffold_resource”. Left with no arguments like that, you get a brief introduction to how it works and what’ll create.

The only real API element that binds all this together is the new map.resources, which is used instead of map.connect to wire a resource-based controller for HTTP verb love. Then, once you have a resource-loving controller, you can link with our verb-emulation link link_to "Destroy", post_url(post), :method => :delete. Again, running the resource scaffolder will give you a feel for how it all works.

Formats and respond_to

While respond_to has been with us since Rails 1.1, we’ve added a small tweak in 1.2 that ends up making a big difference for immediate usefulness of the feature. That is the magic of :format. All new applications will have one additional default route: map.connect ':controller/:action/:id.:format'. With this route installed, imagine the following example:

class WeblogController < ActionController::Base
def index
@posts = Post.find :all
respond_to do |format|
format.html
format.xml { render :xml => @posts.to_xml }
format.rss { render :action => "feed.rxml" }
end
end
end

GET /weblog # returns HTML from browser Accept header
GET /weblog.xml # returns the XML
GET /weblog.rss # returns the RSS

Using the Accept header to accomplish this is no longer necessary. That makes everything a lot easier. You can explore your API in the browser just by adding .xml to an URL. You don’t need a before_filter to look for clues of a newsreader, just use .rss. And all of them automatically works with page and action caching.

Of course, this format-goodness plays extra well together with map.resources, which automatically makes sure everything Just Works. The resource-scaffold generator even includes an example for this using format.xml, so /posts/5.xml is automatically wired up. Very nifty!

Multibyte

Unicode ahoy! While Rails has always been able to store and display unicode with no beef, it’s been a little more complicated to truncate, reverse, or get the exact length of a UTF-8 string. You needed to fool around with KCODE yourself and while plenty of people made it work, it wasn’t as plug’n’play easy as you could have hoped (or perhaps even expected).

So since Ruby won’t be multibyte-aware until this time next year, Rails 1.2 introduces ActiveSupport::Multibyte for working with Unicode strings. Call the chars method on your string to start working with characters instead of bytes.

Imagine the string ‘€2.99’. If we manipulate it at a byte-level, it’s easy to get broken dreams:

'€2.99'[0,1] # => "\342"
'€2.99'[0,2] # => "?"
'€2.99'[0,3] # => "€"

The € character takes three bytes. So not only can’t you easily byte-manipulate it, but String#first and TextHelper#truncate used to choke too. In the old days, this would happen:

'€2.99'.first # => '\342'
truncate('€2.99', 2) # => '?'

With Rails 1.2, you of course get:

'€2.99'.first # => '€'
truncate('€2.99', 2) # => '€2'

TextHelper#truncate/excerpt and String#at/from/to/first/last automatically does the .chars conversion, but if when you need to manipulate or display length yourself, be sure to call .chars. Like:

You've written <%= @post.body.chars.length %> characters.

With Rails 1.2, we’re assuming that you want to play well with unicode out the gates. The default charset for action renderings is therefore also UTF-8 (you can set another with ActionController::Base.default_charset=(encoding)). KCODE is automatically set to UTF-8 as well.

Watch the screencast. (but note that manually setting the KCODE is no longer necessary)

Unicode was in greatest demand, but Multibyte is ready handle other encodings (say, Shift-JIS) as they are implemented. Please extend Multibyte for the encodings you use.

Thanks to Manfred Stienstra, Julian Tarkhanov, Thijs van der Vossen, Jan Behrens, and (others?) for creating this library.

Routes

Action Pack has an all new implementation of Routes that’s both faster and more secure, but it’s also a little stricter. Semicolons and periods are separators, so a /download/:file route which used to match /download/history.txt doesn’t work any more. Use :requirements => { :file => /.*/ } to match the period.

Auto-loading

We’ve fixed a bug that allowed libraries from Ruby’s standard library to be auto-loaded on reference. Before, if you merely reference the Pathname constant, we’d autoload pathname.rb. No more, you’ll need to manually require 'pathname' now.

We’ve also improved the handling of module loading, which means that a reference for Accounting::Subscription will look for app/models/accounting/subscription.rb. At the same time, that means that merely referencing Subscription will not look for subscription.rb in any subdir of app/models. Only app/models/subscription.rb will be tried. If you for some reason depended on this, you can still get it back by adding app/models/accounting to config.load_paths in config/environment.rb.

Prototype

To better comply with the HTML spec, Prototype’s Ajax-based forms no longer serialize disabled form elements. Update your code if you rely on disabled field submission.

For consistency Prototype’s Element and Field methods no longer take an arbitrary number of arguments. This means you need to update your code if you use Element.toggle, Element.show, Element.hide, Field.clear, and Field.present in hand-written JavaScript (the Prototype helpers have been updated to automatically generate the correct thing).

// if you have code that looks like this
Element.show('page', 'sidebar', 'content');
// you need to replace it with code like this
['page', 'sidebar', 'content'].each(Element.show);

Action Mailer

All emails are MIME version 1.0 by default, so you’ll have to update your mailer unit tests: @expected.mime_version = '1.0'

Deprecation

Since Rails 1.0 we’ve kept a stable, backward-compatible API, so your apps can move to new releases without much work. Some of that API now feels like our freshman 15 so we’re going on a diet to trim the fat. Rails 1.2 deprecates a handful of features which now have superior alternatives or are better suited as plugins.

Deprecation isn’t a threat, it’s a promise! These features will be entirely gone in Rails 2.0. You can keep using them in 1.2, but you’ll get a wag of the finger every time: look for unsightly deprecation warnings in your test results and in your log files.

Treat your 1.0-era code to some modern style. To get started, just run your tests and tend to the warnings.

January 19, 2007 01:19 AM

Why TheLuckyStiff image

Kchhhk (Small Implosion)

Kevin Clark: This might be the longest post with the least substance I’ve read in a long time. Why would you use this space to tout your history? How did you get post access on the O’Reilly Ruby Blog?

Let the blogging contests begin!!

January 19, 2007 12:39 AM

January 18, 2007

Justin Palmer image

Prototype 1.5 Released and Documentation Site Live

We’ve worked really hard getting the official Prototype site up and running and it’s finally here, not to mention we’re also releasing 1.5!

January 18, 2007 11:12 PM

Tobias Luetke image

Want to work on a cool project?

I have it on authority that working on something like Shopify is tons of fun. Now you can experience the thrill as well ;)

They give you a 30 days deadline which should be plenty. Considering that some people can write something like Shopify in C in a few days
this should be plenty.

Objection!

January 18, 2007 10:58 PM

Amy Hoy image

OMG, Prototype Docs!

Prototype users, your days of longing and sexy (and not-so-sexy) nail-biting are over... There's now an official site. With docs. Yes, docs! Loads of them!

Congrats (and a huge thanks!) to all the folks who made it happen.

Check out Slash7 for more -- and let me know what you think!
image imageimage

January 18, 2007 10:40 PM

Thomas Fuchs image

Prototype 1.5 out now, with complete API docs

Prototype 1.5.0 has arrived. Besides tons of additions, this release marks the unvealing of the all-new Prototype site, available at:

http://prototypejs.org/

Thanks to the heroic efforts of foremost Justin Palmer and the rest of the Prototype core team we now present complete API docs, one of the things that has been missing from this great library.

Enough talk, head over to the official site to read the details, and get Prototype 1.5.0 today.

Don’t forget to digg this.

image image

January 18, 2007 10:20 PM

Justin Palmer image

Infected with the 5 Things Meme

It seems Mr. Webb had it out for me and has bestowed upon me the 5 things meme. I’m not that interesting, but here goes.

January 18, 2007 09:43 PM

Jamis Buck image

ActiveRecord association scoping pitfalls

ActiveRecord’s associations let you specify just about every option that ActiveRecord#find accepts. Want your account’s people returned in sorted order? Just specify ”:order => ‘name’” in the association.

1
2
3
class Account < ActiveRecord::Base

has_many :people, :order => "name"
end

What could be simpler? Alas, there are all kinds of hidden pitfalls in this approach.

Note that any query scoped by that association is going to use that order, whether you need (or even want) it or not. One consequence of this is that if your scoped find uses an index that doesn’t include the sort key (“name”, in this case), you’re going to be taxing your database unnecessarily. Let’s assume that your “people” table has an index on “account_id” and “name”, so that the default query is nice and performant:

1
2
3
4

5
6
7
8
9
10
11
# SELECT * FROM people WHERE (people.account_id = 1)

# ORDER BY name
account.people

# SELECT * FROM people WHERE (people.account_id = 1
# AND (admin = 1)) ORDER BY name
account.people.find(:all, :conditions => ["admin = ?", true])


# SELECT * FROM people WHERE (people.account_id = 1)
# ORDER BY role, name
account.people.find(:all, :order => "role")

Note that last example, in particular. Specifying a sort order in a scoped query appends to the sort order of the scope. In other words, the query will now work the database harder, unless you just happen to have an index on all three of “account_id”, “role”, and “name”. There is not (currently) an easy way to reach into the parent’s scope and alter (or even “switch off”) the existing order.

This gets even uglier if your association happens to specify a default :include clause:

1

2
3
class Account < ActiveRecord::Base
has_many :people, :include => :email_addresses

end

Now, if you try and scope the query, the scope will always inherit the requirement that the email_addresses table must be joined in. Now, sometimes you want that join. But all the time? On every scoped query? Are you sure? Not only does this make your database work harder (since queries involving multiple tables require more work than queries against a single table, in general), but it increases the risk of name clashes if you specify conditions or order keys without fully qualifying the table names:

1

2
3
4
5
6
7
# May cause problems if email_address also have a 'role' column
account.people.find(:all, :order => "role")


# The safer way to do it, but you wouldn't know that
# unless you were well acquainted with how the people
# association is defined.
account.people.find(:all, :order => "people.role")

So, what are your options? I would recommend doing like I’ve discussed in other articles, and like Koz and I have pointed out on The Rails Way: either set up a separate association that includes the sorts and includes, or use an extension method. Then, you can use the unadorned version of the association to do your scoped queries safely and efficiently, having a much better idea of what they are going to be doing to your database.

1
2

3
4
5
6
7
8
9
10
11

12
13
14
15
16
class Account < ActiveRecord::Base

# Option #1, using a second association. Allows you to do:
# account.people
# account.people_by_name
has_many :people
has_many :people_by_name, :class_name => "Person", :order => "name"


# or, using extension methods, you can do:
# account.people
# account.people.by_name
has_many :people do
def by_name

@by_name ||= find(:all, :order => "name")
end
end

end

Either way, you can rest easily knowing that the vanilla “people” association will let you query the database without any scoped assumptions about order. In fact, the only assumption you’ll get at all is the assumption that the query needs to include the “account_id” comparison.

Which is right.

January 18, 2007 08:25 PM

Eric Hodel image

RubyGems 0.9.1

Finally, the much anticipated RubyGems version 0.9.1 is now available.
This release includes a number of new features and bug fixes.

The most important change in RubyGems 0.9.1 is that RubyGems no longer allows files to be installed outside of the installation directory. A separate security bulletin with full details will be posted shortly.

RubyGems 0.9.1 is a required update. The RubyForge gem repository will soon disallow installation by older versions of RubyGems. Manual installation will still be allowed.

Upgrade note

While require_gem was deprecated in 0.9.0, the bin stubs are still using it (oops!). To get rid of the warnings printed by rake or other bin stubs simply run 'gem pristine --all'.

Changes in RubyGems 0.9.1

Major changes include:

  • RubyGems no longer allows installation of files outside the gem directory
  • #require_gem will now print a warning, use #gem instead
  • RubyGems now requires ruby 1.8.2 or greater
  • RubyGems is -w clean

Minor changes include:

  • gem command changes
    • new gem pristine command
    • new gem outdated command
    • new gem sources command
    • gem uninstall can uninstall multiple gems
    • gem install uses the cache instead of downloading
    • gem install returns non-zero exit code on failure
    • gem install can now set shebang on bin stubs (env or ruby)
    • gem help output now fits in 80 columns

many proxy installation improvements
gem cert improvements
RubyGems is now easier to use as a library

  • Easier programatic installs
  • Easier inspection of local and remote gems

extension building enhancements
error reporting enhancements (less odd exceptions)
require now loads .jar files

Bug fixes:

  • installing from scratch fixed
  • gem install --force forces
  • installing from read-only location works
  • gem uninstall requires full name
  • gem install obeys GEM_HOME for bin scripts
  • RubyGems now installs on ruby 1.9
  • fixed issue with Gem::Specification#hash for JRuby
  • RubyGems now installs RDoc and ri for itself
  • RubyGems is now tab-free

What is RubyGems?

RubyGems is a package management system for Ruby applications and
libraries. RubyGems' one command download makes installing Ruby software
fun and enjoyable again.

Many gems are available for download from the RubyForge site. Browse
the list of gems with a "gem list --remote" command and download what
you need with a simple "gem install <name-of-gem>". RubyGems takes care
of the details of installing, not only the gem you requested, but also
any gems needed by the software you selected.

RubyGems Statistics

  • About 1250 different gems are available from RubyForge
  • Over 540 thousand downloads of the RubyGems software
  • Over 8 million gem downloads

If you are interested in finding out when new gems are released, I
maintain an RSS feed at http://onestepback.org/gemwatch.rss.

How can I get RubyGems?

If you have a recent version of RubyGems (0.8.5 or later), then all
you need to do is:

$ gem update --system # you might need to be admin/root
$ gem pristine --all # ... here too

(Note: You may have to run the command twice if you have any previosly
installed rubygems-update gems).

If you have an older version of RubyGems installed, then you can still
do it in two steps:

$ gem install rubygems-update # again, might need to be admin/root
$ update_rubygems # ... here too
$ gem pristine --all # and here

If you don't have any gems install, there is still the pre-gem
approach to getting software, doing it manually:

  1. DOWNLOAD FROM: http://rubyforge.org/frs/?group_id=126
  2. UNPACK INTO A DIRECTORY AND CD THERE
  3. INSTALL WITH: ruby setup.rb all (you may need admin/root privilege)

What's Next

For RubyGems 0.9.2 the RubyGems team is looking to add:

  1. Integration of local and remote installation
  2. Automatic installation of platform-specific gems

Thanks

Contributors to this release include:

Anatol Pomozov, Gavin Sinclair, David Lee, Ryan Davis, Robert James, Chris Morris, Sylvain Joyeux, Sava Chankov, Tom Pollard, Kevin Clark, Andy Shen.

Keep those gems coming!

January 18, 2007 07:00 PM

Why TheLuckyStiff image

Camping's Youthfulness Wins Annual Award

Today, the International Kayak Consortium celebrates Camping (a Microframework)’s 1st birthday. They have honored the paragraph of code by awarding it the Annual First Place in Birthdaying Special Day Award and So Brave.

Click to zoom.

The commissioner of kayaking LeBrock Mitchell gave an acceptance speech on behalf of Camping at this morning’s banquet. His sentiments were brief, but stirring:

I have written two speeches for today, a long one and a short one. However, the pages for both got wet inside my kayak. Yes, I tried blow-drying them. But as I held that that cylinder of hot air, I realize that I couldn’t say anything as brief as Camping itself.

And he held up a printout of Camping from trunk and he wept exactly 4k of tears. We, in fact, measured with a graduated cylinder.

Here is Camping today.

%w[active_support markaby tempfile uri].map{|l|require l}
module Camping;Apps=[];C=self;S=IO.read(__FILE__).sub(/S=I.+$/,'')
P="Cam\ping Problem!";module Helpers;def R(c,*g);p,h=/\(.+?\)/,g.grep(Hash)
(g-=h).inject(c.urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|s.sub p,C.
escape((a[a.class.primary_key]rescue a))}+(h.any?? "?"+h[0].map{|x|x.map{|z|C.
escape z}*"="}*"&": "")end;def URL c='/',*a;c=R(c,*a)if c.respond_to?:urls
c=self/c;c="//"+ [at] env [dot] HTTP_HOST+c if c[/^\//];URI(c)end;def/p;p[/^\//]?@root+p :
p end;def errors_for o;ul.errors{o.errors.each_full{|x|li x}}if o.errors.any?end
end;module Base;include Helpers;attr_accessor:input,:cookies,:env,:headers,:body,
:status,:root;def method_missing*a,&b;a.shift if a[0]==:render;m=Mab.new {},self
s=m.capture{send(*a,&b)};s=m.capture{send(:layout){s}} if /^_/!~a[0].to_s and m.
respond_to?:layout;s end;def r s,b,h={};@status=s;@headers.merge!h;@body=b end
def redirect*a;r 302,'','Location'=>URL(*a)end;Z="\r\n";def to_a;[@status,@body,
@headers]end;def initialize r,e,m;e=H[e.to_hash];@status,@method,@env,@headers,
@root=200,m.downcase,e,{'Content-Type'=>"text/html"},e.SCRIPT_NAME.sub(/\/$/,'')
@k=C.kp e.HTTP_COOKIE;q=C.qsp e.QUERY_STRING;@in=r;if%r|\Amultipart/form-.*boun\
dary=\"?([^\";,]+)|n.match e.CONTENT_TYPE;b=/(?:\r?\n|\A)#{Regexp::quote("--#$1"
)}(?:--)?\r$/;until [at] in [dot] eof?;fh=H[];for l in@in;case l;when Z;break
when/^Content-D.+?: form-data;/;fh.u H[*$'.scan(/(?:\s(\w+)="([^"]+)")/).flatten]
when/^Content-Type: (.+?)(\r$|\Z)/m;fh[:type]=$1;end;end;fn=fh[:name];o=if
fh[:filename];o=fh[:tempfile]=Tempfile.new(:C);o.binmode;else;fh=""end;while l=@in.
read(16384);if l=~b;o<<$`.chomp;@in.seek(-$'.size,IO::SEEK_CUR);break;end;o<<l
end;C.qsp(fn,'&;',fh,q) if fn;fh[:tempfile].rewind if fh.is_a?H;end;elsif@method==
"post";q.u C.qsp(@in.read)end;@cookies,@input= [at] k [dot] dup,q.dup end;def service*a
@body=send(@method,*a)if respond_to?@method;@headers["Set-Cookie"]= [at] cookies [dot] map{
|k,v|"#{k}=#{C.escape(v)}; path=#{self/'/'}"if v!=@k[k]}-[nil];self end;def to_s
a=[];@headers.map{|k,v|[*v].map{|x|a<<"#{k}: #{x}"}};"Status: #{@status}#{Z+a*Z+
Z*2+@body}"end;end;X=module Controllers;@r=[];class<<self;def r;@r;end;def R*u
r=@r;Class.new{meta_def(:urls){u};meta_def(:inherited){|x|r<<x}}end;def M;def M
end;constants.map{|c|k=const_get(c);k.send:include,C,Base,Models;r[0,0]=k if
!r.include?k;k.meta_def(:urls){["/#{c.downcase}"]}if !k.respond_to?:urls}end;def
D p;r.map{|k|k.urls.map{|x|return k,$~[1..-1]if p=~/^#{x}\/?$/}};[NotFound,[p]]end
end;class NotFound<R();def get p;r(404,Mab.new{h1 P;h2 p+" not found"})end end
class ServerError<R();def get k,m,e;r(500,Mab.new{h1 P;h2"#{k}.#{m}";h3"#{e.class
} #{e.message}:";ul{e.backtrace.each{|bt|li(bt)}}}.to_s)end end;self;end;class<<

self;def goes m;eval S.gsub(/Camping/,m.to_s).gsub("A\pps=[]","Cam\ping::Apps<<\
self"),TOPLEVEL_BINDING;end;def escape s;s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.
unpack('H2'*$&.size)*'%').upcase}.tr(' ','+')end;def un s;s.tr('+',' ').gsub(
/%([\da-f]{2})/in){[$1].pack('H*')}end;def qsp q,d='&;',y=nil,z=H[];m=proc{|_,o,n|o.u(
n,&m)rescue([*o]<<n)};q.to_s.split(/[#{d}] */n).inject((b,z=z,H[])[0]){|h,p|k,v=un(p).
split('=',2);h.u k.split(/[\]\[]+/).reverse.inject(y||v){|x,i|H[i,x]},&m}end;def
kp s;c=qsp(s,';,')end;def run r=$stdin,e=ENV;X.M;k,a=X.D un("/#{e[
'PATH_INFO']}".gsub(/\/+/,'/'));k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.
service *a;rescue Object=>x;X::ServerError.new(r,e,'get').service(k,m,x)end
def method_missing m,c,*a;X.M;k=X.const_get(c).new(StringIO.new,H['HTTP_HOST',
'','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s);H.new(a.pop).each{|e,f|k.send(
"#{e}=",f)}if Hash===a[-1];k.service *a;end;end;module Views;include X,Helpers
end;module Models;autoload:Base,'camping/db';def Y;self;end;end;class Mab<
Markaby::Builder;include Views;def tag!*g,&b;h=g[-1];[:href,:action,:src].map{
|a|(h[a]=self/h[a])rescue 0};super end end;H=HashWithIndifferentAccess;class H
def method_missing m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m]:raise(
NoMethodError,"#{m}")end;alias_method:u,:regular_update;end end

More recently:

Update: If all of you can get out your copy of the Camping core team’s group picture, Indian Chief Skittles McQueeny has just sent me the following legend:

  1. Ranger Jake (holding a lizard)
  2. Tiffany Rabbitsapple
  3. (a non-notable prince)
  4. why the lucky stiff
  5. Spud Webb (the same)
  6. Indian Chief Skittles McQueeny
  7. Mrs. Rummly
  8. Jonas Pfenniger
  9. Oarsman C. S. “Celery Shirt” Acornson
  10. Camera Nap
  11. Helps the Janitor (holding a soccer ball under his poncho)

Update from Air Force Staff Sargeant Guds Mandragon:

We try to keep a lid on it, but some pilot folklore has infiltrated our ranks. The tale goes that if you eject from your plane on Camping’s birthday that you will be visited in the night by a red fairy who will grant you a free batch of caramel apples, answering to any quantity you provide. In some permutations of the rumor, she grants an infinite quantity. Four aircraft have been ditched, two have struck earth, one crushing a cereal factory. I am told Grape Nuts. Please dispell this rumor forthrighly.

Hmm, interesing stuff. Thanks, Guds!

Update:

Update: The latest Camping trunk lets you add a query string to your routes by adding a Hash argument.
>> a "version 2", :href => R(Show, page.title, :version => 2)
=> "<a href='/wiki/title?version=2'>version 2</a>"

January 18, 2007 06:46 PM

Jim Weirich image

Using Rake as a Library -- Update

Why Not Find?

Why Not Find?

After posting FindInCode, someone legitimately asks: “Why not just use Find?”

Good question! Find is a Ruby supplied module to recursively search
directories. So why not use it instead of Rake. Then your script
won’t have a dependency on Rake.

Well, in short:

  1. Rake provides two functions, recursive directory searching
    and line by line searching (note that egrep is a FileList
    method provided by Rake, and is not the same as the grep method
    provide by Ruby arrays). Find only handles the directory search
    thing.
  2. I almost never use a Ruby installation without Rake installed as
    well. So the extra dependency is not a concern to me.
  3. Since I use Rake all the time, the syntax is at my fingertips. I
    don’t use Find often enough to use it without checking RI.
  4. The Find version of the script is several times longer than the Rake
    version (included below for comparison).

However …

The find version has one advantage over the Rake version in that it
does not need to pull in the entire list of files into memory at once.
That may be important to you.

Comparisons

Here’s the original version again:

require 'rake'
FileList["**/*.rb"].egrep(Regexp.new(ARGV.first))

And here is the Find version:

require 'find'
RE = Regexp.new(ARGV[0])
Find.find('.') do |fn|
next if fn =~ /(^(\.svn|CVS)$)/
next unless fn =~ /\.rb$/
open(fn) do |file|
lines = 0
file.each do |line|
lines += 1
puts "#{fn}:#{lines}:#{line}" if line =~ RE
end
end
end

Update (31/Aug/06)

James Edward Grey II points out that my find example could use a
little makeover. First, the regex that causes .svn
directories to be skipped is incorrect, it only skips the actual
directory, not the contents of the directory. Removing the ”$” from
the match will fix that, but he provides a better solution. Replace
that entire line with:

Find.prune if fn =~ /(^(\.svn|CVS)$)/

I totally forgot about prune.

A minor correction is the use of the lines counter. He
suggests either using each_with_index (I should have
thought of that), or better yet, use file.lineno.

Thanks James!

January 18, 2007 04:40 PM

Using Rake as a Library

I’ve been exploring using Rake as a Ruby Library.

Find In Code

Lately, I’ve been experimenting with using Rake as a normal library in
regular Ruby scripts (rather than in Rakefiles). It turns out there
are some very useful things you can do.

For example, to locate a particular piece of code in a not so small
Ruby project, I often use the following command line:

$ find . -name '*.rb' | xargs grep -ni "snippet of code"

This quickly searches all my Ruby files and displays matching lines
with file names and line numbers. However, the line is long to type
and won’t work in windows (unless you have cygwin installed).

So I wrote the following Ruby program and saved it in a file called “fic” (Find In Code):

#!/usr/bin/env ruby
require 'rake'
FileList["**/*.rb"].egrep(Regexp.new(ARGV.first))

An Enhanced Version

This proved so useful, that I enhanced the code to allow for searching
for files ending in arbitrary extendsions and to handle more matching
options on the command line.

Here’s the enhanced version:

#!/usr/bin/env ruby
# -*- ruby -*-

exts = ['.rb']
if ARGV[0] =~ /^\.[a-zA-Z0-9]+$/
exts = []
while ARGV[0] =~ /^\.[a-zA-Z0-9]+$/
exts << ARGV.shift
end
end

ext = "{" + exts.join(',') + "}"

if ARGV.size < 1
puts "Usage: #{File.basename($0)} [.ext ...] pattern ..."
exit 1
end

require 'rake'
FileList["**/*#{ext}"].egrep(Regexp.new(ARGV.join('|')))

And if you are using Emacs …

If you are using Emacs, and you have my “visit source” code loaded,
all you need to do is put the cursor on the line you are interested in
and press F2.

Oh, you would like to see the elisp code for “visit source”? Let’s
see, where did I put that?

$ cd .elisp/
$ fic .el jw-visit-source
ini/ini-cust.el:131:(defun jw-visit-source ()
ini/ini-zkeys.el:7:(global-set-key [f2] 'jw-visit-source)

Now, I move the cursor to the first line and press F2, and I find:

;;; Source File Visiting =============================================

(defun jw-current-line ()
"Return the current line."
(let
((bol (save-excursion (beginning-of-line)(point)))
(eol (save-excursion (end-of-line)(point))))
(buffer-substring bol eol) ))

(defun jw-extract-file-lines (line)
"Extract a list of file/line pairs from the given line of text."
(let*
((unix_fn "[^ \t\n\r\"'([<{]+")
(dos_fn "[a-zA-Z]:[^\t\n\r\"'([<{]+")
(flre (concat "\\(" unix_fn "\\|" dos_fn "\\):\\([0-9]+\\)"))
(start nil)
(result nil))
(while (string-match flre line start)
(setq start (match-end 0))
(setq result
(cons (list
(substring line (match-beginning 1) (match-end 1))
(string-to-int (substring line (match-beginning 2) (match-end 2))))
result)))
result))

(defun jw-select-file-line (candidates)
"Select a file/line candidate that references an existing file."
(cond ((null candidates) nil)
((file-readable-p (caar candidates)) (car candidates))
(t (jw-select-file-line (cdr candidates))) ))

(defun jw-visit-source ()
"If the current line contains text like '../src/program.rb:34', visit
that file in the other window and position point on that line."
(interactive)
(let* ((line (jw-current-line))
(candidates (jw-extract-file-lines line))
(file-line (jw-select-file-line candidates)))
(cond (file-line
(find-file-other-window (car file-line))
(goto-line (cadr file-line)) )
(t
(error "No source location on line.")) )))

January 18, 2007 04:40 PM

Tuning Performance

Uncle Bob has a couple examples of why performance tuning almost
always has surprises in store for you.

Not What You Expect!

Bob Martin (Uncle Bob)
relates
a couple of stories on performance tuning and why your expectations
are nearly always wrong.

The moral of the story … measure, measure, measure whenever you have
a performance problem. The root cause is prabably not where you
expect it to be.

January 18, 2007 04:40 PM

Announcing the RailsEdge Conference

Rails Edge

This is exciting. I have been wanting to talk about this for some
time. Well, the time has finally come and I’m happy to announce that
the Pragmatic Programmers are putting together a series of regional
conferences called The Rails
Edge
.

The conference will be a single track, so all the speakers at the
conference will be available for interaction at all the talks, not
just during their own presentation. The speaker selection is great (I
feel humbled to be a member of the group). We are hoping that it will
a dynamic experiance with the speakers interacting, not only with the
audience, but with the other members of the staff.

So, if you didn’t make it into the “Lucky 250” club going to RubyConf
this year, here is another chance to meet and greet Rubyists in your
area.

I hope to see you there.

Update: You can read the official Pragmatic Programmer’s Announcment too.

January 18, 2007 04:40 PM

Updates to Ruse Wiki Software

The Ruse wiki software gets some updates.

Some Changes to Ruse

I’ve been really pleased with the way Ruse has been handling wiki
related spam on the Ruby Garden site. Now that Ruse has been deployed
for a while, I’ve tweaked a few things to make it even easier to clean
up spam.

  • Queued Review Mode: The original RubyGarden wiki took an
    annoying number of clicks to clean a page of spam. Ruse has the
    cleanup down to one click, but it takes an additional two clicks to
    get to the next page to review. (goto to review page, choose next
    page to review). The new Queued Review mode will now automatically
    advance to the next page for reviewing, bringing you to a true “one
    click per page” review mode. Click on the “Work from Queue” link on
    the review page.
  • Bug Fix: The review page now correctly displays the
    differences for the version you are reviewing. The original
    behavior incorrectly showed the wrong revisions in the differences
    section (although the page content was correct).
  • Minor changes and fixes: The size of the log page is now
    configurable (rather than the fixed 25 entry size). Demotion during
    review is now properly logged.

Future Directions

One technique that has proved very useful in preventing spam is the
content filtering that Ruse is able to do. We download the “bad url”
list from chonqged.org nightly and will reject all posts URL that
match that list. Currently, we can add additional URLS to the
blacklist by editting a configuration file on the server. Future
versions of Ruse might add a web interface to the local blacklist.

January 18, 2007 04:40 PM

Fireworks on the Fourth of July

We had some fireworks on the 4th of July … Unfortunately
they weren’t the usual kind.

Fireworks on the 4th

It is a tradition in the US to fire off fireworks on the 4th of July
in celebration of Independence day. Well, the Weirich household had
some fireworks, but it’s not what you would expect.

What we thought at the time was a really loud firecracker from the
neighbors turned out to be a close lightening strike, probably hitting
the phone line. I discovered later that my DSL router (attached to
the phone line) was dead (as in no lights, no power).

After a picking up a new DSL router on Wednesday from the phone
company, it still didn’t connect and the phone company promised to
send a technician out one Friday. Arrgh! Three days with no
internect! Sigh.

The technician arrives Friday, checks out the wiring and decides to
upgrade the “system”. Part of the upgrade is another new DSL router
(different model from the replacement unit I picked up Wednesday). We
connect up the laptop to the DSL router and everything looks great.

So once the phone guy leaves, I start hooking up the rest of the
network: firewall router, network hub, wireless base station, and the
other computers in the house.

And nothing works.

It looks like the lightening not only took out my DSL router, but it
also got the firewall, network hub and wireless base station.
Fortunately, I have another firewall and hub in my spare parts box.

Bad Cables?

I’m not certain of the total extent of the damage yet. The cables
running to the other computers in the basement seem to be bad now
(tested by against my working laptop). Since I don’t have long enough
replacement cables, I haven’t checked out the network cards in two of
the computers yet.

I am a bit surprised by the cables going bad. I understand delicate
electronic equipment fried by lightening, but the cables are just
wires and connectors. For them to be bad must mean the strike was
strong enough to short them out somehow. And that doesn’t sound good
for the network cards at the other end of the cable. Sigh.

On the good side, the my desktop computer that sits right next to the
network equipment is up and running on the network. So one would that
the network card in it is ok. However, it does seem to be a bit slow
when browsing web pages. I mean really slow. I timed it against
my laptop. What loads two seconds on my laptop takes over 20
seconds on the desktop. But that sounds more like a network
configuration error than a hardware issue. Sigh, more work to do.

At any rate, it looks like there will be a run to the local computer
store soon.

January 18, 2007 04:40 PM

Delete Your RubyGems Cache

Several people have been having RubyGems issues.

Deleting Your RubyGems Cache

Several people have been reporting problems where RubyGems doesn’t
find a gem on RubyForge, or gives other strange errors. It seems
there was a gem on RubyForge that gave the Gem indexing software some
headaches. And as a result, the gem index was corrupted. If you
downloaded the corrupt index, then you may be experiencing strange
problems as well.

The good news is that the problem is easy ot fix. Just delete the gem
index file. You can find it in the directory reported by the “gem env
gemdir” command. For example:

$ gem env gemdir
PATH_TO_DEFAULT_GEM_REPOSITORY
$ rm PATH_TO_DEFAULT_GEM_REPOSITORY/souce_cache

Where PATH_TO_DEFAULT_GEM_REPOSITORY is your default gem repository.

If you run on a Unix system, you default gem repository is probably
non-writable from your regular user account. In that case, you will
need to use “sudo” (or its equivalent) on the “rm” command. You will
probably also have a secondary writable cache in your .gem directory
that you will want to delete.

$ rm $HOME/.gem/source_cache

The next time you run gems, will will refresh the cache by downloading
the index from scratch.

January 18, 2007 04:40 PM

Write a Proposal for RubyConf

We Need Proposals

Write Up Your RubyConf 2006 Talk Proposal

David A. Black is asking for
proposals

for RubyConf 2006. If you have an idea for a talk, please feel free
to propose it for the conference (and you can use this
page
). The deadline is June 30th,
so don’t delay.

RubyConf has always been one of my favorite conferences to attend. If
you are thinking going, then consider this my personal invitation
to attend. I hope to see you there.

January 18, 2007 04:40 PM

Multicasting in Ruby

It’s a bit hard to dig up, but I did figure out how to do UDP packet multicasting in Ruby.

Multicasting

I’ve been playing around with some network peer to peer discovery
techniques and wanted to try some of them out in Ruby. The trick to
self discovery is the ability to send network packets without knowing
the address of the receiver. To do this, you either have to broadcast
or multicast.

Because broadcasted packets are received by every device on the local
network, it is generally considered good manners to not use
broadcasted packets.

Multicasting, on the other hand, is only received by hosts that
explicitly express an interest in the multicast address. Although
abuse of multicasting is still bad manners, it is a better option than
broadcasting.

Sending Multicast Packets

The IP addresses 224.0.0.0 through 239.255.255.255 are reserved for
multicast messages. Simply sending a UDP messsage to an address in
that range is sufficient.

One minor refinement is to set the TTL (Time To Live) option on the
socket. My understanding is that this controls how far the packet is
propagated. As polite net-citizens, we don’t want our multicast
packets travelling too far abroad, so we set the TTL value to 1 (we
need the ugly packing stuff because the value is passed directly to
the C level setsockopt() function with no interpretation by
Ruby).

So the Ruby code to send a multicast message is:

require 'socket'

MULTICAST_ADDR = "225.4.5.6"
PORT= 5000

begin
socket = UDPSocket.open
socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, [1].pack('i'))
socket.send(ARGV.join(' '), 0, MULTICAST_ADDR, PORT)
ensure
socket.close
end

Receiving Multicast Messages

Receiving a multicast message is a bit tricker. Since multicast
messages are generally ignored unless someone has explicitly
registered an interest in a particular address, there is a bit of
setup that needs to be done.

Here’s the code for receiving multicast messages:

require 'socket'
require 'ipaddr'

MULTICAST_ADDR = "225.4.5.6"
PORT = 5000

ip = IPAddr.new(MULTICAST_ADDR).hton + IPAddr.new("0.0.0.0").hton

sock = UDPSocket.new
sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ip)
sock.bind(Socket::INADDR_ANY, PORT)

loop do
msg, info = sock.recvfrom(1024)
puts "MSG: #{msg} from #{info[2]} (#{info[3]})/#{info[1]} len #{msg.size}"
end

The tricky part was figuring out the right setsockopt options and
values needed to register interest in our multicast address. I had to
do a little reading in the Unix man pages on the C level
setsockopt() function call. The third option to the C
function is a structure that contains two 4-byte IP addresses. The
first IP address is the multicast address, and the second IP address
is the address of the local host adapter that we wish to use to listen
for the multicast. The 0.0.0.0 address means use any of the local
network adapters. IPAddr handles parsing the human readable form of
the IP address and returns a string of 4 bytes in the order needed by
the C level setsockopt() function.

Usage

Save the above code in files named send.rb and
rcv.rb. In one console window, type:

ruby rcv.rb

In another console window on the same or different machine (on the
same local network), type:

ruby send.rb This is a test.

For more fun, bring up several receive windows and all will receive
the messages send by the send script.

I can think of all kinds of fun things to do with this.

Update

I added the Time To Live option on send.

January 18, 2007 04:40 PM

Some More Ruse Related News Items

When I checked the wiki last night, I found that over 100 pages had been updated.

Not Spam, Just Weird Stuff

So I started checking out exactly what had changed. It seems that almost
all changes were by a single anonymous individual. Over the coourse
of 7 hours he touched over 100 pages and reverted them to the earliest
possible version. What’s up with that?

It may not be spam, but it certainly counts as destructive behavior.
So, I threw him in the tarpit and all his changes into the tarit. In
20 seconds I wiped out his seven hours of hard work.

I hope he had a good day. I certainly did.

New Ruse Logo

And in other news, we have a new Ruse Wiki logo:

January 18, 2007 04:40 PM

Dave Thomas image

Debugging with Ruby

Thanks to Ed Burnette for this link.

January 18, 2007 04:38 PM

Rails and the Legacy World

I gave what turned out to be a slightly controversial keynote
at RailsConf
. In it, I pointed out that people (like me) who can use
Rails on green-field projects are incredibly privileged. We get to code
using cool technologies in an incredibly agile, reactive environment,
producing applications that just work.

But, at the same time, there are a whole lot of people who don’t get
to enjoy the world of Rails.

I see these people regularly: I talk at No Fluff symposia around the
country, a great set of shows aimed at Java developers. I’m the
outsider, normally giving a full day’s worth of talks on Ruby and
Rails. And, in a way, it makes me sad to do it, because I often see folks
get really excited about the possibilities present in Rails only then to
realize that they’ll be going back to work on Monday with no real
hope of using what they’d just seen. These folks come to me during
the breaks and talk about how bad their world currently is, and how much
better it would be if only they could use Rails. If only…

Sometimes, the things that block these people are not technical issues:
companies have policies dictating that all work is done in Java (or .NET,
or whatever). But many times the road blocks are technical. In their
particular environment, with legacy code and legacy databases, they need to
be able to do things that Rails just doesn’t support out of the
box—more complex schemas, staged deployment, and so on.

So, in my keynote, I asked a simple question. Can we, as a community, do
anything to make the lives of these developers easier. Can we find a way of
bringing them in out of the cold?

Clearly, I believe the answer is yes. As I said in Chicago, the answer is
not to change Rails. Instead, the answer is to use the fact that Rails is
based on Ruby, and Ruby gives developers incredible power to extend
existing code in directions not anticipated by the original developers. I
asked the community to consider creating extensions to Rails to allow
currently disenfranchised developers to join the party.

This seems to have touched people’s nerves. Some have reacted
violently against the idea, others have welcomed it. It’s an
interesting, although ultimately sterile, debate. If people need changes to
Rails, Ruby will let them do it.

An interesting example is Greg Houston’s recent blog post, Let
ActiveRecord support Enterprise Databases
. (Uh oh! He used the

enterprise word). He describes a problem he faces trying to use
Active Record migrations to maintain a legacy schema. The database-neutral
migrations didn’t give him the kind of control he needed, so his post
describes how he extended Active Record to do what he wants (including a
very simple but nicely powerful trick to make migrations spit out SQL,
rather than execute it). And, importantly, he did all this as a regular
user of Rails: he didn’t need any changes to the framework or any
endorsement of his work by the core team. (He does, however, make a good
point at the end of his post. If Active Record had an extension API it
would make it easier for these kinds of plugins to survive changes to the
core code base.)

Greg’s post is a basic experience report: he took what he needed from
Rails, extended it where necessary, and solved a business problem. By
blogging, he’s shown other developers just how to solve this category
of problem. A .NET developer needing to manage a legacy SqlServer schema
could read his post and realize that something that seemed impossible in
Rails is actually fairly easy. One more person can join the party.

You could argue that the stuff in Greg’s post is just a simple matter
of coding. There’s nothing stopping any .NET developer downloading
Rails and making the simple changes he’s suggesting.

But the reality is that you have to have a good idea that this kind of
thing is possible before you invest time in the exercise. If you’re a
Java or .NET developer looking for salvation, and you spend some time
looking at Rails, you’ll currently come across a lot of information
explicitly telling you that Rails is never going to address the issues you
face—Rails is explicitly not "enterprise." And so
you’d move on. And you’d be missing an incredible opportunity.

And this is one of the challenges I’d like us, the Rails and Ruby
communities, to address. While keeping the Rails core focused on new ways
of writing web applications, I’d like others of us to find ways of
educating corporate software developers, showing them that they can also
bring our technologies into their daily lives—using Ruby as an enterprise glue
language
and Rails as a viable enterprise web development platform.

Should Rails be everything to everyone?

No.

Should Rails be "marketed" as a replacement for J2EE or .NET?

God forbid.

But there are a whole group of people out there who could be using
Rails now but aren’t, simply because they don’t know that it is
up to their challenges. And I’d like to try to help these folks.

Let’s not be the only people having fun.

January 18, 2007 04:38 PM

Migrations Outside Rails

I’m about 3 weeks into the rewrite of the Active Record chapters for
the new Rails
book
. In the book, I try to demonstrate Active Record with real, live
code. At the same time, I don’t want to run every single piece of
code in the context of a Web application. So, I use Active Record
stand-alone, without having the rest of Rails loaded. All my demonstration
files start:

require "rubygems"
require_gem "activerecord"

and then include a call to establish_connection to connect to the
database.

At this point, I’m up and running, and I can play with all the Active
Record functionality. But… I still wanted to create tables in the
underlying database. In the first edition, I used DDL to do this, but in
the second I wanted to use migrations.

My first hack was to use the fact that the various schema definition
methods are defined both for migrations and in every database connection
object. That let me use the following in my code:

ActiveRecord::Base.connection.instance_eval do
create_table children, :force => true do |t|
t.column :parent_id, :integer
t.column :name, :string
t.column :position, :integer
end
end

I was pretty chuffed with this until Jamis Buck (who else) pointed out a
more elegant way:

ActiveRecord::Schema.define do
create_table children, :force => true do |t|
t.column :parent_id, :integer
t.column :name, :string
t.column :position, :integer
end
end

As I see more and more people start to use Ruby (and Active Record) as
enterprise glue, being able to bring these kinds of Rails goodies to
non-Rails applications is a win all around.

January 18, 2007 04:38 PM

Decimal Support in Rails

A couple
of blog posts ago
, I commented on the dangers of converting database
decimal columns into Ruby floats. And, five months early, Santa
delivers. In the Rails trunk, numeric and decimal database columns with a
scale factor are now converted into Ruby BigDecimal objects. If the scale
factor is zero, they instead become integers.

Migrations now support decimal columns too, with the addition of two new
attributes, precision and scale.

add_column :orders, :price,
:decimal, :precision => 8, :scale => 2

I just spent a day reworking all the Depot chapters to use this, and it
seems to work great. (And, no, the updated PDF isn’t released yet.
I’m also half-way thought the ActiveRecord chapter rewrite, and need
to get that finished before the next release.)

I’d be interested to hear[1] from folks currently using BigDecimal
for financial calculations. Is there a preferred rounding mode? Any
gotchas?

In the meantime, thanks core team.

  1. dave∂pragprog.com

January 18, 2007 04:38 PM

Pluvo

LtU has a link to Pluvo, a language which seems like a
cross between Python, JavaScript, Ruby, and Lisp. It has some interesting
ideas (coordination is a fun one) and the basic system (written in Python)
is currently less than 50k to download.

January 18, 2007 04:38 PM

Prices in Cents

In the second edition of AWDwR, I changed
the Depot application to store money in integral cents, rather than
floating point dollars and cents. Some folks pushed back on this, saying it
overly complicated the application.

This morning, while working on some code to migrate some legacy data, I
bumped into a problem that boiled down to the following (on my
PPC—your results may differ)

dave[store/migrate 9:00:57] irb
irb(main):001:0> Integer(77.85 * 100.0)
=> 7784

Obviously it’s possible to do rounding (although even that’s
trickier than you might first code if you have to handle negative numbers).

I still feel that Rails should convert decimal(x,y) columns into
BigDecimal format in Ruby, giving us scaled, exact, representations. Until
that day, stick with integers for amounts that you need to be exact.

January 18, 2007 04:38 PM

Rails Guidebook

RailsConf 2006 is in its final day,
and I just realized that I hadn’t blogged on Rails Guidebook.

The Guidebook was a preconference event. For a day before the conference
proper started, attendees got an introduction to all the stuff that’d
be hearing about in the following days. It was a combination of a tutorial
and a glossary. We didn’t charge. Instead, the cost of admission was
a contribution to charity.

The Rails community raised over $8,000

This is wonderful stuff, and Mike and I thank everyone who made it
possible: the Ruby Central folks who agreed to add a day to the agenda, Jay
Zimmerman for organizing the facilities, the core team members and other
experts who turned up to help, Mike and Nicole for doing all the Guidebook
logistics, and, more importantly, the folks who turned up and contributed.

A Challenge

If you’re already organizing a conference, adding a guidebook day
ahead of it isn’t a great incremental cost. So, here’s a
challenge to conference organizers. Let’s start a tradition of these
types of charitable events. Let’s make a point of sharing some of our
success with others. Not only does it do some good—it’s fun.

January 18, 2007 04:38 PM

Glue That Doesn't Set

Back in the old days of computing—those days where I could
still see my knees when standing up—folks used to talk about
languages such as Perl as glue languages. What did they
mean?

Well, Perl is a great general purpose programming language. But it
is exceptional at doing something that no previous language could
do well: Perl made it easy to glue together other stuff. Data,
programs, external systems—all these things could be
integrated using Perl. Thanks to its integration with the
underlying operating system, and its amazing support for text
processing, Perl made a name for itself as an integrator par
excellence
. Want to take the last 20 lines of an error log,
convert them to HTML, and upload the result to your web server? Perl
could do that in a handful of lines of code. Need to screen-scrape a
book's sales rank from Amazon and writing it into a local MySQL
database. Perl to the rescue.

glue

Perl let us glue stuff together. It was magic.

But there was a problem. Perl is a great language. It was my
scripting language of choice before I discovered Ruby. But even on
my most charitable days I could never really claim that these Perl
programs were exemplars of readability. And, in turn, this lack of
readability made it hard for me to pick one of them up six months
after I'd written it and make some change—even small
alterations could involve long periods of head-scratching as I tried
to work out exactly what the entries in my hash of arrays of
hash references9 actually contained.

As a result, I found that the longer it was since I last looked
at a program, the harder it was to maintain and extend it. The
programs effectively became less malleable and more viscous. It
became stickier; I got mired in a gooey mess of details. Leave a
program long enough, and I'd often decide to rewrite it rather than
attempt some piece of surgery: the program had become totally
inflexible.

The glue had set.

Now Ruby is also a glue language. Just like Perl, Ruby works and
plays incredibly well with external data, resources, and programs. I
can do everything with Ruby that I used to do with Perl—I can
use it to integrate all kinds of stuff just as easily as I used to
be able to with Perl. But, there's a major difference. I've
discovered that, over time, my Ruby programs stay malleable and easy
to change. Ruby is the glue that doesn't set.

Glue and the Web

That's all very well, but what does writing little utility scripts
have to do with real-world web programming? A whole lot, as it turns
out.

As we move into a world where the network is the computer,
applications change in character. Rather than writing free-standing
islands of code, developers are increasingly writing programs that
knit together other, existing web resources. Want to annotate a map
with pictures of famous landmarks? Maybe you'll want to use the
Google Maps and Flikr APIs to carry most of the load for you. Want
to let your readers know when their product has shipped? Why not
generate the information as RSS and let their aggregator client do
all the gruntwork of displaying the result? As we move forward, more
and more of our applications will be less and less like one-man
bands and more like orchestra conductors.

Our applications are increasingly becoming glue code. And, if that's
the case, I'd rather write them using a glue that doesn't set over
time.

January 18, 2007 04:38 PM

The Rails Edge


image

Mike Clark has
announced The Rails
Edge
, a set of small, regional Rails conferences. The first will
be November 16-18 in Denver.

I'm really pleased with the way he's put these together. He's
selected a stellar group of speakers, all with deep, practical Ruby
and Rail experience.

Then he's organized it as a single track event. I know this was a
hard decision. But having one track means that everyone shares the
experience, and everyone can build on each session during the breaks
and in the evenings. It means we have a critical mass of folks, and
all the more experience to share.

And what I like most of all is the instructions he's given the
speakers. Unlike events where one person speaks and the other
speakers head off to pick up e-mail and work on projects, Mike is
encouraging the Edge speakers to participate in all the talks. If
Mike's talking, you might find yourself sitting next to Chad Fowler
or core-team member Marcel
Molina, Jr.
If someone asks an Ajax question that Mike doesn't
feel comfortable handling, Stu
Halloway
or Justin
Gehtland
might field it from the floor.

As a speaker, I love this format--it means we're all part of the
same team. Having other people around to help out lets me go
both deeper and broader into stuff. I'm really looking forward to
these events.

January 18, 2007 04:38 PM

Capistrano-Standing Room Only

image

It was standing-room only at Mike Clark's Capistrano talk: one of
the first talks at this
year's RailsConf. Latecomers stole
chairs from other rooms and fought their way to some free floor space
to hear Mike talk about the way we deploy Rails applications.

image

I'd just finished giving the first keynote. One of my topics was
making deployment in Rails easier and more amenable to corporate
use. I suspect from the interest in my talk, followed by the
overwhelming interest in Mike's talk, that deployment will be one of
the hot Rails topics of the coming year.

image

January 18, 2007 04:38 PM

Ryan Daigle image

While I Was Sleeping...

While I was being lazy Scott went ahead and posted a great write-up of the new Simply Helpful plugin that makes a few view-level operations more concise. Go ahead and check it out.

image

image image image image

January 18, 2007 12:26 PM

rela.tv open-sourced

I gave a short and not-very-well-prepared demo of rela.tv at the Raleigh Ruby Brigade last night that generated a few inklings of interest amongst the crowd. And I use the word “interest” generously. However, I’ve been meaning to open-source the app for awhile now since I rarely find the time to play with it anymore – if for nothing else than to see if somebody else wants to use it as a learning tools as I did and try to further its functionality.

This comes with the disclaimer that I am not proud at all of the state of the code, and especially the state of the tests. Look at this as more of an opportunity for improvement than for a model by which all others should be based.

So, if you’ve got some interest in hacking away at a cool little Rails project – let me know. I’d love to see this get taken forward a few steps…

Rela.tv source access

https://saucyworks.devguard.com/svn/projects/rela.tv/trunk

Don’t know what rela.tv is? Check out the overview for a summary.

tags: rela.tv, xfn, rails, rubyonrails

image

image

image image image image

January 18, 2007 12:26 PM

Phil Hagelberg image

minor note

Oh, and somehow I forgot to mention this, but comments, people!

I cooked up a little anti-spam magic inspired by Pastie, so I'm not going to be afraid anymore! Of course, I'm subscribed to its feed now, so if anything stinky does start to happen, I'm totally going to be on top of things.

January 18, 2007 12:16 PM

RubyForge image

Lookup fields plugin:LookupFields Rails Plugin

This plugin provides a simple solution for lookup fields - those cases where you just want to store a single text value, but also want to:
a) restrict the possible options and
b) be able to reflect on the possible options.

You could say it's an ActiveRecord implementation of 'enumerations' using a normalised db structure

January 18, 2007 08:22 AM

Assaf Arkin image

Rounded Corners - 95

Suck-o-meter. Brian Oberkirch lists 11 ways to tell if your product or service sucks. Let’s check back in June, and see how people fell about it.
Scary, but true. If planes were built like software.
A little ironic. Bruce Tate: “The Java community’s obsession with static type checking is curious because Java developers are now spending [...]

January 18, 2007 07:21 AM

Pat Eyler image

Rubinius Serial Interview: Episode III

A comment that seems to be coming up a lot is: "Where are the docs?". Let's detour briefly from testing and talk about docs (okay, it won't be a complete detour ...):

What plans do you have to get solid user and developer level docs for rubinius?

Wilson: In the near future, one of us will kick out a big shiny diagram of all of the moving parts of Rubinius. I like diagrams. Particularly shiny

January 18, 2007 06:57 AM

rubinius Serial Interview: Episode IV

This time around, we're talking about cooperation between JRuby and rubinius developers. It's a timely topic, since Nick Sieger is starting a Serial JRuby Interview. Good times.

Evan wasn't available this time around ... I understand he's in seclusion working on rubinius' Garbage Collection. I'd rather have him get that right than respond to these — I think you'll agree.

I've been really

January 18, 2007 06:56 AM

Serial rubinius Interview: Episode V

This week's episode hits three points; Evan's next steps with rubinius, garnet (the new name for cuby), and Software Transactional Memory (STM). MenTaLguY joins us for the third discussion, and provides a long list of resources to help get up to speed. Happy reading, and happier hacking!

Evan, after hiding out in your secret lair to hack on the newly released GC, what's next on your coding

January 18, 2007 06:55 AM

RubyForge image

RubyCAS-Client 0.11.0 Released

Lots of refactoring, major cleanup. This is probably the last beta release before 1.0.

Also, I'm hopefully going to begin work on RubyCAS-Server.

*CAS is a central authentication (single signon) system for web applications. RubyCAS-Client is a Ruby client library for this protocol.

January 18, 2007 06:34 AM

Michael Koziarski image

Links for 2007-01-17 [del.icio.us]

January 18, 2007 06:00 AM

Obie Fernandez image

Links for 2007-01-17 [del.icio.us]

  • The MacGuffin - (37signals)
    The less specific the qualities of the MacGuffin are, the more interested the audience will be…A loose abstraction allows audience members to project their own desires onto an essentially featureless goal.

January 18, 2007 06:00 AM

RubyForge image

Easy Family Portal 0.6 Alpha is released

Easy Family Portal is the easiest way to keep in touch on the web. The system includes an address book, photo gallery and family news.

Version 0.6 standardizes most of the forms for site consistency. This version also includes Lightbox for the photo album viewer. Finally, there are three new skins to choose from to give your site a new look and feel.

Check out http://efp.rubyforge.org for full details!

January 18, 2007 05:28 AM

Handoff: readable assertions for simple delegation

Handoff provides a fluent interface for making assertions about simple delegation. The goal of the project is to make specifying delegation in unit tests as easy as implementing it with Forwardable--and even more readable.

See an example at http://handoff.rubyforge.org/.

January 18, 2007 04:30 AM

Ryan Daigle image

So You Want to Learn ActiveResource...

But you can’t find much info on the subject? Stay tuned to this little teaser to learn ActiveResource in a live, real-world scenario.

image

image image image image

January 18, 2007 04:12 AM

Nick Ziegler image

JRuby Serial Interview 3

This is part 3 in our ongoing conversation tracking the development of JRuby.

Official Rails support in February? That’s not far away! What do you mean by “official”?

Thomas Enebo: Largely, we just want to spend some extra TLC on fixing up various Rails issues between now and February. Basically, get rid of the remaining known issues with running Rails from JRuby. I think beyond marshalling we are very close to saying that today. We also want to provide a better deployment picture for Rails by then. So we will need to spend some time on that as well (the community has been doing a great job spearheading this).

Software is never perfect, so we know that there will continue to be Rails issues after we say it is supported. By setting this goal, we should give ourselves some pressure to polish what we have and also get a larger number of people some incentive to kick the tires.

Ola Bini: That’s a question of interpretation. In my view, “official” is some kind of high number. 95% of all test cases in 1.1.6, maybe? But the more important part of it is that all the common use cases should work. You should be able to work through AWDwR and everything should work.

It’s ambitious, but we can do it. What’s needed soon is to decide what needs to be done with ActiveRecord-JDBC, and do that, since AR-JDBC is one of the larger points in our Rails support, and sometimes I feel that the support there is our weak link.

Charles Nutter: We could probably say we support Rails today, with a whole list of caveats. Rails runs right now, people are using JRuby on Rails today (in some cases for production apps!), and things largely will “just work”. There’s also a lot of community effort behind alternative deployment scenarios like within a WAR file or behind a fast HTTP server like Grizzly. Rails does run on JRuby today.

Our challenge before making a big official announcement about “Rails support” is to shrink that list of caveats down as small as possible. We want marshalling to work so sessions function correctly. We want AR-JDBC to be cleaned up a bit more, with more testing and even wider database support. We want any remaining core library issues resolved. We want those peripheral deployment projects to work perfectly. There’s a lot of work to get there, but it’s now simply an incremental process; Rails runs today, and will run better tomorrow.

What’s this about YARV instruction interoperability?

Readers: here’s an IRC recap for you:

[1:31pm] olabini: HAHA
[1:31pm] olabini: YEAH BABY.
[1:31pm] olabini: hehe.
[1:31pm] olabini: echo 'puts "Hello world"' > test1.rb
[1:33pm] olabini: ruby-yarv ~/src/yarv/tool/compile.rb -o test1.rbc test1.rb
[1:33pm] olabini: jruby -y test1.rbc #=> "Hello world"
[1:33pm] headius: hah, awesome
[1:33pm] nicksieger: no way!

So this is awesome that you guys are able to track so closely with YARV’s progress, but why do it? Hedge your bets?

Ola Bini: First of all, it shows the maturity of the JRuby runtime that we can implement basic parts of the YARV VM this easily. Second, it can be very interesting for us to try out parts of how 1.9/2.0 will work out within the current JRuby system. Third, we don’t have a YARV compiler yet, but being able to run files compiled with YARV ensures that we stay on track for Ruby compatibility. Fourth: Yeah, hedging your bets is always a good idea. Diversity breeds evolution. I believe where on the right track with the current AOT and JIT compiler works, but there is always a good idea to implement these things in more than one way. And of course, it ‘s just fun!

The next step for this will be to get the loading to handle more things. At the moment, it only runs extremely simple scripts. But I’m planning on handling the more complex things soon too, adding support for labels and defining YARV methods and other such things. The very next step to handle is a compiled recursive fibonacci script. The YARVMachine already has most things needed for it, but the YARV emitted by the compiler contains some tricks that needs to be fixed.

Charles Nutter: I’ve been the primary person responsible for our various interpreter rewrites over the past year or two. Originally I modified it to be mostly “stackless”, using an Instruction object for each element in the AST and pushing down an external stack of previous instructions to maintain context. That seemed like a neat idea, and it certainly did move toward a stackless design (I actually demoed a recursive fib(100_000) at RubyConf 2005), but it was rather slow and complicated enough that only I could maintain it. So in October of 2006 I did another rewrite, basically simplifying the interpreter down to a “big switch statement” that could quickly traverse the AST without a lot of objects and stack manipulation. This new C-like interpreter engine was quite a bit faster, but unfortunately the tradeoff was that we were again burning Java stack frames when we had to dig deeper into the AST, and our maximum stack depth suffered.

I’ve still always wanted the stackless design back in JRuby, and started to think about alternate routes to get there. The most obvious was having our own bytecode engine. The most readily-available set of bytecodes for Ruby…was YARV’s.

Implementing a stack machine is pretty trivial. You need an operand stack, instructions for manipulating it, and instructions that consume values from it. Over the past year, YARV’s core set of bytecodes have started to solidify to the point that I figured implementing a YARV machine in JRuby would be a good idea. So I did a very simple initial implementation that just handled local variables, method calls, while loops, and so on, to see if it would be feasible. I got it as far as running an iterative fib, and the results were very promising: it was quite a bit faster than the current interpreter.

I ended up putting that down for a while to look at Java bytecode compilation, which has been coming along very nicely. Recently, Ola decided to pick up the YARV machine work, and made it double cool by loading real compiled YARV bytecodes into it. And if that wasn’t good enough, the original partial machine I’d implemented was able to run them without modification!

We’re looking toward the future with this work. We know that YARV is now “The” Ruby VM, and that eventually people will start to run compiled Ruby bytecodes. We also know that JRuby will never be able to fully escape interpreted-mode execution. I believe both goals are answered by having a fast Ruby bytecode machine that works in concert with our Ruby-to-Java compilers. And that’s the current roadmap for JRuby’s execution model.

Thomas Enebo: Personally, I would like to see us move from walking our current tree to walking a set of instructions. I think dynamic optimizations (as well as static) will be much easier using instructions and we can also create a simpler AST/parser (the traditional AST in Ruby does quite a bit of static optimization which I think makes the grammar a little tougher to wrap your head around).

Anything YARV-related sort of hits my sweet spot since it may nudge us in this direction. JRuby will probably always mix execution between compiled and interpreted code. I think interpretation will be easier to support at an instruction level. It will also give us a good opportunity to flatten the Java stack more. YARV is a good place to start. It may be right solution for us too. Who knows? I think experimentation is the name of the game for this stuff. So I love to see it happening :)

January 18, 2007 03:59 AM

Phil Hagelberg image

hardware hacks

Norbert
is my latest project: a robot that I plan on building up and
programming.

die roboter

I've got the motor hooked up and running, "mocking out" the control
logic to a pair of switches. The plan is to get my laptop on board
and control the motors through the serial port. Apparently the
circuitry for such a task involves using a UART chip to convert the
serial signals into something usable, which is going to be a bit of
a challenge for me; I haven't worked with ICs before.

Currently Norbert is capable of backward and forward motion as well
as turning, though the limitation of using switches on the chassis
makes control somewhat impractical.

The plan is all laid out in terms of what revisions will include
what features:

  1. Simple motion (done)
  2. Turning capability through switches (done)
  3. Platform on which to mount laptop (done)
  4. Laptop controls forward motion
  5. Laptop controls turning
  6. Laptop controls forward/reverse
  7. Autonomy (laptop can be provided with a predetermined path to
    follow rather than requiring input each step of the way)
  8. Bump sensors so that it will stop rather than keep pushing into an
    unyielding object
  9. ... and more brainstorming
    on the
    wiki page
    .

(Italics indicate completed revisions.)

norbert

I drummed up a bit of code for the controller before I had really
decided on parallel vs serial. (I had an old laptop I was
considering using that had an easier-to-interface-with parallel
port, but it was lacking a battery.) Hopefully it shouldn't be too difficult
to modify it to use the
ruby-serialport
library.

class Robot

COMMAND_BITS = [:right_motor_forward, :right_motor_backward,
:left_motor_forward, :left_motor_backward]

def go_forward
write_byte aggregate_commands(:right_motor_forward, :left_motor_forward)
end

# [go_backward and other commands...]

def aggregate_commands(*commands)
commands.inject(0) do |aggregate, command|
aggregate | bit_place(COMMAND_BITS.index(command))
end
end

def bit_place(place)
(2 ** place)
end

def write_byte(byte)
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/24605
p = open('/dev/port', 'w') # open /dev/port in write mode

p.sync = true # turn buffering off, write to the
# port as soon as it is requested
p.seek(0x378, IO::SEEK_SET) # move writing cursor to the parallel

# port address
p.putc(byte) # write byte to it and activate
# whatever on your I/O board is
# attached to the D0 pin
end
end

January 18, 2007 02:34 AM

RubyForge image

Mailing list for Ruby/Informix

If you are or have the intention to be a user of Ruby/Informix you're invited to join the mailing list, either to get your questions answered, send suggestions, bugs reports or participate in discussions on Ruby/Informix development directions.

Subscribe here: http://rubyforge.org/mailman/listinfo/ruby-informix-misc

January 18, 2007 01:43 AM

January 17, 2007

Dan Webb image

5 Things, That's The Meme, That Meme Again, It's 5 Things

Argh, dammit. It’s 2.15am and I should be sleeping but instead I find myself drawn into this ‘5 Things You Might Not Know About Me’ meme thingy by Pub Standards overlord, Mr Darlow. I’ll try to make this brief and as none-boring as possible.

5 Things You Might Not Know About Me

  1. When I was about 5 I got bitten by a dog at nursery school. It gave me an infection that very nearly paralised me (or so my mum says).
  2. Back in the day I was a rapper and Drum ‘n’ Bass MC. The band I was in was successful(ish). We got on TV, made a few records and supported some big bands. Most of the members went on to be in Simian.
  3. I won a drawing competition in primary school that I didn’t even enter. It was someone else’s picture but I just took the credit (and the prize) regardless. Evil.
  4. In university a friend at the time hired some thugs to do a drive-by shooting on some gangsters. Harsh, eh? That’s not something about me is it? Oh well. I’ve no idea where that friend is now.
  5. I’ve met Ozzy Osborne, Ice-T and, erm…Lauren Laverne.

And for the bonus: I’ve never voted in any kind of election. I’ve traditionallly been pretty disallusioned with politicians but I’ve been reading loads of Noam recently and I’m getting politicked up so this might change. God knows who I’ll vote for though, they are all arseholes.

Tagging some of the JavaScript Mafia and some London Rails peeps:

  1. Dustin Diaz
  2. Justin Palmer
  3. James Adam
  4. Damien Tanner
  5. James Darling

To those I’ve tagged, I apologise. Don’t feel obliged to carry this plague on.

And finally, if you are in London on thursday, Pub Standards beckons. Partake of the Fat Man In A Box and be merry.

January 17, 2007 10:04 PM

Brian Eng / Jeff Cohen image

Copenhagen Ruby Brigade on the Rails Podcast

I just wanted to mention the latest Ruby on Rails podcast, in which Obie Fernandez is the guest interviewer in a visit to the Copenhagen Ruby Brigade. Although the sound environment is a bit distracting at the start (Obie, please don't interview people in clubs anymore), the content is great.

Many of the members of the Brigade are .NET developers that are also using Rails. At RailsConf 2006, Brian and I had the pleasure of meeting Casper Fabricious in person. At that time he mentioned something about getting a local Ruby group together, and it's great to see how it's come together. Casper is a great guy and really smart. Working on .NET during the day and Rails at night (sound familiar?), he and the other guys at the CRB are helping spread the word of Rails to the companies they work with. Unfortunately Caspar was not included in the podcast, but the other guys who were interviewed did a great job and had insightful things to say about making the transition from .NET to Rails at your workplace.

In this podcast they talk about Rails vs. .NET, and the difference it makes in their work. Oh, and these guys aren't just using Rails, they're actively giving back to the community with plugins and trying to write code that can be incorporated into core. So definitely give it a listen to get a perspective on the impact Rails is having on existing .NET shops there.

image image image

January 17, 2007 07:28 PM

RubyForge image

s33r Amazon S3 library version 0.5

This is a radically new version of the s33r S3 library. I've rewritten large chunks of it, so it's not guaranteed to work with your old code. However, most of the methods in previous versions still exist. Hopefully you'll find it more streamlined and easier to use. I've also not got round to the tests for the networking aspects of the application yet, but that's next on my todo. There is also a new usage document at http://s33r.rubyforge.org to titillate and delight.

January 17, 2007 12:01 PM

Chris Neukirchen image

a declaration of independence

when in the course of writing ⁄
it becomes necessary for writers ⁄
to dissolve the syntactical bands ⁄
which have connected them with another ⁄
and to assume ⁄
among the powers of the written word ⁄
the laws of nature ⁄
and of nature’s rule entitle them ⁄
a decent respect to the opinions of mankind ⁄
requires that they should declare ⁄
the causes which impel them to the separation

we hold these truths to be self-evident ⁄
that all words are created equal ⁄
that they are used by their writer on purpose

whenever any form of punctuation becomes destructive to these ends ⁄
and create injustice among the words ⁄
it is the right of the writers to alter ⁄
or abolish it ⁄
and to institute new punctuation ⁄
or no punctuation at all ⁄
laying its foundation on such principles ⁄
and organizing it in such form ⁄
as to them shall seem most likely to effect their purpose

prudence will dictate that punctuation long established ⁄
should not be changed for light and transient causes ⁄
and accordingly all experience has shown ⁄
that writers are more disposed to suffer ⁄
where evils are sufferable ⁄
than to right themselves by abolishing the forms of punctuation ⁄
to which they are accustomed

but when a long train of punctuation rules ⁄
evinces a design to reduce words under absolute despotism ⁄
it is their right ⁄
it is their duty ⁄
to throw off such punctuation ⁄
and provide new punctuation for their future writing

the history of punctuation is a history of repeated injuries ⁄
and usurpations ⁄
all having in direct object the establishment ⁄
of an absolute punctuation ⁄
over our words

it has refused ⁄
to give all words the same importance ⁄
it has dictated ⁄
illogical rules of capitalization ⁄
it has forbidden ⁄
to let the writer express himself however he wants it

in every stage of oppression ⁄
we have petitioned for the most humble terms ⁄
our repeated petitions ⁄
only have been answered by repeated injury

a rule of punctuation ⁄
whose character is thus marked by every act which may define a tyrant ⁄
is unfit to be used by writers

we ⁄
therefore ⁄
writers all over the world ⁄
do ⁄
in the name ⁄
and by the authority ⁄
of our writing ⁄
solemnly publish and declare ⁄
that this new way of writing is ⁄
absolved from all allegiance to punctuation ⁄
and ⁄
all connection between them ⁄
and related parts of language ⁄
is ⁄
and ought to be ⁄
totally dissolved ⁄
and that as free writers ⁄
they have full power to levy war ⁄
conclude peace ⁄
contract alliances ⁄
establish publishing ⁄
and to do all other acts and things ⁄
which free writers may of right do

and for the support of this declaration ⁄
with a firm reliance on the protection by the readership ⁄
we mutually pledge to each other ⁄
our lives ⁄
our writings ⁄
and our sacred honor

christian neukirchen

NP: The Who—Behind Blue Eyes

January 17, 2007 10:39 AM

O'Reilly Ruby image

PHP vs. Ruby on Rails. An evolutionary story of a Web Developer and his tools.

A comparison between the #5 language (ranked popularity by Tiobe on Jan/07) and the #1 framework (ranked lovability by me!).

When it comes to programming, more specifically the development of web applications, it is important to consider all the tools of the trade before using the one that is going to be used for the job.

For some background, I have been programming web applications since I was 13 years old, over 11 years ago today. I started with a simple language called HTML, which evolved into experience with JavaScript mouseovers, then PHP counters and include files, after that onto the MySQL to store the data from the forms for dynamic input, and then into CSS. In retrospect, learning CSS was likely the most difficult thus far to learn out of all of technologies as it required a significant unlearning of the firmly committed <table> tag from my memory. After CSS had been installed, I got equipped with XHTML 1.0, and started looking at more “enterprise” level languages and came across Java, .NET, and even a bit of Perl.

We need to pause here, because this was a major decision in my career. This was now 3 years along my path of web development, and I was working at a company called Tantalus. A major Java shop on Mainland Street in Yaletown that was run by the late Patrick Whelan. It was here that I got my first cup of Java knowledge, and I must say it was hard to swallow.

My brother Martin also worked at Tantalus as a Systems Administrator, managing all their amazing Sun servers and making elegance out of the hosting required for the Java and Oracle apps they were deploying for companies such as Future Shop and other major organizations. Martin continued to push Java as my saviour, saying that if I took a 2 year course at BCIT I could be starting at 45k-60k a year right out of school (which was actually true at the time). He even gave me free books, which I still have on my book shelf (collecting dust). Even more importantly, he gave me a class map of the Java tree and I was amazed. Looking over it in amazement at all the libraries, you could do everything with Java.

Here in lies the problem. Java is a swiss army knife in your web development toolkit, if you ever do decide to learn it. You can pretty much build everything from a cell phone app, to a full on desktop application. It is an amazing language, but it’s just that. Huge. I kept the poster on my wall for months, probably even close to a year if I time-stamped it.

While considering the advice provided by my brother, I decided to take a workshop taught by one of the Tantalus Java gurus and was interested. I learned some C and C++ back in high school in a Computer Science AP (advanced placement), which was a first year university course in high school, and found some very similar characteristics.

I continued along with my PHP development and self-taught education, seeing that Java was a better language at the time, but just didn’t feel my experience at the time (which now I see as really my interest itself in Java) wasn’t solidified enough to begin learning such a massive and complex language. Concepts such as Objects, inheritance, and other OOP terminology was quite foreign. So I held off learning it, and felt once I learned PHP well enough, would upgrade.

PHP was great. With the release at the time of PHP 4 and it’’s initial object functionality I started to get up to speed with many of the OOP principles. I was building some pretty amazing Content Management Systems, Digital Asset Management Systems, even Web Top Publishing Systems. My previous commitment to learn Java was fading as my experience grew with PHP was growing, seeing that I could build all the amazing things with what I had originally felt was a subordinate language.

I continued to expand my knowledge of PHP, get into the core of the internals and sparked a desire to write some core functionality. I eventually got to meet the creator of PHP (Rasmus Lerdorf) at a Vancouver conference I helped organize back in 2004.

When I started seeing the release candidates and beta code of PHP5 I was really excited. The principles of objects which I had grown to love, were being fully supported and embraced by the language I had gained enough knowledge with to realize there was few things, if any, I could actually do with it. This shelved Java way back on the list of technologies to learn at this point. One of the only things that I can see a use for Java is a drag and drop uploader residing within the browser to avoid the one file upload field plagued by today’s forms.

In any case, PHP was my tool of choice. At this point, it had an enormous amount of libraries, nearly as many as Java. Not to mention WAYYY more open source projects on sourceforge.net that Java could ever hope for. The world supported the language, and so did I.

But. There was a problem. After building these amazing systems, that did some really cool things. I found myself repeating the same lines of code over and over again. I was creating objects that had the get and set methods within objects and had the CRUD principle embraced. I began unifying my approach. Creating a save method that did both a update and create depending on the state of the object, centralizing the objects storing and access mechanisms for my all the data within the database. Evolving to standardize date, text, string, url, and all the other MySQL data field types and personal standardized column types in a base class extended by all Models. Basically, I was simplifying tasks I was doing every time I created a new Model so I didn’t have to repeat myself over and over again.

This was a great time in my development career. Realizing that I was paving a path that I would allow me to be able to create objects that could access fields I created in the database without having to implicitly specify by introspecting what was going on, and create the guts of the Model class automatically. Realizing the productivity gains alone on this were enormous I kept on it. I got quite a long way along this path, before something happened that changed the direction of career entirely.

I found this framework called Ruby on Rails. At first I was extremely frustrated. As many would who were working so hard to create something so important for several years in the background while trying to pay the bills would, and see the tool had already evolved to a very usable state by someone else, and even had a budding community behind it. This was an interesting time, and I began to look into the framework a bit more. And more. And then I decided what was the point of developing the remaining pieces of same thing in PHP when it was already pretty much 100% of what I wanted in another language? Simple choice, learn the new language and framework and save what could be hundreds of hours development.

This was the beginning of my journey learning Ruby on Rails, as well as Ruby the language which the framework was built on.

While learning the framework, I seen some major differences between PHP and the language of Ruby. Things like “for” iterators were somewhat non-existant in a 1:1 comparison.

Something like this in PHP…

<?php
$array = array('my list', 'of', 'items');
for ($index = 0; $index count($array); $index++) {
echo "$index. $array[$index]";
}

// alternatively

$array = array('my list', 'of', 'items');
foreach ($array as $index => $item) { echo "$index. $item"; }
?>

Looked like this in Ruby…

%
array = ['my list', 'of', 'items']
array.each_with_index { |item, index| p "#{index}. #{item}" }
%>

The clarity of the syntax, and the language in general was purely impressive.

I continued to ride along the Rails train, finding more and more benefits along the way, such as previously described as ActiveRecord’s ability to dynamically introspect all the fields of a table and have all the functionality needed to create, update, delete, and read any row of data automatically with one line of code.

In addition, ActiveRecord could be done with any database adapter. Whether it was PostgreSQL, MySQL, Oracle, etc. The factor of connectivity alone when in PHP required additional modules such as AdoDB or PEAR::DB. Both of which has some really crazy syntax that was quite complex to learn. You had to learn SQL, then you had to learn the implementation of SQL abstraction. With Rails, this was inherited.

Another great feature of Ruby on Rails I had discovered was the simple concept of organization. A concept known as MVC was perfect. For those that haven’t heard of the term it’s called Model-View-Controller. It was directly in line with what I had done in the past with PHP projects after adopting concepts from frameworks such as FuseBox and the multitude of others sharing the same principles.

The list of benefits for Rails got better and better, the more I learned of the framework, the happier I was realizing that I wouldn’t have to repeat myself nearly as much as when I was writing PHP apps.

So, while along this learning adventure in the world of Ruby on Rails, I started to find out more about the advanced concepts of Ruby, the underlying language of Rails. The most profound realization of mine was when I learned that there was no waterfall approach to a the Class hierarchy. With PHP and many other languages, you have a Class, and you extended a Class in a new Class to inherit and then subsequently add additional functionality. With Ruby, you have a Class defined in one file, and you can change that same Class entirely in another file by overriding methods, adding new ones. The language was showing it’s true colors as one of the most dynamic tools I had ever used.

Constantly finding myself comparing Ruby to PHP while learning the syntax of the language and underlying Objects, finding the equivalents of things like “count” ([1,2,3,4].length), or “str_replace” (”string”.gsub) in Ruby continued. I found myself in a world of Object Oriented bliss, rarely looking back at the dull, functional world of the PHP library.

It’s been close to 2 years now since I started playing with Rails back in February of 2005, and I have found little reason to go back, other than the odd open source project which is too impressive not to use and save the time it would take to rebuild it in Rails.

Actually, there is one other reason I frequently look back at PHP. The documentation. My learning curve in PHP was spring-boarded due to the elegance of the hard working PHP documentation team, and their choices made to organize the information in such a manner that was instrumental to many peoples adoption and education. So much so, that even right now I find myself remembering my appreciation setting up a local version of the PHP documentation at php.inimit.com helping support the threads of access and decreased latency of users dependent on the documentation with hosting a local mirror sponsored by my development business. It never got accepted as a Canadian mirror due to what seemed like messy political tape of the core PHP team, but that’s besides the point. I still appreciate the documentation, and will continue to host the mirror regardless.

What I find in ever increasing potency is that Ruby and Ruby on Rails needs documentation like PHP. Actually, every language ever created needs documentation like PHP. It is, at least it should be, the gold standard of documentation for anyone learning a language, and could likely be construed as the single most instrumental reason why PHP has had such a significant adoption rate within the world of development.

I became a supporter of the Ruby and Rails documentation project known as Rannotate, and on December 18th, 2005 registered the domain railsmanual.org to ensure that the community benefits from the only similar version of the gold standard of documentation that PHP has. RailsManual is a great resource, but needs some major work to raise it’s value to that of the same degree as PHP.net.

There has been quite of attention as of late on this subject. The people over at caboo.se managed to raise some ~$15,000 USD to help out on the documentation effort, but have had some trouble finding people to actually write the documentation itself.

I have given my $0.02 on the mailing list on how we can solve this, which would actually take the PHP.net documentation system to the next level. It’s really a simple process.

Here is a very basic layout of how I see it looking and functioning like.

rubydocumentor.jpg

It’s really quite simple, but to the point. No one person needs to create the documentation It’s a collaborative approach. The main area of concern for such a collaborative system is the prevention around the area of spam. Without registration, or confirmation of email validity, the site will eventually become ridden with Spam, as nearly every blog has been plagued by.

It may appear that I have digressed on my comparison of PHP vs. Ruby on Rails, but I haven’t really. The one area of Ruby and Ruby on Rails that is flawed, or at least needs major improvement, is the documentation. Everything else about Ruby language at it’s core and the framework of Rails, is amazing.

One thing I have simply glazed over at this point is the fact that Rails is a framework, and PHP is a language. And as the saying goes, you should really compare Apples with Apples, and not Apples (Programming Languages) with Oranges (Frameworks). Ruby on Rails is indeed a framework. One which extends upon the foundation programming language known as Ruby. This means that Rails provides additional functionality on top of Ruby. Including a many number of Objects enhancing capabilities within any application built on top of the Rails layer. These Rails enhancements are specifically catered to those building web applications.

Now to go back in my story, remembering when I mentioned how Java was the swiss army knife that could be used to help create everything a programmer wants, specializing in nothing. PHP in this case, is just that now except it caters to web applications. It is also a programming language that can create everything a programmer wants, but it was built first as a web development language. Where Java could do everything a programmer could want, PHP is falling victim to the same virus that creeps into anything that has been around long enough. Unintended growth in all directions. This isn’t entirely a flaw, but now enough leaves room for something better to come along that is focused on one area rather than all areas.

Ruby is the same as PHP, and even can be compared at a fundamental level to that of Java with one major difference I would like to point out. Ruby is as well focused on doing as much as a programmer wants and needs. But it does it with the elegance, simplicity, and dynamism that is lost with PHP, and next to non existent with Java.

So now that we are somewhat clear of comparisons, realizing that PHP and Ruby on Rails are fundamentally different. Seeing that we are actually comparing a language with a framework. Let’s compare a PHP framework such as PHP on Trax, a clone of Ruby on Rails written in PHP, compared to the original framework that sparked the clone wars - being Ruby on Rails.

For this, we look at an ActiveRecord example from each. Starting with a class definition in PHP on Trax written in PHP.

<?php
class Product extends ActiveRecord {
public function validate_title() {
if ($this->title == '')
return array(false, "Title can't be empty");
if ($this->find_first("title = '{$this->title}'") != false)
return array(false, "Title must be unique");
return array(true);
}
public function validate_description() {
if ($this->description == '')
return array(false, "Description can't be empty");
return array(true);
}
public function salable_items() {
return $this->find_all("date_available = now()", "date_available desc");
}
}
?>

And now in the same class in Ruby on Rails, inherently written in Ruby.

%
class Product ActiveRecord::Base
validates_presence_of :title, :message => "Title can't be empty"
validates_uniqueness_of :title, :message => "Title must be unique"
validates_presence_of :description, :message => "Description can't be blank"
def salable_items
Product.find(:all, :conditions => 'date_available = now()', :order => 'date_available desc')
end
end
%>

This is a real comparison between the two frameworks, and you can clearly see just by the lines of code alone. Ruby on Rails is less. Ruby on Rails even helps to clean up the validations to mere single lines of code having inherited functionality built within ActiveRecord::Base. And when it comes to Ruby, ignoring entirely all what is actually happening as far as functionality is concerned within the framework’s Class, you see the language really shine. The precision of each character is far from being wasted. There is next to nothing there that doesn’t need to be, allowing for even those understanding the logical order of words an intuitive grasp of what is happening within the lines of code written.

Now, when we decide to stop ignoring what is actually going on, we may ask “What are each of these blocks of code really doing?”.

Each sample creates a Object called Product that you can access throughout your application providing the programmer with:
1) Access to all rows of data in the “products” table through a single interface to create, update, read, and delete.

2) Optional validations for any data that is set to be stored in the database passes certain conditions
3) Integrated error handling
4) As well as inheriting tons, and I mean _tons_ of additional functionality provided by ActiveRecord (PHP on Trax) and ActiveRecord::Base (Ruby on Rails) respectively.

So, now that we have compared only a single slice of each each of the Apples (Languages) as well as the Oranges (Frameworks). We can see the decision really comes down to how much we enjoy the taste of simplicity at this point. Developing in either framework boils down to nearly the same thing. Saving the programmer time when it comes to creating and maintaining and displaying the data within applications.

Ruby provides to Ruby on Rails the simplicity to save more time for programmers compared to the other frameworks. Provides the ability for programmers to write less lines of code than the comparable frameworks. Requires less time for even the most novice programmer to understand what’s going on. And is quite simply more elegant to work with.

Rails has and will continue to be imitated as it has already been in nearly every language. Whether it’s PHP (PHP on Trax), Java (Sails), Perl (Catalyst), Python (Turbo Gears, Django), and even .NET (Castle) - developers from every language recognize the benefits which Ruby on Rails, as proven by their implementations in their native languages.

Yet with all these framework imitations in their respective languages, it comes down to Ruby at the foundation that makes Rails at the heat of it all, so simple, so elegant, so much the reason why it has caught fire so fast and so far across the globe that nearly every developer that is at all interested in keeping their job, has at least heard of it.

The way I see it, the only framework that is going to replace Ruby on Rails, is another one built in Ruby. It’s not the framework that makes it so simple, elegant, and tasty as a whole. It’s the language the framework is built on that makes Rails what it is today.

I would love to hear your thoughts on this, please do comment below or send me a private email from my website.

Have you converted from PHP for the greener pastures of Rails?

January 17, 2007 09:54 AM

RubyForge image

New Gem Generator:newgem 0.7.1 - deployed gems not dependent on hoe

When you create your gems with 'newgem' and share it with the starving masses, they will no longer need to install hoe to use your gem.

January 17, 2007 06:34 AM

Josh Susser image

Basic Rails association cardinality

Over the weekend I noticed that the Rails API docs didn't have any basic information on relation cardinality and how that maps to associations. It wasn't difficult to come up with some overview documentation, and a patch later, it's now part of the API docs. I'm reproducing it here because most people won't notice its appearance in the docs, and it's good to call out basic stuff like this.

Cardinality and associations

ActiveRecord associations can be used to describe relations with one-to-one, one-to-many and many-to-many cardinality. Each model uses an association to describe its role in the relation. In each case, the belongs_to association is used in the model that has the foreign key.

One-to-one

Use has_one in the base, and belongs_to in the associated model.

class Employee < ActiveRecord::Base
has_one :office
end
class Office < ActiveRecord::Base
belongs_to :employee # foreign key - employee_id
end

One-to-many

Use has_many in the base, and belongs_to in the associated model.

class Manager < ActiveRecord::Base
has_many :employees
end
class Employee < ActiveRecord::Base
belongs_to :manager # foreign key - manager_id
end

Many-to-many

There are two ways to build a many-to-many relationship.

The first way uses a has_many association with the :through option and a join model, so
there are two stages of associations.

class Assignment < ActiveRecord::Base
belongs_to :programmer # foreign key - programmer_id
belongs_to :project # foreign key - project_id
end
class Programmer < ActiveRecord::Base
has_many :assignments
has_many :projects, :through => :assignments
end
class Project < ActiveRecord::Base
has_many :assignments
has_many :programmers, :through => :assignments
end

For the second way, use has_and_belongs_to_many in both models. This requires a join table that has no corresponding model or primary key.

class Programmer < ActiveRecord::Base
has_and_belongs_to_many :projects # foreign keys in the join table
end
class Project < ActiveRecord::Base
has_and_belongs_to_many :programmers # foreign keys in the join table
end

It is not always a simple decision which way of building a many-to-many relationship is best. But if you need to work with the relationship model as its own entity, then you'll need to use has_many :through. Use has_and_belongs_to_many when working with legacy schemas or when you never work directly with the relationship itself.

January 17, 2007 06:31 AM

RubyForge image

uncertain 0.1.0 Released

uncertain version 0.1.0 has been released!

'Uncertain' adds a Numeric class that encapsulates and handles numbers with uncertainty (e.g., 1.0 +/- 0.2).

Changes:

== 0.1.0 / 2007-01-17

* Beta release
* Still needs lots of tests
* doesn't handle trig math yet

January 17, 2007 06:00 AM

Ruby Units:ruby-units 1.0.1 Released

ruby-units version 1.0.1 has been released!

This library handles unit conversions and unit math

Changes:

Change Log for Ruby-units
=========================

2007-01-17 1.0.1 * Force units are now defined correctly.

January 17, 2007 03:02 AM

January 16, 2007

Jamis Buck image

Extending render

Yesterday’s tip demonstrated how to refactor common RJS bits into their own method. Specifically, it gave an example that created a special render_error method which you can call whenever you need to render an error.

Today’s tip is about overriding the existing render method, to add support for your own custom conditions. Specifically, render_error is nice and all, but wouldn’t it be nice to make it look more like the standard Rails render method?

1
2
3
4
5
def create

...
rescue Exception => error
render :error => error

end

It’s remarkably simple, actually. To implement the above, you’d just throw something like the following in your ApplicationController:

1
2

3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
def render(*args)

if args.length == 1 && args.first.is_a?(Hash)
case args.first[:error]

when nil then super
when ActiveRecord::InvalidRecord
render(:update) do |page|

page[:js_error_bold].replace_html(args.first[:message])
page[:js_error_text].replace_html(
args.first[:error].record.errors.full_messages.join("\n"))

page[:js_error].visual_effect :blind_down, :duration => 0.2
end
else raise args.first[:error]

end
else
super
end
end

In other words, first we check to see if the first and only argument is a hash (since that’s all our new feature uses). Then, we test the value of the :error key, calling super whenever we want to delegate to Rails’ render method. We then compare the error raised to some list of errors that we want to handle specially, and do the appropriate work for each.

You could also make it so that it accepted the error directly, as the first argument (render(error)).

You can use this technique anywhere you find yourself rendering the same kind of thing in multiple places. Errors are a good example, and are (frankly) where I use this technique the most.

January 16, 2007 07:39 PM

Ryan Daigle image

Gr.egario.us Done Right

I just ran across an almost exact functional clone of my RailsDay entrant, Gr.egario.us over at Quotiki. I’d say the design is much better than what I was able to do, although they don’t yet have the ability to put quotes on your own site like gr.egario.us offers.

Is that the sound of bitterness you hear? Not at all – in fact I’d love to pull gr.egario.us down at some point so please take a look at Quotiki for your future needs. My only question is – was Quotiki written in a day?

If any of the Quotiki folks want to look at how easy it is to write in Rails, let me know and I can shoot the source over to you. The only thing more satisfying than a Java-to-Rails conversion is a .NET-to-Rails conversion.

tags: rubyonrails, rails, railsday2006, quotiki

image

image

image image image image

January 16, 2007 01:53 PM

Pat Eyler image

Button, Button, Who's Got The Button?

Wow, the nice artists over at Apress have put together a button for this month's How Rails Made Me a Better Programmer blogging contest. If you've already submitted an entry, feel free to grab the image and use it with your essay. If you haven't entered yet, what's keeping you? Time's running out. Just go read the challenge and leave a link to your entry in the comments.

I'm hoping the Apress

January 16, 2007 01:13 PM

Mauricio Fernandez image

URL rewriting with WEBrick

WEBrick isn't as fashionable as it once was, but it's still invaluable for
development and testing. I recently needed it to handle rewrite rules, and
google didn't return anything better than
Simon Strandgaard's code.

On that same thread, GOTOU Yuuzou indicated that he wanted to add proper URL rewriting support to HEAD (1.9). It's been two years, but grep -r rewrite webrick says it hasn't happened yet.

Simon's code choked on query arguments, so I extended it as follows:
class WEBrick::HTTPServer
alias :__rewrite_old_initialize :initialize
alias :__rewrite_old_service :service

def initialize(config={}, default=WEBrick::Config::HTTP)
__rewrite_old_initialize(config, default)

@rewrite_rules = []
end
def rewrite(pattern, subst)

@logger.info("rewrite rule %s -> %s." %
[pattern.inspect, subst])

@rewrite_rules << [pattern, subst]
end
def service(req, res)

olduri = URI.parse(req.path)
olduri.query = req.query_string

old = olduri.to_s
@rewrite_rules.each do |pattern, subst|

if pattern =~ old
uri = URI.parse(old.gsub(pattern, subst))

req.instance_variable_set("@path", uri.path)
req.instance_variable_set("@query_string", uri.query)

req.instance_variable_set("@query", nil) # so it gets reparsed
@logger.info("Rewrote URL %s -> %s" % [olduri.to_s, uri.to_s])

break
end
end
__rewrite_old_service(req, res)

end
end

Yes, it doesn't use define_method to redefine the instance methods while keeping the old definitions*1, but it doesn't matter since the above code is sitting in a 50LoC file and there's no danger of it being loaded twice.

Read more...
image image

January 16, 2007 11:05 AM

Robby Russell image

Every Second Counts with a Piston in your Trunk

Recently, I wrote about using RSpec and autotest (...which I think should be called autospec) together to help boost productivity while working on Rails projects. It seems that a few members of the PLANET ARGON team have picked up on using it, which I’m happy to hear about. :-)

It’s not the only thing that I’m happy about though.

I recently came across another gem. Several of my comrades in #caboose are using piston to manage external plugins for Ruby on Rails. Wait! Isn’t this what Subversion externals is meant for? Well, yes… but externals also eat away at productivity. For example, each day, we may have anywhere from 4-6 designers and developers working on one client project. When we’re in crunch mode, this could account for quite a few subversion commits throughout the day. We all know that we should run svn up on a regular basis to make sure that we’re keeping things in sync… especially when designers and developers are working really closely and fine tuning something specific in the application. Well, the one downside to this process is that each svn up not only checks our repository, but it also checks external repositories.

“But wait! Can’t you just ignore externals on an update?”

Of course, but who wants to type out --ignore-externals each time they run an update? ...or perhaps you could make an alias for this in your shell. In any event, everyone on the team is then left to be responsible for doing this… and an extra 30-60 seconds (if not longer) per svn update times x number of people on project… well… time wasted if you’re closely watching the svn updates. Also, TextMate doesn’t have an option currently (that I could find) to ignore externals, so for those who manage subversion through it… they’re waiting on externals within their primary workspace.

Another issue with svn externals is that when a repository goes down, it really starts to slow stuff down your updates. This is always fun when you go to deploy your application with Capistrano and realize that you can’t finish the update because it can’t connect it to http://svn.lazyatom.com/public/plugins/acts_as_hasselhoff/ to make sure that your application has the latest version of the best plugins available for Rails.

acts_as_hasselhoff

Then there is the whole issue of wanting to make changes to the plugin that you’re including as an external. How does that fit into the whole mix?

There is Hope!

Piston encourages you to keep your external plugins in your local repository. Don’t worry, it remembers where it retrieved the code from so that you can update from the external repository at any time.

Installing Piston

Again, this is really simple like most gems.


$ sudo gem install -y piston
Password:
...
Successfully installed piston-1.2.1

Great, that’s all that you have to do to get started with Piston. Now, let’s get on with the show.

If you don’t have any existing Subversion externals, feel free to skip this section.

Converting existing externals

Okay, so let’s say that you’re working on a Ruby on Rails project and are relying on several external repsitories. For example, a project that I’m working on… currently looks like this.


$ svn proplist --verbose vendor/plugins/
Properties on 'vendor/plugins':
svn:externals :
authorization http://svn.writertopia.com/svn/plugins/authorization
svn_tools http://svn.planetargon.org/rails/plugins/svn_tools
simply_helpful http://dev.rubyonrails.com/svn/rails/plugins/simply_helpful
exception_notification http://dev.rubyonrails.com/svn/rails/plugins/exception_notification
asset_field http://svn.planetargon.org/rails/plugins/asset_field
rspec_on_rails svn://rubyforge.org/var/svn/rspec/tags/REL_0_7_5/rspec_on_rails/vendor/plugins/rspec_on_rails
rspec_autotest http://svn.caldersphere.net/svn/main/plugins/rspec_autotest

Piston is smart enough to know how to convert these Subversion externals into Piston-friendly plugins. This can be done by passing the piston command the convert option from within your Rails application directory.

Go ahead and run the following.


$ piston convert
Importing 'http://dev.rubyonrails.org/svn/rails/tags/rel_1-2-0_RC1' to vendor/rails (-r 5619)
Exported r5619 from 'http://dev.rubyonrails.org/svn/rails/tags/rel_1-2-0_RC1' to 'vendor/rails'

Importing 'http://svn.writertopia.com/svn/plugins/authorization' to vendor/plugins/authorization (-r 83)
Exported r83 from 'http://svn.writertopia.com/svn/plugins/authorization' to 'vendor/plugins/authorization'

Importing 'http://svn.planetargon.org/rails/plugins/svn_tools' to vendor/plugins/svn_tools (-r 119)
Exported r119 from 'http://svn.planetargon.org/rails/plugins/svn_tools' to 'vendor/plugins/svn_tools'

Importing 'http://dev.rubyonrails.com/svn/rails/plugins/simply_helpful' to vendor/plugins/simply_helpful (-r 5700)
Exported r5700 from 'http://dev.rubyonrails.com/svn/rails/plugins/simply_helpful' to 'vendor/plugins/simply_helpful'

Importing 'http://dev.rubyonrails.com/svn/rails/plugins/exception_notification' to vendor/plugins/exception_notification (-r 3900)
Exported r3900 from 'http://dev.rubyonrails.com/svn/rails/plugins/exception_notification' to 'vendor/plugins/exception_notification'

Importing 'http://svn.planetargon.org/rails/plugins/asset_field' to vendor/plugins/asset_field (-r 50)
Exported r50 from 'http://svn.planetargon.org/rails/plugins/asset_field' to 'vendor/plugins/asset_field'

Importing 'svn://rubyforge.org/var/svn/rspec/tags/REL_0_7_5/rspec_on_rails/vendor/plugins/rspec_on_rails' to vendor/plugins/rspec_on_rails (-r 1330)
Exported r1330 from 'svn://rubyforge.org/var/svn/rspec/tags/REL_0_7_5/rspec_on_rails/vendor/plugins/rspec_on_rails' to 'vendor/plugins/rspec_on_rails'

Importing 'http://svn.caldersphere.net/svn/main/plugins/rspec_autotest' to vendor/plugins/rspec_autotest (-r 48)
Exported r48 from 'http://svn.caldersphere.net/svn/main/plugins/rspec_autotest' to 'vendor/plugins/rspec_autotest'

Done converting existing svn:externals to Piston

All we have to do now is checkin our changes to subversion and we’re golden.

svn ci -m "updating repository to use piston instead of those lame-o externals..."

If you find this interesting and want to learn more, be sure to check out this post on Ruby Inside for a detailed introduction to Piston.

update

the following morning I saw this come across our development team channel…

< argonbot> svn.commit( project_name, { :author => 'brian.ford', :rev => 83, :log => 'converted svn:externals to piston for product, cus I can.' }

:-)

image image image

January 16, 2007 07:15 AM

January 15, 2007

Brian Eng / Jeff Cohen image

Web Developer Makeover - It Finally Happened

What a great weekend! We got together with 20 great people to learn Rails together this past Saturday, and Brian and I had a good time. And I'm really glad to say that it seems everyone else also had a good time, too.

We're going to follow up with a more substantial post this week, but I wanted to give an immediate thank-you to Michael Leung for being willing to help us out. Everyone's PC is a little different, and troubleshooting a few problems with Ruby and/or Rails and/or MySQL on Windows would have been hard work for us without his help. Michael has given a lot to the Rails on Windows community. Although Michael isn't actively coding on RideMe anymore, he's still donating time and resources to keep it going. The inevitable question of IDEs came up during our class, and I hope everyone will take a look at RideMe (and even better, contributing to it, if you know C#). Michael is an excellent Rails developer, and it was reassuring to have him there and to keep us honest. :-)

Just a few quick observations about the class:

  • Although advertised as a class for former Microsoft developers who want to learn about Rails on Windows, several very cool-looking Macs showed up. Which we thought was great. We demonstrated Ruby and Rails on Windows Vista, Windows XP running inside Parallels on a Mac, and then on the Mac itself, to show that you can develop your Rails apps on either operating system (and we do). (Brian develops mostly on his awesome MacBookPro these days; I use an iMac at my new day-time Rails job, and I use Windows XP for Rails development when I'm at home.)

  • I was especially happy to see how many attendees had never developed a Web site by themselves before in any programming language. I hadn't either before I learned Rails. I had been a client software developer my whole career (C/C++/C#). My attempts at ASP (and later ASP.NET) just depressed me...writing my own ORM later each time was just the worst. Last year Rails opened up a new world of programming joy to me, and I'm so glad we had a chance to spread the good news of Rails to these folks.

  • Everyone who came was nice! I don't know what it is, but the Ruby community just seems to attract nice people. No heckling the entire day, and no fruit was thrown (ok, I admit, I thought about throwing selected items lunch buffet at Brian at one point, but I resisted the urge.)

  • A surprising number of people were from out of town. I remember people saying they were from Seattle, Florida, Memphis, and New York (and I bet I'm forgetting about a couple others).

Thanks again to all who came. And for those who couldn't attend this time around, we hope to see you next time.

image image image

January 15, 2007 07:58 PM

Jamis Buck image

Refactoring RJS

For today’s tip, I’m going to be cheap and just point you at someone else’s post. :) It’s a good post, though, and it fits right in with my recent posts on RJS, so I think it’s fair. Also, since I posted to The Rails Way this morning, I don’t think too much should be expected of me today, blog-wise!

So, the pointer: RJS Refactoring. Find yourself doing a lot of the same thing in your RJS code? This tip’s for you. (Thanks for writing that up, Gustav!)

January 15, 2007 03:54 PM

Nic Williams image

Five things

I’ve been offline (read: access to dialup only, which is close enough to offline) and discovered today I had 950+ RSS articles to read. Amongst them, was Coty Rosenblath’s link-blog (often includes Ruby related links) and his “Five things” article. At the end, in little font, was my name.
Thusly tagged, here are five things [...]

January 15, 2007 10:19 AM

Ezra Zygmuntowicz image

Merb 0.0.9 released

I have just released version 0.0..9 of Merb to rubyforge. Within a few hours you should be able to gem install merb and get the new version.

There have been a ton of updates since the last release. It’s now easier to get started with merb. There is an app generator as well as mrblog, a lightweight blogging engine build on merb(not finished but good for examples)

Merb is running in production on more then 12 apps that I know of. Some of these apps are handling insane amounts of file uploads every day. And a few javascript tracker style apps are running on merb now for speed.

Here is an excerpt from the changelog. I know I missed a ton of stuff because merb has grown twice as much code since the last release and is working sweet now.

* Added merb app generator $ merb -g appname
* added super snazzy error pages and stack trace. install the coderay gem to get syntax highlighting of error code pages.
* many fixes for efficeincy of overall framework.
* extensiuve refactoring since last version
* form helpers
* template caching
* production test and development environments.
* upload progress built in now. no need for mup gem.
* added helper system.
* Updated merb rails session parasite mode.
* vendored Paginator gem
* added memory sessions
* added transactional yaml store.
* before and after filters, with very powerfult filter chain halting and redirection
* refactor merb_server to be in the framework and not in bin/
* catch_content and throw_content
* updated routing tobe more precise
* added status codes module
* added Request object
* added Merb::Mailer frameowkr
* fixed up exception handling
* added basic auth mixin
* added drb service provider
* refactored merb halnder for speed
* added Enumerable#injecting
* too many more tweaks to list

You can get your own merb app started in a few steps with the new app generator:

$ sudo gem install merb
$ merb -g myapp

And you can look at mrblog to see a merb app with a decent amount of functionality to see how merb works a little bit easier then the old sample app:

mrblog svn

And the rdoc has been updated quite a bit as well:

Merb Rdoc

Stay tuned for some detailed tutorials on making a secure file upload/download server with merb and integrating it with your rails app.

January 15, 2007 01:54 AM

January 14, 2007

Stefan Kaes image

Railsbench gem updated

Today I’ve released a new gem version (0.9.1) of railsbench. It’s mainly a bug fix release for the installation problems discovered for 0.9.0.

However, there’s also a new script called generate_benchmarks, which can be used to generate and maintain the benchmark configuration file used by railsbench.

railsbench generate_benchmarks updates the benchmark configuration file with

  • a benchmark for each controller/action pair (named <controller>_<action>)
  • a benchmark for each controller combining all actions of the controller into one benchmark (named <controller>_controller)
  • a benchmark comprising all controllers (named all_controllers)

This should get you started benchmarking in no time ;-)

After generating the file, you will need to edit the benchmarks and replace routing placeholders (:id, :article_id, etc.) by actual values.

If you add new controllers/actions later in the development process, you can invoke railsbench generate_benchmarks again to add new items to the configuration file. The older entries will not be removed by this process.

Currently, generate_benchmarks only works for the 1.2 release candidate and edge Rails (but I’ll gladly accept patches to make it work with 1.1.6).

Happy benchmarking!

January 14, 2007 02:45 PM

January 13, 2007

Amy Hoy image

Drop That Design! 6 Things You Need to Know About Color

Certain color combinations can make your eyes water, others can make your eyes practically leap out of their sockets in delight. Colors can help instill confidence in a product, company, or design—or undermine it. Color can set the mood, or destroy it. Color can make you fit in, or stand out—and it depends on your situation whether or not that's a good thing.

Despite the seemingly magical power...

Check out Slash7 for more -- and let me know what you think!
image imageimage

January 13, 2007 11:32 PM

Rick Olsen image

RSS Updates for my Subversion Repositories

Chris was the latest person to ask me about RSS updates for Mephisto. I did a little looking, and I found this nifty svnlog xslt from a coding monkey. Only problem was, it creates a feed for a whole repository. However, my public one is made up of several projects and a lot of plugins. (I don’t normally advocate setting up One Repository to Rule Them All, but it requires a textdrive support ticket so they can set the permissions for anonymous read-only.) In the end, I made 3 copies of the xslt to tweak the title, and wrote a shell script for a cron job:

/usr/local/bin/svn log file:///usr/home/technoweenie/svn/projects/$1 --limit 15 -v --xml > /usr/home/technoweenie/tmp-$1.xml
/usr/local/bin/xsltproc /usr/home/technoweenie/bin/svnlog/$1.xslt /usr/home/technoweenie/tmp-$1.xml > /usr/home/technoweenie/public_html/changesets/$1.xml
rm /usr/home/technoweenie/tmp-$1.xml

Point your browsers to http://techno-weenie.net/changesets/ and see what’s available.

January 13, 2007 11:29 PM

Jamis Buck image

SQLite3/Ruby 1.2.0

After nearly 2 years, I’m happy to announce the release of a new version of sqlite3-ruby. This version is primarily a bug-fix release, so don’t expect lots of new goodies, but it does vastly improve the stability of the sqlite3 bindings for Ruby.

To install:

1
gem install sqlite3-ruby

There’s even a precompiled binary gem for you Windows users. (Boy, the world would be a lot less complicated if that OS just went away…I spent about as much time just building that Windows gem as I did applying the patches and fixing all the bugs below, but that’s a rant for another day.)

Two of the most significant things you should note:

  • The DL (pure-ruby) driver has been deprecated. I will no longer be maintaining that driver, and it will be removed altogether in a future release. Honestly, though, there is very little reason why you should be using it. It is quite buggy, mostly due to the limitations of Ruby’s DL library.
  • The SWIG dependency that bit so many users before is gone. I now bundle the generated C file, so it should build fine even if you don’t have SWIG installed.

The list of fixed bugs, more or less in order of severity:

  • Sylvain Joyeux submitted (a long time ago, to my great chagrin) a patch that fixed various problems with the different callbacks (busy_handler, set_authorize, and trace). If you were experiencing problems with sqlite3 crashing randomly, this might very well solve those for you.
  • When using type translation with results that had typeless columns, an exception would be raised. This includes queries with “count(*)”, or even the pragma queries like “table_info”. No more! Queries with typeless columns are now handled safely.
  • Prepared statements are automatically reset when you bind new variables to them. Before, the statement was not reset until it was called again, which made reusing statements problematic.
  • Some exceptions were not being caught inside a transaction, which was causing the transaction to commit, instead of roll back. This is now fixed.
  • Bignum values may now be bound in a prepared statement. Before, you’d get errors about “Bignum being too large for a long”.
  • When a database cannot be created, you’ll now get more detailed error information, such as “file could not be found”. Before, the error was just a generic “the database could not be opened”.
  • There were lots of warning messages that showed up when running ruby with the “-w” flag. Almost all of those have been fixed. (One, that I’m aware of, remains, but it is due to the SWIG bindings, and I’m not sure how to work around it.)

And, lastly, one (minor) new feature: Before this release, if you used named placeholders for bind variables, you had to refer to them with the colon character:

1
2
db.execute "select * from users where user_name = :user",

":user" => "mrmacho"

Now, you can leave the colon off, or even use a symbol:

1
2
3
4
5
6
7
db.execute "select * from users where user_name = :user",

"user" => "mrmacho"

# or

db.execute "select * from users where user_name = :user",
:user => "mrmacho"

So, there you have it. Enjoy!

January 13, 2007 10:48 PM

Rick Olsen image

Taking ARes Out For a Test Drive

Although ActiveResource was announced last June during David’s World of Resources talk at RailsConf, it has yet to see an official release. It currently lives in the rails svn trunk with the rest of Rails, but was left out in the 1.2 Pre Release. A few rails developers (myself included) have been plugging away at it little by little as we’ve been implementing little REST services. (The only public example I know of is Blinksale, which uses what looks like a compatible interface. However, they provide their own REST::Client library as a sample ruby client lib, instead of ARes). From what I gather, ARes is only being used in limited, private services, but I think it’s time to get it out in the open. My goal with this (and possibly more, making this a series of articles) is to get the word out on where we’re at with ActiveResource, and hopefully get some folks interested in helping out.

For those that don’t know, ActiveResource is a client-side XML consumer for APIs created by the latest Rails restful additions. Consider it your reward for figuring out how to wield map.resources appropriately and restructuring parts of your app around it. That’s right, follow these rules, and you’ll get most of a server API and a client library for free.

Installation

Since ActiveResource isn’t released, how do we start playing with it? Probably the easiest way (until a gem is released) is by checking out the whole rails trunk and requiring both ActiveSupport and ActiveResource:

$ svn co http://dev.rubyonrails.org/svn/rails/trunk
$ irb
> require 'activesupport/lib/active_support'
> require 'activeresource/lib/active_resource'

Note: if you don’t already have a checkout of the rails trunk somewhere, all you actually need are ActiveSupport and ActiveResource.

Building a Client API Library for Beast

If you’re still following along with us in irb, you can go ahead and create the ActiveResource classes and start using it. First, we’ll create a base class that will set up the Beast site URL, as well as the optional user/password if you want to make changes.

1
2
3
4
5
6
class BeastResource < ActiveResource::Base
# any recent trunk version of Beast will work here
self.site = 'http://beast.caboo.se'

# site.user = 'rick'
# site.password = 'secret sauce'
end

Now that we have that, we can create classes for the four main resources we’ll be dealing with: users, forums, topics, and posts. Users and forums will be straight forward. Topics and Posts, however, are nested resources. They will need a site value that matches the path prefix set by map.resources in Beast.

1
2
3
4
5
6
7
8

9
10
11
12
13
class User < BeastResource

end

class Forum < BeastResource
end

class Topic < BeastResource

self.site += '/forums/:forum_id'
end

class Post < BeastResource

self.site += '/forums/:forum_id/topics/:topic_id'
end

That’s all there is to it. Now, let’s play around.

1
2
3
4
5
6
f = Forum.find 1

# notice that since Topic has a prefix, we must pass the forum_id.
# This is so it can make the request to /forums/1/topics/1.xml
t = Topic.find 1, :forum_id => f.id
p = Post.find 1, :forum_id => f.id, :topic_id => t.id

u = User.find p.user_id

If that all worked, you should be able to experiment with Beast. If you create any posts, please do so in the Testing forum.

1
2

3
4
5
6
7
8
forums = Forum.find :all

testing = forums.detect { |f| f.name == 'Testing' }

# initialize takes two parameters in ActiveResource. One for the model parameters, and one for the prefix parameters.
topic = Topic.new({
:title => 'Testing out ARes',

:body => 'Testing 1, 2, 3!'},
{ :forum_id => testing.id })

You may notice a few odd things here. First, #initialize takes a second hash param for the prefix options. This is so it can POST to /forums/5/topics.xml. Also, if you look at the schema for a topic, there is no body attribute. Beast cheats a little bit here and creates both a topic and the first post from one request.

ActiveResource doesn’t know the schema and will basically send whatever you give it. If you’re a little mischievous, you may try making requests to change the posts-count, updated-at, and other “unchangeable” fields. Luckily, Beast protects its attributes with attr_accessible, so this won’t be an issue.

That’s about it for part one of this series. Hopefully you have a little more understanding of where we’re at with ActiveResource, and have had a chance to knock it around a bit. In future articles, I’ll talk about how to customize your Resources for custom applications, how to correctly build API support that ActiveResource can understand, and go into what work remains for ActiveResource. If you want to see how it works from the server side, check out Beast.

January 13, 2007 09:30 PM

Mauricio Fernandez image

rcodetools: TDD/BDD++, automagic assertions, 100% accurate completion, doc/code browsing...

update.png Latest release: 0.4.1

Overview

rcodetools is a collection of Ruby code manipulation tools.
It includes xmpfilter and editor-independent Ruby development helper tools,
as well as emacs and vim interfaces.

Currently, rcodetools comprises:

  • xmpfilter: automagic Test::Unit assertions/RSpec expectations and code annotations
  • rct-complete: 100% accurate method/class/constant etc. completion
  • rct-doc: document browsing and code navigator
  • rct-meth-args: precise method info (meta-prog. aware) and TAGS generation

Download

rcodetools can be installed with RubyGems:

gem install rcodetools

If you try this shortly after a release and you get an old version/a 404 error, please allow some time until the packages propagate to RubyForge's mirrors.

rcodetools is available in tarball format. rcodetools' executables will run faster when installed this way, since RubyGems add a noticeable overhead. The last tarball is rcodetools-0.4.1.tar.gz

You can also get it from http://eigenclass.org/static/rcodetools

Usage

See this page for more information on xmpfilter and how to use it to generate Test::Unit assertions and RSpec expectations automagically.

The rct-* programs can be used with any editor, but rcodetools includes emacs and vim interfaces (contributions for other editors are welcome); see README.emacs and README.vim in the sources for more information.

Read more...
image image

January 13, 2007 11:21 AM

Damien Tanner image

Returned from India

This week I managed to escape for Puna to some pleasant surprises on my return home including the iPhone announcement and a Wii. If you even get a chance, visiting India is a must. There are two tips I would give. One: night buses suck, the train is much nicer. Two: if you visit Puna, going to the Osho Meditation Resort is unmissable even if it’s only for the architecture.

Whilst there I also found the time to read The Long Tail. I’d put off buying this because of the high price tag and its deceptively small amount of content. But even if you’re well versed in the concept it’s worth reading if just to put some numbers to the theory.

Also of note: I’ll be speaking at the Skillsmatter RoR eXchange 2007 on Feb 9th. Look forward to seeing you there.

January 13, 2007 09:57 AM

Assaf Arkin image

Rounded Corners - 94

Life is random. Introducing, the iPhone Shuffle. (Brasten Sager)
Object/anything mapping. A lot of people argue that ActiveRecord is not a serious/ideal/complete ORM layer. Maybe. But ActiveRecord did manage, in a very short time, to accomplish something many before it promised, but never quite delivered: to abstract data access. ActiveRecord can talk to SalesForce, LDAP, Amazon, [...]

January 13, 2007 08:28 AM

Solid State Disk Changes The Game

CES came, CES went, and like every year, I ignored it. It might be the size of my apartment, or my checking account, but I don’t have a burning desire to own a TV that’s taller than me. Or to hook it up to a media center that can fit in my pocket. Nor am [...]

January 13, 2007 05:40 AM

January 12, 2007

Jamis Buck image

More inline RJS

In Inline RJS I talked about invoking simple RJS actions right there in your controller. Did you know you can do the same in your views, with (among other helpers) link_to_function?

1
2
3
4
5
6
7

8
# before
<%= link_to_function "Close", "$('some_div').down('form').reset(); $('some_div').hide()" %>

# after

<%= link_to_function "Close" do |page|
page[:some_div].down('form').reset

page[:some_div].hide
end %>

Furthermore, Sam Stephenson showed me a trick where you can use RJS in arbitrary helper methods to generate Javascript code. Don’t like inlining RJS as above? Then refactor it like this:

1
2
3
4
5
6
7

8
module SomeHelper
def hide_and_reset(div)
update_page do |page|

page[div].down('form').reset
page[div].hide
end
end
end

Then, in your view:

1
<%= link_to_function "Close", hide_and_reset(:some_div) %>

That update_page method is defined in PrototypeHelper, and will return the generated Javascript as a string. Beware, though: whether you use update_page or a block passed to link_to_function, making use of inline RJS has a price. It’s fine if you only need to do it a few times on a page, but stick to explicit Javascript if you’re emitting lots of bits like that.

January 12, 2007 08:03 PM

Amy Hoy image

CoderPath Screencasts

I predict that we're about to witness the birth of the Rails' community's very own "fireside chat."

Entre: CoderPath screencasts. The pitch? Instead of just the screencaster himself speaking, Miles Forrest is interviewing and chatting with others at the same time. Screencast meet interview-style podcast. It's a sweet idea. (And it doesn't hurt that they're free—an excellent addition to the...

Check out Slash7 for more -- and let me know what you think!
image imageimage

January 12, 2007 07:00 PM

Chad Fowler image

The Big Rewrite

This is the first in a series of articles, discussing why
many software rewrite projects end badly and what
to do to avoid some of the ways I've seen them go astray.

You’ve got an existing, successful software product. You’ve hit
the ceiling on extensibility and maintainability. Your project platform is
inflexible, and your application is a software house of cards that
can’t support another new feature.

You’ve seen the videos, the weblog posts and the hype, and
you’ve decided you’re going to re-implement your product in
Rails (or Java, or .NET, or Erlang, etc.).

Beware. This is a longer, harder, more failure-prone path than you expect.

Throughout my career in software development, I’ve been involved in
Big Rewrite after Big Rewrite. I suspect it’s because I have an
interest in learning eclectic computer languages, operating systems, and
development environments. Not being just-a-Java-guy or just-a-Windows-guy
has led to me becoming a serial rewriter. I’ve been on projects to
replace C, COBOL, PHP, Visual Basic, Perl, PLSQL, VBX (don’t ask!)
and all manner of architectural atrocities with the latest and greatest
technology of the day.

In many cases, these Big Rewrite projects have resulted in unhappy
customers, political battles, missed deadlines, and sometimes complete
failure to deliver. In all cases, the projects were considerably
harder than the projects’ initiators ever thought they would be.

This is not a technology problem. It’s not at all Rails-specific, but
being in the limelight these days, Rails implementations are both very
likely to happen and very risky right now.

Why So Hard?

So, why, in software rewrites, when you’re traversing exclusively
familiar territory are the results so often unpredictable and
negative?

For the next week, I’ll post specific reasons I’ve seen things
go wrong. The following is a list which will eventually be made into links:

Stay tuned.

January 12, 2007 04:43 PM

O'Reilly Ruby image

Ruby on Rails training off the beaten track

My hometown, St. Louis, is hardly one of the great meccas of the computing world. Places like San Francisco, Seattle, and New York were the first to have local training available. Yet, even here in St. Louis, if you want Ruby on Rails training you now have more than one choice (competition is good). Last year OCI unveiled local RoR training, and now Inspired Horizons is doing the same. I’d be willing to bet that this is quietly happening all over.

Help prove me right. Do you live in a place that is not considered one of the computing hot spots, yet you still have local Ruby or Ruby on Rails training available? If so, post a comment and tell us about it!

January 12, 2007 02:51 PM

Pat Eyler image

Will rubinius Be An Acceptable Lisp

Yesterday (Wednesday, January 10th, 2007), there was a short discussion on the #rubinius irc channel which prompted a few questions which I thought would be best asked and answered here. Before I get to them though, I thought I'd share some context:

olabini: pate said something about Lisp on rubinius? wanna elaborate Evan? I'm drooling at the thought...

evan: Sure, since i started the project,

January 12, 2007 10:43 AM

Dan Webb image

Scripting Essentials

Although after some persuasion I’ve become somewhat of a convert to the church of JavaScript libraries, some (in fact, for me, most) smaller scripting tasks just don’t require a library. I’m a firm believer, especially with JavaScript, that simple is best. File size / download time arguments aside, the less code you can get away with having the browser parse and execute the better off you are. Less for the browser to do. Less to go wrong. Less to try to understand. In JavaScript development, I think this need for minimalism is as important as the need to write code for re-use which is one of the major aspect in which it differs from traditional software development wisdom. There are however some bits of code I can’t do without for any scripting task.

For years I’ve found myself copying and pasting the same old stuff into my script files before I write a single line. This is a tedious task so, while writing some code for the upcoming @media 2007 site, I decided to put together a JS file of absolute essentials. A set of functions I always use for any scripting task that isn’t a one-liner. It turned out to be an interesting exercise as trying to be absolutely minimal in anything often is. What code is always useful? Here’s what I came up with (in no particular order):

  1. JavaScript 1.6’s new array methods implemented cross browser: Working with lists is 90% of JS development and these make it much better. I only use forEach, map and filter all the time though so I’ll just add them in.
  2. Array methods as generics cross browser: Because you always need to use the above methods as well as slice etc on node lists, the arguments array and other lists that don’t have them.
  3. The good old $ function: It’s a must to stave off the old RSI.
  4. A means of getting elements by class name: This one’s mega important to the unobtrusive scripters amoungst us. I’ve written a version that will try to use XPath whenever possible for extra nippy-ness.
  5. A good cross browser event handler implementation: Having something stable to work with really helps. I use Dean Edwards’. It’s also good to have the script automatically clean up all the handlers on page unload to prevent creeky old IE from leaking it’s memory.
  6. A cross browser DOMContentLoaded event: If you’re not writing script inside the body of your document you’re going to need this. onload just doesn’t cut it. Again, I use a version of the technique that Matthias Miller and Dean Edwards came up with. It’s also in Low Pro and is solid.

So, here are my JavaScript essentials posted for your reference. I’m not releasing this and I’m definitely not supporting it but some of you might find it interesting all the same. It’s worth making your own.

What are your JavaScript essentials?

January 12, 2007 10:41 AM

Josh Susser image

Don't make a new one on my account

Here's a fairly obscure but useful trick to optimize session usage in Rails. I can pretty safely bet that you haven't used it yet because it was broken until two weeks ago when, with bloody forehead, I discovered the bug that had been causing me to bang my head repeatedly on the table. Big kudos to Jeremy Kemper for assisting in the speedy fix. Anyway, where was I?

Oh yeah. Sessions.

Sessions are mostly useless. There, I said it. I'd guess that at least 95% of the time all people are using sessions for in Rails are flash messages and setting the :user_id of authenticated users. If your app doesn't authenticate users or have some other unusual need for sessions, it's a pretty painful waste of that overhead to use them only for flash messages.

Here's a fairly obscure but useful trick to optimize session usage in Rails. I can pretty safely bet that you haven't used it yet because it was broken until two weeks ago when, with bloody forehead, I discovered the bug that had been causing me to bang my head repeatedly on the table. Big kudos to Jeremy Kemper for assisting in the speedy fix. Anyway, where was I?

Oh yeah. Sessions.

Sessions are mostly useless. There, I said it. I'd guess that at least 95% of the time all people are using sessions for in Rails are flash messages and setting the :user_id of authenticated users. If your app doesn't authenticate users or have some other unusual need for sessions, it's a pretty painful waste of that overhead to use them only for flash messages.

One of the nice things about how Mephisto is designed is that only authenticated users get a session when they login to the admin console. (Yes, there are no flash messages.) That means that the kajillions of guest users who are just reading a blog don't get a session. And that removes a lot of overhead from serving up pages, especially when most of the pages are cached as static HTML (yay for Rails' page caching!). I think that was a great decision, but it became a pain when I decided I wanted to highlight comments I made in my own blog as special so readers could easily see which comments were mine.

The problem was that the main controller is configured with session :off, so no session was available to check to see if there was an authenticated user making the comment. Now, the admin controller has sessions on, so if I had already logged in on the admin console I'd have a session_id cookie in the browser, and the main controller could just notice it there and use it to get the commenter's user id to mark the comment as special. At least in theory. But you can't see an existing session with sessions turned off in your controller!

It turns out there is a lovely option on the session directive for controllers.

LazyController < ActiveController::Base
session :new_session => false
# ...
end

Using the :new_session => false option tells Rails not to create a new session if there isn't one already, but if there is, go ahead and use it. That's exactly what I needed, and it ended up working perfectly to let me hack Mephisto to mark my comments as special. (At least it did after Jeremy and I fixed the crashing bug.) If you use this option and there is no previously existing session, the session will appear as an empty hash. You can set values in that hash, but they won't stick around to the next action.

You can see the special comments in action right here in my blog - just look around. You can also use that feature in your own Mephisto blog, since Rick accepted my patch and now trunk will do that for you too. Check out the wiki page on how to do it.

And if you're not using Mephisto, you can still use the :new_session => false option to lighten the load on your web app. I think this is potentially very useful for RESTful apps. I like the idea of blending admin functions into the normal content UI. This way you can have sessionless guest users and still provide authorized admin features on public pages.

January 12, 2007 07:42 AM

Obie Fernandez image

Links for 2007-01-11 [del.icio.us]

  • Meta, shmeta: learning Ruby horizontally
    There’s no natural separation between programming and metaprogramming in Ruby, and no reason to make life harder by breaking them apart. The thrust of Ruby’s design is to dissolve complexities, so that even things that appear to be “wizardly” or f

January 12, 2007 06:00 AM

Michael Koziarski image

Links for 2007-01-11 [del.icio.us]

  • SOA Facts
    "One person successfully described SOA completely, and immediately died."

January 12, 2007 06:00 AM

Nick Ziegler image

Self-cloning JRuby and RubyGems in a Jar

As part of some work I’m doing to make JRuby more portable and easier to run standalone without all the $JRUBY_HOME launcher scripts, it’s now easier than ever to get up and running with JRuby, or to launch in your build scripts or IDE in a platform-neutral way. (Note: as of this writing, this feature is in 0.9.3 jruby-complete snapshots older than 2007/01/11 only.)

Here, give it a try:

IRB in a jar

$ curl -o jruby-complete.jar http://snapshots.repository.codehaus.org/org/jruby/jruby-complete/0.9.3-...
$ java -jar jruby-complete.jar --command irb
irb(main):001:0>

RubyGems in a jar

RubyGems needs a place to unpack and run gems, so JRuby currently will hide all that away from you in ~/.jruby. (Also, unfortunately we exceed Java’s default memory size when downloading the RubyGems index file, so you’ll have to add the -Xmx256m argument for now to avoid an out of memory condition.)

$ java -Xmx256m -jar jruby-complete.jar --command gem install tattle -y --no-rdoc --no-ri
creating /Users/nicksieger/.jruby/bin/gem
... more files extracted ...
copying /Users/nicksieger/jruby-complete.jar to /Users/nicksieger/.jruby/lib
Bulk updating Gem source index for: http://gems.rubyforge.org
Successfully installed tattle-1.0.1
Successfully installed hoe-1.1.7
Successfully installed rubyforge-0.4.0
Successfully installed rake-0.7.1

You can still have JRuby unpack to a shared directory if you like, and use the regular shell scripts for launching JRuby. In this case, JRuby is actually replicating itself into the directory you choose. Simply add the bin subdirectory to your $PATH, and continue to use JRuby just as you would a regular Ruby installation.

$ sudo java -jar jruby-complete.jar --command extract /opt/local/jruby
Password:
creating /opt/local/jruby/bin/gem
... more files extracted ...
copying /Users/nicksieger/jruby-complete.jar to /opt/local/jruby/lib
$ PATH=/opt/local/jruby/bin:$PATH
$ which gem
/opt/local/jruby/bin/gem
$ jirb
irb(main):001:0>

Tattle-tale

The --command argument is not limited to just gem and irb. Once you’ve installed any gem that has an accompanying executable script, you can simply pass that argument as the --command:

$ java -jar jruby-complete.jar --command tattle report
ruby_install_name, jruby
LIBRUBY, jruby
target, java
arch, java
host_vendor, Apple Computer, Inc.
key, b1bd5eaf4254d9874ca297995b906be6f4975d395dd0136432f859c62a33cc8c
host_os, Mac OS X
ruby_version, 1.8.5
build, java
target_cpu, i386
prefix, /Users/nicksieger/.jruby
report_time, Thu Jan 11 22:21:57 CST 2007
rubygems_version, 0.9.0
host_cpu, i386
LIBRUBY_SO, jruby
SHELL, /bin/sh
$ java -jar jruby-complete.jar --command tattle
Posting information to Tattle server. Thanks!

And lo and behold, there’s a ruby_install_name of java at the new Gem Tattle homepage!

January 12, 2007 04:27 AM

Phil Hagelberg image

must be what it feels like to get old

Time for a little honesty here. I actually had a fairly lousy month
in December--for the first time in almost two years I went through a
month where I didn't feel at the end like I was at all better at
what I do than I was at the month's beginning. Sure, I had
learned a lot
about Javascript,
but that's mostly been about extending Firefox/Conkeror and only
marginally related to What I Do.

I'm sure most of this was due to the fact that I spent most of the
month looking for work or waiting for projects to get started. I
tried to keep busy with personal projects and whatnot, but when I
finally did start on a Rails job at the beginning of this month, it
was a bit distressing how rusty I felt. Part of this was also due to
picking up both RSpec (more on this in a future post) and the new Restful style, which was a bit
disorienting. (Though Geoffrey's
excellent PeepCode
screencast helped a lot with that; give it a spin if you're having
trouble.)

I'm thinking I should take this as a bit of a warning to practice
Pragmatic-Programmer-style continual learning. It was a pretty
jarring experience, but it helped remind me that staying sharp and
active is a really important part of maintaining competence. Falling
into complacency is easy to do, especially when you really feel on
top of your game, but it gets you nowhere.

experimenting with inserting random images in my posts

On an entirely unrelated note, when I was first getting into Ruby (around RubyConf '05),
I joked about how "Ruby
is becoming Lisp"
because of some superficial changes
regarding how parameters were specified. Well it turns out some of
the
stuff they're doing with Rubinius
could make that a reality;
you should be able to feed the Rubinius straight S-expressions,
and from there it's a short leap to providing a defmacro
facility.

Which is cool.

January 12, 2007 12:49 AM

January 11, 2007

Ruby Quiz image

Word Blender (#108)

by Ben Bleything

This is a riff on the Jumble puzzle found in many (US) newspapers. More specifically, it's based on the game TextTwist[1], made by GameHouse[2] and published in various places around the web.

The mechanic of TextTwist is simple. The player is given six letters and is tasked with unscrambling those letters into as many words as possible. If the player can use all six letters in a word, they proceed to the next round.

Your task is to build the back-end engine to run a TextTwist clone. Effectively, this means that you must generate a list of three- to six-letter words that can all be constructed from the same six letters. This list must contain at least one six-letter word.

Bonus points for building a completely functional game!

[1]: http://games.yahoo.com/games/texttwist.html (just one example, java)[2]: http://www.gamehouse.com/

January 11, 2007 11:43 PM

Matt Biddulph image

Connecting First and Second Life

I've been interested for some time in the possibilities offered by bringing external data into virtual environments like Second Life. This data might come from the web, but it could also come from the real world - from physical sensors and interfaces.

Over the last couple of weeks I've enjoyed playing with the Arduino hardware prototyping board. This week's open-sourcing of the Second Life client came at exactly the right time for a new experiment.

Here's a video demonstration (people reading the feed, start your web browsers). On the left you'll see an Arduino reading analogue values from a potentiometer and feeding the results in via the USB-serial interface to my Mac. On the right, you'll see a modified version of Second Life that is feeding those values in via my avatar's chat channel. An object in the Second Life world is reacting, with perhaps a half-second lag.

How does this work? All it takes is a few small code fragments in the right places. The Arduino code is trivial:

void setup() {
Serial.begin(9600);
pinMode(0,INPUT);
}
void loop() {
delay(100);
Serial.println(analogRead(0));
}

The in-world LSL code is trivial:

vector pos;
default
{
state_entry()
{
llListen(42,"Matt Basiat",NULL_KEY,"");
pos = llGetPos();
}
listen(integer channel, string name, key id, string message) {
float val = (float)message;
llSetPos(pos + 0,0,(val/100.0)>);
}
}

The clever bit, such as it is, involves adding a bit of good old-fashioned Unix file-descriptor code to the SL client's idle loop (located in viewer.cpp in the source) that polls the Arduino. Once I've got the reading, all it takes to make my avatar speak to the server is the line:

gChatBar->sendChatFromViewer(reading, CHAT_TYPE_NORMAL, FALSE);

In total, I added about 150 lines of code to a single file to achieve this. Obviously this is just a concept demo, and there are plenty of places to take it from here, but I'm encouraged by the progress.

If you're curious about the details, here's the patch against viewer.cpp in the newview directory of the source. It's definitely not The Right Way To Do It - just the fastest route I could find into the heart of the code. It has hardcoded device names and other bad practice. I release it under the GPL, and must thank Tod Kurt for the use of his arduino-serial.c code and Massimo Banzi for everything he taught me about Arduino over the holiday season.

Permalink

January 11, 2007 10:40 PM

Jamis Buck image

Moving associated creations to the model

Have you ever done something like this in a controller?

1
2
3
4
5
6
7
8

9
10
11
12
13
14
15

# The corresponding view looks something like this:
#
# Name: <input type="text" name="person[name]" /><br />
# Email: <input type="text" name="email_address[address]" /><br />

# Phone: <input type="text" name="phone_number[number]" /><br />
#
def create
Person.transaction do

@person = current_account.people.create(params[:person])
@person.create_email_address params[:email_address]
@person.create_phone_number params[:phone_number]

end
redirect_to person_url(@person)
end

Harkening back to the Skinny Controller, Fat Model idea, I’ve lately been converting the above, into the following:

1
2
3
4
5
6
7

8
9
10
11

# The corresponding view looks something like this:
#
# Name: <input type="text" name="person[name]" /><br />

# Email: <input type="text" name="person[data][email_address][address]" /><br />
# Phone: <input type="text" name="person[data][phone_number][number]" /><br />

#
def create
@person = current_account.people.create(params[:person])
redirect_to person_url(@person)

end

This works by moving all of the creation logic to the models. Consider the Person model for the above:

1
2

3
4
5
6
7
8
9
10
11

12
13
14
15
16
17

class Person < ActiveRecord::Base

has_one :email_address
has_one :phone_number

attr_writer :data
after_create :update_data


private

def update_data
return if @data.nil?

create_email_address(@data[:email_address]) if @data[:email_address]
create_phone_number(@data[:phone_number]) if @data[:phone_number]

@data = nil
end
end

So, when the params[:person] hash gets used to create the new Person, the data subhash, if it exists, gets assigned to the data writer on the Person model. Then, after the create happens, the update_data callback is invoked, which examines that @data variable to see what needs to be done.

It keeps your controllers slim, and puts all the creation logic in one place, so if you ever want to create the email address and phone number from a different action, it’s all ready for you!

With a little more effort, this can work for updates and deletes, too, but I’ll leave that as an exercise for the reader. ;)

January 11, 2007 09:40 PM

Assaf Arkin image

Rounded Corners - 93

Tactile. What do you think? Is this just a glossy concept, or will people really be able to use it?
The Grinch who stole my brackets. James Bennett injects some humor (and wise words) into the debate: “The XML guys are sitting up on the mountaintop like the Grinch, with his pile of stolen presents, wondering [...]

January 11, 2007 05:33 PM

Amy Hoy image

How Rails Helped Me Level Up

Pat Eyler is running a Rails-related blogging challenge, in cahoots with Apress. The topic How has Ruby on Rails made you a better programmer? was proposed by Jarkko Laine.

How could I resist such a fertile topic? (Psst! The answer is: I can’t!)

Among other factoids, Pat and Jarkko are both Slash7 readers and sometimes commenters—hi, guys!

So Much Better, Baby

Really, Rails has made...

Check out Slash7 for more -- and let me know what you think!
image imageimage

January 11, 2007 05:07 PM

Pat Eyler image

Refactoring Ruby

Over in my 2007 Ruby prediction post on Linux Journal, I wrote:

Refactoring tools — This is something I think there's just too much clamor for (and too much momentum toward) not to hit in 2007. The JRuby team is making steady progress in NetBeans and Eclipse while wierd, wonderful things are being done with code rewriting on top of ParseTree and other tools. This year, we'll be able to stop

January 11, 2007 11:00 AM

Advance Directives For Hosted Projects

Well, it looks like I'm not the only one thinking about this problem. Dries Buytaert blogged about it (from a drupal perspective) a while ago. I'll be interested to see if this idea is useful to the Drupal community.

My original post also seems to be making the rounds, having shown up over on the squeak smalltalk list and on LWN (in a subscription only page, for now). I'm glad that people are

January 11, 2007 10:36 AM

Nick Ziegler image

JRuby Serial Interview 2

This is part 2 in our ongoing conversation tracking the development of JRuby.

It’s been exciting to see all the discussion between the JRuby developers and Rubinius developers, especially in #rubinius. What benefits do you see coming from this kind of cooperation?

Charles Nutter: Evan and I have been talking since this summer, actually, when he was working on early versions of Rubinius. We both have gone through many of the same growing pains dealing with Ruby’s quirkier features and evaluating interpreter/VM design options. I don’t know how Evan feels about it, but I was very glad to find someone else who was interested in such things.

Now that Rubinius is in the public eye and has some real momentum, there’s more sharing going on. We’ve been talking about those same design options, weighing them together and coming up with new choices we can both implement. Others on the Rubinius team have forwarded the idea of reusing portions of the Rubinius source in JRuby.

It’s also become apparent that we’re trying to solve very similar problems from different directions. In JRuby’s case, we already have a fully-functional Ruby interpreter, functional enough to run apps as complicated as Rails. Our challenge is to keep JRuby running well and evolve a working interpreter toward a more future proof, performant, and maintainable design. Rubinius is really just starting out, only to the point of running a small portion of the Ruby corpus, but the design is easier to follow and simpler to evolve. Their challenge is to keep the design simple while expanding compatibility and improving speed. JRuby is mostly Java with some Ruby code, though we’d like to make it more Ruby code in the future. Rubinius is obviously mostly Ruby code with some C, but they’re interested in being able to migrate it to other underlying languages. We’re both interested in a Java-based Rubinius.

I think it’s been very positive for everyone involved to have this level of cooperation, and it’s helped us all understand Ruby better.

Ola Bini: Well, the exchange with Rubinius is obviously very valuable. The more people working on implementations and sharing information, the better for all the implementations, of course. I also see Rubinius as something very intriguing, and it would be very interesting to see how much we could port to JRuby.

Thomas Enebo: I have not personally been in contact with Rubinius developers (Charles has though), but I can say more generally that many implementations will necessitate some level of cooperation. As we discover differences between implementations, we need dialogue to help understand why those differences exist. It is possible this dialogue will end up identifying poorly-identified cross-platform issues or general mis-features.

At an implementation level it will yield suggestions across the fence for how to do things differently. A thread in ruby-core a month or so ago had some exchanges on how MRI could be optimized. Charles and I chimed in about some of those ideas because we had considered and implemented some of them in JRuby. I think as time goes on, this exchange of ideas will increase.

The biggest news in Ruby land recently is probably the announcement of a fully merged YARV. What affect does this have on JRuby?

Thomas Enebo: This seems like great news for Ruby, but I am not sure it has much affect currently on JRuby. We are still focused on 1.8.x support. It is getting easier for us to change language semantics now and when 1.9/2 starts getting closer to release I feel comfortable that we can spin a Ruby 2 branch pretty quickly.

From a personal standpoint, it is great to see Ruby hit this next milestone. I think the perception of progress is pretty important and merging YARV will give Ruby 2 development a nice perceptual boost. Also this will mean many more people pounding on YARV, which will help run it through its paces better.

Ola Bini: YARV is important news. Very much so. But at the moment the effects will not be that noticeable. Right now we’re still working hard to get 1.8-compatibility complete. But, Charles have begun work on a YARVMachine that runs some basic scripts (including the famous iterative fib bench). I’ve started looking on this the last few days, and have some ideas. My first priority will probably be to implement a reader for YARV bytecode. This will make it easier to test our machine, since we can compile with YARV and then run the compiled files with JRuby. Alongside with that I am going to start tinkering on a new backend to Charles current compiler, so it will emit YARV bytecode instead. I’m not sure exactly when this is going to happen, though, but we try to stay on top of YARV.

Charles Nutter: The merging of YARV (no longer “yet another” Ruby VM but instead “the” Ruby VM) is a very big event for the Ruby world. Koichi has worked long and hard on it, and I’m very glad to see it’s now officially part of Ruby core. I had some time to talk with Koichi and Matz about implementation challenges at RubyConf 2006, and we came to agreement on a number of items, most prominently that critical= needs to go away. Again, more cross-project sharing.

We’re watching the newly-reset 2.0 design process closely, since we know it will eventually affect JRuby’s future. In the interim, however, we’re trying to solve at the 1.8 level many issues YARV is designed to solve in 1.9 and 2.0. So many of the design choices made by Koichi and Matz for 1.9 play directly into how we tackle those same decisions in JRuby.

I think in general the merging of YARV shows that Ruby is moving forward and evolving on all fronts.

January 11, 2007 04:03 AM

Ryan Daigle image

Rela.tv and Gr.egario.us Taken Down

As part of a larger consolidation effort I have taken down Rela.tv and gr.egario.us. They were mostly play apps for me and I’m moving on to other things. As my boss tells me, “you don’t want to dilute your brand…”

For the curious or nostalgic amongst you, you can get the source for both from my subversion repository:

Rela.tv source

svn co https://saucyworks.devguard.com/svn/projects/rela.tv/trunk rela.tv

gr.egario.us source

svn co https://saucyworks.devguard.com/svn/projects/gr.egario.us/trunk gr.egario.us

And if either of these domain names appeals to you, let me know. I’m willing to transfer them over to you if you have a project or cause that speaks to me (and even if you don’t have such a cause…)

tags: rails, rubyonrails, rela.tv, gr.egario.us

image

image

image image image image

January 11, 2007 03:06 AM

How to Turn Deprecation Warnings Off in Rails

I was talking with a friend of mine last week about the new Rails deprecation warnings that you’ll see when you do naughty things like access @cookies from your controller or use deprecated methods like ActiveRecord’s find_all. Sometimes it’s useful to turn off those warnings – especially when they’re coming from a part of your application you don’t control (i.e. a third-party library).

To turn off all deprecation warnings, just do the following:

ActiveSupport::Deprecation.silenced = true

Or, if you want to perform something other than spit out deprecation warnings you can re-route them however you want within a block:

ActiveSupport::Deprecation.behavior = Proc.new { |msg, stack| MyLogger.warn(msg) }

Or, if you want to be more granular, you can silence specific parts of your code that you know reference deprecated code:

def bad_action
ActiveSupport::Deprecation.silence { p "Referencing #{@cookies} is bad" }
end

Hopefully this will get you past any annoying deprecations you can’t do much about (without giving you an easy out for those that you can do something about).

image

image image image image

January 11, 2007 02:50 AM

Mauricio Fernandez image

eigenclass.org "Happy 2007!" Ruby mini-contest started

The contest started on Sat. 2007-01-06 20H UTC

News

  • 2007-01-06 20:39 UTC: the contest has been running for 40 minutes and nobody has cracked the script yet.
  • 2007-01-07 00:52 UTC: 6 people have cracked the script so far (out of >120 who downloaded it)
  • 2007-01-07 10:27 UTC: 160 participants, still only 6 people managed to decode the message. If you crack it, you can claim that your Ruby is stronger/you are more patient than 96% of the people.
  • 2007-01-07 15:51 UTC: 8/182, 4.2% completion rate
  • 2007-01-08 00:53 UTC: 9/206, at least ~120 people have had the code for over 24H now...
  • 2007-01-08 20:03 UTC: 11/266, down to 4.1% :)
  • 2007-01-09 23:50 UTC: 13/324, 4.0%
  • 2007-01-11 00:04 UTC: 14/344, 4.1%.
  • 2007-01-13 10:15 UTC: 14/456, 3.1%.

code-small.png

Task

Your mission, should you choose to accept it, is to find the secret message
hidden in that Ruby script, follow the instructions to generate the code that
will prove you've found the message, and claim your chance to win a (very)
modest prize at http://eigenclass.org/rubychallenge2007/YOURCODE .
The completion times will be recorded and Kernel#rand will also pick a few lucky winners.

Here's what people had to say about a similar puzzle I made last year:

Wow, I'm really impressed. That was a tough (and fun) puzzle. -- Kevin Ballard

Thanks Mauricio, you made my day! -- olivier

My head hurts. Took me nearly two hours -- aniero

How long will it take?

Anything from a few minutes (say 10-20 minutes if you're having a good day and
aren't easily scared off by tricky Ruby code) to several hours. Many will give
up before, though :-) I cannot really know, but I can say I've spent quite some time making this fairly tricky...

Sources

There's a different script for each supported Ruby version; get the one
corresponding to your ruby executable or you won't be able to run it at all,
let alone crack it.

Read more...
image image

January 11, 2007 12:06 AM

January 10, 2007

Jamis Buck image

Inline RJS

We all know and love RJS templates in Rails. (If you don’t, please do google them and read up—you’re missing out on some of the hottest stuff around.). I honestly believe they are the most significant advance in web development technology since the introduction of XmlHttpRequest.

Sometimes, though, it seems like a bit of overkill to have to create a new file if all you’re doing is highlighting some element, or removing one. If your action only responds to “text/javascript” requests, it’s often much simpler just to inline the RJS calls, right there in your controller:

1
2
3
4
5
6
7

class ItemsController < ApplicationController
def destroy
@item = current_account.items.find(params[:id])

@item.destroy
render(:update) { |page| page[dom_id(@item)].remove }
end
end

(Note that the dom_id helper is courtesy of the simply_helpful plugin.)

That call to render(:update) just yields the RJS page instance to the block. Then, you can do all your RJS calls in the block, instead of having to create a file for a single line of code.

When would you not want to do this? Well, if your RJS stuff is particularly complex, or does more than a handful of things, you might be better off throwing it in its own template. Also, if your action responds to more than just RJS (e.g., via the respond_to method), you should use a separate RJS template file as well.

January 10, 2007 08:28 PM

Dan Webb image

Event Wax Is The First Production UJS Application

The In-Line Help System

Screenshot showing the open help sidebar One of my favourite features in Event Wax is the help sidebar in the admin area. The interface itself is kept pretty clean but if you need help on a particular page you can just open the help which shows the relevant help page. This way we avoid filling the screen with prompts and help content that will get in the way of experienced users but still give new users plenty of help if they need it.

The help content is in fact taken from the help site which resides at eventwax.com/help but is re-purposed and pulled into the help sidebar via Ajax. This way we have a searchable, printable plain HTML version of the documentation for users to refer to if needed but are able to provide context sensitive help to users as they use the application. Of course, this is all implemented unobtrusively and still provides users with a decent experience if for some reason JavaScript isn’t behaving. Here’s how:

Firstly, we define the inline help link and a div to hold the help content:

<a href="/help/your_account/your_event/the_attendees_tab" id="hlink"><span>Help</span></a>

<!-- code omitted for clarity -->

<div id="help"></div>

Notice that the href of the link is pointing to the location of that particular help page in the regular site so as it stands now our help link will just send us through to the correct documentation. In order to pop up the content in a side bar I’ve implemented a help script that’s responsible for opening and closing the sidebar by applying a class to the help div and triggering an Ajax.Updater request to fill it with content. I’m not going to show that here but you can check it out if you like. Essentially this gives us Help.show(url), Help.hide() and Help.toggle(url) to play with.

Now we can use UJS to apply some behaviour and make our sidebar come alive:

<% apply_behaviour '#hlink:click', 'Help.toggle(this.href); return false;' %>

This catches the help links click event and instead triggers the sidebar to open and close. We call Help.toggle() to open the sidebar passing in the href of the link as the content to get to place in the help div. At this point, it’s all pretty much working but there’s one snag: there are links inside the help content and we want them to change the sidebar rather than link normally. Time for some more UJS:

<% apply_behaviour '#help a:click', 'Help.open(this.href); return false;' %>

We hijack the click events of all the links inside the help div and make them call Help.open() with their href instead of their default behaviour which causes them to open within the sidebar. Sorted.

There’s a final problem to solve. The normal help content is going to need to be inside a full HTML document with a header and footer while the help content in the sidebar doesn’t need any of that. We solve this with a bit of Rails magic. The Help controller that displays the help pages looks like this:

class HelpController < ApplicationController

# displays a page of help given the path
def page
# page finding code ommitted for clarity
respond_to do |type|
type.html { render :file => page, :layout => :help }
type.js { render :file => page, :layout => false }
end
end

end

This means that requests for help pages via Ajax get no layout and just get the html content and normal requests get the whole page, doctype, html tag and all. As you can see it would be easy to dispense these pages in lots of other formats if we need to.

So that’s that…As you can see, it’s really quite simple to get some impressive features working unobtrusively, especially with Rails and UJS. In coming posts I’ll highlight how I went about implementing some of the other features of Event Wax but in the meantime register and check out the application and plan an event while you’re at it. Get it while it’s free!

January 10, 2007 08:26 PM

Robby Russell image

Meet the Cheat

Hey! You’re a cheater!

Well, if you’re not… I’m hoping to make one out of you.

“A thing worth having is a thing worth cheating for.”—W. C. Fields

I’m a fan of the PDF cheat sheets as I like the consolidated content contained in them. However, I don’t like having to read PDFs any more than I have to. Printing them isn’t always ideal either as I really don’t like to carry around extra paper in my laptop bag. So, what are we to do?

Well, you can cheat the system! ...and I’m going to show you how!

Cheat is this really nice command-line tool that outputs a plain text cheat sheet whenever and wherever you want.

Install the Cheat

Like all the happy and good Rubygems, this is quite simple…


$ sudo gem install cheat

Done! Okay… let’s try to do some cheating. Don’t worry, your friends and family will forgive you.

Becoming a Cheat(er)

To view a cheat sheet, just run the cheat command from your favorite terminal window.

$ cheat _cheat name_

So, for example… to see the cheat sheet for RSpec, run cheat rspec.


$ cheat rspec
rspec:
INSTALL
=======
$ sudo gem install rspec

$ ./script/plugin install
svn://rubyforge.org/var/svn/rspec/tags/REL_X_Y_Z/vendor/rspec_on_rails/vendor/p
ugins/rspec
Where X_Y_Z is the version number.

$ ./script/generate rspec
create spec
create spec/spec_helper.rb
create spec/test2spec.erb
create test/test2spec_help.rb
create script/rails_spec
create script/rails_spec_runner

HOW TO USE
==========
./script/generate rspec_model User

####################################################
# truncated to save precious bandwidth
####################################################

Because this is all printing out in your shell, you can take advantage of your favorite command line tools.

Piping to grep

$ cheat rspec | grep 'equal'
@user.errors.on(:username).should_equal "is required"
target.should_equal <value>
target.should_not_equal <value>

Piping to TextMate

$ cheat rspec | mate

Find more Cheats

Head over to this list of cheats to see what is currently available.

Thanks to the Err team for putting this together!

image image image

January 10, 2007 06:37 PM

The Zen of Auto Rspec

Several months ago, I heard that people were using a program called autotest to have their tests continue to run as you made changes to your code base, which comes with ZenTest. It’s a really nice tool written by Ryan Davis and I hadn’t gotten a chance to play with it as of yet. Well, our team isn’t spending too much time in the test/ directory these days as we jumped ship near the end of last summer and found ourselves hanging out on the Isle of BDD. The locals are quite thoughtful about these sorts of things.

I just started working on a project that has been under development for several months and as I’m getting to learn the ins/outs of the system, I find myself having to rerun the specs, which can take quite a bit of time watching. Watching your specs or tests run sometimes is as productive as watching your code compile. Oddly enough, this is as close to compilation as we really get when working with Ruby on Rails… and it’s a productivity killer for me.

There Must Be a Better Way!

So, I did a quick google search and found an announcement for Rails that ran specs through ZenTest. This was exactly what I was searching for!

Some requirements

Please makes sure that you have the following gems installed in your development environment as they are dependencies to make this all work.

  • zentest
  • diff-lcs


$ sudo gem install zentest diff-lcs

note I’m going to assume that you have rspec and rspec for rails installed… if not… tsk. ;-)

Install RSpec autotest


$ script/plugin install http://svn.caldersphere.net/svn/main/plugins/rspec_autotest

If you’re using subversion, you might consider installing it as an external.


$ script/plugin install -x http://svn.caldersphere.net/svn/main/plugins/rspec_autotest

Running RSpec autotest

This is where it gets tricky. ;-)


$ rake spec:autotest

Now, you can keep a terminal window open and autotest will watch your application and detect when files change. When they change, it’ll attempt to rerun your specs (specifically those that changed). This helps save you the time of having to rerun all your specs throughout the development process and keep your spec:all sanity checks for when you’re about to commit code to your repository.

I’ll post another entry in the next few days to show you how you can use Growl with RSpec Autotest to keep you from having to look at your terminal all the time.

Until then… have fun!

image image image

January 10, 2007 05:08 PM

Eric Hodel image

Tattle Host OS

After two days and 562 tattle reports a picture of rubyists' operating system choice is emerging:

$ ruby filter_host_os.rb tattle-host_os-20070110-1053.yml
darwin8: 242
linux-gnu: 161
mswin32: 116
freebsd6: 16
solaris2: 7
darwin7: 5
cygwin: 4
openbsd4: 4
linux: 2
freebsd5: 2
darwin9: 2
openbsd3: 1

Generated from:

$ cat filter_host_os.rb
require 'yaml'

data = YAML.load ARGF.read

collapsed = Hash.new 0
data['host_os'].each do |os, count|
os =~ /^(.*?)(\.|$)/
collapsed[$1] += count
end

length = collapsed.keys.sort_by { |k| -k.length }.first.length

collapsed.sort_by { |o,c| -c }.each do |os,count|
puts "%#{length}s: %d" % [os, count]
end

January 10, 2007 04:03 PM

Chris Neukirchen image

How Rails made me a better programmer

(Consider this an entry for the contest.)

The question how Rails made me a better programmer can be answered in
a short, but incomplete and actually wrong way: It didn’t.

That is only half the truth. When Rails was released in 2004, I
already had almost three years of programming experience in Ruby.
Therefore, I don’t think I learned much from Rails in a technical way.
I knew MVC, the code didn’t particularly impress me, and, in the end, I
didn’t care a lot about web development either. At that time, at least.

The things I’ve learned (or everyone could learn) from Rails are
social lessons. Some of them were to be expected, some were very
unexpected and a few still make me question the universe everytime I
think of them.

So, what did I learn from Rails?

  1. Community matters. The best idea is useless even in the literal
    sense if nobody uses it. I did not learn that directly from Rails,
    since Ruby had (and still has) a very nice, but at that time rather
    small community. (Which is not necessarily a bad thing.)

  2. Don’t underestimate the community. I primarily noticed this
    attending RailsConf Europe. Almost everybody I talked to really
    knew his/her stuff well, and lots were really experienced in Ruby,
    too. Of course, it was a rather small and exclusive selection of
    Rails users, and they had enough time to learn Ruby until September
    2006.

  3. Don’t overestimate the community. Scaling a community is hard, and
    Rails soon got into a storm of newbies from Java and PHP camps.
    The eager and clever people of these can learn and pick up
    everything. The rest proably still lurks in #rubyonrails waiting
    for their answers. Just because something was made easy, it
    doesn’t mean it’s less complex in itself, there is less to learn or
    less to think. Rails may be easy to use, and quick to get started,
    but it’s not a silver bullet, and designing, programming and
    deploying a real life website is still demanding.

  4. Learn to sell. Before Rails, one rarely saw a screencast, but they
    are a great way to convince people of some piece of software
    quickly—there is no denying. The whole “PR” of Rails worked very
    well in the end. Everyone now knows about it. But also see 3.

  5. Opinions help you and the users. Writing a totally generic
    framework without any defaults and conventions turns out to be lots
    of effort for the users. The less opinionated the software is, the
    bigger the possible userbase becomes, at the cost of passion.
    Avoid this. Rather, enable useful (to you) defaults, and make
    going beyond them not cost flexibility, but convenience. The users
    with vastly different needs will find a different solution (cf. 7).

  6. Gauge evolution and revolution. In the end, Rails is just
    meta-programming the boring tasks of web development—there is
    nothing really revolutionary, at least compared to more
    “advanced” frameworks based on continuations and so on. However,
    this technically slight evolution had a huge effect, while a more
    revolutionary framework would have had an even harder time to get
    acknowledged and appreciated.

  7. Everything has its niche. Many thought that with Rails’ uprising
    the other Ruby web frameworks had no chance. It turned out to be
    wrong: today there are more Ruby web frameworks that ever (we still
    have a long way to go to catch up with Python, though ;-)). If you
    absolutely can’t stand Rails, of if it simply doesn’t satisfy your
    needs, just check them out. Or write your own.

  8. Mastering anything takes time. It’s rare nowadays, but it
    occasionally still happens that I discover a Ruby method/trick/dark
    corner that I haven’t heard of before, despite year long learning and
    using the language. The same is true for Rails, both for its users
    as well as its programmers. Lots of Rails programmers came to Ruby
    via Rails, and lots of them probably today bitch as much as me
    when I have to read some piece of their early code. That’s not
    a problem by itself, but one needs to recognize that even though
    doing Ruby for, say, half a year, mastery has not been reached.
    Furthermore, if you realize an often used piece of code is written
    in a newbie style, don’t hesitate to refactor.

  9. Success comes after the hype. There have been times I’ve pondered
    myself for not really liking Rails, but just like in real life,
    people quickly recognized that Rails is not paradise either. Just
    about everybody stumbled over some rough parts, got bitten by a
    nasty bug, or completely became befuzzled trying to add more magic
    to ActiveRecord. And a fair lot admit that Rails could be better
    than it is. However, people still use it. Even a big part of
    these critics uses it, and some make their money with it. Rails
    clearly survived the hype, and still looks good. This can be known
    only afterwards, though.

  10. Make programming fun. With Rails as with Ruby, one often sees the
    word “fun” in the same sentence as the word “programming”. As a
    hobbyist programmer, I pity people that need to program non-fun
    stuff, and I knew all the time that I vastly prefer fun
    programming. Guess how happy I was when I found Ruby.

NP: Bob Dylan—Visions Of Johanna

January 10, 2007 03:40 PM

Jeremy Voorhis image

Large merge, tiny automation

or, awk’s not dead

At Values of n, we branch our codebase to create a safe environment for experiments or non-trivial changes to Stikkit. After spending a week on the east coast for holidays, I had the cough pleasure of merging over a weeks’ changes into my branch to keep current.

In my first approach, I tried merging everything at once. I ended up catching a multitude of conflicts – some of which made no sense since I was missing a weeks’ worth of context in a fast-paced environment. Clearly that was not the way to go.

My second attempt: divide and conquer. Using our revision history to look up changesets, I merged a day’s worth of changes at a time. Because a small number of issues tend to prevail on any given day, this allowed me to deal wih actual conflicts as they came. Actual, meaningful conflicts as opposed to conflicts in binary files or code I haven’t touched.

For reverting and resolving files I had no interest in, I learned the smallest bit of awk.

svn st | awk '/^C/ { print "svn revert " $2 | "sh"; print "svn resolved " $2 | "sh" }'

This handy one-liner finds all conflicted files from the output of svn status, reverts them, and resolves them, allowing me to proceed. Other awk invocations resolved conflicts for a particular set of files by copying them from another directory and resolving. Familiarity with tools like lex and racc made awk a cinch to learn and more useful than I would have guessed.

Open question: what small-time automation do you rely on to support regular development?

January 10, 2007 07:30 AM

Chad Fowler image

XML and J2EE: Commodity Skills

In My Job Went to India, I talked about using supply and demand as a gauge with which to make decisions about which technologies you should invest in as a software developer:

The offshore market has injected its low-cost programmers into a relatively narrow set of technologies. Java and .NET programmers are a dime a dozen in India. India has a lot of Oracle DBAs as well. Less mainstream technologies are very much underrepresented by the offshore development shops. When choosing a technology set to focus your career on, you should understand the effects of increased supply and lower prices on your career prospects.

As a .NET programmer, you may find yourself competing with tens of thousands of more people in the job market than you would if you were, for example, a Python programmer. This would result in the average cost of a .NET programmer decreasing significantly, possibly driving demand higher (i.e., creating more .NET jobs). So, you’d be likely to find jobs available, but the jobs wouldn’t pay all that well. The supply of Python programmers might be much smaller than that of .NET programmers with a demand to match.

If the Python job market were to support noticeably higher prices per-programmer, additional people might be attracted to supply their services at this higher price range, resulting in competition that would drive the price back down.

The whole thing is a balancing act. But, one thing seems certain (for now). India caters to the already balanced IT services markets. You don’t find mainstream Indian offshoring companies jumping on unconventional technologies. They aren’t first-movers. They generally don’t take chances. They wait for technology services markets to balance, and they disrupt those markets with significantly lower per-programmer costs.

Yesterday, one of the Rails Core guys passed along an interesting link to and article called Who’s Searching for XML? by XML noteworthy, David Megginson.

David used Google Trends to compare and contrast where searches for certain technologies were coming from geographically. Have a look at a few:

Now look at these:

As David says, it’s totally unscientific. But if I were a young programmer trying to figure out where to invest my time, I might spend just a little of it on Google Trends researching who I’m likely to be competing with.

January 10, 2007 07:20 AM

Obie Fernandez image

Links for 2007-01-09 [del.icio.us]

  • MoreMoney home page
    More Money is a gem which helps you managing money amounts using just
    integer as backend to store the data.
    It's a fork of the original money gem.
    As a plus over the original project it provides support for virtually
    any currency and more fine control

January 10, 2007 06:00 AM

Why TheLuckyStiff image

Gemtacular Gone Be Bona Fide

Chad Fowler: I was thinking we could deploy this on rubygems.org and maybe open up the source for a few collaborators.

RE: Gemtacular.com. Added to hoodwink.d, if you want to comment on gems. Also related and interesting: Dr. Nic and Erik Kastner offer Gem metastuff in JSON.

January 10, 2007 02:24 AM

January 09, 2007

Assaf Arkin image

Rounded Corners - 92

Redundancy. So we know some languages (*cough*java*cough*) thrive on verbosity and have a lot of redundancy. And we know redundancy interfers with your frontal debugging cortex. But how do you measure the amount of redundancy? Compress the source code! Eric did just that. Scientific? Maybe. But definitely a cool party trick.
Type casted. If marriage was [...]

January 09, 2007 10:43 PM

Jamis Buck image

Extending ActiveRecord associations

I really, really love the feature of ActiveRecord that lets you extend arbitrary associations with additional methods. For instance, suppose you have some Project that can have multiple Tasks:

1
2

3
class Project < ActiveRecord::Base
has_many :tasks, :dependent => :delete_all

end

Now, what you want to be able to do is partition the tasks association into subcollections based on the status of the tasks. One way to do that is by using extra associations with conditions:

1

2
3
4
5
class Project < ActiveRecord::Base

has_many :tasks, :dependent => :delete_all
has_many :active_tasks, :conditions => "status = 'active'"

has_many :inactive_tasks, :conditions => "status = 'inactive'"
end

That works…but it feels messy to me, like it is cluttering the Project namespace unnecessarily. What I want to be able to say is something like “project.tasks.active” and have it return me a list of the active tasks. Like this:

1
2
3
4
5
6
7

8
9
10
11
12
13
class Project < ActiveRecord::Base

has_many :tasks, :dependent => :delete_all do
def active(reload=false)

@active = nil if reload
@active ||= find(:all, :conditions => "status = 'active'")

end

def inactive(reload=false)
@inactive = nil if reload

@inactive ||= find(:all, :conditions => "status = 'inactive'")
end
end

end

There! But…it’s a bit verbose, isn’t it? I find myself using this particular scenario quite frequently. To save myself some keystrokes, I can just define an extra method on the core Module class:

1
2
3

4
5
6
7
8
9
10
class Module

def memoized_finder(name, conditions=nil)
class_eval <<-STR
def #{name}(reload=false)

@#{name} = nil if reload
@#{name} ||= find(:all, :conditions => #{conditions.inspect})

end
STR
end
end

Armed with that extension, I can minimize the active and inactive helper methods to just:

1
2
3
4
5
6
class Project < ActiveRecord::Base
has_many :tasks, :dependent => :delete_all do

memoized_finder :active, "status = 'active'"
memoized_finder :inactive, "status = 'inactive'"
end
end

It is worth noting here (since if I don’t, someone else will) that you could also define those “active” and “inactive” methods on the Task class itself, as class methods, and then call them from tasks association (since associations delegate missing methods to the association’s class):

1
2
3
4

5
6
7
8
9
10
11
12
13

class Task < ActiveRecord::Base
def self.active

find(:all, :conditions => "status = 'active'")
end

def self.inactive

find(:all, :conditions => "status = 'inactive'")
end
end

project = Project.find(:first)
project.tasks.active
project.tasks.inactive

The reason I generally prefer to avoid that in cases like this, is because I want to be able to memoize the result. In other words, I want to be able to call “project.tasks.active” multiple times and have it only query the database on the first call.

Also, I like having the finders on the association, rather than the class, because I almost never want to search the entire database for (in this case) all active tasks. Rather, I want to find all active tasks for a specific project. If you define the methods on Task, you are kind of giving the impression that you expect to call them unscoped.

January 09, 2007 09:27 PM

Ruby on Rails image

Rails blogging contest

Pat Eyler is running a Ruby blogging contest, sponsored by Apress, and the first month’s topic is Rails Revelations: How Rails made me a better programmmer. Read the requirements at that post, and then write up your article and post a link to it in the comments here. Pat Eyler, Apress editor Jason Gilmore, and Jarkko Laine will judge the entries, picking a winner in February. Go to it!

January 09, 2007 08:07 PM

Chad Fowler image

Advanced Rails Studio

Early in my career, I worked as a computer support person in the IT department of a state university. There was a batch of us that came in at the same time. We all started at the help desk, worked our way into doing service calls around campus, and eventually graduated to back-room system administration or programming.

After you graduated into the back room, the next step was to get a real job. I mean, the university job was fun, but the pay wasn’t so great. Especially if you started as a help desk person. Minimum wage is a bad starting point to get increments from as a computer professional. So, for that reason, back in the back room it was pretty common to hear colleagues on phone interviews.

A close friend of mine had a particularly funny interview that a few of us heard his end of. It went something like this:

“I haven’t used Windows NT Advanced Server, because there’s no such thing. I’ve done advanced things with NT Server.” He said it snottily. Still sore from sitting at the help desk helping users with their “FTP” problems, he found it difficult to hide his distaste for ignorance. The problem is, there actually was such a thing as Windows NT Advanced Server. He just hadn’t heard of it. Before he finished the interview, another friend went into his cubicle, retrieved a copy of Windows NT Advanced Server, and place it on his desk.

This brings us to the point of this post. Yesterday, registration for Pragmatic Studio’s March Advanced Rails Studio in Chicago has opened. So far this year, we’ve only got one of these on the schedule, and they tend to sell out fast. Mike, Dave, and I are proud of what we’ve put together for this class. We did the first one back in the fall and got great reviews from the attendees. It was a joy to teach and (we think) a joy to attend.

Just to be clear, being pretty close to what’s happening in the Rails world, I can confidently tell you that there’s no such product or piece of software as “Advanced Rails”. But we’ve done advanced things with Rails, and we’re going to show you how. :)

January 09, 2007 07:11 PM

Don't Follow the Lemmings

Back in November, I did a presentation for the XP West Michigan at the Atomic Object office in Grand Rapids. They’ve recently posted the talk to Google Video.

The talk was titled “Don’t Follow the Lemmings” and is a continuation of the thoughts laid out in my book, My Job Went to India.

It being on Google Video, you can watch it online (embedded here, in fact) or download it to your computer or iPod for off-line viewing (a discovery I’ve recently made which makes plane trips much more enjoyable).

Watching on an iPod should be fine, because there are no slides to squint at.

<embed salign="TL" bgcolor="#ffffff" scale="noScale" src="http://video.google.com/googleplayer.swf?docId=-8984753198261505541&hl=en" type="application/x-shockwave-flash" id="VideoPlayback" flashvars="playerMode=embedded" quality="best" align="middle" style="width:400px; height:326px;"> </embed>

January 09, 2007 06:19 PM

Robby Russell image

Apple listens to Robby and releases an iPhone

Well, they must be listening to me.

A few months ago, I posted that I was looking to switch mobile services. Well, I switched over to Cingular after a lot of back and forth and have been fairly happy with their service. I opted to get their lowend/entry phone as I wanted to get a nicer phone when I found something that met my requirements.

I wanted…

  • wifi
  • bluetooth
  • ssh client
  • lightweight web browsing
  • scheduling that sync’d well with ical

Well, I hadn’t found anything that really caught my attention. So, I heard rumors about Apple releasing a phone in January. So… I waited.

“Yay Apple! I think I’m in the right office, we’re all sitting here reading the keynote updates.”—Audrey

So, how much is this going to cost us? ..a few of us here came up with our predictions.

Thank you, Apple!

...well… I would have given Apple a hug if I didn’t have to wait til June.

...back to work.

image image image

January 09, 2007 06:13 PM

Brian Eng / Jeff Cohen image

Discovering Capistrano

Although I hate to admit it, yes, I've been developing web applications with Rails for almost two years and I've just started using Capistrano for application deployment. Why has it taken so long?

I suspect that if you're like me (i.e. a Windows guy) you've found this whole new world of Linux, Apache, lighttpd, mongrel, etc, etc. daunting. So at first glance, Capistrano can certainly be a bit intimidating. When I read the list of assumptions Capistrano makes about your Rails app for the first time last year, I was really only able to see one bullet point:

  • You know what the heck you're doing, Brian.

Fast forward to the present day. I'm feeling more comfortable with the Linux command line. I have a solid understanding of Subversion and mongrel and even Apache. So why not give Capistrano another go?

In short, it's very powerful. And surprisingly, for most things you might want to do, it's actually quite simple. Sure beats the pants off of SSH'ing to your production server and managing it by hand all the time. If you've been meaning to give it a try, go for it - I promise, it's worth it.

Highly recommended is the Peepcode Screencast on Capistrano Concepts. Although released about two month too late for me (arggh!), it is simply the best way to get yourself up-to-speed.
(Disclosure: Peepcode is a paid sponsor of this blog.)

image image image

January 09, 2007 04:57 PM

Zenspider image

FreeImage on OSX

If you develop on OSX and want to try out image_science, things just got even easier:

% sudo port selfupdate
% sudo port install freeimage
% sudo gem install image_science

I welcome any and all help on the linux side to get freeimage packaged up in their various packaging systems. It'll make it easier to get freeimage accepted on various ISPs/ASPs.

FreeBSD already has a port. It is a bit old but I think it should actually be compatible.

January 09, 2007 09:22 AM

Ryan Daigle image

What's New in Edge Rails: Get Your RSS & Atom Feeds for Free

Rails is all about some open-ness and interopability and it has become incrementally easier to achieve this with the new Resource Feeder plugin. This plugin gives you an easy way to create RSS and Atom feeds in your controllers from a collection of model objects with the use of the rss_feed_for and atom_feed_for methods:


class PostsController < ActionController

# Build an rss feed
def rss
render_rss_feed_for Post.find(:all, :order => 'created_at DESC',
:limit => 10)
end

# Build an atom feed
def atom
render_atom_feed_for Post.find(:all, :order => 'created_at DESC',
:limit => 10)
end

end

So how do these feed methods know how to pull information from each individual resource of the collection? It uses a combination of options passed into the feed methods and specific properties of the resource. If you don’t pass any options into these feed methods your model objects should have title, description and created_at reader methods (and updated_at for atom).

Options

There are several options you can pass into these nice little feed methods to customize the title of the feed and most of the other feed elements. Here’s my attempt at enumerating all of them for RSS:

Feed options (w/ defaults):

  • options:feed ; Pluralization of the model class, i.e. “Posts”
  • options:feed ; Url to this record
  • options:feed ; omitted if not specified
  • options:feed ; “en-us”
  • options:feed ; 40

Individual item options (w/ defaults). These are the method symbols used to retrieve the proper values from each individual object:

  • options:item ; :title
  • options:item ; :description
  • options:item ; :created_at

General options:

  • options[:url_writer] ; an instance of UrlWriter for your app (I think? Help me out here!)

Just pass in these options to your feed methods as needed:


class PostsController < ActionController

# Build an rss feed
def rss
render_rss_feed_for(Post.find(:all, :order => 'created_at DESC',
:limit => 10),
{ :feed => {:title => "All posts"},
:item => {:title => :name,
:pub_date => :updated_at} })
end

end

Feelin’ sassy? Try taking advantage of this guy :


class PostsController < ActionController

# View a collection of posts. If "format" is specified
# will return view of that type (of either rss or atom format)
# /posts/list?format=rss => RSS
# /posts/list?format=atom => Atom

def list
@posts = Post.find(:all, :order => 'created_at DESC',
:limit => 10)
options = { :feed => {:title => "All posts"},
:item => {:title => :name,
:pub_date => :updated_at} }

respond_to do |wants|
wants.html
wants.rss { render_rss_feed_for @posts, options }
wants.atom { render_atom_feed_for @posts, options }
end
end
end

It just feels so right sometimes!

oh yeah, and to install this pup just do:

script/plugin install resource_feeder

tags: rubyonrails, rails, rss, atom

image

image image image image

January 09, 2007 02:30 AM

What's New in Edge Rails: Around Filters are Here

For the second time I’ve had my virtual hand slapped for trumpeting a poor usage of with_scope . For the record, I want to make it clear that one should be using the rich domain model that active record provides to operate on associated objects: user.assets.find() and user.asset.create() instead of scoping to a user as my and Roman’s examples implied. Just a case of not thinking hard enough to come up with an appropriate example. Sorry David, won’t happen again!

I’ve mentioned the Meantime filter plugin by Roman Le Negrate in the past as a very useful little utility – apparently the core team agrees as around filtering is now part of edge Rails.

Usage is pretty much the same as with meantime:


class AssetController < ActionController

before_filter :verify_login
around_filter :benchmark

def assets
@assets = Asset.find(:all)
end

def benchmark
benchmark("Asset benchmark") { yield }
end

end

You can also define a class to handle your filtering needs (whose filter method yields to the action block)


class AssetController < ActionController

around_filter BenchmarkFilter # or BenchmarkFilter.new
...

class BenchmarkFilter
def filter
benchmark("Benchmarking...") { yield }
end
end

end

Or you can directly pass a Proc in as the filter:

class AssetController < ActionController

around_filter (:only => :assets) do |controller,action_block|
controller.benchmark("Benchmarking...") { action_block.call }
end
...
end

Since the around filter explicitly governs the execution of the action being requested, you can use them to skip the action completely. This would act the same as a before_filter that returned false.

tags: rubyonrails, rails

image

image image image image

January 09, 2007 02:23 AM

What's New in Edge Rails: Prettier Error Pages!

This may not seem like a biggie, but we all know you haven’t gotten around to prettying up your error pages yet..

The new, pretty, 404 error page

and

The new, pretty, 500 error page

It’s the little things sometimes…

tags: rubyonrails, rails

image

image image image image

January 09, 2007 02:23 AM

What's New in Edge Rails: I Smell Version 1.2...

It’s gotta be right around the corner, right?

image

image

image image image image

January 09, 2007 02:23 AM

What's New in Edge Rails: ActiveResource Pulled from v1.2, World Weeps

The REST client framework, ActiveResource, has been pulled from the up and coming Rails v1.2 release.

I’ve been using it to develop some REST client libraries and there are some refinements I can see being needed, but I don’t know if that’s the reasoning for its exclusion in the up-coming release. As a quick refresher – ActiveResource is the client framework that lets you invoke REST services from model objects. Think of it as ActiveRecord for REST.

However, get your REST panties out of their collective knot – you can still develop completely RESTful apps using the Simply RESTful server side functionality and the link helpers for enhancing the web tier with REST compliant requests.

Thanks to Tom of GiftHat for beating my feedreader to the punch on this one.

tags: rails, rubyonrails, REST

image

image image image image

January 09, 2007 02:23 AM

What's New in Edge Rails: New Http Authentication Plugin - And a Plea to Contribute

If you’re just not happy with some of the existing options out there for doing Http Authentication in Rails, we’ve got another entry into the market. There’s now an official Rails http authentication plugin in the Rails repo that makes this a simple proposition.

A few convenient methods are now available to you in your controllers to hold your hand: authenticate_or_request_with_http_basic that hands the basic username and password to a block for evaluation and request_http_basic_authentication that asks the client to authenticate itself using http basic authentication. Using them is pretty simple – their inclusion in an authentication filter seems to be the most intuitive use:


class DocumentsController < ActionController
before_filter :verify_access

def show
@document = @user.documents.find(params[:id])
end

# Use basic authentication in my realm to get a user object.
# Since this is a security filter - return false if the user is not
# authenticated.
def verify_access
authenticate_or_request_with_http_basic("Documents Realm") do |username, password|
@user = User.authenticate(username, password)
end
end
end

When the block of authenticate_or_request_with_http_basic evaluates to false, request_http_basic_authentication is invoked which requests that the user enter their credentials. You can also manually invoke request_http_basic_authentication if you are doing a mix of authentication methods and want to use http authentication only if session authentication fails etc…

So what’s with the “plea”? Well, digest authentication hasn’t been added to the plugin yet – though the structure and framework as all but been laid at your feet to contribute the digest logic yourself. Take a look at HttpAuthentication::Digest and see how easy it would be to contribute back to your favorite framework. Just fill in those tiny places that say stuff like # Fancy nouncing goes here and # You compute me and the world will revere you.

References

tags: rails, rubyonrails, http authentication

image

image image image image

January 09, 2007 02:21 AM

January 08, 2007

Eric Hodel image

Tattle: The Ruby Census

The most-requested feature for RubyGems is the addition of a platform preference for automating installs and ignoring gems for the platforms you aren’t on. In order to help get there, Jim, Chad and Bruce have put together tattle:

At the first Rails Edge conference, Jim
Weirich
, Bruce Williams, and I were chatting about how to improve the

RubyGems platform-specific behavior, when we realized that it would be really helpful to have more info about the install footprint of the Ruby community at large.

So instead of going right into hacking RubyGems as was our plan, we
created a little census tool and an accompanying web site to help us
collect information. Most of the info we collect is from
Config::CONFIG, with the addition of the RubyGems version.

We know this information will help the implementers of RubyGems, and
we hope it will also help Ruby implementers and library developers as
well.

To install:

$ sudo gem install tattle

To submit your info:

$ tattle

If you want to see what would be posted before posting, you can do:

$ tattle report

The information gets posted to http://tattle.rubygarden.org. You can
view the posted data with your web browser at that URL.

Tattle: The Ruby Census via ChadFowler.com

January 08, 2007 09:23 PM

Chad Fowler image

Tattle: The Ruby Census

At the first Rails Edge conference, Jim
Weirich
, Bruce Williams, and I were chatting about how to improve the
RubyGems platform-specific behavior, when we realized that it would be
really helpful to have more info about the install footprint of the
Ruby community at large.

So instead of going right into hacking RubyGems as was our plan, we
created a little census tool and an accompanying web site to help us
collect information. Most of the info we collect is from
Config::CONFIG, with the addition of the RubyGems version.

We know this information will help the implementers of RubyGems, and
we hope it will also help Ruby implementers and library developers as
well.

To install:

$ sudo gem install tattle

To submit your info:

$ tattle

If you want to see what would be posted before posting, you can do:

$ tattle report

The information gets posted to http://tattle.rubygarden.org. You can
view the posted data with your web browser at that URL.

As a side note, Eric posted the latest RubyGems beta this weekend. Please do give it a go if you’re so inclined.

January 08, 2007 09:07 PM

Jamis Buck image

Watching ActiveRecord Do Its Thing

ActiveRecord is cool and all, and it goes without saying that we all trust its judgment, but sometimes you just want to watch while it does its thing. For instance, just today, I wanted to verify that, in edge Rails, ActiveRecord no longer loads the entire collection when doing a scoped “create”.

In other words, consider the following snippet:

1
2
3
4
5
6
class Account < ActiveRecord::Base
has_many :people
end

account = Account.find(:first)
person = account.people.create :name => "Jamis Buck"

Before Rails 1.2, that last line would actually load all of the people in that collection, before creating the new person. This was problematic if the collection had thousands of rows, because a simple insert suddenly became a monstrous resource sink.

So, how to verify that the collection is no longer being loaded?

Did you know you can install your own logger instances in Rails? Yah, you can. And yah, it’s pretty cool:

1
2

3
4
5
6
7
8
9
10
11

12
13
$ script/console
>> ActiveRecord::Base.logger = Logger.new(STDOUT)
=> #<Logger:0x2814134 ...>
>> account = Account.find(:first)

Account Load (0.000346) SELECT * FROM accounts LIMIT 1
=> #<Account:0x2665478 ...>
>> account.people.create :name => "Jamis Buck"
Account Columns (0.000271) SHOW FIELDS FROM accounts
Person Columns (0.000246) SHOW FIELDS FROM people

SQL (0.000093) BEGIN
SQL (0.000351) INSERT INTO people (`account_id`, `name`) VALUES (1, 'Jamis Buck')
SQL (0.253635) COMMIT
=> #<Person:0x27cb628 ...>

There you have it. Each call to ActiveRecord now logs all of its activity to STDOUT (e.g., the console), via your custom logger instance. The tale it tells is revealing, and reassuring: scoped creates do not, in fact, load the entire collection anymore.

Yay!

(One caveat: be sure to set up your logger first, before doing anything else, otherwise the default logger will get cached with no simple way to uncache it.)

January 08, 2007 08:02 PM

Chad Fowler image

Dabble Plugin API

I recently had the privilege of writing a tutorial for Dabble DB’s new plugin API. If you haven’t heard of Dabble DB yet, it’s one of the few really innovative applications you’ll find with the “web 2.0” label. For a quick look at what it’s all about, check out the popular 7 minute demo movie that Avi made.

Even if you’re not planning to use Dabble DB, I think it’s worth reading the tutorial to see how they’ve implemented plugins. It may have been done before, but I haven’t seen it done like this. When you host an application on the open internet, how do you allow users to safely “plug” their own code into your application? You could go to a lot of trouble and create a sandboxed interpreted environment inside your application, exposing an API. But that’s really really hard to do.

What Smallthought did might be more aptly called “plugouts”. Instead of just exposing services that you can consume into your own mashup, they allow Dabble DB to call out to custom, internet-accessible services. And, rather than clutter things up with an ugly XML API, they deal in simple CSV in and out, kind of like UNIX pipes.

It’ll be interesting to see what happens with this both in Dabble DB and other applications that start to adopt this approach. Immediately after the plugin API’s release, there are already a couple of publicly available plugins (from an apparent Rubyist. Hi Tim!)

What other interesting approaches have you seen to accomplish this same goal?

January 08, 2007 06:25 PM

Stefan Saasen image

Debugging Ruby -RubyOSA continued

The day before yesterday i wrote a short post about RubyOSA. RubyOSA is a Ruby/AppleEvent Bridge which in the end means that you can use Ruby to script Mac OS X applications like iTunes, iChat, Address Book and many more.

As a small introductory example i wrote (read: quick, dirty hack) a small script to print all contacts in a Mac OS X Address Book.

Running this script with Ruby 1.8.4 worked just fine. Running it with Ruby 1.8.5 resulted in a (eval):2: [BUG] Segmentation fault
ruby 1.8.5 (2006-12-25) [i686-darwin8.8.1]
. Without further investigation i just wrote RubyOsa seems to work better with Ruby 1.8.4 than with Ruby 1.8.5.. What i should have done is what i like to explain in this post.

Laurent Sansonetti the maintainer and main developer of RubyOSA left a comment and asked about the problems with Ruby 1.8.5.
The sensible thing to do in the first place would have been to investigate if Ruby 1.8.5 really caused the aforementionend segmentation fault and if that was the case - to file a bug report with as much information as needed.

Laurent asked me if Ruby had been build as a shared library. A quick and easy way to determine this is to check rbconfig.rb.

When building Ruby rbconfig.rb is being created with all relevant informations about the specific build. The following script prints all configuration options and shows if Ruby was built as a shared lib (mine actually was).

require 'rbconfig'

# Print all available configuration options
Config::CONFIG.each do |k,v|
puts "#{k}: #{v}"
end

# Ruby built as shared library?
puts Config::CONFIG['ENABLE_SHARED']

To debug the Ruby interpreter or any low level library (like in this case) gdb the GNU Project debugger yields valuable informations.

GDB just recently gained a new momentum in the Rails community after Jamis Buck and Mauricio Fernandez described how to easily attach the gnu debugger to a running ruby process.

To debug a short running ruby script (without attaching the debugger to a process id) the following steps are neccessary:

Start gdb with the ruby interpreter as the first argument. You will get an interacive gdb session with a gdb prompt. There are more than 130 GDB commands but few will be sufficent to get the information that is needed.

macbook-sts:~/Desktop stefan$ gdb `which ruby`
GNU gdb 6.3.50-20050815 (Apple version gdb-573) (Fri Oct 20 15:50:43 GMT 2006)
[... output stripped...]
This GDB was configured as "i386-apple-darwin"...Reading symbols for shared libraries .... done

Run the script that causes the bug. In this case it is rubyosa_ad.rb.

(gdb) run rubyosa_ad.rb
Starting program: /usr/local/bin/ruby rubyosa_ad.rb
Reading symbols for shared libraries .+... done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries ... done
Reading symbols for shared libraries . done
Reading symbols for shared libraries ............................................................... done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
[... output stripped...]

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x6552534e
0x9000c5f8 in __vfprintf ()

The output now shows what is really happening: Program received signal EXC_BAD_ACCESS, Could not access memory.. To get even more information type backtrace (or bt) to get a backtrace.

(gdb) bt
#0 0x9000c5f8 in __vfprintf ()
#1 0x90022818 in snprintf ()
#2 0x000b4562 in rbosa_app_send_event (self=6878720, event_class=6826060, event_id=6826040, params=6826020, need_retval=2) at src/rbosa.c:231
#3 0x00217f54 in call_cfunc (func=0, recv=980578162, len=-1, argc=0, argv=0x0) at eval.c:5672

GDB allows you to set breakpoints, step interactively through program execution and as shown in this really short example: Examine what has happened, when your program has stopped. This is what makes a bug report valuable and what really helps the developer who has to or wants to fix the bug you are reporting.

Laurent already fixed the bug in the RubyOSA trunk and even improved the address book example. The improved version is now in the RubyOSA sample directory which contains some interesting usage examples. Go and check them out!

For more information about GDB check out the GDB manual.

Have a look at RubyOSA or RubyCocoa - a Ruby/Objective-C Bridge for Mac OS X Cocoa. Great and interesting librarys for Ruby development on Mac OS X.

image image image

January 08, 2007 06:20 PM

Ruby on Rails image

Hackfest 2007 and CD Baby sprint

Ah, Portland. The open-source motherland. Pacific springtime beauty. RailsConf ‘07 nirvana.rb # => true and home of CD Baby, a little record store that digs Ruby and Rails.

We’re gearing up for a RailsConf hackfest at the Jupiter hotel just down the street and figured, heck, let’s start now! The top twenty Rails contributors between the new year and conference registration opening day will have a free conf pass and a room at the Jupiter specially reserved, CD Baby’s treat.

No kidding. Registration opens in a matter of weeks. Sprint!

Rails contribution is measured by real Trac activity weighted in favor of well-tested, committed patches but also accounts for new tickets and even comments. We’re joining forces with Working With Rails to track Rails contributions from the new year onward. To be included, mark yourself as a core contributor and give your Trac username in your account profile.

Have a Rails itch you’ve longed to scratch? Now’s the time! Happy hacking, and see you at RailsConf.

Update: Derek @ CD Baby’s announcement with more details.

January 08, 2007 04:44 PM

O'Reilly Ruby image

CD Baby awards free RailsConf registrations+hotel to top 20 contributors to Rails

You’ve probably heard that RailsConf 2007 will be May 17-20 in Portland, Oregon.

Since my company CD Baby depends on Rails, and since we’re based in Portland, I decided to spend some company money to reward the people that MAKE Rails. Not just the ones who invented it, but the people who are actively improving it by contributing patches to Rails code.

* - We bought 20 full RailsConf registrations from O’Reilly. ($800 value)

* - We pre-paid for 20 rooms at the Jupiter Hotel, an incrediby cool funky modern hotel, a few blocks from the conference, with free wi-fi everywhere - for three nights : May 17, 18, 19 (a $300 value)

* - We reserved the DreamBox conference room at the Jupiter Hotel for the nights of May 17, 18, 19, for elite Rails hackers to gather, plug in, hack, eat, drink, etc. (priceless)

These 20 registrations, 20 hotel rooms, and access to the DreamBox will go to the top 20 contributors of Rails patches (as measured here) between January 1 and January 22!

(RailsConf is opening registration soon after January 22 - that’s why we have to make the Jan 22 cutoff date.)

In other words : if you want CD Baby to save you $1100 on RailsConf, sprint!

If you’re not already signed up at workingwithrails.com, sign up now. In your workingwithrails profile, mark yourself as a core contributor and enter your Trac username. Then all of your patches will be linked to your account.

Bookmark http://workingwithrails.com/contests/hackfest2007 to watch progress

Also see Jeremy’s announcement at http://weblog.rubyonrails.org/2007/1/8/hackfest-2007-and-cdbaby-sprint

January 08, 2007 04:37 PM

Robby Russell image

RailsConf 2007 in style

Wow, this is pretty cool.

CDBaby is sponsoring conference passes AND twenty rooms at the Jupiter Hotel in Portland, OR during RailsConf 2007 to the top 20 contributors to the Ruby on Rails project from during January.

Start submitting patches!

image image image

January 08, 2007 03:50 PM

Pat Eyler image

The Five Things Meme

Now that Charles Nutter has tagged me with the Five Things meme, I guess I ought to give it a shot. Here are five things you probably don't know about me:
I never intended to get into computing as anything more than a hobby. I planned on being a chmical engineer instead.
I joined the army straight out of High School to earn money to go to college, and got involved in computers and networks.

January 08, 2007 10:47 AM

Assaf Arkin image

Six tips for building better Web apps with Rails

The API comes for free
And are you going to turn away a free gift?
With Rails 1.2, you can easily respond to the same request with different content types. Say you have an action that displays an HTML page with all the books in the category ‘Ruby’. From the same action, you can also return the [...]

January 08, 2007 09:11 AM

Pat Eyler image

RSpec and Unit Tests: Localizing Problems or Reducing Coupling

I'm just starting to work through a copy of Working Effectively with Legacy Code by Michael Feathers. I've had my eye on the book for a while, and am really glad I was able to borrow a copy (now I just need to buy my own). Like any good book it's making me think, making me question things I've taken at face value. So far, the best example of this is in his discussion of Unit Testing.

I've

January 08, 2007 08:53 AM

Why TheLuckyStiff image

Eigenclass Considered... Considered!

Matz is warming up to the term eigenclass, the People’s slang for (class << self; self; end). From [ruby-talk:231992]:

In my mindset, two candidates have survived. singleton_class (or singletonclass), which can easily be confused with a class in the singleton design pattern. And eigenclass, which is unfamiliar for most people.

Does anyone know if Perl 6 folks still use it?

January 08, 2007 07:16 AM

Cody Fauser image

Move to Mephisto

I finally bit the bullet and moved my blog over to Mephisto. So far I am loving it. Thanks to Justin Palmer and Rick Olson for all of their hard work that went into making this an awesome application.

I migrated from Typo and used the great howto Converting Typo to Mephisto on the Octoblog. What an awesome name for a blog! The only thing I did differently, since I'm using the latest code from the Mephisto trunk, was the support for Typo style article URLs. I just opened up config/routes.rb and tweaked it to look as follows:

1
2
3

4
5
6

ActionController::Routing::Routes.draw do |map|

Mephisto::Routing.connect_with map do
map.connect 'articles/*path', :controller => 'mephisto', :action => 'dispatch'

end
end

January 08, 2007 04:30 AM

eBay API Client for Ruby

I recently released my Ruby client for the eBay XML API. The source code can be found on Google Code. Benefits of this implementation include:

  • Simple and easy to use Ruby implementation.
  • Ability to return a raw response for calls that return an extremely large response such as GetCategoriesRequest.
  • Up-to-date with the latest eBay API version 485.
  • Months of usage in a production environment.
  • Support for Platform Notifications baked right in.

Enough talking about why you should use this library, let's get started with the eBay equivalent to 'Hello World', which is the GeteBayOfficialTime call.

Firstly you'll need to sign up for an eBay developer account. You can sign up at the eBay Developer Center. Once you have signed up you need to follow the directions in the confirmation email to get your Developer ID, Application ID, and Certificate ID. Record this information, as you'll need it when setting up the eBay client.

Now you need to setup a sandbox user to make API calls on behalf of.

Next you'll need to generate your Authentication Token. Simply enter the information you previously recorded into the form, select the sandbox environment from the dropdown menu and click the "Continue to generate token" link. Then sign in as the sandbox user you just created above and agree to allow your developer account to make API calls on behalf of the sandbox user. Record the Authentication Token that is now displayed.

The Authentication Token is your means of sending requests for different users. All you have to do to send a request for a different eBay user is change the Authentication Token that pass into the API call you are making. Of course, you'll need permission to make API calls on their behalf.

Now that we have all of the information needed for authenticating the API calls we can setup the configuration file that we'll use for the following example.

Start by creating a file config.rb and place the following code into it:

1
2
3
4
5

6
7
8
9
10
11

Ebay::Api.configure do |ebay|

ebay.auth_token = 'YOUR AUTH TOKEN HERE'
ebay.dev_id = 'YOUR DEVELOPER ID HERE'
ebay.app_id = 'YOUR APPLICATION ID HERE'

ebay.cert = 'YOUR CERTIFICATE HERE'

# The default environment is the production environment
# Override by setting use_sandbox to true
ebay.use_sandbox = true

end

Obviously you'll want to place your own IDs and tokens into the configuration.

After you've signed up for the Developer Program and you have the API configuration ready to go you can get started installing the Ruby ebayapi gem. Install this gem as by running:

1

2

> sudo gem install ebayapi -y

The -y flag tells gems to install all the dependencies that the the gem requires.

Now that you've got the API client installed we can finally go ahead and get the official eBay time from eBay's servers.

Create a file named official_time.rb, in the same directory as the config.rb file we created earlier, and place the following code in it:

1
2
3
4

5
6
7
8
9
10
11
12
13

14
15
16
17

#!/usr/bin/env ruby

require 'rubygems'

require 'ebay'

# Include the API configuration
require 'config'

# Create the eBay client
ebay = Ebay::Api.new


# Get the official eBay time
response = ebay.get_ebay_official_time

# Display the time to the user
puts response.timestamp

Now you can run this simple application:

> ruby official_time.rb
# => Wed Nov 22 06:03:35 UTC 2006

That was easy. Once we got all of the IDs and tokens that eBay requires, that is. Next time I'll go into some more depth and background the client.

In the meantime you can checkout the examples I've provided in the source. Happy coding.

January 08, 2007 03:25 AM

Ninjistix - 1st Place, Most Creative, Rails Day 2006

Way back on June 16th, Tobi, Daniel, and I decided to enter the Rails Day 2006 programming contest. The contest was on June 17th. Somehow the theme became ninjas and Ninjistix was born.

A really good overview of Ninjistix and the rest of the Rails Day winners can be found on Evan Weaver's blog.

The day was really good. We started around 9am or so and worked until 12am that night. I can't really say that I did anything productive after around 9pm, but hey, we stuck it out to the end.

What I loved most about doing the project was the kind of discussions we had regarding the project. I remember asking "Ok, so add an attack method to the Ninja model?". Then later on I can recall Tobi announcing "I just added an RSS feed for the Ninja's kills". The bugs were also amusing: "Why does meditating cause the ninja to lose consciousness?" I don't remember hearing too much from Daniel, but that's because he was creating the killer UI that even included little Ninja attack and action icons.

So, the end result.... We won first prize for the most creative entry! Kudos to my teamates. I still can't believe how much work a team of 3 can do in one day. Also, congratulations to the other teams and thanks to the judges for judging the copious number of entries (> 100).

January 08, 2007 03:24 AM

PeepCode Rails Screencast Series

Geoffrey Grosenbach a.k.a. Topfunky of nuby on rails fame has launched an excellent new Rails screencast series called PeepCode.

The first episode in the series is on RJS templates. I was able to watch the screencast before its release and I was mightily impressed.

Geoffrey gives RJS a very thorough treatment from the basics of getting started all the way up to advanced concepts like collection proxies and testing RJS with ARTS.

I would highly recommend this screencast even if you're already familiar with RJS because you'll definitely learn a new trick or two. Congratulations to Geoffrey on a job well done.

January 08, 2007 03:24 AM

RJS Templates for Rails - Updated

First I'd like to thank the 600 or so people who bought RJS Templates for Rails in the past week.

I'd also like to thank all of the people who contacted me with their feedback and errata.

On that note, I'd like to let you know that if you have already purchased the book that you can go and download an updated, hopefully errata free, version from O'Reilly.

January 08, 2007 03:24 AM

RJS Templates for Rails

I'm happy to announce the availability of RJS Templates for Rails published by O'Reilly. Here's the intro from the book:

RJS templates are an exciting and powerful new type of template added to Rails 1.1. Unlike conventional Rails templates that generate HTML or XML, RJS templates generate JavaScript code that is executed when it is returned to the browser. This JavaScript generation allows you to perform multiple page updates in-place without a page reload using Ajax. All the JavaScript you need is generated from simple templates written in Ruby. This document helps you get acquainted with how RJS templates fit into the Rails framework and gets you started with a few easy-to-follow examples.

The book covers all aspects and features of RJS that are included in Rails 1.1. It also walks through a few examples, debugging with FireBug, and finishes off with some reference material.

I'm really happy with how the book has turned out and I think you'll really enjoy it.

January 08, 2007 03:23 AM

Testing RJS with ARTS

Are you tired of debugging your RJS calls ? If you answered "yes" then it is your lucky day. Kevin Clark has created a new plugin for Rails called ARTS: Another RJS Testing System.

ARTS allows you to write assertions for your RJS calls in your functional test cases. Kevin has also created an excellent tutorial Test Driven RJS with ARTS.

What are you waiting for? Get over to Kevin's site and get started.

January 08, 2007 03:22 AM

Canada on Rails Ticket For Sale - SOLD

Update: The ticket has been sold

I am unable to attend the Canada on Rails conference, but I've already purchased a ticket.

The conference just sold out, so if you want a ticket for the price of $150 CAD, you should contact me before April 10th and I can transfer the ticket to you. The last day they will allow the transfer of the ticket is April 10th.

Email me at codyfauser [at] gmail [dot] com

January 08, 2007 03:21 AM

RJS Element and Collection Proxies

Background

Some powerful new features have been added to Rails RJS Templates. What are these new features? They are called element and collection proxies.

Element Proxies

First, from Wikipedia, the definition of the Proxy pattern:

A proxy, in its most general form, is a class functioning as an interface to another thing.

So, in the case of RJS templates, the proxy is functioning as an interface to a JavaScript DOM object. The syntax is quite similar to the syntax of the original RJS templates, except that we use the [] operator on the page object within the template. So, if we wanted to hide the DOM element with id header, we'd use the following code:

1
2

page['header'].hide

You can also use symbols, so passing in :header will also work.

Currently there is support for all of the RJS methods that you are already familiar with like replace_html, replace, visual_effect, show and hide. In addition, there is an interesting new method named reload, which will call replace on the element and replace the element's content with the rendered output of a partial of the same name. Example:

1
2

page['header'].reload

Is equivalent to

1
2

page['header'].replace :partial => 'header'

The proxy will also correctly pass through other Prototype methods that previously had to be called using page.call, such as remove_class_name.

So far the proxies may just look like a matter of semantics, however, when combined with the new select method, the results are very powerful.

Collection Proxies

The new select method returns an array of DOM objects. select takes as an argument a CSS based selector and returns an array of DOM objects matching that selector. So, to get all paragraphs within the <div> with id content, we would use:

1
2

page.select('#content p')

Now combine this with the enumerable methods available through the collection proxy and you can do things like:

1
2
3
4

page.select('#content p').each do |element|
element.hide
end

All <p> elements within the <div> with id content will be hidden.

Not only is it easy to iterate through the elements of the collection, but Rick Olson, the newest Rails core team member, went out and got all sorts of other enumerable methods that Prototype supports working. I'm going to leave those as an exercise for you to explore. You can start with the changeset.

Summary

The new element and collection proxies are a very nice and powerful addition to RJS. They allow us more flexibilty and we now have to write even less JavaScript. They also provide a nicer syntax for calling existing Prototype methods on DOM elements from RJS templates.

January 08, 2007 03:21 AM

The Pixel Box

I've started working at Jaded Pixel on a top secret project known as the Pixel Box.

I can't say much, but what I can say is that I've laid my eyes on Shopify and it is absolutely incredible.

So if you haven't yet, go check it out. You won't be sorry.

January 08, 2007 03:21 AM

Using with_scope to refactor Rails finder methods.

Background

I have come across a great way of refactoring finder methods, yet still maintaining the flexibilty of the built in ActiveRecord finder methods.

First I'll show an inflexible way of refactoring a simple finder. I was calling the following method from several places in my controller:

1
2

3
4

@emps = Employee.find(:all,
:conditions => "work_status <> 'Gone'"

)

Creating a static finder in my Employee class makes calling this method a bit more simple.

1
2
3

4
5
6
7
8

class Employee < ActiveRecord::Base

def self.find_all_current
find(:all,
:conditions => "work_status <> 'Gone'"

)
end
end

Now I can call:

1

2

Employee.find_all_current

Finding employees that aren't "Gone" will be a common task throughout the application and it would be nice to have some flexibility in finding them. I'd hate to have to create another static finder method like just to order the employees differently or add another simple condition.

Utilizing with_scope

The best way to remove this duplication is to use with_scope. with_scope allows finder methods to be called normally, but have conditions applied to find or create methods called from within the block. An example will clarify this concept:

1
2
3
4
5

6

Employee.with_scope(:find => { :conditions => "work_status <> 'Gone'" } ) do

Employee.find(1) # => SELECT * from employees
# WHERE work_status <> 'Gone'
# AND id = 1

end

Now we can apply this concept to help make the refactored finder method a lot more flexible:

1
2
3
4

5
6
7
8

class Employee < ActiveRecord::Base

def self.find_current(*args)
with_scope(:find => { :conditions => "work_status <> 'Gone'" }) do

find(*args)
end
end
end

This allows us to find all current employees, but with the flexibility to specify more parameters. A few examples are:

1
2
3
4
5
6
7
8

9

@emp = Employee.find_current(:first)

@emps = Employee.find_current(:all)


@emps_named_bill = Employee.find_current(:all,
:conditions => "name like '%bill%'",

:order => 'last_name, first_name'
)

Summary

As you can see from the above code we maintain all the power of ActiveRecord's finder methods while imposing a constraint of our own in a straight forward, legible manner. In addition, it would be in the spirit of DRY to create other static finders in terms of find_current, such as Employee.find_current_ordered. One current limitation is that nested scopes are not yet supported.

Update

Nested with_scope will be supported in Rails 1.1. To see the true potential of Rails ActiveRecord scoping check out this article on Nested with_scope by AnnaChan. It will rock your world.

January 08, 2007 03:20 AM

RJS Templates Plugin Subversion Repository

I recently had a few minutes to create a subversion repository for the RJS Templates Plugin that I recently packaged.

Installation is now much simpler. First, run:


script/plugin discover

This will question you whether or not you want to add the plugin repositories that have been listed on the Rails Plugins wiki page to your local list of plugin repositories. Ensure that you add my repository, http://www.codyfauser.com/svn/projects/plugins/, when prompted. You can ensure that you have by ensuring my repository is listed when you execute:


script/plugin sources

Now all you have to do is:

script/plugin install javascript_generator_templates

If you don't want to add my repository to your list of plugin sources you can install the plugin in one shot as follows:


script/plugin install \
http://www.codyfauser.com/svn/projects/plugins/javascript_generator_temp...

Update: The plugin now has its own page

January 08, 2007 03:20 AM

Rails RJS Templates Plugin

Update

Go and get Rails 1.1 and you won't need this plugin.

Background

Marcel Molina Jr. recently announced that RJS templates would not be included in the 1.0 release of Rails, but that they might include them as a plugin.

I thought that it was about time for me to learn the plugin system in Rails anyway, so I packaged up all of Sam Stephenson's hard work on the RJS templates from changesets 3078 and 3084 and turned it into a plugin.

This means that you can add the new RJS templates functionality to your application without having to run on the bleeding edge. Please note that the plugin updates quite a few methods from ActiveRecord::Base and ActionView::Base, but mostly in minor ways. Take a look at the changesets, linked to above, for more details.

The plugin should work if you are running the latest Rails gem (0.14.3) or if you are running the stable branch from the subversion repository. If you are running on Edge Rails already then please stop reading now because this plugin won't do anything for you.

Installation

Follow these directions to install the plugin from my subversion repository

Now that you have installed the plugin you can proceed with my tutorial or Rick Olson's more advanced tutorial.

Please notify me of any problems or feedback you may have.

Update: The plugin now has its own page

January 08, 2007 03:20 AM

Rails RJS Templates

Some background

During my daily reading of the Ruby on Rails mailing list I ran across a post asking about RJS templates. I hadn't heard of them before and I was intrigued to find out more.

It turns out that RJS templates are a new form of template, called JavascriptGeneratorTemplates, and end with a .rjs file extension.

Ok, so there is a new type of template, but what does it do? Here is the description from the rdoc documentation in the changeset:

Unlike conventional templates which are used to render the results of an action, these templates generate instructions on how to modify an already rendered page. This makes it easy to modify multiple elements on your page in one declarative Ajax response. Actions with these templates are called in the background with Ajax and make updates to the page where the request originated from.

Trying out the rjs templates requires checking out the latest Rails code from the subversion repository. You can use these instructions to help get your project running on edge Rails. After you are running edge Rails be sure to run the following:


rake update_javascripts

A short example

First, create the view that will be updated by the rjs template:

1
2

3
4
5
6
7
8
9

<h1 id='header'>RJS Template Test</h1>
<ul id='list'>

<li>Dog</li>
<li>Cat</li>
<li>Mouse</li>
</ul>

<%= link_to_remote("Add a fox",
:url =>{ :action => :add }) %>

Ensure that your layout is including the javascript libraries:

1
2

<%= javascript_include_tag :defaults %>

Then add the action that will be called by link_to_remote to your controller:

1
2
3

def add

end

Rails now looks for templates with an extension of .rjs, in addition to .rhtml and .rxml, so create a view named add.rjs for your controller and add the following code to it:

1
2
3
4

5
6

page.insert_html :bottom, 'list',
content_tag("li", "Fox")

page.visual_effect :highlight, 'list', :duration => 3
page.replace_html 'header',

'RJS Template Test Complete!'

If you're curious where the page object comes from, the rdocs provide the explanation:

An instance of the JavaScriptGenerator object named +page+ is automatically made available to your template, which is implicitly wrapped in an ActionView::Helpers::PrototypeHelper#update_page block.

Now when you load the page in your browser and click the 'Add a fox' link, a Fox list item will be added to the list and the entire list will be highlighted. The header will also be updated. You can also render partials:

1
2

page.replace_html 'header', :partial => 'my_partial'

Summary

As you can see from the example, the new RJS templates make it dead simple to update multiple page elements using AJAX. This example barely scratched the surface of what is possible. Kudos to the Rails developers for yet another wonderful addition to the framework.

Update

Checkout the new RJS Element and Collection Proxies.

Rails 1.1 has been released

No longer do you need Edge Rails or any plugin to get RJS working. Just upgrade to Rails 1.1 to get RJS baked right into the framework. Have fun!

January 08, 2007 03:20 AM

Shopify is Live!

Shopify has been released. You'll be blown away at how easy it is to setup your shop and start selling online. I could go on and on, but the homepage has more than enough information to whet your appetite. Have fun.

January 08, 2007 03:18 AM

Eric Hodel image

RubyGems Beta 0.9.0.9

Beta version 0.9.0.9 is now available with:

gem update --system --source http://onestepback.org/betagems

This will be the last beta with major changes before the release of 0.9.1.

Upgrade note

While require_gem was deprecated in 0.9.0, the bin stubs are still using it (oops!). To get rid of the warnings printed by rake or other bin stubs simply run gem pristine --all.

What’s new since 0.9.0?

Lots! Many changes both big and small! Here’s an incomplete summary:

  • require_gem is deprecated and will print a warning. Use gem instead.
  • RubyGems now requires ruby 1.8.2 or greater.
  • gem command changes
    • new gem pristine command
    • new gem outdated command
    • new gem sources command
    • gem uninstall can uninstall multiple gems
    • gem install uses the cache instead of downloading
    • gem install returns non-zero exit code on failure
    • gem install can now set shebang on bin stubs (env or ruby)
    • gem help output now fits in 80 columns

now -w clean
many proxy installation improvements
gem cert improvements
RubyGems is now easier to use as a library

  • Easier programatic installs
  • Easier inspection of local and remote gems

extension building enhancements
error reporting enhancements (less odd exceptions)
many bugs fixed or closed (0 bugs in tracker!)
require now loads .jar files
select bug fixes:

  • installing from scratch fixed
  • gem install --force forces
  • installing from read-only location works
  • gem uninstall requires full name
  • gem install obeys GEM_HOME for bin scripts
  • RubyGems now installs on ruby 1.9

New since beta 0.9.0.8

  • fixed issue with Gem::Specification#hash for JRuby
  • RubyGems now installs RDoc and ri for itself
  • RubyGems is now tab-free
  • require_gem warning prints file and line information

For full details, read the ChangeLog.

January 08, 2007 01:28 AM

January 07, 2007

Casper Fabricius image

Your own Mac OS XP with Parallels

Simple question: Am I running Mac OS X or Windows XP in the screenshot above? (Click to enlarge).
Simple answer: I’m running both.
Complicated answer
I’m really running Parallels with the coherence feature enabled. Parallels is an application that utilizes the Intel processors in newer Macs, allowing Windows XP to run in a virtual machine, but without the [...]

January 07, 2007 06:21 PM

Obie Fernandez image

On Bush's Sacrifice

I normally stay away from political material on my blog, but this bit by Keith Olbermann on Sacrifice was just too compelling not to post. In the words of Dion, "If only he would listen."

Tired of your job? Need to hire developers? Visit DZone Jobs: great people, great opportunities.

image

image image image image

January 07, 2007 05:53 PM

Chris Neukirchen image

Es jährt sich...

Dieses Bild hat ja schon eine lange Tradition auf “chris blogs”.
Dieses Jahr gabs allerdings keinen Schnee, da mussten wir auf eine
andere Kühltruhe ausweichen.


Inhalt des Gefrierschanks

NP: Minutemen—One Reporter’s Opinion

January 07, 2007 01:40 PM

Assaf Arkin image

Rounded Corners - 91

Stop the press. Microformats make it to InformationWeek, with a mention of hListing. Exciting times! (Thanks John)
Unintended consequences. LinkedIn, the social network I love to ignore, just added a new feature. You can send questions to your network of contacts. I received a couple of questions, both rethorical questions on non-interesting topics, with … you [...]

January 07, 2007 06:50 AM

Eric Hodel image

rbayes 1.0.0 Released

rbayes version 1.0.0 has been released!

rbayes-1.0.0 documentation.

An bayesian filter fed by a tokenizer that throws crap out you’d find in emails. Originally by Dan Peterson

Changes:

1.0.0 / 2007-01-06

  • Birthday!
  • Fully refactored from Dan Peterson’s original to be in a single class.

January 07, 2007 06:24 AM

Nick Ziegler image

Tagged

Crap, I saw this coming as soon as Tor tagged Charlie. I never was a chain letter person, and I’m kinda getting sick of this one, so I’ll let it end here, but just to not be seen as a complete curmudgeon, I’ll bullet-pointilize with these five items:

  • In a previous programming life (my first job out of school), I helped develop a small-market Playstation 1 title called Monkey Magic. (Hey, it has a Wikipedia entry! Yeah, it does suck, sorry. None of us ever watched the cartoon, which made the content of the game pretty lame for fans of it.)
  • I lived in New York City, the greatest city in the world, for two years while working on MM.
  • In a previous previous life, I worked on audio analysis techniques in graduate school using wavelets, Markov models and other spectral analysis techniques. I had all of one paper published.
  • My youngest daughter is named Ruby. But, she’s 4, and I’ve only been programming Ruby (the language) for less than two years, so nyahhhhh.
  • I actually enjoy shopping.

January 07, 2007 04:13 AM

Obie Fernandez image

Copenhagen Rails Podcast

"We're recording this in at a club by the way; to all you aspiring podcasters, it doesn't matter where you record, just get something good!"

My recorded interview of a few opinionated guys (Thomas, Tobias, Jesper and Olle) from copenhagenrb.dk is finally published at the Rails Podcast. The background noise is indeed from the rest of the bustling club, where we had holed up in the little VIP room to drink beer and record our podcast.

Among their practical tidbits of advice: Instead of trying to specify and prototype web applications using Word documents or static html documents, just do it in Rails. I also get them to predict the future of Rails in Denmark in the upcoming year. Good times!

Bonus: As promised to the guys, here is the Takahashi version of the podcast (1min 20s) My web server didn't like the m4a extension, so gunzip to listen.

Tired of your job? Need to hire developers? Visit DZone Jobs: great people, great opportunities.

image

image image image image

January 07, 2007 01:48 AM

Brian Eng / Jeff Cohen image

My New Year's Resolution: Out With The Old...

I've always kept almost every technical book I've ever bought. I guess I wanted to keep a historical record of my career by being able to look at my bookshelves. I imagined being 60 years old, reminiscing to some kid fresh out of college, pointing over to my original copy of Don Box's classic Essential COM and saying, "See, son, back when I was your age, we had to program uphill... both ways."

But I decided it was time for some real-life refactoring. Time to throw out all that dead code -- er, books, that is. Here are many of the books I just took out to the curb (snif). This picture kind of represents my work life for the past 10 years in one glance (click to zoom in if you really want to read the titles):

My old books

Now for me, this was actually a hard thing to do. Those old books you see in the picture at the top (plus others that I didn't get into the picture) represent uncountable hours of work, fun, stress, and growth for me over the past 10 years or so. Sure, I don't really need them anymore - I do Ruby full-time now - but it's still hard to make such a big change without a little fear.

Getting these books out of my daily sight was one way for me to make my committment to Ruby more tangible than ever.

It's similar to how I feel when I refactor a big ugly function, or remove a lot of deadcode, and then I run the tests and they still pass - I feel so much better. So much better.

And now, here's the glorious picture of all that remains: books that represent my current career and interests:

My new books

(There's one cool book missing from this picture because I have the .pdf of it instead, and another life-changing book that's missing because the co-writer of this blog borrowed it about a year ago and still has yet to return it... but I digress...)

What books on your shelf today were once important but don't really represent your interests anymore? Or perhaps, what books have you acquired recently that you would recommend?

image image image

January 07, 2007 12:57 AM

January 06, 2007

Francis Hwang image

Annals of fashion, January 2007

Eyelid surgery stigma fades among Asian-Americans

Even if the patient is ambivalent, [Dr. Edmund] Kwan said the mother is often convinced of the surgery’s benefits. “It’s ingrained in their mind that an eyelid fold will look better, will help their daughter get a better husband,” Kwan said.

Skinny girls to blame for late trains?

“You have women trying to get their bodies tight for the summer and they won’t eat,” said Asim Nelson, a Transit emergency medical technician based in Grand Central Station. “Not eating for three or four days, you are going to go down. If you don’t eat for 12 hours you are going to get weak.”

Japan, Home of the Cute and Inbred Dog

The breeder told Mr. Sasaki that he had bred a dog with three generations of offspring—in human terms, first with its daughter, then a granddaughter and then a great-granddaughter—until Keika was born. The other four puppies in the litter were so hideously deformed that they were killed right after birth.

January 06, 2007 11:50 PM

Robby Russell image

Working in Portland Coffee Shops and Cafes Reviews, part 2

During the summer of 2005, I wrote a post that listed several coffee shops in Portland, Oregon that I found to be really good places to work on your laptop at. I’ve gotten bored with my regulars and have recently begun to look for new places to venture to.

Pier Coffee

Pier Coffee is in a weird part of Portland that is somewhat isolated due to the train tracks that will block you in when a long train is moving through town. It’s a very short walk from Allison’s place and they have Oregon Chai, which has become my replacement for drinking coffee. The chairs in Pier Coffee are very comfortable and they have an electrical outlet at most of their tables. When you get bored, you can walk over and play darts, or get a glass of wine. The wireless works really well and when it’s not raining, you can sit out front and overlook the train tracks and downtown, while hacking on your laptop. Pier Coffee is what I would consider an easy place for me to feel productive. There usually isn’t too many people here and I believe most of the customers are from the two condo complexes next to it. The staff is very friendly and their music tastes aren’t annoying.

Backspace is about a half block from the PLANET ARGON office. They don’t serve Oregon Chai, so I usually only get a tea, a viso, or a hot cocoa while there. They have a few tables and couches and I haven’t found this a good place to be productive. It’s a good place to have a short meeting with a coworker though. Music tastes are better here than most places, and they have a food menu now that caters to my vegetarian diet. There are a few electrical outlets, but the seats near them are often occupied.

Three Lions Bakery is about a block from the PLANET ARGON office. They do have Oregon Chai, so I stop by here often in the morning to get my fix. Not many electrical outlets, so your visits are usually not very long. They have a few sandwiches that are quite good. This is a good place to stop by if you’re in the mood to work for about a hour and have some chai and an excellent (and freshly baked) cookie.

If you’re in Portland and have some recommendations, please do share. I’m looking for a few places that are open later in the evening.

image image image

January 06, 2007 09:02 PM

Nick Ziegler image

JRuby Serial Interview 1

In cooperation with Pat Eyler, we present this conversation as a parallel thread to his recent string of Rubinius “serial” (ongoing) interviews. We aim to bring short, frequent, looks at the two alternate Ruby implementations’ developments, and have the conversations intersect from time to time.

A lot has happened since the last JRuby interview with Pat – Java was open-sourced, you’ve been to Javapolis, pushed out another release, and a slew of new contributions have poured in. How have your plans and goals for JRuby changed (if at all) since then?

Charles Nutter: For me the biggest items are the following, in order:

  • We need to announce full Rails support as soon as possible
  • We need to resolve the remaining runtime performance bottlenecks
  • We need to keep working on the compiler

All these of these have been the hot topics on the JRuby mailing lists lately. I’ve launched into a newly-refactored compiler that’s showing great performance gains. Many of us have discussed how to speed method dispatch and finally push interpreted-mode performance up to or beyond Ruby’s speed. And we’ve started to test and track Rails 1.2, while continuing to resolve remaining issues running Rails 1.1.6.

Now there’s a lot of work to do, but we’ve seen steady, continuous growth among JRuby contributors. Just in the past week we’ve had a number of new names on the mailing lists, we’ve added a new committer (Nick Sieger), and we’ve seen patches pouring in for more and more bugs. Things are going great.

Ola Bini: I was very happy about the last release. It fulfilled the goals I had set for it, which was to get OpenSSL and complete Java-backed YAML into it. Besides that, we also got seriously many bugs fixed in just a few months. Since I have a tendency to plan mostly for the next release, what I want to see in 0.9.3 is support for Sandbox, all those strange block scope bugs that surface in Rails gone, our load times improved (by refactoring the LoadService code), and finalizers finally working.

The Sandbox stuff is mostly done, and I also hacked a Generator that is so much faster than MRI that we come out faster, all in all, in a
test case with generators.

Thomas Enebo: Largely, I think three goals are important: 1. Support Rails well enough where people do not need to ask us if it is ready for prime time; 2. Round out java integration support to do what most people expect it to do; 3. Make the runtime ‘fast’ enough. These three goals existed before JavaPolis, so I do not feel much has changed goal-wise.

How much closer have you come to achieving them? What is your perception of delta in growth in the JRuby community and acceptance of JRuby as a viable alternative to MRI?

Ola Bini: What I like about the last few months - since RubyConf - is that it really feels like JRuby and the other implementations will actually be viable alternatives and that there is something really useful going on. With Java open source, one of the major roadblocks for adoption in certain circumstances has all but disappeared. The contributions we have gotten is mostly visible in how many bug reports we get. That is really great, because that makes it that much easier to fix things. So I would say that the future looks brighter than ever.

Thomas Enebo: If you look at the amount of time between releases then you get a better idea of how much development has sped up. The time between 0.9.1 and 0.9.2 was a little under two months. This is the shortest development cycle to date and it seemed like we got so much done. Sun hiring us obviously had something to do with this, but also our community involvement is at an all time high. We get so many emails, bug reports, patches, tests, ideas, and enthusiasm coming in from the JRuby community. The community impact on JRuby is huge.

I think acceptance of JRuby as a Ruby interpreter is certain. Compatibility keeps improving, we keep getting faster, and we also offer integration with Java. If you look at the trend of how often JRuby is mentioned in blogs or the volume of email on our mailing lists, then I think you can get a picture as to whether people are willing to accept JRuby as a Ruby runtime.

Charles Nutter: Rails is probably the most visible measure of success for JRuby right now, and I’d say we’re able to run something like 75% of Rails 1.1.6 code and test cases. We’ve been using Rails’ own test suite as a yardstick for compatibility, with the idea that if we can run all the Rails test cases, we can say we support it. And that 75% is better than it might sound, since it’s the most heavily-used functions.

Now this might change, but we’re really hoping to claim full Rails support some time in February. We’re not sure if that will mean 90% of 1.1.6 test cases or 100% of 1.2 test cases, but we’re weighing options now. Finally having Rails support behind us will let us change focus toward outward to other applications and inward to improving JRuby internals and performance.

We’re also seeing daily gains in the performance area, with more to come. Since this past summer, we’ve managed to eliminate all the major performance bottlenecks seen when profiling. The only remaining area is the interpreter itself. My work on the compiler will eventually resolve that, and our work to improve the performance of method lookup and dispatch will help both interpreted and compiled execution. Everything’s moving very fast now. It’s going to be a great Spring for JRuby.

Probably the most intriguing change of the past month is the support from Aslak Hellesøy, creator of RSpec. Aslak has helped us get JRuby running RSpec extremely well, and we’re looking forward to the RSpec team using JRuby as part of their regression testing. I hope more Ruby app developers will take this same path, since their users are going be running JRuby more and more. Compatibility and regression testing for those apps should include JRuby just like it includes different Ruby versions and host operating systems.

January 06, 2007 06:21 PM

Continuous Integration Goodness(TM) for Your Ruby Project

As much as we’d like to think we live in a Ruby-glasses-colored world, the fact is there are plenty of neat toys out there that don’t know a bit about us. One that I’m currently enamoured with is Bamboo, Atlassian’s new continuous integration server. But, most commercial CI products are aiming for a wider market, and that means Java and Ant. Ant and JUnit predate Rake and Test::Unit by a few years, so I’m afraid they beat us to the punch, so that now the JUnit Ant task’s XML format is pretty much the first consideration for a continuous integration server to understand in order to display a test report for a build.

Where does that leave us Rubyists who want to play along with the bigs? Right here!. With support for not just RSpec, but Test::Unit too.

Right now, it’s packaged as a Rails plugin, because I’m lazy and I don’t need anything else right now. If you’re interested in a gem, please leave a comment. To install into your Rails app, the usual:

./script/plugin install http://svn.caldersphere.net/svn/main/ci_reporter

That’s it! Now all you have to do is have your CI server invoke an extra target before the main target that runs your tests.

For RSpec,

rake ci:setup_rspec spec

will leave one XML file per context in the spec/reports directory (creating it if it doesn’t exist).

For Test::Unit,

rake ci:setup_testunit test

will leave one XML file per test case class in the test/reports directory.

Most CI servers have configuration telling them where to look for test reports. Simply plug in one of these directories, and you’re set. Now sit back and watch your test or spec failures get tracked in your automated builds.

test results

January 06, 2007 05:28 PM

Edward Summers image

identifiers and authority records

Authority files are rather important for unambiguously talking about a person, place or thing. In database lingo they essentially amount to a primary key for a table. Given the time and effort libraries spend in maintaining authority records and assigning control numbers to individuals it makes sense that a URI could be assigned to an [...]

January 06, 2007 12:51 PM

Chris Neukirchen image

5 things you didn't know yet about me

Alas, manveru tagged me and I need
to tell you five things you probably didn’t know yet about me. It’s
like the perfect start into a year with the resolution of writing
more.

Here’s my list:

  • I have a photographic memory for URLs. Want to show me “something new”?
    I’ll tell you immediately if I already have been on that site.

  • I’m a programming language fetishist. Well, if you read my blog,
    you probably guessed that already, but I can recognize almost every language
    given a short snippet and likely heard of the rest too.

  • I love to sleep long. Don’t even dare to wake me on weekends!

  • I have every official Bob Dylan disk on my hard drive. Must be the
    collector’s disease.

  • My mind goes all weird when I’m drunk. And I mean really weird.
    For example, I once couldn’t sleep in a bus because I did too many
    sudokus that day, and desperately tried to sleep in a different
    position than the people in my row and my column. Or, one time, I
    tried to analyze relationships in a discotheque using advanced
    algebra. It sucks if love isn’t commutative.

    Actually, that’s pretty funny, but rather scary too when you
    remember it, no?

The next people to tell five things we didn’t yet know about them are, umm,
Aria, David,

Ferstl, Baschde
und Nici.

NP: The Kooks—See the World

January 06, 2007 12:15 PM

Obie Fernandez image

Links for 2007-01-05 [del.icio.us]

  • Mike Clark's Weblog
    I've tried various approaches and options over the last few months, and these seem to work best for me. The results for all the unit, functional, and integration tests get aggregated into one report so I can scan everything quickly. Your mileage may vary.

January 06, 2007 06:00 AM

Ruby on Rails image

Capistrano 1.3.1

I’ve been remiss in announcing recent Capistrano releases, so I’m making up for lost time now. Capistrano 1.3.1 is now available!

Capistrano, for those of you that are late to the game, is a utility for executing commands in parallel on multiple remote machines. It comes with support for vastly simplifying the deployment process of Rails applications, but can be customized to work with virtually any environment.

Since 1.2.0, the following enhancements and changes have been made:

  • You can encode the username and port for a host in the host string. Does one machine require a different user than another? A non-standard port for SSH access? It’s as simple as:

role :app, "app1.host.com"
role :web, "webuser [at] web1 [dot] host [dot] com"
role :db, "db1.host.com:1234"
role :file, "fileuser [at] file1 [dot] host [dot] com:1234"

  • You can pass an :as option to sudo, to specify which user a command should be run as:

sudo "spinner", :as => "app"

  • If you define a ”.caprc” file in your home directory, Capistrano will automatically load that file on every invocation. (It has the same format as any other Capistrano recipe file.)
  • Assets in the images, javascripts, and stylesheets directories are now touched after updating the code, to ensure that Rails’ asset timestamping feature works correctly.
  • Make sure new setups and checkouts are group-writable.
  • Do not run the cleanup task on servers marked “no_release”.
  • Rake integration is now deprecated. You should be invoking ‘cap’ directly. A future release will remove rake integration altogether.

Feel free to read the changelog several other fixes and tweaks. It might be a few hours before the 1.3.1 gem reaches all the mirrors, but when it gets there, a simple “gem install capistrano” ought to do the trick!

January 06, 2007 05:15 AM

Edward Summers image

DemoCampDC

DemoCampDC is an adaptation of BarCamp to provide an informal mechanism for sharing technology shtuff in the DC area. If you are interested and in the DC area please add your name to the list of attendees and stay tuned.

January 06, 2007 03:36 AM

Geoffrey Grosenbach image

PeepCode: Capistrano Concepts and a Free Rails + Ubuntu Screencast

Capistrano Concepts is the newest PeepCode (released earlier this week). People are already saying that “it put a lot of things into perspective and really helped [me] grasp the concepts. I think I’ve learned Rails faster from your screencasts than all the books I have combined.” (Jon Baer, Developer)

Also available as a free bonus is a 10 minute screencast showing you how to install a full Rails stack on Ubuntu using the deprec gem. It’s a great way to build a staging server or a sandbox for experimentation. Download it at the new site.

The new site also has some new features that people have been asking for:

  • The option to sign up and keep a record of the screencasts you purchase from now on
  • Subscribe for a discount
  • All screencasts are now available in a format compatible with the video iPod
  • Now running on Mongrel and speedy new RailsMachine hardware
  • Other features coming soon…

January 06, 2007 12:10 AM

January 05, 2007

Jamis Buck image

Custom maintenance pages

Mike Clark has got a great writeup on how to create custom maintenance pages for use with Capistrano and Apache. I haven’t seen much written where people are using the render helper in Capistrano—it’s good to see it getting some use, anyway!

January 05, 2007 11:34 PM

Zenspider image

STI and Abstract Classes Driving You Nuts?

If you happen to be hit by Ticket #5704: Bug in ActiveRecord::Base when mixing STI and abstract models, and you're seeing failures to find STI instances intermittently in development mode, try the following:

class MyAbstractModel < ActiveRecard::Base
self.abstract_class = false
# ...
end

-----

class MySTIModel < MyAbstractModel
TYPES = %w(Sub1 Sub2 Sub3)
def self.inherited(cls)
super
raise "not in #{self.class}::TYPES: #{cls}" unless TYPES.include? cls.name
end
end

MySTIModel::TYPES.each do |f|
require_dependency f.underscore
end

-----

class Sub1 < MySTIModel; end
class Sub2 < MySTIModel; end
class Sub3 < MySTIModel; end

It is a stupid bug and I can't do much about it, but the above workaround seems to be a nice tradeoff between horrible hack and maintainability. By pushing the list of subclasses up to the TYPES array, you keep it visible and near the top of the file. By having the inherited hook, you keep slipups in maintainability as visible as possible.

UPDATED: All of the classes in my actual use were single word classes. Kevin Clark pointed out that my code doesn't work with camel-cased/multiple-word class names. The code above has been updated to fix that.

January 05, 2007 11:16 PM

Jamis Buck image

Brevity vs. Clarity

Today’s TADFALAICKIU: balancing brevity and clarity.

I’m a big fan of the ternary operator. (That’s the bizarre little foo ? bar : baz construct which Ruby, and others, borrowed from C.) It lets you express simple conditionals very concisely. However, the poor ternary operator gets a lot of flak. It is easily abused, and some people have even gone so far as to swear that any use of it is an evil use.

If that’s you, then I guess we’ll have to agree to disagree. :)

I’ll admit that I’m still learning the balancing act. I’ve been going through some older code of mine and discovering things like the following:

1
2
3
4
5
def smart_overview_url(options)

@project ?
project_overview_url(options.merge(:project_id => @project.id)) :
overview_url(options)

end

Although certainly not one of the evilest invocations of the ternary operator, it is undeniably destined for some circle of Hell. Ternary Operator Rule #1: if you can’t fit the entire condition on a single line, use an explicit if-then-else construct.

1

2
3
4
5
6
7
def smart_overview_url(options)

if @project
project_overview_url(options.merge(:project_id => @project.id))
else

overview_url(options)
end
end

There, isn’t that cleaner? Other rules of thumb:

  • If you need to nest a ternary operator inside another ternary operator, you’re almost certainly doing it wrong. Nested ternaries are hard to read, and that’s bad. Break it out. Be verbose.
  • If you need to parenthesize any of the component parameters of the operator, you’re almost certainly doing it wrong. Parentheses add line noise to a sequence that already has quite a bit. Break it out. Be verbose.

So, when is it ok to use the ternary op? Try these examples:

1
2
3
4
5
6
# trivial conditions
increment = x < y ? 1 : -1
# simple type conversions
value = record.respond_to?(:something) ? record.something : nil

# unfolding hashes
element = hash[:here] ? hash[:here][:there] : nil

Note that in the case where something is either a result of some operation or nil, you can also use the && operator in Ruby:

1
2
3
4
# simple type conversions
value = record.respond_to?(:something) && record.something

# unfolding hashes
element = hash[:here] && hash[:here][:there]

That works because && does not (necessarily) return a boolean value—it returns the first false/nil value, or the last value if none are false/nil.

January 05, 2007 10:25 PM

Nick Ziegler image

MenTaLguY on Concurrency

Overheard on #rubinius, MenTaLguY, the modern-day concurrent programming guru, on memory barriers:

MenTaLguY: as far as memory barriers go, the issue is that modern processors do all kinds of crazy stuff behind the scenes
MenTaLguY: reordering reads/writes, deferring writethroughs, etc
MenTaLguY: it’s like one of those shady delis where they don’t seem to do much actual deli business, but people are always going in and out and there’s a room in back full of cigar smoke
MenTaLguY: you walk in at the wrong time, and … well

MenTaLguY: memory barriers are like loudly announcing “WHY, HELLO THERE OFFICER, NICE DAY TODAY, I’M JUST GOING TO THE DELI NOW” before you come in

deli

January 05, 2007 09:28 PM

O'Reilly Ruby image

NubyGems: Don't Use Class Variables!

This was actually inspired by some thoughts at a new_haven.rb meeting I wasn’t able to attend, reintroduced in a RubyTalk thread, and solidified in another blog entry that’s worth a look.

The topic here is simple, and it’s that for most common needs, there is absolute no reason to use class variables. I will show how you can use class instance variables to avoid the problems associated with class variables in most cases at the end of this article, but first, take a look at two compelling and mind melting reasons for *not* using class variables.

From Gary Wright:

>> class A
>> @@avar = 'hello'
>> end
=> "hello"
>> A.class_variables
=> ["@@avar"]
>> A.class_eval { puts @@avar }
NameError: uninitialized class variable @@avar in Object
from (irb):5
from (irb):5
>> class A
>> puts @@avar
>> end
hello
=> nil
>> class A
>> def get_avar
>> @@avar
>> end
>> end
=> nil
>> a = A.new
=> #
>> a.get_avar
=> "hello"
>> a.instance_eval { puts @@avar }
NameError: uninitialized class variable @@avar in Object
from (irb):16
from (irb):16

And the real scary one, from David A. Black:

@@avar = 1
class A
@@avar = "hello"
end
puts @@avar # => hello

A.class_eval { puts @@avar } # => hello

Yes, there are reasons why both of these problems occur. Yes, they are likely to give you a headache.

If you’re just looking to store some data in a variable which is unique to your class, but accessible from instances or externally, why not just use instance variables?

>> class A
>> @foo = "bar"
>> class self; attr_reader :foo; end
>> end
=> nil
>> A.foo
=> "bar"

Yup, classes are just regular old ruby objects, and class instance variables are just regular old instance variables. This avoids the above problems, as well as simplifies the concepts of where your variables actually live.

Yeah, maybe @@foo is easier to type than self.class.foo
But good luck debugging it! :)

January 05, 2007 06:40 PM

Thomas Fuchs image

Rails 1.2 coming soon

With release candidate 2 out now, Ruby on Rails 1.2 is scheduled to be released in the very near future.

Again, if you want to make use of the tons of tweaks, additions and improvements, grab it, and test with your apps!

On the JavaScript side of things, Prototype has seen lots of updates lately, and this new improved version is part of the Rails release candidate, so don’t miss it.

image image

January 05, 2007 02:34 PM

Firebug reloaded

Firebug, the DOM messin’ around and JavaScript debugging tool everyone loves, is nearing it’s 1.0 release.

New and improved features include:

  • Live HTML and CSS editing
  • CSS metrics
  • Network activity monitor
  • JavaScript profiling
  • Pimped error messages
  • Flexible layout (can run in its own window!)

It’s currently in closed beta, but will hopefully arrive soon.

Check out the all-new firebug site, www.getfirebug.com.

Two thumbs up for Mr. Hewitt and easing the pain the web development can be. Maybe it can be fun after all…? :)

image image

January 05, 2007 11:41 AM

Mauricio Fernandez image

eigenclass.org 'Happy 2007!' Ruby contest, Sat 2007-01-06 20H UTC

code.png

  1. download script
  2. flex Ruby muscle, have fun and crack code
  3. submit confirmation code to eigenclass.org
  4. claim chance to win very modest prize

update.png I'm releasing the code on Sat. 2007-01-06 20H UTC (barring technical problems).

Stay tuned to the RSS feed for more details...

Read more...

image image

January 05, 2007 11:35 AM

Zenspider image

image_science 1.1.0 Released

image_science version 1.1.0 has been released!

sudo gem install image_science

http://rubyforge.org/projects/seattlerb

ImageScience is a clean and happy Ruby library that generates
thumbnails -- and kicks the living crap out of RMagick. Oh, and it
doesn't leak memory like a sieve. :) For more information including build steps, see http://seattlerb.rubyforge.org/

Changes:

1.1.0 / 2007-01-05

  • 3 major enhancements:
    • Added resize(width, height)
    • Added save(path)
    • All thumbnail and resize methods yield instead of saving directly.
  • 1 minor enhancement:
    • Will now try to use FreeImage from ports if /opt/local exists.
  • 2 bug fixes:
    • Fixed the linker issue on PPC.
    • Rakefile will now clean the image files created by bench.rb

http://rubyforge.org/projects/seattlerb

January 05, 2007 10:24 AM

been quiet lately

I've been quiet lately, both bloggy and email (sorry if I haven't gotten back to you!). I think I'm hitting information overload and my brain is pushing back. That said, I'm going to try to actively fix this. I have a bunch of stuff to release and even more stuff sitting around that could be blog-fodder. Hopefully from here on I'll be publishing daily at least until I'm through my current blog-fodder queue and the releases...

January 05, 2007 10:18 AM

Ruby on Rails image

DailyKos considers Ruby on Rails

Earlier this week, Hunter, uber technocrat at DailyKos.com started talking about how they will build the next version of DailyKos. The discussion has been going for a day or two now with over 700 comments as I write this.

While DailyKos is the highest-traffic political blog in the US, I don't think it's particularly newsworthy that they are considering Rails. In fact, I think it's quite the opposite. What I do find interesting is the evolving discussion about the choices. Hunter essentially set out Perl/mod_perl, Python/Django and Ruby/Rails as the main choices. What people have to say about the differences and why they would choose one over the others makes for some really I-should-have-been-in-bed-an-hour-ago reading. Some of what people think they know about Ruby and Rails seems to be out of date or otherwise misinformed, but there are some good arguments on all sides.

If you are gearing up to have a conversation with management about picking Rails for a big project, take a read to see in one place all the arguments you will have to deal with!

January 05, 2007 07:27 AM

Obie Fernandez image

Links for 2007-01-04 [del.icio.us]

January 05, 2007 06:00 AM

Ruby on Rails image

Rails 1.2: Release Candidate 2

This is it. We’re a mere two shakes of a lamb’s tail from releasing the final version of Rails 1.2. But before we light the fireworks and pop the champagne, we’ll just do one itsy, bitsy, tiny test run. Like wearing protection glasses in downtown Copenhagen on New Year’s. You know, just for precautions.

So please do give it a good run. We’re looking for STOP THE BOAT and HOLD THE PRESSES kind of issues for this one. Nothing else will stop it (but please do report every thing you find any way).

For a reminder on how to install and what’s new, see the release notes for Release Candidate 1. We also did a series of highlights for Active Record, Action Pack, and Active Support. Read those and hold your breath in anticipation. Unless a surge of heinous issues appear, we’re expecting the final version to land some times next week.

Yay, hurray!

January 05, 2007 05:42 AM

Why TheLuckyStiff image

Instiki to Junebug

Want to move from Instiki to Junebug? I exported my Instiki as a zip of .textile pages and wrote instiki2junebug.rb to import my pages. Give it the Junebug username to assign the pages to and a path to the unzipped directory of files.

junebug wiki
cd wiki
ruby instiki2junebug.rb _why ~/instiki-dump

January 05, 2007 02:27 AM

Assaf Arkin image

Rounded Corners - 90

Color theory corrected. Color theory for developers was good at explaining HSB to this RGB geek, but according to Amy Hoy (recommended blog) … well you better read what she has to say.
Boxing day. Something to read in your spare time. (Thanks Sterling).
Open door. Sometimes a blog is a place to vent, sometimes a place [...]

January 05, 2007 12:59 AM

January 04, 2007

Robby Russell image

Those that Tend the Store need Dialogue

I’ve been keeping my eye on a series of blog posts by Chad Fowler, which he calls The Big Rewrite.

Today, Chad posted an entry titled, Who’s Tending the Store? He writes…

“the experts keep the old system running while the new system is being built. So, who builds the new system? Not the experts, that’s who. Usually, it’s people like me: technology experts. And while we’re banging away at the existing system’s UI, trying to figure out what needs to be coded, the domain experts are doing their jobs. Unfortunately, this means the domain experts aren’t watching the Big Rewrite very closely. Regardless of how good the team, if communication is impaired between the domain experts and the technology experts, things are going to move slowly, and wrong software is going to be created.”

I wanted to follow up on this issue as it’s an area of great interest to me.

I feel like this issue runs deeper and while it’s important to be mindful of the communication between domain and technology experts, it’s a good idea for each of us to take a break every few days (or everyday) to assess our perceptions in all areas of the project. More specifically, I’m suggesting that in order for us to be effective in our communication, we must make time to refactor our perceptions about the state of a project. From the design, to the development, to team communication, to the schedule, and all the way to customer satisfaction… or what Martin Fowler calls, Customer Affinity. These things are not static and we must see them as extremely dynamic variables… much more dynamic than our wonderful language of choice.

When Brian Ford and I started discussing Dialogue-Driven Development (d3), we were initially focused on an area that always seems to come up in projects. Client communication. From managing expectations to delivering the right product, d3 has become an essential tool in our team’s tool belt. We refactored our entire Design and Development process (and it’s always evolving) to focus on the things that we felt were the most important to a successful project. Clients come to us in search of expertise and guidance so that we can build them innovative solutions. When it comes to this process, clients deserve simplicity.

For starters, we’re misguided

If there is one thing that I have learned, it is that our initial perceptions are often misguided. We have to work really hard to think critically, not only of the problem we’re trying to build a solution for, but also of how we, ourselves, are actually looking at the problem. It’s easy to fall victim to tunnel vision. I often find myself having to take a step back from problems on a very regular basis. While I have no scientific proof to back this, it seems to feels natural for us to keep firing once we pull the trigger. It’s important to re-aim.

Chad raises a very important topic and leaves readers to think about the problem. After thinking about this, it’s my opinion that in order for the domain and technology experts to be effective, they need healthy collaboration. But, I feel like this applies to many other areas of our process as well.

Is there even a problem?

So, what is the solution? Better yet, what is the problem? Is there even a problem?

How can we avoid situations where communication becomes impaired? We’ve all been there. We know how to spot impaired communication, but how can we spot it… before we perceive it as too late? How can we recover from it? What causes the communication to break down? What if… it were possible to repair the situation?

These questions don’t have easy answers. These are complicated problems that reach far beyond the development community. These are the same problems that all members of organizations, communities, countries, and planets all face, each and every day.

Take action!

While it’s important to make sure we’re engaging in healthy dialogue through a project, bad things will happen. They are inevitable. As Agilists, we’re accepting this as a fact of (project) life and should be prepared to take action. If you see communication being impaired, it’s time to step up and help the team out. Otherwise, you’re only hurting yourself… and your colleagues.

“Be the change you wish to see in the world.”—Mahatma Gandhi

If these sorts of topics are of interest to you, I encourage you to join the Dialogue-Driven community and help us figure this stuff out!

image image image

January 04, 2007 11:18 PM

Why TheLuckyStiff image

Christoffer's Hpricot Goodies

So, in what ways have you guys extended Hpricot? I really enjoy this collection of accessories to Hpricot by Christoffer Sawicki, who also wrote the Hpricot-based HTML-to-feed library called Feedalizer.

He has one script that does gsub! on all text nodes in the document. Another script is for generating tables of contents from the headers on an HTML page. I imagine that would go great with Markdown and Textile. (See also: del.icio.us/tag/hpricot.)

January 04, 2007 10:27 PM

O'Reilly Ruby image

Ruby declared TIOBE's Programming Language of the Year 2006!

Ruby is now in the top ten languages in the TIOBE index, and has been declared Programming Language of the Year for 2006 because it had the largest popularity increase in 2006 of all the languages tracked:

We are glad to announce that Ruby has become “Programming Language of the Year 2006″. Ruby has the highest popularity increase in a year of all programming languages (+2.15%). Runner up this year is JavaScript with +1.31%. Both languages are boosted by their corresponding frameworks, Ruby On Rails and Ajax. This might be a new trend. In the recent past it was necessary to have a large company behind the language to get it in the spotlight (Sun with Java, Microsoft with C#), but nowadays a killer app appears to be sufficient. Viral marketing via the Internet works! The winners of the last 2 years, PHP and Java, are the losers of this year. Other trends that are observed are the growth of dynamically typed languages and the fact that the difference in popularity between languages is getting less.

This is awesome… ‘nuf said.

January 04, 2007 10:16 PM

Edward Summers image

#9

22:01 edsu> i would try to separate them now before it's
too late :)
22:02 erikhatcher> it's never too late, but i certainly want
to keep this clean from the start

New Years Resolution #9 - never underestimate the power of a positive attitude…

January 04, 2007 07:49 PM

O'Reilly Ruby image

The joy of 'rolling your own' with Camping.

Beauty is in the eye of the beholder

In my experience, there are a few different attitudes when it comes to beautiful design. Many consider Rails to be a beautiful framework to work with. In it’s own right, I certainly would agree with these folks. If you’re willing to accept the 80/20 divide and the tool fits the job, it could be dreamy to work with Rails. But in my limited experience, I sort of feel like a decision to work with Rails is more or less an all-or-nothing decision.

Like a train that wants to go east but only has tracks running North to South, a change in course is going to create some major problems. I don’t think this is a bad design, that’s what a train is meant to do. But maybe for some jobs, you need a dune buggy. That’s where the little wheels come in.

The camping framework is designed in light of another definition of beauty, and that definition is closer to the austere. When I started a job in it, I asked the usual questions one might run into when dealing with a small web app. “Does camping support sessions|file uploads|static files”

The answers were, ’sort of’,'nope’,'nope’. But all three were also appended with a “but it’s easy to roll your own”. The rest of this article will show you one way to do all three, and hopefully show some appreciation for the simplicity of the task.

Sessions with Camping

There is optional support for sessions. To me, it totally rocks how easy these are to set up. Camping lets you use SQLite3 with zero config, so all you need to do is use the session library to create a schema, and you’re right off the ground in no time.

Straight from an actual job of mine, the relevant parts look like this.

require "camping/session
module Importer
include Camping::Session
end
def Importer.create
Camping::Models::Session.create_schema
end

Now in the rest of my app, the @state variable will hold a unique session that I can just stuff things in for the user, no further thoughts needed.

for example:

@state.my_attribute = "Chunky Bacon"

could be accessed throughout my app, maintaining state. Very cool.

The thing is, to a Rubyist with minimal rails experience, this kind of thing might make more sense. I *see* where the schema is being created, I see the library that’s in charge of my sessions, etc. And if I really wanted to, I can hack on those things without digging much deeper. This to me is a valuable tradeoff from ‘just works’ to ‘works easily and you can see how’. Now yeah, I’d be annoyed if I was looking for more high level support, but for what I was looking for, I saw this as ’super cool’

File Uploads

Note that the way I do this is a hack, but the joy of Camping is that’s okay! This particular app is meant to run locally, and all users to be considered equal, so I had no need for ACLs or any other constraints, which others may.

Here is the controller:

class Upload R '/upload'
def get
render :upload
end
def post
file = @input.File.tempfile.read
@state.mi.load(file) #does something with the file, using sessions
redirect Import
end
end

And the relevant bits of the view:

def upload
form :action => "?upload_id=#{Time.now.to_f}", :method => 'post',
:enctype => 'multipart/form-data' do
p do
input({:name => "File", :id => "File", :type => 'file'})
input.newfile! :type => "submit", :value => "Upload"
end
end
end

Nothing particularly magical here, and that’s the way I like it. This just creates the appropriate form, lets me select a file from my machine, whack the ‘Upload’ button, and then handle that in my controller. There are a ton of other ways to deal with this, and the more complicated they get, the more likely you’ll be to say something like “Maybe I should be using Rails”. But for simple needs, I like having this kind of “roll your own” power.

Static Files

I copied and pasted this code from the camping wiki, but again, I was awestruck by the coolness of the ‘if I need to tweak that, it should be easy’ effect.

require 'pathname'

module Camping::Controllers
class Static R '/static/(.+)'
MIME_TYPES = {'.css' => 'text/css', '.js' => 'text/javascript',
'.jpg' => 'image/jpeg'}
PATH = File.expand_path(File.dirname(__FILE__))

def get(path)
@headers['Content-Type'] = MIME_TYPES[path[/.w+$/, 0]] || "text/plain"
unless path.include? ".." # prevent directory traversal attacks
@headers['X-Sendfile'] = "#{PATH}/static/#{path}"
else
@status = "403"
"403 - Invalid path"
end
end
end

You can happily ride the little wheels too!

I realized that this was the kind of tool I was looking for. Something simple, basic, and super extendable. I’m not afraid of rolling my sleeves up, and sparse documentation isn’t enough to keep me away from code that seems cool. If you’re in the same boat, be sure to check Camping out. Most of my code here is either taken directly from the wiki page or via suggestions from the kind folks in #camping on Freenode.

A slight warning is that if you plan on working with the framework, give yourself some extra exploration time. The little wheels are *awesome*, but I can promise you you’ll spend more time on IRC and sifting blogs and wikis at first then you might for the equivalent Rails job. I personally think it’s well worth it for the minimal web needs I have, and even if you don’t have a pressing need for a minimal tool like this, it’s great eye opener to the benefits of a simple design.

January 04, 2007 07:48 PM

Why TheLuckyStiff image

(Poignant) Guide Earlies

As I’m wrapping up the 8th chapter of my obscure Ruby book, you might be interested in a sneak peek at some of the art going into this 20-page fully-illustrated chapter. The Poignant Guide Earlies set on flickr has just a few scans.

This weekend I’ll also be posting some scans from Expansion Pak No. 2, which covers packaging libraries. This expansion pak will have appearances by Spiderman, Indiana Jones, various illegal Windows product keys, illegal scans of sheet music—in short, a pile of things which will render the book unprintable. With any luck, the first illegal programming manual.

January 04, 2007 07:18 PM

Jamis Buck image

assert_xml_select

Yeah, I’m on a real testing kick these days. Today’s TADFALAICKIU is a little trick you can play with assert_select.

Out of the box, assert_select works only with HTML documents. If you try it on an XML document (like, say, an RSS or Atom feed), you’ll more than likely see warnings about the document being malformed. It’s easy enough to work around, though.

The trick is to define your own HTML::Document instance before calling assert_select. When you define your own instance, you can pass some optional parameters that make HTML::Document play nicely with XML:

1
2
3
def xml_document
@xml_document ||= HTML::Document.new(@response.body, false, true)

end

The second parameter says whether you want to parse the document in strict mode or not. “False” is the default; if you set it to “true”, you’ll get an exception (instead of a warning) whenever the parser hits what looks like a malformed document.

The third parameter says whether or not the document is an XML document or not. It defaults to “false”, meaning that, by default, only HTML documents are parsed. Here, we set it to “true”.

Once you’ve defined your custom document, you just need to define your assert_select wrapper:

1
2
3

4
def assert_xml_select(*args)
@html_document = xml_document
assert_select(*args)

end

The assert_select method then will reuse the existing html_document value. Nothing to it! Just put these two methods in your test/test_helper.rb file, and you’re all set.

(Caveat: the above won’t work if you’re trying to use assert_select on XML returned via RJS, since when assert_select parses the RJS response to extract the document, it builds it’s own html document.)

January 04, 2007 04:51 PM

Chad Fowler image

Who's Tending the Store?

(This article is part of the Big Rewrite series.)

While we’re all in the back creating the next revision of a product, who’s tending to the day to day issues of the existing product? Typically, it’s the domain experts and the original implementers of the product.

Regardless of our intentions, day to day life and in-your-face time-sensitive issues can very easily steal all of the attention from a Big Rewrite. Screaming customers need their problems solved. Outages and serious bugs need to be fixed. Enhancements have to keep rolling in if your project takes as long as projects tend to take. Somebody has to do these things. Training new people is hard and doesn’t seem to make sense. If we’re getting rid of a system, why would we train someone how to maintain it?

So, the experts keep the old system running while the new system is being built. So, who builds the new system? Not the experts, that’s who. Usually, it’s people like me: technology experts. And while we’re banging away at the existing system’s UI, trying to figure out what needs to be coded, the domain experts are doing their jobs. Unfortunately, this means the domain experts aren’t watching the Big Rewrite very closely. Regardless of how good the team, if communication is impaired between the domain experts and the technology experts, things are going to move slowly, and wrong software is going to be created.

January 04, 2007 03:59 PM

Dan Webb image

From The Archives: Cleaner Callbacks With Partial Application

Here’s a really simple example:

function adder(num) {
return function(a) {
return a + num;
}
}

This function returns functions that add the given number to the argument:

var plus5 = adder(5);
plus5(7); //=> 12
plus5(1); //=> 6

This works because the returned function remembers the value of num originally passed into adder(). This is behaviour is called a closure but you can read more about them elsewhere. Let’s get on to how you can apply this technique.

function map(arr, iterator) {
var narr = [];
for (var i = 0; i < arr.length; i++) narr.push(iterator(arr[i], i));
return narr;
}

This function is very simple version of the handy map method as implemented in many scripting languages like Python and Ruby. Essentially, it takes an array and a function then loops through the array passing each value in the array to the iterator function. It then returns a new array which contains the returned value of each function call.

var nums = map(["1", "2", "3"], parseInt); //=> [1, 2, 3]

function getElement(id) {
return document.getElementById(id);
}

var els = map(['a-div', 'a-form'], getElement); //=> returns an array of DOM Nodes

Now say you wanted to call a method on each of these such as toUpperCase(). You could do this:

var caps = map(['a', 'b', 'c'], function(letter) {
return letter.toUpperCase();
});

But what if you find yourself wanting to call lots of methods on objects in map(). You can generalise with a partially applied function:

function callMethod(method) {
return function(obj) {
return obj[method]();
}
}

This returns a function that will call the given method on any object you pass it:

var upperCase = callMethod('toUpperCase');
upperCase('a'); //=> returns 'A'

Now you can use this for your function in map:

map(['a', 'b', 'c'], callMethod('toUpperCase')); //=> ['A', 'B', 'C']

How elegant is that? This is just a simple example but lets get on to how this helps us with callbacks. Say we have an ajax function called request. It’s takes a url and a callback function for when it’s loaded. We want to update an element with the response:

request('comment.php', function(resp) {
document.getElementById('item').innerHTML = resp.responseText;
});

We can generalise the update callback with a curried function like this:

function update(id) {
return function(resp) {
document.getElementById(id).innerHTML = resp.responseText;
}
}

Now we can write our request call like this:

request('comment.php', update('item'));

Nice eh? How about if we made a whole raft of other curried functions to automate other types of response:

request('data.json', sendTo(processData));
request('form.php', updateForm('comments'));
request('time/now', insertAfter('header'))
request('thing.rjs', evaluateResponseIf('text/javascript'));

sendTo(), updateForm() and evaluateResponseIf() all are functions that return pre-built callback functions for common tasks, the implementation of which is left as an exercise for the reader (I hate it when people say that…well, back at ‘cha blogosphere!). In a large body of code creating a small amount of functions like this can make your code much more readable and maintainable.

There are tonnes of ways of using partial application in your scripts, not just for callbacks. I’d really like to see some of the libraries using techniques like this to simplify the function calls for common cases…

new Ajax.Request('entry/create', postFormAndUpdate('formname', 'mydiv'));

…would be quite nice. But of course, you can make your own.

January 04, 2007 02:49 PM

Ruby Quiz image

Word Search (#107)

by Daniel Finnie

Today's quiz would've been most useful in elementary school, where over half of the homework assignments were word search puzzles. The concept of these puzzles is simple enough that an elementary school student could understand it: given a box of letters, find a line containing the letters of a specified word in order.

For example, find the words ruby, dan, rocks, and matz in the following text:

U E W R T R B H C DC X G Z U W R Y E RR O C K S B A U C US F K F M T Y S G EY S O O U N M Z I MT C G P R T I D A NH Z G H Q G W T U VH Q M N D X Z B S TN T C L A T N B C EY B U R P Z U X M S

The correct answer in the correct output format:

+ + + R + + + + + ++ + + + U + + + + +R O C K S B + + + ++ + + + + + Y + + ++ + + + + + + + + M+ + + + + + + D A N+ + + + + + + T + ++ + + + + + Z + + ++ + + + + + + + + +Y B U R + + + + + +

Notice that the words can go backwards and diagonally, and can intersect one another. Searching is case insensitive.

The word search solver should accept input entered by the user after running the program, i.e., not exclusively through STDIN or a file, by entering the puzzle line by line, pressing return after each line. A blank line indicates the end of the puzzle and the start of the comma separated words to find. The following example shows how a user would enter the above puzzle, with descriptive text from the program removed.

$ ./wordsearch.rbUEWRTRBHCDCXGZUWRYERROCKSBAUCUSFKFMTYSGEYSOOUNMZIMTCGPRTIDANHZGHQGWTUVHQMNDXZBSTNTCLATNBCEYBURPZUXMSRuby, rocks, DAN, matZ

Now, by itself, this quiz is fairly simple, so I offer an additional challenge. Write a beautiful, extensible, and easily-modifiable program without looking at the extra credit before starting. When you're done, try implementing extra credit options using less than 5 or 6 (reasonable) lines of code.

* An output format superior to the one given. The output format given should remain the default unless both formats don't differ on a textual basis. That should sound cryptic until pondered, I can't give too much away!* Allow for "snaking" of answers, in other words, the letters composing a word don't have to be in a straight line.* An option to give a hint, i.e., "The word ruby traverses the bottom left and bottom right quadrants."* Decide what to do with accented letters.* Allow for wildcard letters.

January 04, 2007 02:14 PM

Pat Eyler image

Abandoned Projects, Bus Proofing, and a Draft Directive

I'm glad the people behind RubyForge have come out with a formal plan for handling 'abandoned' projects. I don't like the decision they made, but it's their's to make, so I guess I can't argue. Instead, I'd like to make sure I 'bus proof' my projects — if I get hit by a bus (or otherwise drop off the 'Net),

To me, running a project is both an opportunity and a responsibility. In starting

January 04, 2007 01:59 PM

Zenspider image

2006 in Review

As I semi-jokingly stated for _why's Year in Review, 2006 for me could best be summed up by: "release lecture release consult release overwhelmed release conference release".

January 04, 2007 10:13 AM

Jon Tirsen image

ActiveMessaging: New home and new maintainer

ActiveMessaging now has a new home at Google Code. As I barely have time to even post to this blog any more we also have a new maintainer: Andrew Kuklewicz.

Please direct all questions, thoughts, ideas to the new mailing list.

image

January 04, 2007 06:19 AM

Michael Koziarski image

Links for 2007-01-03 [del.icio.us]

January 04, 2007 06:00 AM

Obie Fernandez image

Links for 2007-01-03 [del.icio.us]

  • InfoQ: Evolving Embedded Domain Specific Languages in Java
    They list some conclusions at the end, including the need to make sure a framework always works well in a modern IDE, that scaling EDSLs into complex languages may not be a good idea as the complex cases make the code harder to read, and that for the most
  • Speed up page loads (in Ruby on Rails)
    By using a wildcard subdomain or manually setting dns so that you spread out the static assets over a few different subdomains, you let the browser open two connections per subdomain so all the assets will download in a more parallel fashion. This can be
  • Jay Fields Thoughts: Rails: Enterprise Ready
    Jay says "yes" and lists his reasons. Good information about his current Rails project for ThoughtWorks, which is currently the largest enterprise Rails project that anyone is aware of.
  • The Pochi Superstar Mega Show! » Projects
    The goal of YM4R is to ease the use of the Google Maps and the Yahoo! Maps Building Block API’s from Ruby and Rails. Lately support for the Mapstraction library has also been added.

January 04, 2007 06:00 AM

Assaf Arkin image

Rounded Corners - 89

Suckbuster. From David Platt, a blog that chronicles software that sucks, and software that just works. And he’s asking for your help identifying the sucky and the worky.
The road to Lisp. Arto Bendiken takes on the challange and presents some of the better arguments I’ve read.
Cut off. And it still doesn’t work.
Next step. Brian Oberkirch [...]

January 04, 2007 04:22 AM

Jamie van Dyke image

Simple AJAX and Inline Javascript with Rails

I've noticed a lot of people asking questions about ajax, rjs, scriptaculous and other whizzy cool effects lately. So I thought I'd document a couple here so there's less confusion about some of the simpler effects. I've included an element toggle on a hyper link, a simple div that updates with data from an action using link_to_remote, and others. Enjoy.

You'll learn effects like these: Video of ajax effects

Prepare

All of these examples assume you have included the default javascript files in your application.rhtml file:

<head>
<%= javascript_include_tag :defaults %>
</head>

Toggle

The first of our simple effects is going to have to be the simple toggle (hide/show) of a div element. There is no remote call used in this, it simply uses javascript (generated by our ruby code) to show and hide a element of our choice.

<%= link_to_function "toggle with my div", "Element.toggle('to_toggle')" %>
<div id="to_toggle">
Now you see me, now you don't!
</div>

Remote

Next we're going to fire an action from a link_to_remote and then update a list of items on the page, this involves multiple code pieces in different files, keep up.

## app/views/words/index.rhtml
<ul id="sentence">
<li id="word_1">baby</li>
<li id="word_2">unzip</li>
<li id="word_3">my</li>

</ul>
<%= link_to_remote "WHAT?!?", :url => { :controller => 'words', :action => 'update' },
:loading => "Element.show('loading')" %>
<div id="loading" style="display:none;">Loading...</div>

## app/controllers/words_controller
def update
@word = "laptop bag!"
return if request.xhr?
end

## app/views/words/update.rjs
# hide the loading text
page.hide 'loading'
# insert a new li into the element with an id of sentence
page.insert_html :bottom, 'sentence', "<li id='word_4'>#{@word}</li>"

Notice how we use the same name for our rjs file as we did for the action we called, and then we ask the controller to return if the request was an xml http request (which is what ajax uses). This way if we want to do both rjs and standard requests with the update action we can.

I also demonstrated the use of a loading div here, but you could use a loading image as well, like a spinny circular thing or dots...or whatever takes your fancy.

Highlight

Let's modify the above example to highlight the new element when it arrives, this one's far too easy. Add this to the bottom of update.rjs:

page.visual_effect :highlight, 'word_4', :duration => 3

Now when the element is added, you'll have your attention drawn to it. The duration can be left off because it's optional and defaults to 2 seconds, I just wanted to make you aware that it's there.

Blind

Again, modify our existing call and make it slide down instead of just appear, change the update.rjs to this:

# hide the loading text
page.hide 'loading'
# insert a new li into the element with an id of sentence
page.insert_html :bottom, 'sentence', "<li id='word_4' style='display:none;'>#{@word}</li>"
page.visual_effect :blind_down, 'word_4', :duration => 2

We added to our li item a style of display, and set it to none. This is standard inline css markup, so when the item is added to our page it's hidden. Then we use the blind_down visual effect to slide it down with a duration of 2 seconds.

Simmer

I hope this helps all the ajax beginners get started with effects you can play with, be sure to check out the Rails api documentation for more scriptaculous effects.

Any questions boys and girls?

image image imageimage

January 04, 2007 12:27 AM

January 03, 2007

Ezra Zygmuntowicz image

New Nginx.conf with optimizations

I have been working on optimizing my nginx.conf file as I use it on more and more sites. Thanks to folks on the nginx and mongrel mailing lists for some of these fixes. Main improvements is in gzip of dynamic and other content as well as setting the proxy buffers to 0 and a few improvemets in the proxy header settings. This conf also includes a second vhost for ssl that points to the same mongrel cluster so you can hanlde ssl and non ssl with the same cluster and rails request.ssl? helper will work correctly.

Another big improvement is with static file handling. The credit on this one goes to Zed Shaw. He notcies that the rewrites and regex tests for rails cached pages were getting run for every request including static images. So a request for /images/foo.jpg woudl get served in this manor:

/images/foo.jpg/index.html # no file found continue
/images/foo.jpg.html # no file found continue
/images/foo.jpg # good send it!

This is obviously a performance hit for static files as it has two extra regexes and two extra file stats for every static image. Suck, I wish I found this sooner. To fix this all we need to do is add this test right at the top before the other rewrite tests:

# If the file exists as a static file serve it directly without
# running all the other rewite tests on it
if (-f $request_filename) {
break;
}

In my benchmarks this does increase the speed of static files about 8%. Also allowing gzip on HTTP 1.0 requests made sure that the proper static assets are gzipped when possible. Also we force all proxied requests to be gzipped if they are the right content type. I also added more gziped content types and corrected a wrong one for javascript.

This is an important lesson about your production environment folks. With regards to what you accept as gospel from someone like me. “Trust but verify”. Zed was trying to track down how to do a custom rewrite for alternate cache directories and so he at my behest turned on the debug logging and consequently saw the rewrites happening on every static file. I haven’t been in the rewrite log for a while since I thought my config was good. So when you get config files from people like me off the net, please trust but verify on your own systems.

This new config is running close to 100 instances of nginx at Engine Yard. Nginx has proven to be an excellent choice for a front end proxy balancer for mongrel. It beats apache in all my tests now as far as non gzipped proxy requests, static file requests and it ties with apache for gzipped proxy requests. And its about 30 times more lightweight then apache.

If you were holding off to try nginx until it was proven out by others then let me tell you it has proven itself to me time and time again already as a very easy to manage, high performance options for rails deployment on mongrel. I don’t personally use apache2.2 right now for anything other than mod_svn for subversion over HTTP. But there is stirring of upcoming support for nginx and svn over webdav so stay tuned. When that happens I will happily drop apache from our rotation entirely. Of course take this with a grain of salt as always, I don’t have to support any php apps or legacy stuff right now, just rails. I haven’t personally used php with nginx yet but I see others getting fantastic results so I am not worried for when I may need it.

All in all this new config file performs significantly better then my old one. Somewhere on the order of 20% total improvement overall over the last config file. I have updated the link to poitn from the old article to the right confi file and I am linking it here again for your enjoyment:

New Nginx.conf

January 03, 2007 10:28 PM

Jamis Buck image

rcov

Tip of the day: rcov.

Writing tests is all well and good, but how do you know when your application is sufficiently tested? Especially when you’re just learning how to do automated testing, it can sometimes feel pretty arbitrary. However, there are many different metrics for evaluating the efficiency of your tests, and one of the simpler to measure is code coverage. How much of your code do your tests exercise?

Mauricio’s “rcov” utility does just that. You use it to run your tests, and it then reports a percentage (total, as well as per file) of how many lines of code were executed. It even gives you a view of each file, with the untested lines in red! Really, really helpful. Your tests will run slower under rcov, but not much slower—and it is incredibly faster than other previous tools. Also, it works really well with Rails applications.

Now, those of you that are testing gurus will be quick to point out that relying solely on code coverage can be dangerous, and I will agree. Code coverage should not be the only metric you use to evaluate your tests. Ensuring that every line of code has been executed at least once does not even come close to guaranteeing that your application is correct, but it is a lot better than shooting tests randomly into your domain and hoping for the best.

Besides simple code coverage, others in the Ruby community are working all the time on different techniques for testing. You could do a lot worse than to follow what Ryan Davis is concocting with his ZenTest suite of tools.

January 03, 2007 10:09 PM

Geoffrey Grosenbach image

A Hodel 3000 Compliant Logger for the Rest of Us

The Rails Analyzer Tools are a very useful way to keep tabs on the performance of your site. They were written by Eric Hodel and have been open-sourced to the community by the Robot Co-Op.

The problem is that you need to install and run SysLogLogger to make it work. If you have more than one Rails app on a box, or if you don’t have root access to the box, or if you are on a shared host, you are out of luck.

No longer!

Install the Gems on Your Server

gem install production_log_analyzer
gem install rails_analyzer_tools

Install the Hodel3000CompliantLogger in your Rails app

Download the logger replacement and put it in your lib directory. (I’ll make this into a proper plugin soon.)

In the Initializer section of environment.rb, add

require 'hodel_3000_compliant_logger'
config.logger = Hodel3000CompliantLogger.new(config.log_path)

Run your app

For some reason, the standard script/server forces logging to work the old way. If I run mongrel_rails start, it works fine. I’m also running a production app with mongrel and it works as expected.

If you tail -f log/development.log you should see something like this:

Jan 03 10:08:09 topfunky rails[4535]: Rendered shared/_menu (0.14430)
Jan 03 10:08:09 topfunky rails[4535]: Rendered shared/_flashes (0.00882)
Jan 03 10:08:09 topfunky rails[4535]: Completed in 1.70117 (0 reqs/sec) | Rendering: 1.61409 (94%) | DB: 0.02340 (1%) | 200 OK [http://localhost/products/capistrano-concepts]

Analyze

Deploy your app, or just try this out locally from the command-line.

$ pl_analyze log/development.log

Request Times Summary: Count Avg Std Dev Min Max
ALL REQUESTS: 33 0.226 0.304 0.005 1.695

OrdersController#show: 6 0.071 0.112 0.005 0.316
ProductsController#show: 3 0.306 0.061 0.231 0.381
ProductsController#home: 2 0.318 0.068 0.249 0.386
OrdersController#index: 2 0.328 0.206 0.123 0.534
PagesController#show: 2 0.432 0.047 0.385 0.479
ProductsController#index: 1 0.279 0.000 0.279 0.279

Slowest Request Times:
OrdersController#index took 0.534s
PagesController#show took 0.479s
ProductsController#home took 0.386s
PagesController#show took 0.385s
ProductsController#show took 0.381s

# DB times and Render times follow

rails_stat is also nice for seeing a live report of the performance of your app.

$ rails_stat log/development.log

~ 0.9 req/sec, 14.2 queries/sec, 19.9 lines/sec
~ 0.3 req/sec, 14.1 queries/sec, 17.0 lines/sec

Once more, with feeling!

Run the report in a cron task and send the results to yourself via email (see the -e flag to pl_analyze), or automate the reporting with Capistrano.

desc "Analyze Rails Log instantaneously"
task :pl_analyze, :roles => :app do
run "pl_analyze #{shared_path}/log/#{rails_env}.log" do |ch, st, data|
print data
end
end

desc "Run rails_stat"
task :rails_stat, :roles => :app do
stream "rails_stat #{shared_path}/log/#{rails_env}.log"
end

For more details on Capistrano, buy the new PeepCode Capistrano Concepts screencast.

And again, from the top

For extra credit, use my Mint Pepper plugin and my Mint Rails Plugin to put nightly data into the database (also requires the setup of logrotate, to be discussed later).

Note

Remember, this is not about maximum performance. These reports show you the actual performance of your app as it is being browsed, not the theoretical maximum performance.

Shameless Advert

January 03, 2007 07:00 PM

Stefan Saasen image

Ruby 1.9 with YARV - Ruby is getting faster

As mentioned here Ruby trunk now contains YARV. YARV is a Virtual Machin for Ruby and Ruby trunk is what will become Ruby 1.9.1 (it is 1.9.0 as of now).

The benchmark looks really promising.

image image image

January 03, 2007 06:59 PM

Soundboard Beta released

Nifty little application for Mac OS X.

SoundBoard ist an Application to play sounds. Yeah. You can define soundsets and load sounds into them. All sounds are accessible via the dock menu for quick intervention :)"

read more... | digg story

image image image

January 03, 2007 05:41 PM

Chad Fowler image

Justifications and Lies

(This article is part of the Big Rewrite series.)

To add to the stress of the Big Bang comes another, mostly people-related issue. Almost all technology rewrites are driven by some technologist. Behind almost every technologist pushing for a Big Rewrite is a business person saying “But, why?” The question is valid. The product already works. It’s successful enough to even consider re-plumbing it, so we must have already gotten something right, no?

So, then come the justifications. They start with the real reasons the software is being rewritten (but usually censored to avoid the technologist looking like he or she screwed up big time on the initial development of the product). The system will be more maintainable. It will be easier to add features. “Oh yea? So we can do more features faster?” “Uh, yea.” “How much faster?” And so on.

As those discussions get heated and prove unsatisfactory, the list of promises gets longer. The system will be more scalable. System response time will improve for our customers. We will have greater uptime. And so on.

It’s rare, in fact, that a technology rewrite can deliver on all these fronts. A J2EE Web application may not prove in practice to provide higher availability than a mainframe application. Rails might be a more flexible and productive environment for a developer, but Rails apps slightly underperform equivalent PHP apps. So, you don’t sell Rails as something that will be faster than PHP. You sell it as something that is more flexible and maintainable, and will perform reasonably compared to a PHP application.

The piles of justification lead to piles of additional work and/or piles of mismatched expectations and disappointment after release.

January 03, 2007 05:13 PM

The Big Bang

(This article is part of the Big Rewrite series.)

When you do a technology rewrite, you want things to be clean. That’s usually a major goal in a project like this. And at the beginning of a Big Rewrite, while you’re still wide-eyed and hopeful for your application’s ultra-elegant, scalable, maintainable future, you’re faced with a question: Should we deliver the Rewrite incrementally or all in one big release? Now, imagine your existing infrastructure is a home-grown Oracle Pro*C-based CGI framework with its own cookie-based authentication mechanism which relies on carnal knowledge of an aging mainframe ERP system. Incremental deliveries means making the new technology work within the dirty framework of the old system. One big release would mean we could just turn off the old system, turn on the new one, and keep our new efforts isolated and pristine.

In most cases, it’s the Big Bang approach that wins the argument.

Now picture yourself as a developer or project leader nine months into this project. The old system, still in production, has been patched and enhanced along side the new one as you’ve been developing it. You haven’t had time to keep up with each and every change that took place in the old system. As a result, on top of behavioral changes, you’ve got an ever-evolving database schema to port to the new platform. And the new system’s wish list has gotten so out of control, that there are major differences between the old and the new. To top it all off, working from the old system as a specification didn’t work, and you’re way behind schedule due to misunderstood requirements and rework.

The table has been set. The guests are on their third course. And now you have to come along and replace the table on which they’re eating without disturbing their meal.

On a big system with a lot of customers, data migration can be a huge problem. Not only do we have to keep track of what gets migrated when, but we have to actually perform the migration at some point. The Big Bang sounds like a lovely idea until you get to the actual event, and you realize it’s kind of like preparing for a world title boxing match when you know it’s the first and last time you’ll ever compete. The processes and software you have to create, the attention you have to pay before you can create an event like this is often as consuming, complex, and potentially disastrous as the system development effort itself.

But by making it a Big Bang release, you’ve maximized the chances that you’ll be behind schedule when you get to the end, and you’ve therefore maximized the chances that you won’t spend enough time preparing. This results in a bad time for both you and your customers.

Unfortunately, perhaps due to something intrinsic in human nature, this scenario is a cliche for Big Rewrite projects.

January 03, 2007 05:12 PM

Jamie van Dyke image

Testing with my new Theme

I love TextMate, it's beautiful, efficient, and extensible to the nth degree. So as I was running though some tests I thought I'd make my own theme based on Sunburst, and here's what I came up with:

New Theme

I'll bundle it up as a theme if anyone is interested, but for now it's mine, all mine!

Edit: Grab the succulent theme from here.
Please comment below if you use /like/dislike the theme, thanks.

image image imageimage

January 03, 2007 04:59 PM

Pat Eyler image

Representing Ruby Objects

Just a note, this post is a work in progress, and should see updates about twice a week. Hopefully it's useful even while it's incomplete.

Representing Ruby Objects
To start with, it's probably worth describing a bit about how rubinius source is laid out, then we can dive into the specifics about Ruby objects.

The rubinius source tree is laid out like this (omitting stuff we're not interested

January 03, 2007 11:12 AM

rubinius Internals Guide

A while ago, Mauricio Fernandez posted an excellent Guide to Ruby Internals. Since YARV, JRuby, and rubinius are all drawing more attention, I thought it would be great to see parallel guides to each of these platforms as well. I'm going to try to take on rubinius, but I'll happily link to anyone doing the others.

Here's a quick table of contents. It's not complete, nor are the sections

January 03, 2007 10:52 AM

Assaf Arkin image

Rounded Corners - 88

Double of half. “But I think it worth it - to sacrifice three times slowdown for doubling the speed almost arbitrarily and almost effortlessly.” Freudian slip?
swap(ctrl, cmd) A handy reference to what every OS/X user knows, and what a non-OS/X user like me finds bewildering.
Eye candy. KDE4 promises some serious eye candy with SVG rendering. [...]

January 03, 2007 08:30 AM

Pat Eyler image

Author Interview: Christian Hellsten

This time around, I'm interviewing Christian Hellsten, the co-author of Beginning Ruby on Rails E-Commerce (I interviewed Jarkko Laine the other co-author here).

Christian, would you please introduce yourself?

Christian: I'm a father of two, a software consultant, and as of lately founder and CEO of Aktagon.

Why do you do outside of Ruby on Rails devleopment? Any hobbies?

Christian: I

January 03, 2007 08:08 AM

Michael Koziarski image

Links for 2007-01-02 [del.icio.us]

January 03, 2007 06:00 AM

Ads