Sunday, September 19, 2010

easy install node js.

if you've got your ear to to ground you'll know that the thing all the web dev early adopters are raving about it node js.

since yesterday, install it on ubuntu like this:

sudo add-apt-repository ppa:jerome-etienne/neoip
sudo apt-get update
sudo apt-get install nodejs


do it!

Friday, September 10, 2010

Run your ruby Gist on heroku

Gist is a great service on GitHub which serves up a copy-pasteable text boxes with full version control.

It's useful for sharing snippets of code around...

but what if you could run that code!

well, now you can! with GistRunner

just enter the gist id into the field, or copy-paste the url of the gist.

it'll download your gist and execute it on server!

insane? maybe.

it's pretty alpha, (wrote it all yesterday) so there is lots of room for improvement,

but when you just want to convince your friends that we should all go to base 12, by wipping up a quick base 12 times table.... you can!

base12 times table

base12 gist

Thursday, September 9, 2010

sneak a custom gem into heroku

today, I've been trying to get Wee running on heroku.

I have a custom version of the gem, and want to run it on heroku.

i looked down a few avenues, but decided they where all too complicated right now - I was having trouble getting something basic to work, if I tried something complex then that is just more stuff I will have to debug.

so my plan was: load by custom gem as normal code in the local directoy

> gem unpack wee

then, add to my config.ru:

libdir = "wee-2.2.0/lib/"
$LOAD_PATH.unshift(libdir)

now, when ever this is a line like require 'wee' it will look into the local wee-2.2.0/lib/ and find wee.rb instead of loading from the gem directory.

uploaded it to heroku and it worked!

p.s. the rest of the config.ru looked like this:

require 'continuations.rb'

app = Wee::Application.new { Wee::Session.new(Page.instanciate, Wee::Session::ThreadSerializer.new) }
run app

Sunday, August 22, 2010

getting started with DataMapper

I've just spent all day trying to get started with DataMapper

I've found a few gotchas:

say i have two model objects with a many to many relationship,
given two instances of those:
t = Thing.create
w = Whatever.create

creating a joining resource:

ThingWhatever.create(:thing => t, :whatever => w)

[t] == w.things #true
[w] == t.whatevers #true

#then create a second join resource from t to a new Whatever

ThingWhatever.create(:thing => t, :whatever => (w2 = Whatever.create))

[w,w2] == t.whatevers #false

I'm new to DataMapper so this was very confusing.

eventaully i discovered I could work around the problem with:

t2.reload
[w,w2] == t.whatevers #true

however, reload is not mentioned in the getting started documentation and it took me hours to figure out why it wasn't working.

It's a bit of a leaky abstraction. you can see the database through the cracks.

posted a ticket

I considered trying ActiveRecord but it smelled even leakier.

Monday, July 12, 2010

instance_eval weirdness in ruby

I've been doing a lot of meta-programming in ruby recently, and ruby people are always saying eval is dangerious, or that using it is a sign you don't know what you are doing... but when someone questions them they can't give a straight answer...

well, I just found one but it's about perl (and page two, which is more direct)

the link refers specifically to storing the name of a variable in a variable, the problem being that it can create collisions.

in perl:
$value refers to the value of the variable 'value'
$$value refers to the value of the variable that is named 'value'.

basically anything could end up in the variable, and if you change the value of that named variable you could change something important. particularity if it's an important variable that's core to the language like $0 or __FILE__. It sounds like this is a lot more dangerous in Perl, because variables are global by default. to define a local variable you have to say 'my $value'
no wonder perl people are against variable names stored in variables.

basically, it's about scope. ruby doesn't have this insane global variable by default feature.

but either way, if you only doing something boring like dynamicially deciding which variable your interested in, you can use hashes.

lets use eval for cool stuff!

like making some code in one place and calling it in other contexts,

or allowing users to run arbitrary code on your web server!

but seriously,

you can still run into name collision problems. one I've just discovered (and fixed) today is as follows.

say you want to define some code and run it in another context:

class Context
attr_accessor :one,:two
end

def add (a,b)
puts "#{a} + #{b} = #{a+b}"
end

def context_a(l,code)
puts "context_a"
l.instance_eval(code)
end
def context_b(l,code)
puts "context_b"
one = 11
two = 22
l.instance_eval(code)
end
def context_c(l,code)
puts "context_c.1"
begin
l.instance_eval(code)
rescue Exception => e
puts e.message
end
puts "context_c.2"
one = 101
two = 202
l.instance_eval(code)
end

l = Context.new
l.one = 1
l.two = 2
code = "add one,two"

context_a(l,code)
context_b(l,code)
context_c(l,code)

so what will happen?
the eval will call add and interpret the meaning of one and two from the context of the instance of Context stored in l, right?

well... not quite. All that eval_instance does is change the value of 'self' while it evaluates the code string. The variables in the local context are still visible, as if the current function was now inside the receiver of instance_eval.

here is the output:

context_a
1 + 2 = 3
context_b
11 + 22 = 33
context_c.1
undefined method `+' for nil:NilClass
context_c.2
101 + 202 = 303
Whats happening is the methods of Context declared in each function are over written by the local variables in context_b and context_c. context_c is even more interesting, because here the local variable haven't even been initialized yet. however they already are already assigned nil at the start of the method!



if you don't know what is in the code you will be evaluating is yet, or then potentially anything could come through and it might collide, producing unexpected errors which will be difficult to diagnose.

However, this problem is easily avoided.

o get a clean call of instance_eval you must call it from a function with a clean local context.
for example, adding the following function to Context and calling that instead will fix the problem.
def clean_instance_eval(code)
eval code
end
you could monkeypatch instance_eval, but then there might be some bit of code which depended on the weird behaviour of eval, and that monkeypatch is no longer bug compatible!

also note that a variable/method named 'code' within code will collide with the context of clean_instance_eval. you could parse code and escape any occurences of code with, but it is much more convienent to just name the code variable to something highly unlikely to be used as a variable for example append a magic number: code_324792523532 or do_not_name_variable_this.

Anyone naming a variable do_not_name_variable_this is looking for trouble, so they deserve it!