2008-01-03 @ 11:31

Happy New Year! (RKelly Progress report)

I’ve just started getting the runtime working with RKelly. Its working well enough at this point that I was able to execute my earlier Fibonacci example. I’ve added a method to the runtime that allows you to define ruby functions that may be called from inside javascript. For example, the alert function in the following example is defined in ruby and delegates to puts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
runtime = RKelly::Runtime.new

runtime.define_function(:alert) do |*args|
  puts(*args)
end

runtime.execute(<<END
function f(n) {
  var s = 0;
  if(n == 0) return(s);
  if(n == 1) {
    s += 1;
    return(s);
  } else {
    return(f(n - 1) + f(n - 2));
  }
}
alert(f(20));
END
)

Here is the execution time with ruby 1.8.6 on my machine: [aaron@mac-mini rkelly]$ time ~/.multiruby/install/1.8.6-p111/bin/ruby -I lib test.rb 6765

real 0m54.332s user 0m53.913s sys 0m0.336s [aaron@mac-mini rkelly]$ ~~~

Same code, same machine, but with ruby 1.9.0:

[aaron@mac-mini rkelly]$ time ~/.multiruby/install/1.9.0-0/bin/ruby -I lib test.rb 6765

real 0m20.863s user 0m20.678s sys 0m0.142s [aaron@mac-mini rkelly]$ ~~~

I need to get loops working next!

read more »

2008-01-15 @ 00:00

mechanize version 0.7.0 has been released!

The Mechanize library is used for automating interaction with websites. Mechanize automatically stores and sends cookies, follows redirects, can follow links, and submit forms. Form fields can be populated and submitted. Mechanize also keeps track of the sites that you have visited as a history.

Changes:

Mechanize CHANGELOG

0.7.0

  • Removed Ruby 1.8.2 support
  • Changed parser to lazily parse links
  • Lazily parsing document
  • Adding verify_callback for SSL requests. Thanks Mike Dalessio!
  • Fixed a bug with Accept-Language header. Thanks Bill Siggelkow.

  • http://mechanize.rubyforge.org/
read more »

2008-01-19 @ 13:11

パンツないな興奮 - Javascript stuff

While writing RKelly (a pure ruby javascript interpreter), I’ve run across weird cases in the ECMA spec that I didn’t know about before. For example, when coercing an object into a number, first the “valueOf” property is checked. That seemed to make sense to me. But then the spec says that if there is no “valueOf” property, to check the “toString” property and try to coerce that in to a number.

So, this bit of code:

var x = new Object;
x.valueOf = function() { return 11; };
x++;

is equivalent to this bit of code:

var x = new Object;
x.stringValue = function() { return "11"; }
x++;

That is some underpants-free excitement.

read more »

2008-01-23 @ 10:18

Clean it up! RKelly::Nodes::Node#to_ecma

Last night at Nerd Club, I decided to add a “to_ecma” method to <a href=”http://rubyforge.org/projects/rkelly/”“>RKelly</a>. This means you can turn your ECMA AST back in to ECMAScript, with the added bonus of properly indenting your code. For example:

require 'rkelly'

parser = RKelly::Parser.new
puts parser.parse(DATA.read).to_ecma

__END__
function yo(a,b,a) { this.be.some(); if(nasty) { code();} }

will output this:

function yo(a, b, a){
  this.be.some();
  if(nasty) {
    code();
  }
}

Now you should be able to modify your AST and generate javascript. Next I want to add finders to easily find nodes in the tree.

read more »

2008-01-24 @ 23:29

Pointcut Your Javascript

Sorry for all of the RKelly updates, but thats what I’ve been doing in my free time. I mean, besides J-School. But I don’t think anyone wants to read my poor Japanese!

I wanted to make my ASTs easily searchable, so I added an AOP style interface to my AST. The AST will now let you pointcut your javascript and give you back a list of all of the points it finds. Take this javascript for example:

try {
  Element.update('another_id',"blah blah blah");
  Element.update(10,"blah blah blah");
} catch (e) { }

Lets say you wanted to find every place that Element.update() was called with 2 arguments, and mess with those arguments. You can pointcut the ast, then modify the arguments by giving the AST a pattern to match on like so:

parser = RKelly::Parser.new
ast = parser.parse(DATA.read)
ast.pointcut("Element.update(Object, Object)").matches.each do |m|
  m.arguments.value.each { |x|
    x.value = rand(20)
  }
end

puts ast.to_ecma

But lets say you only want to update the call that was made with a number as the first parameter. No problem! Just change your pattern to use a number, like so:

parser = RKelly::Parser.new
ast = parser.parse(DATA.read)
ast.pointcut("Element.update(Number, Object)").matches.each do |m|
  m.arguments.value.each { |x|
    x.value = rand(20)
  }
end

puts ast.to_ecma

You can even get more specific and match the arguments exactly. For example, matching just the function call where the first argument is ‘another_id’:

parser = RKelly::Parser.new
ast = parser.parse(DATA.read)
ast.pointcut("Element.update('another_id', Object)").matches.each do |m|
  m.arguments.value.each { |x|
    x.value = rand(20)
  }
end

Maybe you don’t care the update is being called on an Element, but you want to match all places that update is being called on something. The pointcut will match on node type too, so this is a perfectly valid pattern:

parser = RKelly::Parser.new
ast = parser.parse(DATA.read)
ast.pointcut("ResolveNode.update('another_id', Object)").matches.each do |m|
  m.arguments.value.each { |x|
    x.value = rand(20)
  }
end

Hopefully you get the picture. This feature isn’t full tested yet, but I think I might do my first RKelly release after I finish testing.

read more »