ruby and the tools 740tools07rubymetaprogramming topics blocks yield iterators mix-ins spring 2014...
TRANSCRIPT
Ruby and the tools740Tools07RubyMetaprogramming
Ruby and the tools740Tools07RubyMetaprogramming
TopicsTopics
Blocks Yield Iterators Mix-ins
Spring 2014
CSCE 740 Software Engineering
– 2 – CSCE 740 Spring 2014
Tools - Tools -
Last TimeLast Time Blocks Iterators Closures
New RubyNew Ruby Yield Iterators Duck-Typing Mix-ins
Next Time: System Modelling Next Time: System Modelling
– 3 – CSCE 740 Spring 2014
REMEMBER!REMEMBER!
a.ba.b means: call method means: call method bb on object on object aa a is the receiver to which you send the method
call, assuming a will respond to that method
does not meandoes not mean:: bb is an instance variable of is an instance variable of aa
does not meandoes not mean: : aa is some kind of data is some kind of data structure that has structure that has bb as a member as a member
5.class.superclass5.class.superclass
Understanding this distinction will save you Understanding this distinction will save you from much grief and confusionfrom much grief and confusion
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 4 – CSCE 740 Spring 2014
3.2 Everything is an Object - revisited3.2 Everything is an Object - revisited
““Ruby’s object model descends from Smalltalk, whose Ruby’s object model descends from Smalltalk, whose design was inspired by ideas in Simula.”design was inspired by ideas in Simula.”
Ruby:Ruby:
is dynamically typedis dynamically typed
is lexically scopedis lexically scoped
does not support multiple inheritancedoes not support multiple inheritance
supports reflection (asking about objects)supports reflection (asking about objects)
““Even a class in Ruby is itself an object—it’s an Even a class in Ruby is itself an object—it’s an instance of Class, which is a class whose instances instance of Class, which is a class whose instances are classes (a metaclass).”are classes (a metaclass).”
def class xxx …def class xxx …SaaS book 2012 Fox Patterson
– 5 – CSCE 740 Spring 2014
Poetry Mode revisited Poetry Mode revisited
To improve readability by removing clutter:To improve readability by removing clutter:
omit parentheses, braces as long as parsing remains omit parentheses, braces as long as parsing remains unambiguousunambiguous
spreading long lines over multiple linesspreading long lines over multiple lines
using “ ; ” instead of newline as separatorusing “ ; ” instead of newline as separator surround “;” with spaces – making meaner clearer
attr_accessor :yearattr_accessor :year
SaaS book 2012 Fox Patterson
– 6 – CSCE 740 Spring 2014
long lines multiple lines http://pastebin.com/dFJjugTflong lines multiple lines http://pastebin.com/dFJjugTf
# downcase and split are defined in String class# downcase and split are defined in String class
words = IO.read("file").words = IO.read("file").
split(/\W+/).split(/\W+/).
select { |s| s =~ /^[aeiou]/i }.select { |s| s =~ /^[aeiou]/i }.
map { |s| s.downcase }.map { |s| s.downcase }.
uniq.uniq.
sortsort
– 7 – CSCE 740 Spring 2014
http://pastebin.com/K6ev3S7g Splat Argshttp://pastebin.com/K6ev3S7g Splat Args
# using 'keyword style' arguments# using 'keyword style' arguments
def mymethod(required_arg, args={})def mymethod(required_arg, args={})
do_fancy_stuff if args[:fancy]do_fancy_stuff if args[:fancy]
endend
mymethod "foo",:fancy => true # => args={:fancy => true}mymethod "foo",:fancy => true # => args={:fancy => true}
mymethod "foo" # => args={}mymethod "foo" # => args={}
# using * (splat) arguments# using * (splat) arguments
def mymethod(required_arg, *args)def mymethod(required_arg, *args)
# args is an array of extra args, maybe empty# args is an array of extra args, maybe empty
end end
mymethod "foo","bar",:fancy => true # => args=["bar",mymethod "foo","bar",:fancy => true # => args=["bar",{:fancy=>true}]{:fancy=>true}]
mymethod "foo" # => args=[]mymethod "foo" # => args=[]
– 8 – CSCE 740 Spring 2014
3.5 All Programming is Metaprogramming3.5 All Programming is Metaprogrammingattr_accessor :yearattr_accessor :year
creating code at run-timecreating code at run-time
SaaS book 2012 Fox Patterson
– 9 – CSCE 740 Spring 2014
# Note: Time.now returns current time as seconds since # Note: Time.now returns current time as seconds since epochepoch
class Fixnumclass Fixnum
def seconds ; self ; enddef seconds ; self ; end
def minutes ; self * 60 ; enddef minutes ; self * 60 ; end
def hours ; self * 60 * 60 ; enddef hours ; self * 60 * 60 ; end
def ago ; Time.now - self ; enddef ago ; Time.now - self ; end
def from_now ; Time.now + self ; enddef from_now ; Time.now + self ; end
endend
Time.now Time.now # => Mon Nov 07 10:18:10 -0800 2011# => Mon Nov 07 10:18:10 -0800 2011
5.minutes.ago5.minutes.ago # => Mon Nov 07 10:13:15 -0800 2011# => Mon Nov 07 10:13:15 -0800 2011
5.minutes - 4.minutes5.minutes - 4.minutes# => 60# => 60
3.hours.from_now3.hours.from_now # => Mon Nov 07 13:18:15 -0800 2011# => Mon Nov 07 13:18:15 -0800 2011
– 10 – CSCE 740 Spring 2014
method_missinghttp://pastebin.com/G0ztHTTPmethod_missinghttp://pastebin.com/G0ztHTTPclass Fixnumclass Fixnum
def method_missing(method_id, *args)def method_missing(method_id, *args)
name = method_id.to_sname = method_id.to_s
if name =~ /^(second|minute|hour)$/if name =~ /^(second|minute|hour)$/
self.send(name + 's')self.send(name + 's')
elseelse
super # pass the buck to superclasssuper # pass the buck to superclass
endend
endend
endend
– 11 – CSCE 740 Spring 2014
3.6 Blocks: Iterators, Functional Idioms, and Closures3.6 Blocks: Iterators, Functional Idioms, and Closures
Fox, Armando; Patterson, David (2014-01-31). Fox, Armando; Patterson, David (2014-01-31). Engineering Software as a Service: An Agile Engineering Software as a Service: An Agile Approach Using Cloud Computing (Kindle Location Approach Using Cloud Computing (Kindle Location 2514). Strawberry Canyon LLC. Kindle Edition. 2514). Strawberry Canyon LLC. Kindle Edition.
– 12 – CSCE 740 Spring 2014
Loops—but don’t think of them that wayLoops—but don’t think of them that way["apple", "banana", "cherry"].each do |string|["apple", "banana", "cherry"].each do |string| puts stringputs stringendend
for i in (1..10) dofor i in (1..10) do puts iputs iendend
1.upto 10 do |num|1.upto 10 do |num| puts numputs numendend
3.times { print "Rah, " }3.times { print "Rah, " }
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 13 – CSCE 740 Spring 2014
If you’re iterating with an index, you’re probably doing it wrongIf you’re iterating with an index, you’re probably doing it wrongIterators Iterators let objects manage their own traversallet objects manage their own traversal
(1..10).each do |x| ... end(1..10).each do |x| ... end(1..10).each { |x| ... }(1..10).each { |x| ... }1.upto(10) do |x| ... end1.upto(10) do |x| ... end => range traversal=> range traversal
my_array.each do |elt| ... endmy_array.each do |elt| ... end=> array traversal=> array traversal
hsh.each_key do |key| ... endhsh.each_key do |key| ... endhsh.each_pair do |key,val| ... endhsh.each_pair do |key,val| ... end=> hash traversal=> hash traversal
10.times {...} 10.times {...} # => iterator of arity zero# => iterator of arity zero
10.times do ... end10.times do ... endUCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 14 – CSCE 740 Spring 2014
“Expression orientation”“Expression orientation”
x = ['apple','cherry','apple','banana']x = ['apple','cherry','apple','banana']x.x.sort sort # => ['apple','apple','banana','cherry']# => ['apple','apple','banana','cherry']
x.uniq.reverse x.uniq.reverse # => ['banana','cherry','apple']# => ['banana','cherry','apple']x.reverse! x.reverse! # => modifies x# => modifies xx.map x.map do do |fruit||fruit| fruit.reversefruit.reverseendend.sort .sort # => ['ananab','elppa','elppa','yrrehc']# => ['ananab','elppa','elppa','yrrehc']x.collect { |f| f.x.collect { |f| f.include?include?("e") }("e") }x.any? { |f| f.x.any? { |f| f.length length > 5 }> 5 }
A real life example....A real life example.... http://pastebin.com/Aqgs4mhEUCB CS169 Sp 2012 Slides Fox, Patterson and Sen
ananab
anana
The above code won’t run due to syntax error(s)
naan☐
☐
☐
☐
15
Which string will not appear in the result of:['banana','anana','naan'].map do |food| food.reverseend.select { |f| f.match /^a/ }
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 16 – CSCE 740 Spring 2014
Collection OperatorsCollection Operators
Method - #Args - Returns a new collection containing. . .Method - #Args - Returns a new collection containing. . .
c.map 1 - elements obtained by applying block to each c.map 1 - elements obtained by applying block to each element of c element of c
c.select 1 Subset of c for which block evaluates to truec.select 1 Subset of c for which block evaluates to true
c.reject 1 Subset of c obtained by removing elements c.reject 1 Subset of c obtained by removing elements for which block evaluates to true for which block evaluates to true
c.uniq all elements of c with duplicates removedc.uniq all elements of c with duplicates removed
c.reverse elements of c in reverse order c.reverse elements of c in reverse order
c.compact all non-nil elements of c c.compact all non-nil elements of c
c.flatten elements of c and any of its sub-arrays, c.flatten elements of c and any of its sub-arrays, recursively flattened to contain only non-array elementsrecursively flattened to contain only non-array elements
– 17 – CSCE 740 Spring 2014
More Collection OperatorsMore Collection Operators
c.sort -If sort is called without a block, the elements are c.sort -If sort is called without a block, the elements are sorted according to how they respond to <=>.sorted according to how they respond to <=>.
c.partitionc.partition
c.sort_byc.sort_by
c.maxc.max
c.minc.min
Fox, Armando; Patterson, David (2014-01-31). Engineering Fox, Armando; Patterson, David (2014-01-31). Engineering Software as a Service: An Agile Approach Using Cloud Software as a Service: An Agile Approach Using Cloud Computing (Kindle Locations 2594-2595). Strawberry Computing (Kindle Locations 2594-2595). Strawberry Canyon LLC. Kindle Edition. Canyon LLC. Kindle Edition.
– 18 – CSCE 740 Spring 2014
What is “duck typing”?What is “duck typing”?
If it responds to the same If it responds to the same methods as a duck...it might methods as a duck...it might as well be a duckas well be a duck
More than just overloading; More than just overloading; similar to Java Interfacessimilar to Java Interfaces
Example: Example: my_list.sortmy_list.sort[5, 4, 3].sort["dog", "cat", "rat"].sort[:a, :b, :c].sortIO.readlines("my_file")
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 19 – CSCE 740 Spring 2014
ModulesModules
A A module module is a collection of class & instance methods is a collection of class & instance methods that are not actually a classthat are not actually a class you can’t instantiate it Some modules are namespaces, similar to Python: Math::sin(Math::PI / 2.0)
The more interesting ones let you The more interesting ones let you mix the methods into mix the methods into a class: a class: class A < B ; include MyModule ; endclass A < B ; include MyModule ; end A.foo will search A, then MyModule, then B sort is actually defined in module Enumerable, which is mixed into Array by default
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 20 – CSCE 740 Spring 2014
A Mix-in Is A ContractA Mix-in Is A ContractExample: Example: EnumerableEnumerable assumes objects of target assumes objects of target
class respond to class respond to eacheach ...provides all?, any?, collect, find, include?, inject, map, partition, ....
Example: Example: Comparable Comparable assumes that objects of assumes that objects of target class respond to target class respond to <=><=> provides < <= => > == between? for free
EnumerableEnumerable also provides also provides sortsort, which requires , which requires elementselements of target class (things returned by of target class (things returned by eacheach) ) to respond to to respond to <=><=>
ClassClass of objects doesn’t matter: only of objects doesn’t matter: only methodsmethods to to which they respondwhich they respond
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 21 – CSCE 740 Spring 2014
Example: sorting a fileExample: sorting a file
Sorting a fileSorting a file File.open returns an IO object
IO objects respond to each by returning each line as a
String
So we can say So we can say File.open('filename.txt').sortFile.open('filename.txt').sort relies on IO#each and String#<=>
Which lines of file begin with vowel?Which lines of file begin with vowel?
File.open('file').select { |s| s =~ /^[aeiou]/i }
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
Doesn’t work, but would work if we passed a comparison method to sortDoesn’t work, but would work if we defined <=> on SavingsAccount Doesn’t work: SavingsAccount isn’t a basic Ruby type so can’t compare them
Works, because account balances (numbers) get compared
☐
☐
☐
☐
22
a = SavingsAccount.new(100)b = SavingsAccount.new(50)c = SavingsAccount.new(75)What’s result of [a,b,c].sort
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 23 – CSCE 740 Spring 2014
Making accounts comparableMaking accounts comparable
Just defineJust define <=><=> and then use the and then use the ComparableComparable module module to get the other methodsto get the other methods
Now, an Now, an AccountAccount quacks like a numeric quacks like a numeric
http://pastebin.com/itkpaqMh
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 24 – CSCE 740 Spring 2014
When Module? When Class?When Module? When Class?
Modules reuse Modules reuse behaviors behaviors high-level behaviors that could conceptually apply to many
classes
Example: Enumerable, Comparable Mechanism: mixin (include Enumerable)
Classes reuse Classes reuse implementationimplementation subclass reuses/overrides superclass methods
Mechanism: inheritance (class A < B)
Remarkably often, we will Remarkably often, we will prefer composition over prefer composition over inheritanceinheritance
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 25 – CSCE 740 Spring 2014
Blocks (anonymous λ)Blocks (anonymous λ)
(map '(lambda (x) (+ x 2)) mylist )(map '(lambda (x) (+ x 2)) mylist )
mylist.map { |x| x+2 }mylist.map { |x| x+2 }
(filter '(lambda (x) (even? x)) mylist)(filter '(lambda (x) (even? x)) mylist)
mylist.select do |x| ; x.even? ; endmylist.select do |x| ; x.even? ; end
(map(map
'(lambda (x) (+ x 2))'(lambda (x) (+ x 2))
(filter '(lambda (x) (even? x)) mylist))(filter '(lambda (x) (even? x)) mylist))
mylist.select {|x| x.even?}.map {|x| x+2 }mylist.select {|x| x.even?}.map {|x| x+2 }UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 26 – CSCE 740 Spring 2014
Turning iterators inside-outTurning iterators inside-out
Java: Java: You hand me each element of that collection in turn. I’ll do some stuff. Then I’ll ask you if there’s any more left.
Ruby:Ruby: Here is some code to apply to every element of the collection. You manage the iteration or data structure traversal.
Let’s do an example... Let’s do an example...
http://pastebin.com/T3JhV7BkUCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 27 – CSCE 740 Spring 2014
http://pastebin.com/0sTEMcdNhttp://pastebin.com/0sTEMcdN
<!DOCTYPE html><!DOCTYPE html>
<html><html>
<head><head>
<title>Report</title><title>Report</title>
</head></head>
<body><body>
<div id="main"><div id="main">
...user-generated content here......user-generated content here...
</div></div>
</body></body>
</html></html>SaaS book 2012 Fox Patterson
– 28 – CSCE 740 Spring 2014
1 def one_page 1 def one_page
2 page = ’’ 2 page = ’’
3 page << make_header() 3 page << make_header()
4 page << "Hello" 4 page << "Hello"
5 page << make_footer() 5 page << make_footer()
6 end 7 def another_page 6 end 7 def another_page
8 page = ’’ 8 page = ’’
9 page << make_header() 9 page << make_header()
10 page << "World" 10 page << "World"
11 page << make_footer() 11 page << make_footer()
12 end12 end
SaaS book 2012 Fox Patterson
– 29 – CSCE 740 Spring 2014
http://pastebin.com/TsvTN5ZThttp://pastebin.com/TsvTN5ZT
def make_page(contents)def make_page(contents)
page = ''page = ''
page << make_header()page << make_header()
page << contentspage << contents
page << make_footer()page << make_footer()
endend
##
def one_pagedef one_page
make_page("Hello")make_page("Hello")
endend
def another_pagedef another_page
make_page("World")make_page("World")
endend
– 30 – CSCE 740 Spring 2014
http://pastebin.com/zQPh70NJhttp://pastebin.com/zQPh70NJ
def make_pagedef make_page
page = ''page = ''
page << make_header()page << make_header()
page << yieldpage << yield
page << make_footer()page << make_footer()
endend
def one_pagedef one_page
make_page domake_page do
"Hello""Hello"
endend
endend
def another_pagedef another_page
… …SaaS book 2012 Fox Patterson
– 31 – CSCE 740 Spring 2014
We can exploit Ruby’s idiom for single-line blocks to We can exploit Ruby’s idiom for single-line blocks to boil this down to: http://pastebin.com/Nqe8MwA5boil this down to: http://pastebin.com/Nqe8MwA5
def make_pagedef make_page
make_header << yield << make_footermake_header << yield << make_footer
endend
def one_pagedef one_page
make_page { "Hello" }make_page { "Hello" }
endend
def another_pagedef another_page
make_page { "World" }make_page { "World" }
endend
SaaSbook http://pastebin.com/Nqe8MwA5
– 32 – CSCE 740 Spring 2014
http://pastebin.com/T3JhV7Bkhttp://pastebin.com/T3JhV7Bk
class RandomSequenceclass RandomSequence
def initialize(limit,num)def initialize(limit,num)
@limit,@num = limit,num@limit,@num = limit,num
endend
def eachdef each
@num.times { yield (rand * @limit).floor }@num.times { yield (rand * @limit).floor }
endend
endend
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 33 – CSCE 740 Spring 2014
Iterators are just one nifty use of yieldIterators are just one nifty use of yield# in some other library# in some other librarydef def before_stuffbefore_stuff ...before code......before code...endenddef def after_stuffafter_stuff ...after code......after code...endend
# in your code# in your codedef do_everythingdef do_everything before_stuff()before_stuff() my_custom_stuff()my_custom_stuff() after_stuff()after_stuff()endend
Without yield(): expose 2 Without yield(): expose 2 calls in other librarycalls in other library
# in some other librarydef around_stuff ...before code... yield ...after code...end
# in your codedef do_everything around_stuff do my_custom_stuff() endend
With yield(): expose 1 call in other library
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 34 – CSCE 740 Spring 2014
Blocks are ClosuresBlocks are Closures
A A closure closure is the set of all variable bindings you can is the set of all variable bindings you can “see” at a given point in time“see” at a given point in time In Scheme, it’s called an environment
Blocks are closures: Blocks are closures: they carry their environment they carry their environment around with themaround with them
Result: blocks can help reuse by separating Result: blocks can help reuse by separating what to do what to do from from where & when to do itwhere & when to do it We’ll see various examples in Rails
http://pastebin.com/zQPh70NJ
UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
– 35 – CSCE 740 Spring 2014
Summary of YieldSummary of Yield
In the body of a method that takes a block as a In the body of a method that takes a block as a parameter, yield transfers control to the block and parameter, yield transfers control to the block and optionally passes it an argument. optionally passes it an argument.
A block is a closure, its scope is the one that was in A block is a closure, its scope is the one that was in effect when the block was defined,effect when the block was defined,
Yielding is the general mechanism behind iterators: Yielding is the general mechanism behind iterators: an iterator is simply a method that traverses some data
structure and uses yield to pass one element at a time to the iterator’s receiver.
SaaS book 2012 Fox Patterson
– 36 – CSCE 740 Spring 2014
3.9 Fallacies and Pitfalls3.9 Fallacies and Pitfalls
PitfallPitfall: Writing Java in Ruby: Writing Java in Ruby
PitfallPitfall: Thinking of symbols and strings as : Thinking of symbols and strings as interchangeable.interchangeable.
PitfallPitfall: Naming a local variable when you meant a : Naming a local variable when you meant a local method.local method.
PitfallPitfall: Confusing require with include.: Confusing require with include.
Fox, Armando; Patterson, David (2014-01-31). Fox, Armando; Patterson, David (2014-01-31). Engineering Software as a Service: An Agile Engineering Software as a Service: An Agile Approach Using Cloud Computing (Kindle Locations Approach Using Cloud Computing (Kindle Locations 2811-2812). Strawberry Canyon LLC. Kindle Edition.2811-2812). Strawberry Canyon LLC. Kindle Edition.
SaaS book 2012 Fox Patterson