360 likes | 479 Views
Ruby and the tools 740Tools07RubyMetaprogramming. CSCE 740 Software Engineering. Topics Blocks Yield Iterators Mix-ins. Spring 2014. Tools -. Last Time Blocks Iterators Closures. New Ruby Yield Iterators Duck-Typing Mix-ins Next Time: System Modelling. REMEMBER!.
E N D
Ruby and the tools740Tools07RubyMetaprogramming CSCE 740 Software Engineering • Topics • Blocks • Yield • Iterators • Mix-ins Spring 2014
Tools - • Last Time • Blocks • Iterators • Closures • New Ruby • Yield • Iterators • Duck-Typing • Mix-ins • Next Time: System Modelling
REMEMBER! • a.bmeans: call method b on object a • a is the receiver to which you sendthe method call, assuming a will respond tothat method • does not mean:b is an instance variable of a • does not mean: a is some kind of data structure that has b as a member • 5.class.superclass Understanding this distinction will save you from much grief and confusion UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
3.2 Everything is an Object - revisited • “Ruby’s object model descends from Smalltalk, whose design was inspired by ideas in Simula.” • Ruby: • is dynamically typed • is lexically scoped • does not support multiple inheritance • supports reflection (asking about objects) • “Even a class in Ruby is itself an object—it’s an instance of Class, which is a class whose instances are classes (a metaclass).” • def class xxx … SaaS book 2012 Fox Patterson
Poetry Mode revisited • To improve readability by removing clutter: • omit parentheses, braces as long as parsing remains unambiguous • spreading long lines over multiple lines • using “ ; ” instead of newline as separator • surround “;” with spaces – making meaner clearer • attr_accessor :year SaaS book 2012 Fox Patterson
long lines multiple lines http://pastebin.com/dFJjugTf • # downcase and split are defined in String class • words = IO.read("file"). • split(/\W+/). • select { |s| s =~ /^[aeiou]/i }. • map { |s| s.downcase }. • uniq. • sort
http://pastebin.com/K6ev3S7g Splat Args • # using 'keyword style' arguments • defmymethod(required_arg, args={}) • do_fancy_stuff if args[:fancy] • end • mymethod "foo",:fancy => true # => args={:fancy => true} • mymethod "foo" # => args={} • # using * (splat) arguments • defmymethod(required_arg, *args) • # args is an array of extra args, maybe empty • end • mymethod "foo","bar",:fancy => true # => args=["bar",{:fancy=>true}] • mymethod "foo" # => args=[]
3.5 All Programming is Metaprogramming • attr_accessor :year • creating code at run-time SaaS book 2012 Fox Patterson
# Note: Time.now returns current time as seconds since epoch • class Fixnum • def seconds ; self ; end • def minutes ; self * 60 ; end • def hours ; self * 60 * 60 ; end • def ago ; Time.now - self ; end • deffrom_now ; Time.now + self ; end • end • Time.now # => Mon Nov 07 10:18:10 -0800 2011 • 5.minutes.ago # => Mon Nov 07 10:13:15 -0800 2011 • 5.minutes - 4.minutes # => 60 • 3.hours.from_now # => Mon Nov 07 13:18:15 -0800 2011
method_missinghttp://pastebin.com/G0ztHTTP • class Fixnum • defmethod_missing(method_id, *args) • name = method_id.to_s • if name =~ /^(second|minute|hour)$/ • self.send(name + 's') • else • super # pass the buck to superclass • end • end • end
3.6 Blocks: Iterators, Functional Idioms, and Closures • Fox, Armando; Patterson, David (2014-01-31). Engineering Software as a Service: An Agile Approach Using Cloud Computing (Kindle Location 2514). Strawberry Canyon LLC. Kindle Edition.
Loops—but don’t think of them that way ["apple", "banana", "cherry"].each do |string| puts string end for i in (1..10) do puts i end 1.upto 10 do |num| puts num end 3.times { print "Rah, " } UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
If you’re iterating with an index, you’re probably doing it wrong • Iterators let objects manage their own traversal • (1..10).each do |x| ... end(1..10).each { |x| ... }1.upto(10) do |x| ... end=> range traversal • my_array.each do |elt| ... end=> array traversal • hsh.each_key do |key| ... endhsh.each_pair do |key,val| ... end=> hash traversal • 10.times {...} # => iterator of arity zero • 10.times do ... end UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
“Expression orientation” x = ['apple','cherry','apple','banana'] x.sort # => ['apple','apple','banana','cherry'] x.uniq.reverse # => ['banana','cherry','apple'] x.reverse! # => modifies x x.map do |fruit| fruit.reverse end.sort # => ['ananab','elppa','elppa','yrrehc'] x.collect { |f| f.include?("e") } x.any? { |f| f.length > 5 } • A real life example.... http://pastebin.com/Aqgs4mhE UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
Which string will not appear in the result of: ['banana','anana','naan'].map do |food| food.reverse end.select { |f| f.match /^a/ } naan ☐ ananab ☐ anana ☐ The above code won’t run due to syntax error(s) ☐ UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
Collection Operators • Method - #Args - Returns a new collection containing. . . • c.map 1 - elements obtained by applying block to each element of c • c.select 1 Subset of c for which block evaluates to true • c.reject 1 Subset of c obtained by removing elements for which block evaluates to true • c.uniq all elements of c with duplicates removed • c.reverse elements of c in reverse order • c.compact all non-nil elements of c • c.flatten elements of c and any of its sub-arrays, recursively flattened to contain only non-array elements
More Collection Operators • c.sort -If sort is called without a block, the elements are sorted according to how they respond to <=>. • c.partition • c.sort_by • c.max • c.min • Fox, Armando; Patterson, David (2014-01-31). Engineering Software as a Service: An Agile Approach Using Cloud Computing (Kindle Locations 2594-2595). Strawberry Canyon LLC. Kindle Edition.
What is “duck typing”? • If it responds to the same methods as a duck...it might as well be a duck • More than just overloading; similar to Java Interfaces • Example: my_list.sort [5, 4, 3].sort ["dog", "cat", "rat"].sort [:a, :b, :c].sort IO.readlines("my_file") UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
Modules • A module is a collection of class & instance methods that 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 mix the methods into a class: class 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
A Mix-in Is A Contract • Example: Enumerable assumes objects of target class respond to each • ...provides all?, any?, collect, find, include?, inject, map, partition, .... • Example: Comparable assumes that objects of target class respond to <=> • provides < <= => > == between?for free • Enumerable also provides sort, which requires elements of target class (things returned by each) to respond to <=> Class of objects doesn’t matter: only methods to which they respond UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
Example: sorting a file • Sorting a file • File.open returns an IO object • IO objects respond to each by returning each line as a String • So we can say File.open('filename.txt').sort • relies on IO#each and String#<=> • Which lines of file begin with vowel? File.open('file').select { |s| s =~ /^[aeiou]/i } UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
a = SavingsAccount.new(100) b = SavingsAccount.new(50) c = SavingsAccount.new(75) What’s result of [a,b,c].sort Works, because account balances (numbers) get compared ☐ Doesn’t work, but would work if we passed a comparison method to sort ☐ Doesn’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 ☐ UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
Making accounts comparable • Just define<=> and then use the Comparable module to get the other methods • Now, an Account quacks like a numeric http://pastebin.com/itkpaqMh UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
When Module? When Class? • Modules reuse behaviors • high-level behaviors that could conceptually apply to many classes • Example: Enumerable, Comparable • Mechanism: mixin (include Enumerable) • Classes reuse implementation • subclass reuses/overrides superclass methods • Mechanism: inheritance (class A < B) • Remarkably often, we will prefer composition over inheritance UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
Blocks (anonymous λ) (map '(lambda (x) (+ x 2)) mylist ) mylist.map { |x| x+2 } (filter '(lambda (x) (even? x)) mylist) mylist.select do |x| ; x.even? ; end (map '(lambda (x) (+ x 2)) (filter '(lambda (x) (even? x)) mylist)) mylist.select {|x| x.even?}.map {|x| x+2 } UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
Turning iterators inside-out • 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: • 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... http://pastebin.com/T3JhV7Bk UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
http://pastebin.com/0sTEMcdN • <!DOCTYPE html> • <html> • <head> • <title>Report</title> • </head> • <body> • <div id="main"> • ...user-generated content here... • </div> • </body> • </html> SaaS book 2012 Fox Patterson
1 defone_page • 2 page = ’’ • 3 page << make_header() • 4 page << "Hello" • 5 page << make_footer() • 6 end 7 defanother_page • 8 page = ’’ • 9 page << make_header() • 10 page << "World" • 11 page << make_footer() • 12 end SaaS book 2012 Fox Patterson
http://pastebin.com/TsvTN5ZT • defmake_page(contents) • page = '' • page << make_header() • page << contents • page << make_footer() • end • # • defone_page • make_page("Hello") • end • defanother_page • make_page("World") • end
http://pastebin.com/zQPh70NJ • defmake_page • page = '' • page << make_header() • page << yield • page << make_footer() • end • defone_page • make_page do • "Hello" • end • end • defanother_page • … SaaS book 2012 Fox Patterson
We can exploit Ruby’s idiom for single-line blocks to boil this down to: http://pastebin.com/Nqe8MwA5 • defmake_page • make_header << yield << make_footer • end • defone_page • make_page { "Hello" } • end • defanother_page • make_page { "World" } • end SaaSbook http://pastebin.com/Nqe8MwA5
http://pastebin.com/T3JhV7Bk • class RandomSequence • def initialize(limit,num) • @limit,@num = limit,num • end • def each • @num.times { yield (rand * @limit).floor } • end • end UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
Iterators are just one nifty use of yield # in some other library def before_stuff ...before code... end def after_stuff ...after code... end # in your code def do_everything before_stuff() my_custom_stuff() after_stuff() end Without yield(): expose 2 calls in other library # in some other library def around_stuff ...before code... yield ...after code... end # in your code def do_everything around_stuff do my_custom_stuff() end end With yield(): expose 1 call in other library UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
Blocks are Closures • A closure is the set of all variable bindings you can “see” at a given point in time • In Scheme, it’s called an environment • Blocks are closures: they carry their environment around with them • Result: blocks can help reuse by separating what to do from where & when to do it • We’ll see various examples in Rails http://pastebin.com/zQPh70NJ UCB CS169 Sp 2012 Slides Fox, Patterson and Sen
Summary of Yield • In the body of a method that takes a block as a parameter, yield transfers control to the block and optionally passes it an argument. • A block is a closure, its scope is the one that was in effect when the block was defined, • 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
3.9 Fallacies and Pitfalls • Pitfall: Writing Java in Ruby • Pitfall: Thinking of symbols and strings as interchangeable. • Pitfall: Naming a local variable when you meant a local method. • Pitfall: Confusing require with include. • Fox, Armando; Patterson, David (2014-01-31). Engineering Software as a Service: An Agile Approach Using Cloud Computing (Kindle Locations 2811-2812). Strawberry Canyon LLC. Kindle Edition. SaaS book 2012 Fox Patterson