+ All Categories
Transcript
Page 1: Hacking with ruby2ruby

Hacking with ruby2rubyMarc Chung

OpenRainblog.marcchung.comblog.openrain.com@heisenthought

Page 2: Hacking with ruby2ruby

Hacking with ruby2rubyMarc Chung

OpenRainblog.marcchung.comblog.openrain.com@heisenthought

Page 3: Hacking with ruby2ruby
Page 4: Hacking with ruby2ruby

ruby2ruby

Ruby2RubyWalks the Ruby AST

To emit Ruby

Page 5: Hacking with ruby2ruby

sudo gem install ruby2ruby

Page 6: Hacking with ruby2ruby

Limitations

• Only Ruby 1.8

• Not 1.9, yet

• Built into Rubinius

Page 7: Hacking with ruby2ruby

function rhino_rocks() { return “Rhino, rocks!”;}

Page 8: Hacking with ruby2ruby

js> rhino_rocks();

Rhino, rocks!

Page 9: Hacking with ruby2ruby

js> rhino_rocks.toString();

function rhino_rocks() { return “Rhino, rocks!”;}

Page 10: Hacking with ruby2ruby

js> eval(rhino_rocks.toString()).call();

Rhino, rocks!

Page 11: Hacking with ruby2ruby

ruby_rocks = proc { return “Ruby, rocks”;}

Page 12: Hacking with ruby2ruby

irb> ruby_rocks.call;

Ruby, rocks!

Page 13: Hacking with ruby2ruby

irb> require “ruby2ruby”irb> require “parse_tree_extensions”irb> ruby_rocks.to_ruby

proc { return \“Ruby, rocks\” }

Page 14: Hacking with ruby2ruby

irb> eval(ruby_rocks.to_ruby).call

Ruby, rocks!

Page 15: Hacking with ruby2ruby
Page 16: Hacking with ruby2ruby

define_methodclass Voice define_method(:shout) do |word| word.upcase! endend

puts Ruby2Ruby.translate(Voice)

Page 17: Hacking with ruby2ruby

class Voice < Object def yell(word) word.upcase! endend

Page 18: Hacking with ruby2ruby

aliasclass AliasClass def old_busted "42" end

alias_method :new_hotness, :old_bustedend

puts Ruby2Ruby.translate(AliasClass)

Page 19: Hacking with ruby2ruby

class AliasClass < Object def new_hotness "42" end def old_busted "42" endend

Page 20: Hacking with ruby2ruby

#module_functionmodule HelperModule def help puts "Help me" end module_function : helpend

puts Ruby2Ruby.translate(HelperModule)

Page 21: Hacking with ruby2ruby

module HelperModule def help puts("Help me") end def self. help puts("Help me") endend

Page 22: Hacking with ruby2ruby

ActiveRecord Models

class Doctor < ActiveRecord::Base has_many :patientsend

Page 23: Hacking with ruby2ruby

See, Ruby, Run!

• Drmap

• git clone git://github.com/mchung/drmap.git

• Optionally, install Journeta

Page 24: Hacking with ruby2ruby

Under the hood

• Abstract syntax trees

• S-expressions

• ParseTree

Page 25: Hacking with ruby2ruby

class Book def title “Ruby programming” endend

Page 26: Hacking with ruby2ruby

case NODE_BREAK:case NODE_NEXT: if (node->nd_stts) add_to_parse_tree(self, current, node->nd_stts, locals);

break;

case NODE_YIELD: if (node->nd_stts) add_to_parse_tree(self, current, node->nd_stts, locals);

if (node->nd_stts && (nd_type(node->nd_stts) == NODE_ARRAY || nd_type(node->nd_stts) == NODE_ZARRAY) && !node->nd_state) rb_ary_push(current, Qtrue);

break;

Page 27: Hacking with ruby2ruby

[:class, :Book, [:const, :Object], [:defn, :title, [:scope, [:block, [:args], [:str, "Ruby programming"]]]]]

Page 28: Hacking with ruby2ruby

class Book < Object def title “Ruby programming” endend

Page 29: Hacking with ruby2ruby

/opt/local/usr/bin

• parse_tree_show

• r2r_show

Page 30: Hacking with ruby2ruby

class Book def title “Ruby programming” endend

Page 31: Hacking with ruby2ruby

$ parse_tree_show book.rb

Page 32: Hacking with ruby2ruby

s(:class, :Book, nil, s(:scope, s(:defn, :title, s(:args), s(:scope, s(:block, s(:str, "Ruby programming"))))))

Page 33: Hacking with ruby2ruby

$ r2r_show book.rb

Page 34: Hacking with ruby2ruby

class Book def title() “Ruby programming” endend

Page 35: Hacking with ruby2ruby

Operator Precedence with Guy Decoux: a b c, d

[[:fcall, :a, [:array, [:fcall, :b, [:array, [:vcall, :c], [:vcall, :d]]]]]]

