dynamic languages, for software craftmanship group

106
Dynamic languages Reuven M. Lerner • [email protected] Software Craftsmanship Group, Tel Aviv March 22 nd , 2011 1

Upload: reuven-lerner

Post on 26-Jan-2015

761 views

Category:

Technology


0 download

DESCRIPTION

Reuven Lerner's talk about dynamic programming languages in general, and about Ruby in particular. Why would you want to use a dynamic language? What can you do with one that isn't possible (or easy) with a static language?

TRANSCRIPT

Page 1: Dynamic languages, for software craftmanship group

Dynamic languagesReuven M. Lerner • [email protected] Craftsmanship Group, Tel Aviv

March 22nd, 2011

1

Page 2: Dynamic languages, for software craftmanship group

Who am I?

• Web developer, software architect, consultant, trainer

• Linux Journal columnist since 1996

• Mostly Ruby on Rails + PostgreSQL, but also Python, PHP, jQuery, and lots more...

2

Page 3: Dynamic languages, for software craftmanship group

Language wars!

• Static vs. dynamic languages

• I’m here representing the good guys

• (Just kidding. Mostly.)

• Not just a different language — a different mindset and set of expectations

3

Page 4: Dynamic languages, for software craftmanship group

What is a dynamic language?

• Dynamic typing

• Usually interpreted (or JIT compiled)

• Interactive shell for experimenting

• Closures (anonymous code blocks)

• Flexible, “living” object model

• Result: Short, powerful, reusable code

4

Page 5: Dynamic languages, for software craftmanship group

Who is in charge?

• Static language: The language is in charge, and it’s for your own good!

• Dynamic language: The programmer is in charge, and changes the language to suit his or her needs

5

Page 6: Dynamic languages, for software craftmanship group

6

Page 7: Dynamic languages, for software craftmanship group

Examples

• Lisp

• Smalltalk

• Python

• Ruby

• JavaScript

7

Page 8: Dynamic languages, for software craftmanship group

Examples

• Lisp

• Smalltalk

• Python

• Ruby

• JavaScript

7

Page 9: Dynamic languages, for software craftmanship group

Values, not variables, have types

x = 5

=> 5

x.class

=> Fixnum

x = [1,2,3]

=> [1, 2, 3]

x.class

=> Array

8

Page 10: Dynamic languages, for software craftmanship group

Values, not variables, have types

x = 5

=> 5

x.class

=> Fixnum

x = [1,2,3]

=> [1, 2, 3]

x.class

=> Array

8

Page 11: Dynamic languages, for software craftmanship group

Values, not variables, have types

x = 5

=> 5

x.class

=> Fixnum

x = [1,2,3]

=> [1, 2, 3]

x.class

=> Array

8

Page 12: Dynamic languages, for software craftmanship group

Values, not variables, have types

x = 5

=> 5

x.class

=> Fixnum

x = [1,2,3]

=> [1, 2, 3]

x.class

=> Array

8

Page 13: Dynamic languages, for software craftmanship group

Values, not variables, have types

x = 5

=> 5

x.class

=> Fixnum

x = [1,2,3]

=> [1, 2, 3]

x.class

=> Array

8

Page 14: Dynamic languages, for software craftmanship group

Less code!

• No need for variable declarations

• No function parameter declarations

• No function return-type declarations

9

Page 15: Dynamic languages, for software craftmanship group

Ahhhh!

• Are you serious?

• Can real software be developed without a compiler and type checking?

• How can you possibly work this way?

10

Page 16: Dynamic languages, for software craftmanship group

Ahhhh!

• Are you serious?

• Can real software be developed without a compiler and type checking?

• How can you possibly work this way?

• Answer: Very well, thank you.

10

Page 17: Dynamic languages, for software craftmanship group

11

Page 18: Dynamic languages, for software craftmanship group

Flexible collections

a = [1, 2, 'three', [4, 5, 6]]

=> [1, 2, "three", [4, 5, 6]]

