Skip to content

Instantly share code, notes, and snippets.

@Zapotek
Created December 4, 2011 17:01
Show Gist options
  • Save Zapotek/1430686 to your computer and use it in GitHub Desktop.
Save Zapotek/1430686 to your computer and use it in GitHub Desktop.
V8 interpreter with basic DOM in Ruby using TheRubyRacer and Taka
require 'v8'
require 'open-uri'
require 'pp'
require 'ap'
require 'taka'
require 'ostruct'
#
# Monkey patch all elements to include a 'style' attribute
#
class Nokogiri::XML::Element
attr_reader :style
class Style < OpenStruct
end
def initialize( *args )
super
@style = Style.new
end
end
#
# Taka lacks a few important interfaces
# so I've added some rough ones for the test's sake
#
module Taka::DOM::Document
attr_accessor :location
end
class Window
attr_reader :document
attr_reader :navigator
attr_reader :readyState
attr_accessor :location
def initialize( html = '' )
@document = Taka::DOM::HTML( html )
@navigator = Navigator.new
@location = Location.new( '' )
@document.location = Location.new( '' )
ready!
end
def open( url )
@document = Taka::DOM::HTML( Kernel::open( url ) )
@document.location = @location = Location.new( url )
ready!
self
end
def alert( msg )
# puts msg
pp msg
ap '---------'
end
def debug( obj )
ap obj
end
def window
self
end
private
def ready!
@readyState = 'complete'
end
end
class Window::Navigator
attr_accessor :userAgent
def initialize
@userAgent = 'Arachni'
end
end
class Window::Location
def initialize( url )
@url = URI( url )
end
def host
@url.host + ':' + @url.port.to_s
end
def hostname
@url.host
end
def href
@url.to_s
end
def path
@url.path
end
def port
@url.port
end
# def hash
# return 0 if !@url.fragment
# '#' + @url.fragment
# end
def search
'?' + @url.query
end
def protocol
@url.scheme + ':'
end
def to_s
@url.to_s
end
end
#
# Taken from a Johnson example
#
html = <<EOHTML
<html>
<head>
<script>
function populateDropDown() {
var select = document.getElementById('colors');
var options = ['red', 'green', 'blue', 'black'];
var i;
for( i = 0; i < options.length; i++ ) {
var option = document.createElement( 'option' );
option.appendChild( document.createTextNode( options[i] ) );
option.value = options[i];
select.appendChild( option );
}
}
div = document.createElement( "div" );
div.style.display="none";
div.textContent = 'Test div';
body = document.getElementsByTagName('body')[0];
body.appendChild( div );
</script>
</head>
<body onload="populateDropDown()">
<h1>Behold the V8</h1>
<form>
<select id="colors">
</select>
</form>
</body>
</html>
EOHTML
window = Window.new( html )
document = window.document
V8::Context.new( :with => window ) do |cxt|
document.xpath( './/script' ).each {
|script|
if src = script['src']
src = script['src'].to_s
code = IO.read( open( src ) )
else
code = script.text
src = 'EMBEDED'
end
begin
cxt.eval( code )
rescue Exception => e
ap src
code.split( "\n" ).each_with_index {
|line, i|
puts "#{i+1} #{line}"
}
raise e
end
}
# should be 0
p document.getElementsByTagName('option').length
# execute body's onload which will create the options
p cxt.eval document.getElementsByTagName('body')[0].onload
# should be 4
p document.getElementsByTagName('option').length
# HTML code with updated DOM
# puts window.document.to_html
end
@laspluviosillas
Copy link

You just made my day sir.

@Zapotek
Copy link
Author

Zapotek commented Feb 3, 2012

Glad to hear it, you might want to check this out: https://github.com/Zapotek/dom-js-experiment

@laspluviosillas
Copy link

Just what I need. +1.

@laspluviosillas
Copy link

You should make this some sort of gem btw (I might contribute)

@Zapotek
Copy link
Author

Zapotek commented Feb 3, 2012 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment