x ||= y, Redux

Posted by Rick DeNatale Sat, 26 Apr 2008 15:11:00 GMT

A while back there was quite a thread on the Ruby-lang mailing list about the real semantics of the expression.
a[x] ||= some_value

In many books and articles on Ruby the form:

a <op>= b

Where <op> is an operator like + Is described as syntactic sugar:

a = a <op> b

While this is true in most cases, it isn’t’ true if the operator is ||.

This comes to light when the left hand side is a method call, to an accessor, or accessor-like method. For example

h = Hash.new("hello")
h[:fred] ||= ""
h #=> {}

Some find it surprising that the assignment doesn’t cause the hash to have :fred as a key. What this code snippet shows is that the assignment doesn’t actually assign anything if the left hand expression returns a logically true value. A Hash with a default value will return the default value when accessed by any key which is not present in the hash. Since h[:fred] returns the default value, the assignment doesn’t happen.

This affects any object which has ‘accessor’ methods. Here’s a class cooked up just to explore this aspect of Ruby.

class ChattyCathy

  def initialize(x=nil)
    @x = x
    puts "created x is now #{x.inspect}"
  end

  def x
    puts "x read x is #{@x.inspect}"
    @x
  end

  def x=(val)
    puts "x written, now #{val.inspect}"
    @x = val
  end
end

The purpose of this class is simply to let us see exactly when the x attribute is read and written. Now if we run this code

c = ChattyCathy.new(42)
puts "about to evaluate c.x ||= 43"
c.x ||= 43
c = ChattyCathy.new
puts "about to evaluate c.x ||= 43"
c.x ||= 43

We get the following output:

created x is now 42 about to evaluate c.x ||= 43 x read x is 42 created x is now nil about to evaluate c.x ||= 43 x read x is nil x written, now 43

Which clearly illustrates just when the assignment actually happens.

The real expansion of x ||= y

Matz explains that the real expansion of x ||= y is:

x || x = y

The expectation that x ||= y is the same as x = x || y, does seem reasonable to someone ‘coming from’ C or one of it’s derivative languages. As far as I can determine, C introduced the notion of assignment operators like += and -=. And K&R defined these assignment operators as a shorthand for x = x + y, etc.

On the other hand, although C has logical operators || and && which, like Ruby have ‘short-circuit’ evaluation, it doesn’t allow ||=, or &&= as assignment operators.

Since || is a ‘short-circuit’ boolean operator, the left hand operand expression is only evaluated if the right hand operand expression evaluates to a logically false value, i.e. either nil or false.

The way that Matz included ||= as an assignment operator makes perfect sense to me. The ||= assignment operator reserves the short-circuit nature of ||.

So what about x &&= y

Although I haven’t seen this discussed anywhere, &&= in Ruby has similar behavior:

c = ChattyCathy.new
puts "about to evaluate c.x &&= true"
c.x &&= true
puts "about to evaluate c.x = \"hi\""
c.x = "Hi"
puts "about to evaluate c.x &&= true"
c.x &&= true
created x is now nil about to evaluate c.x &#38;&#38;= true x read x is nil about to evaluate c.x = &#8220;hi&#8221; x written, now &#8220;Hi&#8221; about to evaluate c.x &#38;&#38;= true x read x is &#8220;Hi&#8221; x written, now true

So the expansion of x &&= y is x && x = y

Posted in  | 5 comments | no trackbacks

It's About Time!

Posted by Rick DeNatale Wed, 23 Apr 2008 20:17:00 GMT

The third edition of Agile Web Development With Rails is now in Beta.

Sam Ruby has become the third author, along with Dave Thomas and DHH. According to PragDave, Sam has converted the Depot App tutorial to be compatible with Rails 2, and the rest of the book is also being revised.

Posted in  | no comments | no trackbacks

Rails Integration Test File Upload Plugin

Posted by Rick DeNatale Fri, 18 Apr 2008 22:07:00 GMT

Some time ago, I wrote a rails patch which allows http file uploading in integration tests.

You just use the same TestUploadedFile class used in functional tests or controller specs if you’re an RSpec’er. So you can do something like.
    post '/upload' :file => TestUploadedFile("/path/to/blah.txt")

The patch detects a TestUploaded file amongst the parameters, and converts the request into a proper multi-part request.

It will work for both posts and updates.

