Metaprogramming Ruby - What the hell's a DSL? murphee (Werner - - PowerPoint PPT Presentation

metaprogramming ruby what the hell s a dsl
SMART_READER_LITE
LIVE PREVIEW

Metaprogramming Ruby - What the hell's a DSL? murphee (Werner - - PowerPoint PPT Presentation

Metaprogramming Ruby - What the hell's a DSL? murphee (Werner Schuster) Blog @ http://jroller.com/page/murphee Meta? Programs that write Programs Compiler DSLs Regexes, anyone? Always good to start with quotes by... Alan Kay The


slide-1
SLIDE 1

Metaprogramming Ruby - What the hell's a DSL?

  • murphee (Werner Schuster)
  • Blog @ http://jroller.com/page/murphee
slide-2
SLIDE 2

Meta?

slide-3
SLIDE 3

Programs that write Programs

slide-4
SLIDE 4

Compiler

slide-5
SLIDE 5

DSLs

slide-6
SLIDE 6

Regexes, anyone?

slide-7
SLIDE 7

Always good to start with quotes by...

slide-8
SLIDE 8

Alan Kay

slide-9
SLIDE 9

The general attitude seems to be that people should wear square shoes, because squares are easier to design and manufacture than foot shaped shoes. ...

slide-10
SLIDE 10

If the shoe industry has gone the way of the computer industry it would now be running a $200-a- day course on how to walk, run and jump in square shoes."

Alan Kay

slide-11
SLIDE 11

DSLs

  • Internal

– use host language

  • External

– Yacc, ANTLR, ...

slide-12
SLIDE 12

Executable Spec

slide-13
SLIDE 13

Let's start with... Dylan

  • http://www.networknightvision.com/
  • Dylan
  • declarative protocol spec
slide-14
SLIDE 14

Ethernet spec in Dylan

define protocol ethernet−frame ( header−frame ) summary ”ETH %= −> %=/%s ” , source−address , destination−address , compose ( summary , payload ) ; field destination−address : : <mac−address >; field source−address : : <mac−address >; field type−code : : <2byte−big−endian−unsigned−integer >; var iably−typed−field payload , type−function: select ( frame . type−code ) #x800 => <ipv4−frame >; #x806 => <arp−frame >;

  • therwise => <raw−frame >;

end ; end ;

slide-15
SLIDE 15

Ethernet spec in Dylan

define protocol ethernet−frame ( header−frame )

summary ”ETH %= −> %=/%s ” , source−address , destination−address , compose ( summary , payload ) ; field destination−address : : <mac−address >; field source−address : : <mac−address >; field type−code : : <2byte−big−endian−unsigned−integer >; var iably−typed−field payload , type−function: select ( frame . type−code ) #x800 => <ipv4−frame >; #x806 => <arp−frame >;

  • therwise => <raw−frame >;

end ; end ;

slide-16
SLIDE 16

Ethernet spec in Dylan

define protocol ethernet−frame ( header−frame ) summary ”ETH %= −> %=/%s ” , source−address , destination−address , compose ( summary , payload ) ; field destination−address : : <mac−address >; field source−address : : <mac−address >; field type−code : : <2byte−big−endian−unsigned−integer >; var iably−typed−field payload , type−function:

select ( frame . type−code )

#x800 => <ipv4−frame >; #x806 => <arp−frame >;

  • therwise => <raw−frame >;

end ; end ;

slide-17
SLIDE 17

Design Process

slide-18
SLIDE 18

Incremental does it

  • Sketching
  • Make it work
  • ?
  • Profit!
slide-19
SLIDE 19

Example time

  • http://www.infoq.com/articles/properties-metaprogramming
slide-20
SLIDE 20

Properties in Ruby/1

  • C#-like Properties in Ruby
  • Why?

– to piss of Java zealots

slide-21
SLIDE 21

Properties in Ruby/2 - Sketching

class Foo property name end

slide-22
SLIDE 22

Properties in Ruby/2 - Sketching

class Foo property name end NameError: undefined local variable or method `name' for main:Object

slide-23
SLIDE 23

Properties in Ruby/3 - Fix

class Foo property :name end

slide-24
SLIDE 24

Properties in Ruby/3 - Fix

class Foo property :name end NameError: undefined method `property' for main:Object

slide-25
SLIDE 25

Properties in Ruby/3 - Fix

def property(sym) ... end

class Foo property :name end

slide-26
SLIDE 26

Properties in Ruby/3 - Fix

