Ruby wizardry, p.17

Ruby Wizardry, page 17

 

Ruby Wizardry
Select Voice:
Brian (uk)
Emma (uk)  
Amy (uk)
Eric (us)
Ivy (us)
Joey (us)
Salli (us)  
Justin (us)
Jennifer (us)  
Kimberly (us)  
Kendra (us)
Russell (au)
Nicole (au)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

Larger Font   Reset Font Size   Smaller Font  

  Lastly, Ruby does have some built-in methods that can help make your code more secure (or at least control which methods can be called). If you like, you can read all about it in the Ruby docs: http://ruby-doc.org/core-2.0.0/Module.html#method-i-private.

  You Know This!

  You learned some tricky stuff in this chapter, but I’m confident you’ve got a good handle on it. Just to be sure, let’s go through it all once more.

  First, we reviewed how to create a Ruby class using the class keyword.

  class Greeting def say_hello puts 'Hello!' end end

  Next, you found out that Ruby classes can share information and methods with each other through inheritance: just as a person can inherit traits from her parents, one Ruby class can inherit information and behavior from another. The class that does the inheriting is called a subclass or child class, and the class it inherits from is called the superclass or parent class.

  Inheritance syntax looks like this:

  class Dog < Animal def bark puts 'Arf!' end end

  In this example, because Dog inherits from Animal, instances of the Dog class (made with Dog.new) can use any of the methods defined in the Animal class.

  We also learned about method overriding and the super keyword. Method overriding is just writing a method in a subclass that has the same name as a method in the superclass; when we create an instance of the subclass, it will use the subclass’s version of the method instead of the superclass’s. You’d want to override the superclass’s method any time you want different or more specific behavior in the subclass. For example, say you’re writing a game where your wizard is a hero (class Wizard < Hero), and wizards use magic in their attack method instead of the game’s default sword.

  You can override a method like so:

  class Hero def initialize(name) @name = name end def attack puts "Swung sword for #{rand(5)} damage!" end end class Wizard < Hero def attack puts "Cast spell for #{rand(20)} damage!" end end

  We can see this in the following example: the hero’s pretty good with a sword, but the wizard knows how to cast spells!

  >> aragorn = Hero.new('Aragorn') => # >> aragorn.attack Swung sword for 4 damage! => nil >> gandalf = Wizard.new('Gandalf') => # >> gandalf.attack Cast spell for 17 damage! => nil

  If we want to change only part of a method, we use super; we add whatever extra functionality we want, then call super to call the superclass’s version of the method, like so:

  class Wizard < Hero def attack super # This calls Hero's attack method puts 'But I also know magic! You shall not pass!' end end

  The attack method is doing two things. First, it calls the superclass’s version of attack using super (that is, the attack defined in Hero that just prints the Swung sword message). Then it prints an additional message (But I also know magic! You shall not pass!). You’d do this when you want to modify the behavior of the superclass’s method, but not replace it completely.

  >> gandalf = Wizard.new('Gandalf') => # >> gandalf.attack Swung sword for 2 damage! But I also know magic! You shall not pass! => nil

  Last but not least, you saw that you can call super with arguments in order to send the right arguments to the superclass’s method:

  class Dog attr_accessor :name def initialize(name) @name = name end end class GuardDog < Dog attr_reader :strength def initialize(name, strength) @strength = strength super(name) end end

  Now when we create a GuardDog, it adds its own @strength and lets Dog take care of adding the @name:

  >> mook = GuardDog.new('Mook', 2) => # >> mook.name => "Mook" >> mook.strength => 2

  All right! At this point, you’re a class master. Well, almost—just as there are ways to update and change your methods, there are ways to update and change your classes; you can even mix behaviors from a bunch of different classes into the Ruby classes you create! The last piece of the Ruby class puzzle is modules, and if we hurry, we can get down to the Royal Stables just in time to learn all about them.

  Chapter 10. A Horse of a Different Color

  Utter Panda-monium

  The King, the Queen, Ruben, and Scarlet spiraled down staircase after staircase toward the Royal Stables. Just when Ruben and Scarlet thought there would be no end to the twisty maze of stairs, the Queen reached a huge set of heavy oak doors and threw them open. They all ran blinking into the sudden light of the fields behind the palace, and only a stone’s throw away stood the entrance to the Royal Stables.

  “Over here!” said the Queen. “Quickly now!”

  They ran to the front gate of the stables, where two of the Queen’s guards were waiting. Each held a very familiar-looking Senior Apprentice to the Royal Plumber by the arm.

  “Haldo!” gasped Ruben.

  “Now, now,” said the King. “I’m sure there’s a reasonable explanation for all this.” Despite his words, the King looked worried. He turned to Haldo. “Haldo, what in the name of the Hashery’s glorious breakfast hash is the explanation for all this?”

  Before Haldo could respond, the Queen approached the guards. “Haldo isn’t who I saw in my Royal Office,” she said. “There were four of them, and they were much shorter. Please release him.”

  The guards nodded and dropped Haldo’s arms.

  “Thank you, Your Highness,” Haldo said, brushing himself off.

  “Why are you down here at the stables?” asked the King.

  “That’s what we were just asking him,” said the guard with the crooked nose.

  “I was trying to explain,” said Haldo. “You see, after searching through the Ambrose Caverns and finding nothing, I returned to my work as the Senior Apprentice to the Royal Plumber. I’d learned so much from Scarlet and Ruben about Ruby, though, that I could do a day’s work in just a few hours. I had a bit of spare time on my hands, so I took on the job of Part-Time Apprentice to the Royal Stableman as well.”

  “Marvelous,” said the King, visibly relieved that Haldo was not the villain they’d been chasing. “A veritable jack-of-all-trades!”

  “I’m not sure I’d go that far,” Haldo said, blushing slightly.

  “Your Majesties,” said the guard without the crooked nose, “we chased a group of hooded figures from the Queen’s office, but lost track of them once they got out here to the stables. When we saw what had happened, Haldo was the only one around. We thought he might be involved, so we called the Queen.” He shrugged. “Turns out Haldo had come out to see what the trouble was and try to help.”

  “One moment,” said the Queen. “When you saw what had happened in the stables?”

  The guards exchanged an uneasy look. “You’d better come see,” said the guard with the crooked nose.

  The group hurried into the stables. The two guards pointed to the first stall, and the King, the Queen, Ruben, and Scarlet peered inside.

  “Strangest horse I’ve ever seen,” said the King.

  “That . . . is a panda,” said Ruben.

  “And it’s red!” moaned the Queen. “Good heavens, what’s happened here?”

  “It’s not supposed to be red?” Scarlet asked.

  “Not at all!” said the Queen. “All royal pandas are supposed to be purple!” She ran to the next stall, then the next, then the next. “This one’s blue!” she cried. “And this one’s yellow! Not a single panda is purple!” She threw up her hands. “Whoever heard of a Purple Panda-monium Parade with pandas of every color except purple?”

  “Wait, the pandas were purple, but now they’re not?” said Ruben. “Aren’t they born purple?”

  “And what, exactly, is the Purple Panda-monium Parade?” Scarlet asked.

  “One at a time,” said the Queen. She turned to Ruben “No, the pandas aren’t born purple. They’re born white, but we feed them special extra-nutritious food that turns them purple. As for the parade,” she said to Scarlet, “We hold it once a month to celebrate the peace and prosperity of the kingdom. We figure if there’s going to be a little craziness in our lives, we should at least be in control of it.” She sighed. “Of course, given all the chaos today, we won’t be able to hold the parade.”

  “Not so fast,” said Scarlet. “I’ll bet we can fix this! It sounds like someone must have tampered with the pandas’ food. Where is it?”

  “Over here,” said Haldo. “The food is prepared by the Panda Provisionator 3000.”

  They all walked past the rows of stalls to the far side of the stable, where a huge round machine covered in dials and switches hummed away. A familiar-looking screen glowed in its center.

  “A Computing Contraption!” said Ruben. “Does the Panda Provisionator 3000 run on Ruby?”

  “Absolutely,” said Haldo. “Ever since you kids helped me fix the Mysterious Pipe, I’ve been learning as much Ruby as I can. I daresay I’ve gotten pretty good,” he said, hooking his thumbs behind the straps of his overalls. “I’ve even gotten the hang of the Panda Provisionator here.”

  “Could you tell us if someone’s messed with the pandas’ food?” Ruben asked.

  “And can you fix it?” asked the Queen, looking anxious.

  Creating Modules

  “I think so,” said Haldo. “Let’s have a look.” He opened a file called colorize.rb on the Computing Contraption, and this is what the group saw:

  module Colorize def color [:red, :blue, :green, :yellow].sample end end

  “Aha!” said Haldo. “I see the trouble here. Someone’s changed the color method to return a random color as a symbol—either red, blue, green, or yellow. That’s what the sample method does,” he explained. “It picks a random item from an array.”

  “That’s why the pandas are all different colors except purple!” Ruben said. “But wait a minute—there’s nothing about panda food in this file. And what does the first line mean?”

  “That? That means this code is a module,” said Haldo, scratching his heavy black beard. “You can think of a Ruby module as a bucket of handy information and methods that we can use whenever we need it.”

  “It looks kind of like a class,” said Scarlet.

  “It’s very much like a class!” said Haldo. “Like classes, modules have their own methods. In fact, that’s all modules really are: just collections of methods!”

  “Then what’s the difference between classes and modules?” Ruben asked.

  “Modules are actually exactly like classes, only we can’t make new modules with the new method,” Haldo explained. “First, let’s do a lightning-quick review of classes.” He started up IRB and typed:

  >> class FancyClass; end => nil

  “That just creates a new, empty class called FancyClass,” Haldo explained.

  “What’s that semicolon for?” Scarlet asked.

  “It’s just a way of telling Ruby you’re done with a line of code,” Haldo said. “Normally in IRB you do that by pressing RETURN or ENTER and starting a new line, but since our class and module definitions are empty, we can just use the semicolon to tell Ruby we’re done with one line and we’re starting a new one.” He shrugged. “Some people don’t like to use semicolons. To each her own! Now, let’s create an instance of our FancyClass.”

  >> FancyClass.new => #

  “You’ve created instances of classes before, right?” Haldo asked. Scarlet and Ruben nodded. “Good!” he said. “Now, let’s create a module and try to create an instance of it.”

  >> module ImportantThings; end => nil >> ImportantThings.new NoMethodError: undefined method `new' for ImportantThings:Module

  “Trying to create an instance of a module causes an error because modules don’t have the new method that classes do,” Haldo said.

  “So if you can’t create instances of a module,” Ruben said, “what can you do with it?”

  “I’ll show you!” said Haldo. “Let’s create a module of our own.” He typed:

  >> module Bucket >> MAX_BITS_AND_TRINKETS = 100 >> def announcing_bits_and_trinkets >> puts 'Step right up! Bits and trinkets available now!' >> end >> end => nil

  “What’s MAX_BITS_AND_TRINKETS,” Scarlet asked, “and why is it in all caps?”

  Constants

  “That’s a constant,” said Haldo. “Constants are like variables, only their values don’t change once you set them. They start with a capital letter—for example, class and module names are constants—and while you technically can reassign them during your Ruby program, Ruby will warn you if you do. See?” He typed:

  >> RUBY = 'Wonderful!' => "Wonderful!" >> RUBY = 'Stupendous!' (irb):2: warning: already initialized constant RUBY => "Stupendous!"

  “When you create your own constant that isn’t a class or module—that is, just a name for a value that won’t change—you usually write it in ALL CAPS,” Haldo said.

  “Can you use constants only inside modules?” Ruben asked.

  “Nope!” Haldo said. “You can use them anywhere in your Ruby program. I just bring them up now because class names and module names are technically constants, since they start with a capital letter.”

  “That’s pretty cool,” said Scarlet, “but how do we get to our ALL CAPS constants and methods if they’re stuck inside a module?”

  “I’m glad you asked,” Haldo said, smiling. “Let’s have a look!” He typed some more:

  >> class Announcer >> include Bucket >> end => Announcer

  “Here, I’ve made an Announcer class that includes the Bucket module. Our Bucket module contains a constant, MAX_BITS_AND_TRINKETS, which is set to 100, and a method, announcing_bits_and_trinkets, that prints some text on the screen.

  When we include a module in a class, the constants and methods in that module can be used by any instance of the class. Because we’ve included Bucket in Announcer, an Announcer can now use any of the constants and methods defined in Bucket! Let’s create an instance of Announcer and see what happens when we use a method we defined in Bucket.”

  >> loud_lucy = Announcer.new => # >> loud_lucy.announcing_bits_and_trinkets Step right up! Bits and trinkets available now! => nil

  “Wow!” said Ruben. “loud_lucy knows how to use the announcing_bits_and_trinkets method, even though it’s defined in the Bucket module!”

  Extending Your Knowledge

  “Exactly!” said Haldo. “But include isn’t the only way to get constants and methods defined in modules into other classes. Have a look at this.” He typed some more:

  >> class Announcer >> extend Bucket >> end => Announcer >> Announcer.announcing_bits_and_trinkets Step right up! Bits and trinkets available now! => nil

  “If we extend the module Bucket into the class, then those constants and methods can be used by the class itself,” Haldo explained. “In this case, the class Announcer—instead of its instance, loud_lucy—can use the method. You usually end up wanting your instances to have the method rather than your classes, so in my experience, you tend to include more often than you extend.”

  “Remember when I said there was a Ruby trick that lets you mix the behavior of several classes into one?” asked the Queen. “This is how you do it!”

  Mixins and Inheritance

  “Wait,” said Ruben. “So you can have a class that inherits from another class and includes modules to add extra methods?”

  “See for yourself!” replied Haldo, and he typed:

  >> module Enchanted >> def speak >> puts 'Hello there!' >> end >> end => nil

  “First, I’ve just created an Enchanted module with a single speak method.”

  >> class Animal >> def initialize(name) >> @name = name >> end >> end => nil

  “Next, I’ve created an Animal class that takes care of setting the names of the Animal instances we create.”

  >> class Dog < Animal >> include Enchanted >> def bark >> puts 'Arf!' >> end >> end => nil

  “In the next step, I’ve created a Dog class that inherits from Animal and includes Enchanted. If we’ve done everything right, our Dog instances should be able to use the Dog bark method and the Enchanted speak method. Let’s try it now!”

  >> bigelow = Dog.new('Bigelow') => # >> bigelow.bark Arf! => nil >> bigelow.speak Hello there! => nil

  “When we use a module this way, we call it a mixin,” Haldo said, “because you’re mixing new constants and methods into an existing class. Basically, Dog now gets the powers of Animal and Enchanted, even though it only directly inherits from Animal. We can include as many classes as we like! Assuming we defined all these modules somewhere, we could use them all in a row:

  class Dog include Enchanted include Magical include AnythingWeLike # ...and so on and so forth end

  “So if you had a Dog class and the modules Enchanted, Magical, and AnythingWeLike,” said the King, “if you were to make a dog with the Dog class, that dog could use any of the methods defined in Enchanted, Magical, or AnythingWeLike.”

  “Exactly,” Haldo said. “We could also extend our class with as many modules as we wanted.” He continued typing:

  class Dog extend Enchanted extend Magical extend AnythingWeLike # ...and so on and so forth end

  “That’s amazing!” said Scarlet.

  “But hang on just a second,” Ruben said. “That means that somewhere on the Computing Contraption, there’s a file for the panda food that includes the Colorize module?”

 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
Add Fast Bookmark
Load Fast Bookmark
Turn Navi On
Turn Navi On
Turn Navi On
Scroll Up
Turn Navi On
Scroll
Turn Navi On
183