If you’re running edge rails you’ve already got this. But many have asked for a version for earlier rails versions. At work, I’ve been working on an RSpec story which requires file uploading, and we’re using the 2.0.2 gem version of Rails for deployment purposes, so I whipped up a little plugin which patches 2.0.2 Rails with the changes from Rails changeset 8978. The plugin checks the rails version and throws an exception if it’s anything other than “2.0.2” since I haven’t tried this with anything earlier, and it’s not necessary for anything newer.

You can get it from git hub at git://github.com/rubyredrick/integration_upload_plugin.git

This also marks the first time I’ve used git for anything but gitting Rubinius.

Posted in  | Tags ,  | no comments | no trackbacks

RSpec Anti-Pattern - Don't Set @controller yourself

Posted by Rick DeNatale Wed, 26 Mar 2008 21:30:00 GMT

I was adding to an existing controller today at work and I was stumped because one of the examples in its controller spec was failing due to an exception thrown while rendering a view.

Normally RSpec controller tests, which are usually used to specify controller logic, bypass view rendering unless you specifically use the integrate_views method in the example group. The idea is that you should use view specs to specify the logic and output of views.

Since I was working in existing code, which pre-existed my being here, I’d followed some of the existing example groups in the file. These would typically look something like this:

describe HobbitController, "doing something" do

    before(:each) do
      @controller = HobbitController.new
      #.. more setup stubbing etc.
    end

   #examples
end

I finally realized that that first line in the before block was clobbering RSpecs ability to control whether or not views should be rendered. RSpec actually creates the controller instance variable for you, and extends it with a module which overrides the render method to allow integrate_views to control the rendering while allowing the expect_render expectation to work whether or not rendering actually happens.

So I’ve got a new task to clean up all the other controller specs.

Posted in  | Tags  | no comments | no trackbacks

Ch-ch-changes

Posted by Rick DeNatale Sat, 22 Mar 2008 20:45:00 GMT

Things have been hectic over the past month or so, and big changes have been in the wind.

As of the 3rd of March, I’ve been working full-time at Near Time as a Senior developer.

I really enjoyed the projects I did with Terralien and I can’t thank Nathaniel enough, but the opportunity to have a steady diet of work, and to work on a large-scale project with a talented group which is enthusiastic about my favorite tools and technologies like Ruby, Rails, and RSpec was just too good to pass up.

I must admit that I’m still adjusting to the idea of a 9-5 job (actually more like 9-7 or 8), and a 30+ mile commute instead of waking up the stairs, or out to the family room, but I’m having a blast.

I still plan to post my thoughts here, although perhaps a bit less frequently, albeit more frequently than over the past month.

Posted in  | no comments | no trackbacks

Best Practice Patterns, Accessors and Encapsulation

Posted by Rick DeNatale Fri, 15 Feb 2008 13:29:00 GMT

Kent's Autograph to me on STBPP One of the classics in the Smalltalk literature, which has also had a big influence on the Ruby community is Kent Beck’s “Smalltalk Best Practice Patterns”, which captures the best practices for designing and coding Smalltalk programs. Back when it was published, I used to see Kent a few times a year, and happened to be in the Bay area when he made an author appearance at the Computer Literacy Bookstore in San Jose, where I got my copy, and the autograph shown here.

The Ruby language has many similarities with Smalltalk, so much of Kent’s advice applies to Ruby. I frequently hear prominent Rubyists mention the book.

On the other hand, Ruby is not exactly Smalltalk, so Kent’s book isn’t an exact fit to Ruby. I’ve been wanting to start writing about adapting some of these patterns to Ruby for a while, so this article will hopefully be the first in a series.

The Motivation For This Article

Recently on the ruby-talk forum a thread discussing accessor methods vs. direct instance variable access came up. This was a hot debate topic in the Smalltalk community back in the 90s, and Kent addressed it in two competing patterns in the book, one of which Ryan Davis (a.k.a ZenSpider) brought up in the conversation.

Read more...

Posted in , ,  | Tags , ,  | no comments | no trackbacks

Yegge's At It Again!

Posted by Rick DeNatale Tue, 12 Feb 2008 14:42:00 GMT

Another thought provoking piece from Steve Yegge.
Well, we also know that static types are just metadata. They’re a specialized kind of comment targeted at two kinds of readers: programmers and compilers. Static types tell a story about the computation, presumably to help both reader groups understand the intent of the program. But the static types can be thrown away at runtime, because in the end they’re just stylized comments. They’re like pedigree paperwork: it might make a certain insecure personality type happier about their dog, but the dog certainly doesn’t care. – Steve Yegge

And he’s getting the predictable responses from the static-typing advocates.

