A while back, I released a tiny library called laze for making the use of lazy attributes easy in JavaScript.
I thought I’d do a post to provide some more context of how laze fits into my workflow in a node.js project. There are definitely some terrible things you can do with this library, but hopefully this post will outline the intended use and convince you to try it out.
Imagine I want to create a new server, and then start listening on a given port. I start out with some really tightly coupled code:
Server.prototype = {
start: function () {
var host = this.config.host || '127.0.0.1';
var port = this.config.port || 8080;
var server = http.createServer();
server.on('request', this.handleRequest.bind(this));
server.listen(port, host);
}
};
This code works well, but in my opinion it just does way too much. In here, we have logic for:
Imagine we want to start splitting this function up a bit. We’ll start with pulling the host/port configuration out.
Server.prototype = {
getHost: function () {
return this.config.host || '127.0.0.1';
},
getPort: function () {
return this.config.port || 8080;
},
start: function () {
var server = http.createServer();
server.on('request', this.handleRequest.bind(this));
server.listen(this.getPort(), this.getHost());
}
};
So this works pretty well actually – but if somewhere else in this object we’d like to have access to the host and port, we’re re-running the logic inside of `getHost` and `getPort`. Not a big deal for these quick functions, but something that did a bit more would make that approach just wasteful.
So we could proceed in one of two ways:
var Server = function () {
this.host = this.getHost();
this.port = this.getPort();
};
If we call the two methods from the constructor, we can have properties set that contain the proper host and port. This is nice – but crowding our constructor with calls to methods that aren’t needed *unless* start gets called. You can see that if these were time-intensive tasks – we’d end up wasting time for methods that may not be called at all.
Server.prototype.start = function () {
this.host = this.getHost();
this.port = this.getPort();
var server = http.createServer();
server.on('request', this.handleRequest.bind(this));
server.listen(this.port, this.host);
};
This approach is good – its made our start function a bit more complicated but the separation is correct. The one remaining problem with this approach is that if another method wants to access `host` or `port` before `start` has been called – they’ll both be undefined.
Laze uses `defineProperty` to give us another option. We can define properties that won’t be set until they are used. Then we get the best of all worlds. The host or port can be called at any time and have the proper values. And – once they’re called one time, they’ll hold onto their value for the next time without recomputing it. Let’s take a look at the code:
Server.prototype = {
start: function () {
var server = http.createServer();
server.on('request', this.handleRequest.bind(this));
server.listen(this.port, this.host);
}
};
laze.defineAll(Server.prototype, {
port: function () {
return this.config.port || 8080;
},
host: function () {
return this.config.host || '127.0.0.1';
}
});
If you want to – you could take this whole thing another step, and make the creation of the server lazy too.
Server.prototype = {
this.server.listen(this.port, this.host);
};
laze.defineAll(Server.prototype, {
port: function () {
return this.config.port || 8080;
},
host: function () {
return this.config.host || '127.0.0.1';
},
server: function () {
var server = http.createServer();
server.on('request', this.handleRequest.bind(this));
return server;
}
});
I hope this post gave a good overview of using lazy attributes in JavaScript with laze – if you’re interested in reading how it works check out the code (which is pretty simple), or go straight to the github page.
You can also install laze via npm:
npm install laze
I couldn’t find this practically anywhere, so I thought I’d write a quick post on how to test multi-part uploads with RSpec. The problem is that if you try to write something like:
post :photo, :file => File.open(path)
You’ll actually be sending the string “<File:…>” down as a request parameter. What you actually want is a bit more obscure, but works perfectly:
post :photo, :file => Rack::Test::UploadedFile.new(path, mime_type) # text/jpg
In Ruby, it can be really useful to know, in the flow of execution, the call stack within a certain method. For that we have Kernel#caller.
#caller returns an Array representing the current call stack, where each element is a String like “file:line in ‘name’”. Here’s an example:
def actually_do_it
caller.join("\n")
end
def do_it
actually_do_it
end
puts do_it
which will output:
ex.rb:8:in `do_it' ex.rb:11:in `<main>'
Today’s post was inspired by my friend Mat Brown.
So, in Ruby it’s quite possible to hide the class of an object, and make it pretend to be something else. Sometimes this can be useful – for example if you don’t want to extend a core object, but want people to be able to work with an object as if you had. A core example of this is how Rails *used* to treat ActiveSupport::TimeWithZone. You can take the concept pretty far:
class String
def class
Fixnum
end
end
So, the class is…
"hello".class # Fixnum
Then we get smart with Ruby, but the library implementers keep up with us:
"hello".is_a?(Fixnum) # false
class String
def is_a?(clazz)
clazz == Fixnum
end
end
"hello".is_a?(Fixnum) # true, gahhhh
Again and again, every time we think we’ve figured out the real class – we get stumped.
Luckily, there are a few ways that are normally not (and shouldn’t be) overridden:
Fixnum === "hello" # false
# which you can mess up with
class Class
def ===(obj)
if obj.is_a?(String) && self == Fixnum
true
elsif String === obj
false
else
super
end
end
Fixnum === "hello" # true
String === "hello" # false
And .. for the most fun, we can bind Object’s base implementation of #class against an object and call it:
Object.instance_method(:class).bind("hello").call # String
And wouldn’t you know it:
class Object
def class
if self.is_a?(String)
Fixnum
else
super
end
end
end
Object.instance_method(:class).bind("hello").call # Fixnum
Ruby has some nice sugar around rescuing from errors that may be thrown from a method. A lot of times, I see code like this:
def some_method
begin
danger_danger
true # good return
rescue Error
false # error return
end
end
But you can make it a bit nicer to do the same with:
def some_method danger_danger true # good response rescue Error false # error response end