a.length

=> 4

a << {first_name:'Reuven', last_name:'Lerner'}

=> [1, 2, "three", [4, 5, 6], {:first_name=>"Reuven", :last_name=>"Lerner"}]

12

Page 19: Dynamic languages, for software craftmanship group

Flexible collections

a = [1, 2, 'three', [4, 5, 6]]

=> [1, 2, "three", [4, 5, 6]]

a.length

=> 4

a << {first_name:'Reuven', last_name:'Lerner'}

=> [1, 2, "three", [4, 5, 6], {:first_name=>"Reuven", :last_name=>"Lerner"}]

Integer

12

Page 20: Dynamic languages, for software craftmanship group

Flexible collections

a = [1, 2, 'three', [4, 5, 6]]

=> [1, 2, "three", [4, 5, 6]]

a.length

=> 4

a << {first_name:'Reuven', last_name:'Lerner'}

=> [1, 2, "three", [4, 5, 6], {:first_name=>"Reuven", :last_name=>"Lerner"}]

Integer String

12

Page 21: Dynamic languages, for software craftmanship group

Flexible collections

a = [1, 2, 'three', [4, 5, 6]]

=> [1, 2, "three", [4, 5, 6]]

a.length

=> 4

a << {first_name:'Reuven', last_name:'Lerner'}

=> [1, 2, "three", [4, 5, 6], {:first_name=>"Reuven", :last_name=>"Lerner"}]

Integer String Array

12

Page 22: Dynamic languages, for software craftmanship group

Flexible collections

a = [1, 2, 'three', [4, 5, 6]]

=> [1, 2, "three", [4, 5, 6]]

a.length

=> 4

a << {first_name:'Reuven', last_name:'Lerner'}

=> [1, 2, "three", [4, 5, 6], {:first_name=>"Reuven", :last_name=>"Lerner"}]

Integer String Array

Hash

12

Page 23: Dynamic languages, for software craftmanship group

Collections

• Built-in collections (arrays, hashes) are good for most basic data structures

• Only create a class when you need to!

• Learning to use arrays and hashes is a key part of dynamic programming, and can save you lots of time

13

Page 24: Dynamic languages, for software craftmanship group

Functional tricks

• collect (map)

• detect (find)

• select (find_all)

• reject

• inject

14

Page 25: Dynamic languages, for software craftmanship group

Sorted username list

File.readlines('/etc/passwd').