One quibble I’ve got with what I’ve just quoted, is that, in many languages, static types aren’t just comments. In the C++ implementations I’ve looked at, for example, the typing is used to generate runtime code which relies on the typing done at compile time. The other day I wrote about instance variable access in Java, Smalltalk and Ruby. In C++ instance variable (field) access is static and based on offsets. If a type error get’s past the compiler, say by a bad pointer manipulation, the run-time code can access a non-existant variable, possibly clobbering something vital.

In fact this “bug” is possible not in spite of static type checking, but because the compiler uses static type checking to affect the code, and “throws away” the information needed at run-time to avoid it.

Posted in  | Tags ,  | no comments | no trackbacks

Agora disponível no português

Posted by Rick DeNatale Mon, 11 Feb 2008 13:18:00 GMT

Fabio Akita emailed me this morning to tell me that he had translated my recent article about variables in Ruby, Java, and Smalltalk into Portuguese.

I think this is the first time I’ve been translated!

Posted in  | no comments | no trackbacks

Whose Variable Is It Anyway?

Posted by Rick DeNatale Fri, 08 Feb 2008 21:14:00 GMT

The more I think about Ruby in relation to other object programming languages I’ve worked with, the more I realize that there’s a continuum of static vs. dynamic typing.

Ruby fits close to one end of that continuum. Understanding this can help understand how to best use the language. I recently had a quick look at Russ Olsen’s new book Design Patterns in Ruby and looked at his section on the observer pattern. I’d just posted to ruby-talk about this pattern, how it was implemented in Smalltalk, and a more Rubyish implementation. I’ll get to that at the end of this article, but first I really feel the urge to talk about instance variables.

If we view a type as a particular interpretation of a memory layout, I see something like this

Language Outside inside
Java static static
Smalltalk encapsulated static
Ruby encapsulated dynamic
Read more...

Posted in ,  | Tags , ,  | 3 comments | no trackbacks

Validating RSS Feeds with RSpec

Posted by Rick DeNatale Fri, 08 Feb 2008 15:38:00 GMT

One of my current Rails projects involves generating an RSS feed. While I was working on this the other night, it seemed to be working, so I deployed it to the staging server. Everything looked fine. If I fetched it with Firefox, the browser offered to let me subscribe to the feed with Google Reader, and if I used Safari I'd see a nice view of the feed just like I expected.

So I sent a note via our campfire to check it out, and a colleague replied that his Safari was saying that it was in an invalid format.

So I went to the W3 RSS Feed Validation Service and worked through the validation issues, after which his browser was as happy as mine.

Of course, having been through that, I wanted to make sure that RSS validation was covered in the specs for the project.

I went looking for an existing RSpec matcher, and found a matcher to validate XHTML but nothing for RSS.

I then found the feedvalidator gem which provides a Ruby interface to the SOAP interface to the W3 feed validator. You would think that W3 would be providing a REST interface! The gem already provides assertions for use with Test::Unit, so I just built an RSpec matcher.

class BeValidFeed
  require 'feed_validator'
  require 'tmpdir'
  require 'md5'

  def matches?(response)
    return true if validity_checks_disabled?
    v = W3C::FeedValidator.new()
    fragment = response.body
    filename = File.join Dir::tmpdir, 'feed.' + MD5.md5(fragment).to_s
    begin
      response = File.open filename do |f| Marshal.load(f) end
      v.parse(response)
  	rescue   
      unless v.validate_data(fragment)
        @failure = " could not access w3 validator to validate the feed."
        return false
      end
      File.open filename, 'w+' do |f| Marshal.dump v.response, f end
  	end
    v.valid?   
  end

  def description
    "be valid xhtml"
  end

  def failure_message
   @failure || " expected xhtml to be valid, but validation produced these errors:\n #{@message}"
  end

  def negative_failure_message
    " expected to not be valid, but was (missing validation?)"
  end

  private
    def validity_checks_disabled?
      ENV["NONET"] == 'true'
    end
end

def be_valid_feed
  BeValidFeed.new
end

I saved this as spec/be_valid_feed.rb

And in a view or controller spec, I can include this file, and test a response with:

response.should be_valid_feed

If you use this in a controller spec, you will need to tell RSpec to integrate_views, or you won't have much of a feed to check. If you use nested example groups, integrate_views needs to be inside the inner group.

Posted in , ,  | Tags , ,  | 4 comments | no trackbacks

Older posts: 1 2 3 4 ... 11