def property(sym) define_method("#{sym}=") do |value|

instance_variable_set("@#{sym}", value) end

end class Foo property :name end

slide-27
SLIDE 27

Properties in Ruby/3 - Fix

def property(sym) define_method("#{sym}=") do |value|

instance_variable_set("@#{sym}", value) end

end class Foo property :name end name=

slide-28
SLIDE 28

Properties in Ruby/3 - Fix

def property(sym) define_method("#{sym}=") do |value|

instance_variable_set("@#{sym}", value) end

end class Foo property :name end @name

slide-29
SLIDE 29

Properties in Ruby/4 - Expand

def property(*sym, &bl) # Code: Homework define_method("#{sym}=") do |value| # More Homework instance_variable_set("@#{sym}", value) end end class Tower property(:width, :height) {|val| val > 200} end

slide-30
SLIDE 30

What we know by now

  • Class definitions are executed
  • Symbols are nice
  • Blocks too
slide-31
SLIDE 31

Another one

slide-32
SLIDE 32

Pattern Matching

slide-33
SLIDE 33

Parseweasel

slide-34
SLIDE 34

Ruby ParseTree

foo.hello(1)

slide-35
SLIDE 35

Ruby ParseTree

foo.hello(1)

  • >

[:vcall, :hello, :foo, [:args, [:lit, 1] ] ]

slide-36
SLIDE 36

Ruby ParseTree

foo.hello(1)

  • >

[:vcall, :hello, :foo, [:args, [:lit, 1] ] ]

AST as: s-expr symbolic expression

slide-37
SLIDE 37

ParseWeasel pattern

[:vcall, :name_, :recv_, :args_]

slide-38
SLIDE 38

ParseWeasel pattern

[:vcall, :name_,:recv_, :args_] someone.something foo.bar murphee.speak

slide-39
SLIDE 39

ParseWeasel pattern/2

[:vcall, :hello,:recv_, :args_]

slide-40
SLIDE 40

ParseWeasel pattern/2

[:vcall, :hello,:recv_, :args_] foo.bar foo.hello huey().lewey().hello() huey().speak

slide-41
SLIDE 41

ParseWeasel handlers

handler([:vcall, :hello,:recv_, :args_]){|s| puts “Found a hello #{s[:recv]}” }

slide-42
SLIDE 42

ParseWeasel use case: optimizer

replace([:call, :op_, :*, [:lit, 0] ]){|s| [:lit, 0] }

slide-43
SLIDE 43

ParseWeasel use case: optimizer

replace([:call, :op_, :*, [:lit, 0] ]){|s| [:lit, 0] } x = foo * 0

slide-44
SLIDE 44

Ruby DSLs

  • Keep it simple
  • Stick to basics
  • If it limps like a hack

– it probably is one

slide-45
SLIDE 45

Let's push it further

slide-46
SLIDE 46

Let's mess up the syntax

slide-47
SLIDE 47

Hello LISP

(defun factorial (x) (if (zerop x) 1 (* x (factorial (- x 1))) ) ) (factorial 42)

slide-48
SLIDE 48

Macros

slide-49
SLIDE 49

C Preprocessor

slide-50
SLIDE 50

C Preprocessor

slide-51
SLIDE 51

LISP Macro example: Infix

(* a 42)

slide-52
SLIDE 52

I want my infix!

slide-53
SLIDE 53

LISP Macro example: Infix

(infix (a * 42) )

what I write

slide-54
SLIDE 54

LISP Macro example: Infix

(defmacro infix (one op two &rest body) `(,op ,one ,two ) ) (infix (a * 42) )

what I write

slide-55
SLIDE 55

LISP Macro example: Infix

(defmacro infix (one op two &rest body) `(,op ,one ,two ) ) (infix (a * 42) ) (* a 42)

what I write what gets executed

slide-56
SLIDE 56

LISP Macro: real use cases

  • Practical Lisp

– MP3 binary parser – executable spec

  • Many LISP control structures
slide-57
SLIDE 57

Macros in the real world

  • Mathematica

– D[x ^ 2] – Integrate[x ^ 3] – Expand[ x ^ 42] –

  • Macro-like
  • “FullForm” ~ s-expr

– 3x -> Times[3, x ]

slide-58
SLIDE 58

Let's wrap up

  • Practical Lisp

– http://www.gigamonkeys.com/book/

  • http://ola-bini.blogspot.com/2006/09/ruby-metaprogramming-techniques.html
  • http://www.infoq.com/articles/properties-metaprogramming