reject {|line| line =~ /^#/}.

map {|line| line.split(':').

first}.

sort

15

Page 26: Dynamic languages, for software craftmanship group

Sorted username list

File.readlines('/etc/passwd').

reject {|line| line =~ /^#/}.

map {|line| line.split(':').

first}.

sort

15

Page 27: Dynamic languages, for software craftmanship group

Sorted username list

File.readlines('/etc/passwd').

reject {|line| line =~ /^#/}.

map {|line| line.split(':').

first}.

sort

15

Page 28: Dynamic languages, for software craftmanship group

Sorted username list

File.readlines('/etc/passwd').

reject {|line| line =~ /^#/}.

map {|line| line.split(':').

first}.

sort

15

Page 29: Dynamic languages, for software craftmanship group

Sorted username list

File.readlines('/etc/passwd').

reject {|line| line =~ /^#/}.

map {|line| line.split(':').

first}.

sort

15

Page 30: Dynamic languages, for software craftmanship group

Sorted username list

File.readlines('/etc/passwd').

reject {|line| line =~ /^#/}.

map {|line| line.split(':').

first}.

sort

15

Page 31: Dynamic languages, for software craftmanship group

Domain counterdomains = Hash.new(0)

File.readlines(list_member_file).each do |line|

email, domain = line.chomp.split('@')

domains[domain.downcase] += 1

end

domains.sort_by {|d| -d[1] }.

each {|d| puts "#{d[1]} #{d[0]}" }

domains.sort_by {|d| [-d[1], d[0]] }.

each {|d| puts "#{d[1]} #{d[0]}" }

16

Page 32: Dynamic languages, for software craftmanship group

Domain counterdomains = Hash.new(0)

File.readlines(list_member_file).each do |line|

email, domain = line.chomp.split('@')

domains[domain.downcase] += 1

end

domains.sort_by {|d| -d[1] }.

each {|d| puts "#{d[1]} #{d[0]}" }

domains.sort_by {|d| [-d[1], d[0]] }.

each {|d| puts "#{d[1]} #{d[0]}" }

16

Page 33: Dynamic languages, for software craftmanship group

Domain counterdomains = Hash.new(0)

File.readlines(list_member_file).each do |line|

email, domain = line.chomp.split('@')

domains[domain.downcase] += 1

end

domains.sort_by {|d| -d[1] }.

each {|d| puts "#{d[1]} #{d[0]}" }

domains.sort_by {|d| [-d[1], d[0]] }.

each {|d| puts "#{d[1]} #{d[0]}" }

16

Page 34: Dynamic languages, for software craftmanship group

Domain counterdomains = Hash.new(0)

File.readlines(list_member_file).each do |line|

email, domain = line.chomp.split('@')

domains[domain.downcase] += 1

end

domains.sort_by {|d| -d[1] }.

each {|d| puts "#{d[1]} #{d[0]}" }

domains.sort_by {|d| [-d[1], d[0]] }.

each {|d| puts "#{d[1]} #{d[0]}" }

16

Page 35: Dynamic languages, for software craftmanship group

Domain counterdomains = Hash.new(0)

File.readlines(list_member_file).each do |line|

email, domain = line.chomp.split('@')

domains[domain.downcase] += 1

end

domains.sort_by {|d| -d[1] }.

each {|d| puts "#{d[1]} #{d[0]}" }

domains.sort_by {|d| [-d[1], d[0]] }.

each {|d| puts "#{d[1]} #{d[0]}" }

16

Page 36: Dynamic languages, for software craftmanship group

Domain counterdomains = Hash.new(0)

File.readlines(list_member_file).each do |line|

email, domain = line.chomp.split('@')

domains[domain.downcase] += 1

end

domains.sort_by {|d| -d[1] }.

each {|d| puts "#{d[1]} #{d[0]}" }

domains.sort_by {|d| [-d[1], d[0]] }.

each {|d| puts "#{d[1]} #{d[0]}" }

16

Page 37: Dynamic languages, for software craftmanship group

Domain counterdomains = Hash.new(0)

File.readlines(list_member_file).each do |line|

email, domain = line.chomp.split('@')

domains[domain.downcase] += 1

end

domains.sort_by {|d| -d[1] }.

each {|d| puts "#{d[1]} #{d[0]}" }

domains.sort_by {|d| [-d[1], d[0]] }.

each {|d| puts "#{d[1]} #{d[0]}" }

16

Page 38: Dynamic languages, for software craftmanship group

Total cost of order

• Total price of an order of books:

total_price = books.

inject(0) do |sum, b|

sum + (b.price * b.quantity)

end

17

Page 39: Dynamic languages, for software craftmanship group

Real-time require

require 'jobs/a'require 'jobs/b'require 'jobs/c'

Dir["#{Rails.root}/app/jobs/*.rb"]. each { |file| require file }

18

Page 40: Dynamic languages, for software craftmanship group

Real-time require

require 'jobs/a'require 'jobs/b'require 'jobs/c'

Dir["#{Rails.root}/app/jobs/*.rb"]. each { |file| require file }

18

Page 41: Dynamic languages, for software craftmanship group

Real-time require

require 'jobs/a'require 'jobs/b'require 'jobs/c'

Dir["#{Rails.root}/app/jobs/*.rb"]. each { |file| require file }

18

Page 42: Dynamic languages, for software craftmanship group

Classes

• Classes allow you to abstract behavior

• Classes contain data and methods

• It’s easy and fast to create a class

19

Page 43: Dynamic languages, for software craftmanship group

Defining classesclass Person

end

=> nil

p = Person.new

=> #<Person:0x00000102105740>

p.class

=> Person

p.class.ancestors

=> [Person, Object, Wirble::Shortcuts, PP::ObjectMixin, Kernel, BasicObject]

20

Page 44: Dynamic languages, for software craftmanship group

Defining classesclass Person

end

=> nil

p = Person.new

=> #<Person:0x00000102105740>

p.class

=> Person

p.class.ancestors

=> [Person, Object, Wirble::Shortcuts, PP::ObjectMixin, Kernel, BasicObject]

20

Page 45: Dynamic languages, for software craftmanship group

Defining classesclass Person

end

=> nil

p = Person.new

=> #<Person:0x00000102105740>

p.class

=> Person

p.class.ancestors

=> [Person, Object, Wirble::Shortcuts, PP::ObjectMixin, Kernel, BasicObject]

20

Page 46: Dynamic languages, for software craftmanship group

Defining classesclass Person

end

=> nil

p = Person.new

=> #<Person:0x00000102105740>

p.class

=> Person

p.class.ancestors

=> [Person, Object, Wirble::Shortcuts, PP::ObjectMixin, Kernel, BasicObject]

20

Page 47: Dynamic languages, for software craftmanship group

Defining classesclass Person

end

=> nil

p = Person.new

=> #<Person:0x00000102105740>

p.class

=> Person

p.class.ancestors

=> [Person, Object, Wirble::Shortcuts, PP::ObjectMixin, Kernel, BasicObject]

20

Page 48: Dynamic languages, for software craftmanship group

Reflection> p.methods # or Person.instance_methods

=> [:po, :poc, :pretty_print, :pretty_print_cycle, :pretty_print_instance_variables, :pretty_print_inspect, :nil?, :, :, :!, :eql?, :hash, :=>, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :__id__, :object_id, :to_enum, :enum_for, :pretty_inspect, :ri, :, :equal?, :!, :!, :instance_eval, :instance_exec, :__send__]

21

Page 49: Dynamic languages, for software craftmanship group

Predicates

p.methods.grep(/\?$/)

=> [:nil?, :eql?, :tainted?, :untrusted?, :frozen?, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :respond_to?, :respond_to_missing?, :equal?]

22

Page 50: Dynamic languages, for software craftmanship group

“Local” methodsclass Person

def blah

"blah"

end

end

=> nil

p = Person.new

p.class.instance_methods - p.class.superclass.instance_methods

=> [:blah]

23

Page 51: Dynamic languages, for software craftmanship group

“Local” methodsclass Person

def blah

"blah"

end

end

=> nil

p = Person.new

p.class.instance_methods - p.class.superclass.instance_methods

=> [:blah]

23

Page 52: Dynamic languages, for software craftmanship group

“Local” methodsclass Person

def blah

"blah"

end

end

=> nil

p = Person.new

p.class.instance_methods - p.class.superclass.instance_methods

=> [:blah]

23

Page 53: Dynamic languages, for software craftmanship group

“Local” methodsclass Person

def blah

"blah"

end

end

=> nil

p = Person.new

p.class.instance_methods - p.class.superclass.instance_methods

=> [:blah]

23

Page 54: Dynamic languages, for software craftmanship group

Calling methods

a.length

=> 5

a.send(:length)

=> 5

a.send("length".to_sym)

=> 5

24

Page 55: Dynamic languages, for software craftmanship group

Calling methods

a.length

=> 5

a.send(:length)

=> 5

a.send("length".to_sym)

=> 5

24

Page 56: Dynamic languages, for software craftmanship group

Calling methods

a.length

=> 5

a.send(:length)

=> 5

a.send("length".to_sym)

=> 5

24

Page 57: Dynamic languages, for software craftmanship group

Calling methods

a.length

=> 5

a.send(:length)

=> 5

a.send("length".to_sym)

=> 5

24

Page 58: Dynamic languages, for software craftmanship group

Preferences become method calls

def bid_or_ask

is_ask? ? :ask : :bid

end

trade_amount = net_basis * (end_rate.send(bid_or_ask) - start_rate.send(bid_or_ask))

25

Page 59: Dynamic languages, for software craftmanship group

Preferences become method calls

def bid_or_ask

is_ask? ? :ask : :bid

end

trade_amount = net_basis * (end_rate.send(bid_or_ask) - start_rate.send(bid_or_ask))

25

Page 60: Dynamic languages, for software craftmanship group

Preferences become method calls

def bid_or_ask

is_ask? ? :ask : :bid

end

trade_amount = net_basis * (end_rate.send(bid_or_ask) - start_rate.send(bid_or_ask))

25

Page 61: Dynamic languages, for software craftmanship group

Define similar methods

['preview', 'applet', 'info', 'procedures', 'discuss', 'files', 'history', 'tags', 'family', 'upload', 'permissions'].each do |tab_name|

define_method(

"browse_#{tab_name}_tab".to_sym ) do

render :layout => 'browse_tab'

end

end

26

Page 62: Dynamic languages, for software craftmanship group

Define similar methods

['preview', 'applet', 'info', 'procedures', 'discuss', 'files', 'history', 'tags', 'family', 'upload', 'permissions'].each do |tab_name|

define_method(

"browse_#{tab_name}_tab".to_sym ) do

render :layout => 'browse_tab'

end

end

26

Page 63: Dynamic languages, for software craftmanship group

Define similar methods

['preview', 'applet', 'info', 'procedures', 'discuss', 'files', 'history', 'tags', 'family', 'upload', 'permissions'].each do |tab_name|

define_method(

"browse_#{tab_name}_tab".to_sym ) do

render :layout => 'browse_tab'

end

end

26

Page 64: Dynamic languages, for software craftmanship group

Define similar methods

['preview', 'applet', 'info', 'procedures', 'discuss', 'files', 'history', 'tags', 'family', 'upload', 'permissions'].each do |tab_name|

define_method(

"browse_#{tab_name}_tab".to_sym ) do

render :layout => 'browse_tab'

end

end

26

Page 65: Dynamic languages, for software craftmanship group

Define similar methods

['preview', 'applet', 'info', 'procedures', 'discuss', 'files', 'history', 'tags', 'family', 'upload', 'permissions'].each do |tab_name|

define_method(

"browse_#{tab_name}_tab".to_sym ) do

render :layout => 'browse_tab'

end

end

26

Page 66: Dynamic languages, for software craftmanship group

Searching by result'a'.what?('A')

"a".upcase == "A"

"a".capitalize == "A"

"a".swapcase == "A"

"a".upcase! == "A"

"a".capitalize! == "A"

"a".swapcase! == "A"

[:upcase, :capitalize, :swapcase, :upcase!, :capitalize!, :swapcase!]

27

Page 67: Dynamic languages, for software craftmanship group

Searching by result'a'.what?('A')

"a".upcase == "A"

"a".capitalize == "A"

"a".swapcase == "A"

"a".upcase! == "A"

"a".capitalize! == "A"

"a".swapcase! == "A"

[:upcase, :capitalize, :swapcase, :upcase!, :capitalize!, :swapcase!]

27

Page 68: Dynamic languages, for software craftmanship group

Searching by result'a'.what?('A')

"a".upcase == "A"

"a".capitalize == "A"

"a".swapcase == "A"

"a".upcase! == "A"

"a".capitalize! == "A"

"a".swapcase! == "A"

[:upcase, :capitalize, :swapcase, :upcase!, :capitalize!, :swapcase!]

27

Page 69: Dynamic languages, for software craftmanship group

Searching by result'a'.what?('A')

"a".upcase == "A"

"a".capitalize == "A"

"a".swapcase == "A"

"a".upcase! == "A"

"a".capitalize! == "A"

"a".swapcase! == "A"

[:upcase, :capitalize, :swapcase, :upcase!, :capitalize!, :swapcase!]

27

Page 70: Dynamic languages, for software craftmanship group

Monkey patching!class Fixnum

def *(other)

self + other

end

end

6*5

=> 11

28

Page 71: Dynamic languages, for software craftmanship group

Monkey patching!class Fixnum

def *(other)

self + other

end

end

6*5

=> 11

28

Page 72: Dynamic languages, for software craftmanship group

Monkey patching!class Fixnum

def *(other)

self + other

end

end

6*5

=> 11

28

Page 73: Dynamic languages, for software craftmanship group

Example: “Whiny nils”

• Try to invoke “id” on nil, and Rails will complain

@y.id

RuntimeError: Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id

29

Page 74: Dynamic languages, for software craftmanship group

Example: RSpec it "should have a unique name" do

c1 = Currency.new(@valid_attributes)

c1.save!

c2 =

Currency.new(

:name => @valid_attributes[:name],

:abbreviation => 'XYZ')

c1.should be_valid

c2.should_not be_valid

end

30

Page 75: Dynamic languages, for software craftmanship group

Example: RSpec it "should have a unique name" do

c1 = Currency.new(@valid_attributes)

c1.save!

c2 =

Currency.new(

:name => @valid_attributes[:name],

:abbreviation => 'XYZ')

c1.should be_valid

c2.should_not be_valid

end

30

Page 76: Dynamic languages, for software craftmanship group

Example: RSpec it "should have a unique name" do

c1 = Currency.new(@valid_attributes)

c1.save!

c2 =

Currency.new(

:name => @valid_attributes[:name],

:abbreviation => 'XYZ')

c1.should be_valid

c2.should_not be_valid

end

30

Page 77: Dynamic languages, for software craftmanship group

method_missing

• If no method exists, then method_missing is invoked, passing the method name, args

31

Page 78: Dynamic languages, for software craftmanship group

Dynamic findersReading.find_all_by_longitude_and_device_id(0, 3)

=> [#<Reading id: 46, longitude: #<BigDecimal:24439a8,'0.0',9(18)>, latitude: ... ]

Reading.instance_methods.grep(/long/)

=> []

32

Page 79: Dynamic languages, for software craftmanship group

Dynamic findersReading.find_all_by_longitude_and_device_id(0, 3)

=> [#<Reading id: 46, longitude: #<BigDecimal:24439a8,'0.0',9(18)>, latitude: ... ]

Reading.instance_methods.grep(/long/)

=> []

32

Page 80: Dynamic languages, for software craftmanship group

Dynamic findersReading.find_all_by_longitude_and_device_id(0, 3)

=> [#<Reading id: 46, longitude: #<BigDecimal:24439a8,'0.0',9(18)>, latitude: ... ]

Reading.instance_methods.grep(/long/)

=> []

32

Page 81: Dynamic languages, for software craftmanship group

Hash methods as keys

class Hash

def method_missing(name, *args)

if has_key?(name)

self[name]

end

end

end

33

Page 82: Dynamic languages, for software craftmanship group

Exampleh = {a:1, b:2}

=> {:a=>1, :b=>2}

h[:a]

=> 1

h.a

=> 1

h['c'] = 3

=> 3

h.c

=> nil

h[:d] = 4

=> 4

h.d

=> 4

34

Page 83: Dynamic languages, for software craftmanship group

Exampleh = {a:1, b:2}

=> {:a=>1, :b=>2}

h[:a]

=> 1

h.a

=> 1

h['c'] = 3

=> 3

h.c

=> nil

h[:d] = 4

=> 4

h.d

=> 4

34

Page 84: Dynamic languages, for software craftmanship group

Exampleh = {a:1, b:2}

=> {:a=>1, :b=>2}

h[:a]

=> 1

h.a

=> 1

h['c'] = 3

=> 3

h.c

=> nil

h[:d] = 4

=> 4

h.d

=> 4

34

Page 85: Dynamic languages, for software craftmanship group

Exampleh = {a:1, b:2}

=> {:a=>1, :b=>2}

h[:a]

=> 1

h.a

=> 1

h['c'] = 3

=> 3

h.c

=> nil

h[:d] = 4

=> 4

h.d

=> 4

34

Page 86: Dynamic languages, for software craftmanship group

Exampleh = {a:1, b:2}

=> {:a=>1, :b=>2}

h[:a]

=> 1

h.a

=> 1

h['c'] = 3

=> 3

h.c

=> nil

h[:d] = 4

=> 4

h.d

=> 4

34

Page 87: Dynamic languages, for software craftmanship group

Exampleh = {a:1, b:2}

=> {:a=>1, :b=>2}

h[:a]

=> 1

h.a

=> 1

h['c'] = 3

=> 3

h.c

=> nil

h[:d] = 4

=> 4

h.d

=> 4

34

Page 88: Dynamic languages, for software craftmanship group

Exampleh = {a:1, b:2}

=> {:a=>1, :b=>2}

h[:a]

=> 1

h.a

=> 1

h['c'] = 3

=> 3

h.c

=> nil

h[:d] = 4

=> 4

h.d

=> 4

34

Page 89: Dynamic languages, for software craftmanship group

Exampleh = {a:1, b:2}

=> {:a=>1, :b=>2}

h[:a]

=> 1

h.a

=> 1

h['c'] = 3

=> 3

h.c

=> nil

h[:d] = 4

=> 4

h.d

=> 4

34

Page 90: Dynamic languages, for software craftmanship group

Hash method accessclass Hash

def method_missing(method_name, *arguments)

if has_key?(method_name)

self[method_name]

elsif has_key?(method_name.to_s)

self[method_name.to_s]

else

nil

end

end

end

35

Page 91: Dynamic languages, for software craftmanship group

Hash method accessclass Hash

def method_missing(method_name, *arguments)

if has_key?(method_name)

self[method_name]

elsif has_key?(method_name.to_s)

self[method_name.to_s]

else

nil

end

end

end

35

Page 92: Dynamic languages, for software craftmanship group

Hash method accessclass Hash

def method_missing(method_name, *arguments)

if has_key?(method_name)

self[method_name]

elsif has_key?(method_name.to_s)

self[method_name.to_s]

else

nil

end

end

end

35

Page 93: Dynamic languages, for software craftmanship group

Hash method accessclass Hash

def method_missing(method_name, *arguments)

if has_key?(method_name)

self[method_name]

elsif has_key?(method_name.to_s)

self[method_name.to_s]

else

nil

end

end

end

35

Page 94: Dynamic languages, for software craftmanship group

Hash method accessclass Hash

def method_missing(method_name, *arguments)

if has_key?(method_name)

self[method_name]

elsif has_key?(method_name.to_s)

self[method_name.to_s]

else

nil

end

end

end

35

Page 95: Dynamic languages, for software craftmanship group

Hash method accessclass Hash

def method_missing(method_name, *arguments)

if has_key?(method_name)

self[method_name]

elsif has_key?(method_name.to_s)

self[method_name.to_s]

else

nil

end

end

end

35

Page 96: Dynamic languages, for software craftmanship group

xml.instruct! :xml, :version=>"1.0"xml.rss(:version=>"2.0"){ xml.channel{ xml.title("Modeling Commons updates") xml.link("http://modelingcommons.org/") xml.description("NetLogo Modeling Commons") xml.language('en-us') for update in @updates xml.item do xml.title(post.title) xml.description(post.html_content) xml.author("Your Name Here") xml.pubDate(post.created_on.strftime("%a, %d %b %Y %H:%M:%S %z")) xml.link(post.link) xml.guid(post.link) end end }}

36

Page 97: Dynamic languages, for software craftmanship group

xml.instruct! :xml, :version=>"1.0"xml.rss(:version=>"2.0"){ xml.channel{ xml.title("Modeling Commons updates") xml.link("http://modelingcommons.org/") xml.description("NetLogo Modeling Commons") xml.language('en-us') for update in @updates xml.item do xml.title(post.title) xml.description(post.html_content) xml.author("Your Name Here") xml.pubDate(post.created_on.strftime("%a, %d %b %Y %H:%M:%S %z")) xml.link(post.link) xml.guid(post.link) end end }}

36

Page 98: Dynamic languages, for software craftmanship group

xml.instruct! :xml, :version=>"1.0"xml.rss(:version=>"2.0"){ xml.channel{ xml.title("Modeling Commons updates") xml.link("http://modelingcommons.org/") xml.description("NetLogo Modeling Commons") xml.language('en-us') for update in @updates xml.item do xml.title(post.title) xml.description(post.html_content) xml.author("Your Name Here") xml.pubDate(post.created_on.strftime("%a, %d %b %Y %H:%M:%S %z")) xml.link(post.link) xml.guid(post.link) end end }}

36

Page 99: Dynamic languages, for software craftmanship group

xml.instruct! :xml, :version=>"1.0"xml.rss(:version=>"2.0"){ xml.channel{ xml.title("Modeling Commons updates") xml.link("http://modelingcommons.org/") xml.description("NetLogo Modeling Commons") xml.language('en-us') for update in @updates xml.item do xml.title(post.title) xml.description(post.html_content) xml.author("Your Name Here") xml.pubDate(post.created_on.strftime("%a, %d %b %Y %H:%M:%S %z")) xml.link(post.link) xml.guid(post.link) end end }}

36

Page 100: Dynamic languages, for software craftmanship group

xml.instruct! :xml, :version=>"1.0"xml.rss(:version=>"2.0"){ xml.channel{ xml.title("Modeling Commons updates") xml.link("http://modelingcommons.org/") xml.description("NetLogo Modeling Commons") xml.language('en-us') for update in @updates xml.item do xml.title(post.title) xml.description(post.html_content) xml.author("Your Name Here") xml.pubDate(post.created_on.strftime("%a, %d %b %Y %H:%M:%S %z")) xml.link(post.link) xml.guid(post.link) end end }}

36

Page 101: Dynamic languages, for software craftmanship group

xml.instruct! :xml, :version=>"1.0"xml.rss(:version=>"2.0"){ xml.channel{ xml.title("Modeling Commons updates") xml.link("http://modelingcommons.org/") xml.description("NetLogo Modeling Commons") xml.language('en-us') for update in @updates xml.item do xml.title(post.title) xml.description(post.html_content) xml.author("Your Name Here") xml.pubDate(post.created_on.strftime("%a, %d %b %Y %H:%M:%S %z")) xml.link(post.link) xml.guid(post.link) end end }}

36

Page 102: Dynamic languages, for software craftmanship group

Module includesmodule MyStuff

def self.included(klass)

klass.extend(ClassMethods)

end

module ClassMethods

def foo; end

end

end

37

Page 103: Dynamic languages, for software craftmanship group

Module includesmodule MyStuff

def self.included(klass)

klass.extend(ClassMethods)

end

module ClassMethods

def foo; end

end

end

37

Page 104: Dynamic languages, for software craftmanship group

Module includesmodule MyStuff

def self.included(klass)

klass.extend(ClassMethods)

end

module ClassMethods

def foo; end

end

end

37

Page 105: Dynamic languages, for software craftmanship group

Module includesmodule MyStuff

def self.included(klass)

klass.extend(ClassMethods)

end

module ClassMethods

def foo; end

end

end

37

Page 106: Dynamic languages, for software craftmanship group

Thanks!(Any questions?)

• Call me: 054-496-8405

• E-mail me: [email protected]

• Interrupt me: reuvenlerner (Skype/AIM)

38