ParseTree.new.parse_tree_for_string(“a b c, d”)

Page 36: Hacking with ruby2ruby

ruby2java

Page 37: Hacking with ruby2ruby

class JavaClass def self.main puts “Java, rocks!” endend

Page 38: Hacking with ruby2ruby

[:class, :JavaClass, [:const, :Object], [:defs, [:self], :main, [:scope, [:block, [:args], [:fcall, :puts, [:array, [:str, "Hello, Java"]]]]]]]

Page 39: Hacking with ruby2ruby

class Ruby2Java < SexpProcessor def process_class(exp) “public class #{exp.shift} #{next_token(exp, true)}” end

def process_const(exp) “extends #{exp.shift}” end....end

Page 40: Hacking with ruby2ruby

public class JavaClass { public static void main(String argv[]) { return “Hello, Java”; }}

Page 41: Hacking with ruby2ruby
Page 42: Hacking with ruby2ruby

Distributing Ruby

• drmap - multi-machine worker queue

• gisting - map/reduce framework

Page 43: Hacking with ruby2ruby

drmapirb> fn = proc {|x| x**10}

irb> Marshal.dump(fn)TypeError: no marshal_dump is defined for class Proc

irb> YAML::dump(fn)=> "--- !ruby/object:Proc {}\n\n"

irb> YAML::dump(fn.to_ruby)=> "--- proc { |x| (x ** 10) }\n"

irb> Marshal.dump(fn.to_ruby)=> "\004\b\"\eproc { |x| (x ** 10) }"

Page 44: Hacking with ruby2ruby

Enumerable#drmap

Page 45: Hacking with ruby2ruby

module Enumerable

def drmap(&block) pool = Drmap::BeanstalkPool.new

jid = rand(100) each_with_index do |element, idx| pool.put_job(jid, block.to_ruby, element) end

results = [] while results.size < length results << pool.next_result(jid) end results end

end

Page 46: Hacking with ruby2ruby

def process loop do begin job_payload = next_job fn = job_payload[:proc] data = job_payload[:data] result = eval(fn).call(data) save(job_payload[:jid], result) success! rescue => e fail!(e) end endend

Page 47: Hacking with ruby2ruby

drmap

• Trivial

• Distributed

• Powerful

Page 48: Hacking with ruby2ruby

Demo time!

Page 49: Hacking with ruby2ruby

Gisting

• MapReduce in Ruby

• http://github.com/mchung/gisting

Page 50: Hacking with ruby2ruby

map / reduce

• Functional programming

• Iterating over collections

• (5..10).map {|x| x+1} #=> [6, 7, 8, 9, 10, 11]

• (5..10).reduce(:+) #=> 45

Page 51: Hacking with ruby2ruby

Google MapReduce

• Modeled after map() and reduce()

• Programming model

• Programs are trivially parallelizable

Page 52: Hacking with ruby2ruby

Demo time!

Page 53: Hacking with ruby2ruby

Gisting::Spec

Page 54: Hacking with ruby2ruby

input.file_pattern = "file.txt" input.map do |map_input| words = map_input.strip.split("\t") Emit(words[1], "1") end

Page 55: Hacking with ruby2ruby

output.reduce do |reduce_input| count = 0 reduce_input.each do |value| count += value.to_i end Emit(count)end

Page 56: Hacking with ruby2ruby

inputs = args spec = Gisting::Spec.new inputs.each do |file_input| input = spec.add_input input.file_pattern = file_input input.map do |map_input| # 2722 mailbox 2006-05-23 00:08:39 words = map_input.strip.split("\t") Emit(words[1], "1") end end output = spec.output output.filebase = "/Users/mchung/Public/datasets/output" output.num_tasks = 2 output.reduce do |reduce_input| count = 0 reduce_input.each do |value| count += value.to_i end Emit(count) end

result = MapReduce(spec) pp result

Page 57: Hacking with ruby2ruby

Gisting

• MapReduce programming model in Ruby

• Uses ruby2ruby to serialize procs

• Uses EventMachine for Map/ReduceServer

Page 58: Hacking with ruby2ruby

• -: 94978

• mailbox: 20872

• google: 6758

• ebay: 2832

• yahoo: 2674

• yahoo.com: 2198

• myspace.com: 1916

• google.com: 1882

Page 59: Hacking with ruby2ruby

self.give(:thanks)OpenRain

openrain.com

My Git Repogithub.com/mchung

Marc Chungblog.marcchung.com

Ruby::AZrubyaz.org

Page 60: Hacking with ruby2ruby

Resources

Code Generation: The Safety Scissors Of Metaprogrammingmwrc2008.confreaks.com/03bowkett.html

Forbidden Fruit: A Taste of Ruby's Parse Treegoruco2008.confreaks.com/03_wanstrath.html

Ruby2Rubyseattlerb.rubyforge.org/ruby2ruby/

ParseTreeparsetree.rubyforge.org


Top Related