Latest Tweet
- Downgraded to iPhone OS 3.1.3, upgraded to responsive 3G iPhone. :P 2 weeks ago
- More updates...
Categories
Tags
academia alcohol animals boyfriend cooking databases email forwards family Flickr food friends health Lexington Linux list Mario math movies music news OS X Perl photos PHP politics programming quizzes Rails rants reading Ruby screenshots shopping Sims sports themes tutorials Twilight is ridiculous vehicles video games videos weather Web development work zombies again-
Recent Comments
-
Random Quote
"Oh, this looks disgusting."
— my differential equations professor when talking about xy" + (x-1)y' - y = 0 Syndication
All posts RSS feed
the power of yield and super
The two keywords
yieldandsuperallow you to pass control back and forth between parent and child methods, to weave power between a more general method (in the parent class) and a more specific method (in the child class) with ease and logic. Usingyieldandsupereffectively can help you maintain the DRY (Don’t repeat yourself) principle, keeping your code easier to maintain.Say you have three classes for image creation: a parent class,
Image, and two children:RasterandVector. Now for your raster images, you’re going to be using the GD2 library for Ruby, and for your vector images, you’re going to be creating SVG images. Some of the functionality used to create any given image will be different, naturally, since with the raster images, you’re creating an image object, and with the vector images, you’re concatenating strings of XML SVG code. However, a lot of the code will be the same, and should thus be shared between the two children to avoid duplication. For example, the logic used to determine what color some text should be, or what shape you should draw, can be shared between the two child classes. Any shared code should go in the one common class between the two children: the parent class,Image.Accessing Shared Code
That is, accessing code in a parent class method from a child class method of the same name. The trick is with
super.write_text()inRasterRuby
super() do |width, height, left, top|
image = Image.new( width, height )
image.draw do |canvas|
canvas.color = color
canvas.font = Font::TrueType[‘/usr/share/fonts/times.ttf‘, 20]
canvas.move_to( left, top )
canvas.text( text )
end
end
image
end
write_text()inVectorRuby
image = ‘<?xml version="1.0" encoding="UTF-8" standalone="no"?>’
image << ‘<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd">’
super() do |width, height, left, top|
image << ‘<svg viewBox="0 0 ‘ + width.to_s + ‘ ‘ + height.to_s + ‘" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">’
image << ‘<text font-family="Times" x="’ + left.to_s + ‘" y="’ + top.to_s + ‘" fill="’ + color.to_s + ‘">’
end
image << text.to_s
image << ‘</text>’
image << ‘</svg>’
image
end
While these two methods accomplish the same thing, they do it differently. However, each of them has a call to
super. That will access a method of the same name in the parent class:write_text()inImageRuby
yield( 300, 100, 5, 5 )
end
All that
Image’swrite_text()is doing is passing values back to the child method that called it. Each child method’ssupercall defines variables in the block: width, height, left, and top in the line that sayssuper() do |width, height, left, top|. Theyieldcall inImagedefines those values to be width = 300, height = 100, left = 5, and top = 5. ToImage’swrite_text(), however, it’s just throwing some numbers at the child method: it doesn’t know that the child method is going to use those numbers to define the dimensions of the image and the starting position of its text.The definition of
write_text()inImageis very simple, but it doesn’t have to be that way. There could be a great deal of calculation involved in determining what values the child methods should use for whichever variables are being passed to it. The parent class’s shared method is a place to store shared logic and shared data; let the child classes do the specific stuff with that general data.Shared Variables Sans
yieldValues can also be reached in the child class methods without using
yieldif instance variables are defined in the parent method:write_text()inImageRuby
@width = 300
@height = 100
@left = @top = 5
end
Then
write_text()in bothRasterandVectorwould be able to accessImage’s@width,@height,@left, and@top, as defined in itswrite_text().Multiple Calls to
superSometimes it may be useful to let the parent class’s method do some work, then the child class’s, then the parent’s again. In this case, you can call
superandyieldas many times as necessary:Method in Child Class
Ruby
return1 = super( ‘a string‘ ) do |my_var|
# Do some stuff with my_var
end
return2 = super( [‘array‘, ‘of’, ’strings’] ) do |my_other_var|
# Do some stuff with my_other_var
end
end
Method in Parent Class
Ruby
if value.class == String
yield( ‘this is my_var’ )
elsif value.class == Array
yield( ‘this is my_other_var’ )
end
# Checks to see if value can work with the <<
# method, which both Array and String objects
# have, and if so, adds another string to it;
# this value is returned since it’s the last
# line of the method
value << ‘ appended to value’ if value.respond_to?( :<< )
end
yieldReturns Data tosuperThe child class method can also throw data back to the parent class method by returning a value from the
superblock:Method in Child Class
Ruby
value_from_parent = super do |my_var|
‘this gets thrown back to the parent class method’
end
end
Method in Parent Class
Ruby
value_from_child = yield( ‘becomes my_var’ )
‘this gets thrown back to the child class method’
end
More Information
superandyielduse.