TKVR

Chris Pine, Learn to Program Chapter 8 - Own Methods

Feb 22nd, 2012
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 15.34 KB | None | 0 0
  1. # Writing Your Own Methods
  2. # Sometimes we want to do the same thing a number of times, but from different places in the program. For example, let's say we were writing a questionnaire program for a psychology student. From the psychology students I have known and the questionnaires they have given me, it would probably go something like this:
  3. puts 'Hello, and thank you for taking the time to'
  4. puts 'help me with this experiment. My experiment'
  5. puts 'has to do with the way people feel about'
  6. puts 'Mexican food. Just think about Mexican food'
  7. puts 'and try to answer every question honestly,'
  8. puts 'with either a "yes" or a "no". My experiment'
  9. puts 'has nothing to do with bed-wetting.'
  10. puts
  11.  
  12. # We ask these questions, but we ignore the answers.
  13. goodAnswer = false
  14. while (not goodAnswer)
  15.   puts 'Do you enjoy eating tacos?'
  16.   answer = gets.chomp.downcase
  17.   if (answer == 'yes' or answer == 'no')
  18.     goodAnswer = true
  19.   else
  20.     puts 'Please answer "yes" or "no".'
  21.   end
  22. end
  23.  
  24. goodAnswer = false
  25. while (not goodAnswer)
  26.   puts 'Do you lieke eating burritos?'
  27.   answer = gets.chomp.downcase
  28.   if (answer == 'yes' or answer == 'no')
  29.     goodAnswer = true
  30.   else
  31.     puts 'Please answer "yes" or "no".'
  32.   end
  33. end
  34.  
  35. # We pay attention to the answer below, however.
  36. goodAnswer = false
  37. while (not goodAnswer)
  38.   puts 'Do you wet the bed?'
  39.   answer = gets.chomp.downcase
  40.   if (answer == 'yes' or answer == 'no')
  41.     goodAnswer = true
  42.     if answer == 'yes'
  43.       wetsBed = true
  44.     else
  45.       wetsBed = false
  46.     end
  47.   else
  48.     puts 'Please answer "yes" or "no".'
  49.   end
  50. end
  51.  
  52. goodAnswer = false
  53. while (not goodAnswer)
  54.   puts 'Do you like eating chimichangas?'
  55.   answer = gets.chomp.downcase
  56.   if (answer == 'yes' or answer == 'no')
  57.     goodAnswer = true
  58.   else
  59.     puts 'Please answer "yes" or "no".'
  60.   end
  61. end
  62.  
  63. puts 'Just a few more questions...'
  64.  
  65. goodAnswer = false
  66. while (not goodAnswer)
  67.   puts 'Do you like eating sopapillas?'
  68.   answer = gets.chomp.downcase
  69.   if (answer == 'yes' or answer == 'no')
  70.     goodAnswer = true
  71.   else
  72.     puts 'Please answer "yes" or "no".'
  73.   end
  74. end
  75.  
  76. #  Ask lots of other questions about Mexican food.
  77.  
  78. puts
  79. puts 'DEBRIEFING:'
  80. puts 'Thank you for taking the time to help with'
  81. puts 'this experiment.  In fact, this experiment'
  82. puts 'has nothing to do with Mexican food.  It is'
  83. puts 'an experiment about bed-wetting.  The Mexican'
  84. puts 'food was just there to catch you off guard'
  85. puts 'in the hopes that you would answer more'
  86. puts 'honestly.  Thanks again.'
  87. puts
  88. puts wetsBed
  89.  
  90. # Repetition is a bad thing. Still, we can't make it into a big loop or iterator, because sometimes we have things we want to do between questions. In situations like these, it's best to write a method. You want to tell the program HOW to say mooo and to DO it.
  91. def sayMoo
  92.   puts 'moooooo...'
  93. end
  94.  
  95. sayMoo
  96. sayMoo
  97. puts 'coin-coin' # French Duck speaking...
  98. sayMoo
  99. sayMoo
  100. # So we defined the method sayMoo. (Method names, like variable names, start with a lowercase letter. There are a few exceptions, though, like + or ==.) But don't methods always have to be associated with objects? Well, yes they do, and in this case (as with  puts and gets), the method is just associated with the object representing the whole program.
  101.  
  102. # Method Parameters
  103. # some methods (like  gets, to_s, reverse...) you can just call on an object. However, other methods (like +, -, puts...) take parameters to tell the object how to do the method. For example, you wouldn't just say  5+, right? You're telling 5 to add, but you aren't telling it what to add.
  104.  
  105. # To add a parameter to sayMoo (let's say, the number of moos), we would do this:
  106. def sayMoo numberOfMoos
  107.   puts 'moooooooo...'*numberOfMoos
  108. end
  109.  
  110. sayMoo 3
  111. puts 'oink-oink'
  112. # sayMoo
  113. # Returns an error because the parameter is missing.
  114. # numberOfMoos is a variable which points to the parameter passed in. So if I type in sayMoo 3, then the parameter is 3, and the variable numberOfMoos points to 3. Thus, the parameter is REQUIRED. If objects in Ruby are like nouns in English, and methods are like verbs, then you can think of parameters as adverbs (like with sayMoo, where the parameter told us how to sayMoo) or sometimes as direct objects (like with puts, where the parameter is what gets putsed).
  115.  
  116. # Local Variables
  117. def doubleThis num
  118.   numTimes2 = num*2
  119.   puts num.to_s+' doubled is '+numTimes2.to_s
  120. end
  121.  
  122. doubleThis 44
  123.  
  124. # The variables are num and numTimes2. They both sit inside the method doubleThis. These (and all of the variables you have seen so far) are local variables. This means that they live inside the method, and they cannot leave. If you try, you will get an error:
  125. #  def doubleThis num
  126. #    numTimes2 = num*2
  127. #    puts num.to_s+' doubled is '+numTimes2.to_s
  128. #  end
  129.  
  130. #  doubleThis 44
  131. #  puts numTimes2.to_s
  132. # Error Message - Undefined local variable... In fact, we did define that local variable, but it isn't local to where we tried to use it; it's local to the method.
  133.  
  134. # While it does mean that you have no access to variables inside methods, it also means that they have no access to your variables, and thus can't screw them up:
  135. def littlePest var
  136.   var = nil
  137.   puts 'HAHA!  I ruined your variable!'
  138. end
  139.  
  140. var = 'You can\'t even touch my variable!'
  141. littlePest var
  142. puts var
  143. # There are actually two variables in that little program named var: one inside littlePest, and one outside of it. When we called littlePest var, we really just passed the string from one var to the other, so that both were pointing to the same string. Then littlePest pointed its own local  var to nil, but that did nothing to the  var outside the method.
  144.  
  145. # Return Values
  146. # Arithmetic methods for numbers return numbers, and arithmetic methods for strings return strings.
  147. # Important to understand the difference between methods returning a value to where the method was called, and your program outputting information to your screen, like  puts does. Notice that 5+3 returns  8; it does not output  8.
  148.  
  149. # So what does puts return? We never cared before, but let's look at it now:
  150. returnVal = puts 'This puts returned:'
  151. puts returnVal # So the first puts returned nil. Though we didn't test it, the second puts did, too;  puts always returns nil. Every method has to return something, even if it's just nil.
  152.  
  153. # Write a program to find out what sayMoo returned.
  154. # Here's how it works: the value returned from a method is simply the last line of the method. In the case of sayMoo, this means it returns  puts 'mooooooo...'*numberOfMoos, which is just nil since puts always returns  nil. If we wanted all of our methods to return the string 'yellow submarine', we would just need to put that at the end of them:
  155. def sayMoo numberOfMoos
  156.   puts 'moooooo...'*numberOfMoos
  157.   'yellow submarine'
  158. end
  159.  
  160. x = sayMoo 2
  161. puts x
  162.  
  163. # Let's try that psychology experiment again, but this time we'll write a method to ask the questions for us. It will need to take the question as a parameter, and return  true if they answered yes and  false if they answered no. (Even though most of the time we just ignore the answer, it's still a good idea for our method to return the answer. This way we can use it for the bed-wetting question, too.) I'm also going to shorten the greeting and the debriefing, just so this is easier to read:
  164. def ask question
  165.   goodAnswer = false
  166.   while (not goodAnswer)
  167.     puts question
  168.     reply = gets.chomp.downcase
  169.      
  170.     if (reply == 'yes' or reply =='no')
  171.       goodAnswer = true
  172.       if reply == 'yes'
  173.         answer = true
  174.       else
  175.         answer = false
  176.       end
  177.     else
  178.       puts 'Please answer "yes" or "no".'
  179.     end
  180.   end
  181.    
  182.     answer # This is what we return (true or false).
  183. end
  184.  
  185. puts 'Hello, and thank you for...'
  186. puts
  187.  
  188. ask 'Do you like eating tacos?' # We ignore this return value.
  189. ask 'Do you like eating burritos?'
  190. wetsBed = ask 'Do you wet the bed?' # We save this return value.
  191. ask 'Do you like eating chimichangas?'
  192. ask 'Do you like eating sopapillas?'
  193. ask 'Do you like eating tamales?'
  194. puts 'Just a few more questions...'
  195. ask 'Do you like drinking horchata?'
  196. ask 'Do you like eating flautas?'
  197.  
  198. puts
  199. puts 'BEBRIEFING:'
  200. puts 'Thank you for...'
  201. puts
  202. puts wetsBed
  203.  
  204. # englishNumber Example Method
  205. # This program will take a number, like 22, and return the englishversion of it (in this case, the string 'twenty-two'). For now let's have it only work on intefers from 0 to 100.
  206. # (NOTE: This method uses a new trick to return from a method early using the return keyword, and introduces a new twist on branching: elsif. It should be clear in context how these work.)
  207. def englishNumber number
  208.   # We only want numbers from 0-100
  209.   if number < 0
  210.     return 'Please enter a number zero or greater.'
  211.   end
  212.   if number > 100
  213.     return 'Please enter a number 100 or lesser.'
  214.   end
  215.  
  216.   numString = '' # This is the string we will return.
  217.  
  218.   # "left" is how much o the number we still have left to write out.
  219.   # "write" is the part we are writing out right now.
  220.   # write and left... get it? ;)
  221.   left = number
  222.   write = left/100 # How many hundreds left to write out?
  223.   left = left - write*100 # Subtract off those hundreds.
  224.  
  225.   if write > 0
  226.     return 'one hundred'
  227.   end
  228.  
  229.   write = left/10 # How many tens left to write out?
  230.   left = left - write*10 # Subtract off those tens.
  231.  
  232.   if write > 0
  233.     if write == 1 # Uh-oh...
  234.       # Since we can't write "twenty-two" instead of "tweleve",
  235.       # we have to make a special exception for these
  236.       if    left == 0
  237.         numString = numString + 'ten'
  238.       elsif left == 1
  239.         numString = numString + 'eleven'
  240.       elsif left == 2
  241.         numString = numString + 'twelve'
  242.       elsif left == 3
  243.         numString = numString + 'thirteen'
  244.       elsif left == 4
  245.         numString = numString + 'fourteen'
  246.       elsif left == 5
  247.         numString = numString + 'fifteen'
  248.       elsif left == 6
  249.         numString = numString + 'sixteen'
  250.       elsif left == 7
  251.         numString = numString + 'seventeen'
  252.       elsif left == 8
  253.         numString = numString + 'eighteen'
  254.       elsif left == 9
  255.         numString = numString + 'nineteen'
  256.       end
  257.       # Since we took care of the digit in the ones place already,
  258.       # we have nothing left to write.
  259.       left = 0
  260.     elsif write == 2
  261.       numString = numString + 'twenty'
  262.     elsif write == 3
  263.       numString = numString + 'thirty'
  264.     elsif write == 4
  265.       numString = numString + 'forty'
  266.     elsif write == 5
  267.       numString = numString + 'fifty'
  268.     elsif write == 6
  269.       numString = numString + 'sixty'
  270.     elsif write == 7
  271.       numString = numString + 'seventy'
  272.     elsif write == 8
  273.       numString = numString + 'eighty'
  274.     elsif write == 9
  275.       numString = numString + 'ninety'
  276.     end
  277.    
  278.     if left > 0
  279.       numString = numString + '-'
  280.     end
  281.   end
  282.  
  283.   write = left # How many ones left to write out?
  284.   left = 0 # Subtract off those ones.
  285.  
  286.   if write > 0
  287.     if    write == 1
  288.       numString = numString + 'one'
  289.     elsif write == 2
  290.       numString = numString + 'two'
  291.     elsif write == 3
  292.       numString = numString + 'three'
  293.     elsif write == 4
  294.       numString = numString + 'four'
  295.     elsif write == 5
  296.       numString = numString + 'five'
  297.     elsif write == 6
  298.       numString = numString + 'six'
  299.     elsif write == 7
  300.       numString = numString + 'seven'
  301.     elsif write == 8
  302.       numString = numString + 'eight'
  303.     elsif write == 9
  304.       numString = numString + 'nine'
  305.     end
  306.   end
  307.  
  308.   if numString == ''
  309.     # The only way "numString" could be empty is if "number" is 0
  310.     return 'zero'
  311.   end
  312.  
  313.   # If we got this far, then we had a number somewhere in between
  314.   # 0 and 100, so we need to return "numString".
  315.   numString
  316. end
  317.  
  318. puts englishNumber(  0)
  319. puts englishNumber(  9)
  320. puts englishNumber( 10)
  321. puts englishNumber( 11)
  322. puts englishNumber( 17)
  323. puts englishNumber( 32)
  324. puts englishNumber( 88)
  325. puts englishNumber( 99)
  326. puts englishNumber(100)
  327.  
  328. # PROBLEMS: First, it has too much repetition. Second, it doesn't handle numbers greater than 100. Third, there are too many special cases, too many returns. Let's use some arrays and try to clean it up a bit:
  329. def englishNumber number
  330.   if number < 0 # No negative numbers.
  331.     return 'Please enter a number that isn\'t negative.'
  332.   end
  333.   if number == 0
  334.     return 'zero'
  335.   end
  336.  
  337.   # No more special cases! no more returns!
  338.  
  339.   numString = '' # This is the string we will return.
  340.  
  341.   onesPlace = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']
  342.   tensPlace = ['ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']
  343.   teenagers = ['eleven', 'tweleve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen']
  344.  
  345.   # "left" is how much of the number we still have left to write out.
  346.   # "write" is the part we are writing out wright now.
  347.   # write and left.. get it? ;)
  348.   left = number
  349.   write = left/100 # How many hundreds left to write out?
  350.   left = left - write*100 # Subtract off those hundreds.
  351.  
  352.   if write > 0
  353.     # Now here's a really sly trick:
  354.     hundreds = englishNumber write
  355.     numString = numString + hundreds + ' hundred'
  356.     # That's called "recursion". So what did I just do?
  357.     # I told this method to call itself, but with "write" instead of
  358.     # "number". Remember that "write" is (at the moment) the number of
  359.     # hundreds we have to write out. After we add "hundreds" to "numString"
  360.     # we add the string ' hundred' after it. So, for example, if
  361.     # we originally called englishNumber with 1999 (so "number" = 1999),
  362.     # then at this point "write" would be 19, and "left" would be 99.
  363.     # The laziest thing to do at this point is to have englishNumber
  364.     # write out the 'nineteen' for us, then we write out ' hundred',
  365.     # and then the rest of englishNumber writes out 'ninety-nine'.
  366.    
  367.     if left > 0
  368.       # So we don't write 'two hundredfifty-one'...
  369.       numString = numString + ' '
  370.     end
  371.   end
  372.  
  373.   write = left/10 # How many tens left to write out?
  374.   left = left - write*10 # Subtract off those tens.
  375.  
  376.   if write > 0
  377.     if ((write == 1) and (left > 0))
  378.       # Since we can't write "twenty-two" instead of "twelve",
  379.       # we have to make a speecial exception for these.
  380.       numString = numString + teenagers[left-1]
  381.       # The "-1" is because teenagers[3] is 'fourteen', not 'thirteen'.
  382.      
  383.       # Since we took care of the digit in the ones place already,
  384.       # we have nothing left to write.
  385.       left = 0
  386.     else
  387.       numString = numString + tensPlace[write-1]
  388.       # The "-1" is because tensPlace[3] s 'forty', not 'thirty'.
  389.     end
  390.    
  391.     if left > 0
  392.       # So we don't write sixtyfour'...
  393.       numString = numString + '-'
  394.     end
  395.   end
  396.  
  397.   write = left # How many ones left to write out?
  398.   left = 0 # Subtract off those ones.
  399.  
  400.   if write > 0
  401.     numString = numString + onesPlace[write-1]
  402.     # The "-1" is because onesPlace[3] is 'four', not 'three'.
  403.   end
  404.  
  405.   # Now we just return "numString"...
  406.   numString
  407. end
  408.  
  409. puts englishNumber(  0)
  410. puts englishNumber(  9)
  411. puts englishNumber( 10)
  412. puts englishNumber( 11)
  413. puts englishNumber( 17)
  414. puts englishNumber( 32)
  415. puts englishNumber( 88)
  416. puts englishNumber( 99)
  417. puts englishNumber(100)
  418. puts englishNumber(101)
  419. puts englishNumber(234)
  420. puts englishNumber(3211)
  421. puts englishNumber(999999)
  422. puts englishNumber(1000000000000)
Add Comment
Please, Sign In to add comment