Stay Beautiful
Mr Hansson has been winding people up recently, with his Twitter Controversy. But one of his more polite recent posts is about Seaside - a Smalltalk web framework that uses stateful objects on the server to allow a modal-style flow of control within your web application. One component receives a callback as the user clicks a link, it calls into another component and sits and waits until the second component returns control to the first - just like calling a subroutine.
I've made no secret of my love of Smalltalk - it's what attracted me to Ruby and Rails in the first place. There's a beauty about Smalltalk code (although please forgive any typos in the code below as I've not done any for a while) that you rarely see anywhere else, although Rails has it in places. I could go on for hours about:
under21s:= people collect: [ person | person under21 ].
Is that better than:
under_21s = people.collect do | person |
person.under_21?
end
Not much in it. Ruby has the question mark - I like that as it makes the code read better. But Smalltalk has less superflous punctuation to make it read better still. And I love the full-stop to finish the sentence.
How about:
nail needsHitting ifTrue: [ nail hitOn: #TheHead with: aHammer ].
Versus:
nail.hit(:on => :the_head, :with => hammer) if nail.needs_hitting?
Ruby has the if at the end of the sentence, which I really like - and it's even better when using unless. And Smalltalk has its slightly weird "everything is an object or message" ifTrue: method on the true and false instance variables that lead to something that is a bit less readable than the Ruby. But Smalltalk doesn't need the parenthesis. And blocks are passed as normal objects (not weird add-ons that may or may not be tacked on to the end and sometimes implicitly converted to Procs). And if is not a reserved word.
Recently I've noticed the Smalltalk creeping into my Ruby style. Things like:
validate(course, :against => template, :on => this_date)
Which is reasonable. But the brackets just kill me.
And then I had to write this:
form_for(:course_template,
:url => course_template_path(@course_template),
:html => {:method => :put} do | form |
# form.stuff
end
It's awful (yeah, yeah, I need SimplyHelpful).
What about, in config/routes.rb:
map.resources(:course_templates,
:member => {:build_courses => :get, :do_build_courses => :post}) do | course_template |
course_template.resources(:course_details)
end
They really ought to read:
courseTemplates:= map resourcesCalled: #CourseTemplates;
withAnAdditional: #GetMethod :called #BuildCourses :on #Members;
withAnAdditional: #PostMethod :called #DoBuildCourses :on #Members;
nesting: (map resourcesCalled: #CourseDetails).
Note: the nested call to resourcesCalled is actually sent to map, not to a nested object as in the Ruby original.
A literal translation would be:
map.resources_called(:course_templates).with_an_additional(
:get_method, :called => :build_courses, :on => :members).with_an_additional(
:post_method, :called => :do_build_courses, :on => :members).nesting(
map.resources_called(:course_details)
)
The semi-colon chains method calls together (assuming each call returns the original return value from map.resources_called. But it's really really ugly in Ruby.
The closest I can think of for this is:
map.resources_called(:course_templates,
:adding => [
GetMethod.called(:build_courses, :on => :members),
PostMethod.called(:do_build_courses, :on => :members)
],
:nesting => map.resources_called(:course_details)
)
which is a lot better but still pretty ugly (nested brackets - urgh).
Of course, map.resources is probably an instance of DHH's syntactic vinegar - I'm sure that in his mind you should never add extra calls as it breaks the nice clean REST architecture. Well tough. I think myserver.com/course_templates/23;build_courses describes what I want very succinctly.
It's definitely something that's on my radar now ... I want my Ruby and Rails code to be beautiful. Otherwise I may just be looking at Seaside in more depth.
No comments:
Post a Comment