Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ruby / Yukihiro Matsumoto_Programming Ruby.doc
Скачиваний:
122
Добавлен:
06.06.2015
Размер:
2.71 Mб
Скачать

Calling a Method

You call a method by specifying a receiver, the name of the method, and optionally some parameters and an associated block.

connection.downloadMP3("jitterbug") { |p| showProgress(p) }

In this example, the object connectionis the receiver,downloadMP3is the name of the method,"jitterbug"is the parameter, and the stuff between the braces is the associated block.

For class and module methods, the receiver will be the class or module name.

File.size("testfile")

Math.sin(Math::PI/4)

If you omit the receiver, it defaults to self, the current object.

self.id

»

537790064

id

»

537790064

self.type

»

Object

type

»

Object

This defaulting mechanism is how Ruby implements private methods. Private methods may notbe called with a receiver, so they must be methods available in the current object.

The optional parameters follow the method name. If there is no ambiguity you can omit the parentheses around the argument list when calling a method.[Other Ruby documentation sometimes calls these method calls without parentheses ``commands.'']However, except in the simplest cases we don't recommend this---there are some subtle problems that can trip you up.[In particular, you must use parentheses on a method call that is itself a parameter to another method call (unless it is the last parameter).]Our rule is simple: if there's any doubt, use parentheses.

a = obj.hash    # Same as

a = obj.hash()  # this.

obj.someMethod "Arg1", arg2, arg3   # Same thing as

obj.someMethod("Arg1", arg2, arg3)  # with parentheses.

Expanding Arrays in Method Calls

Earlier we saw that if you put an asterisk in front of a formal parameter in a method definition, multiple arguments in the call to the method will be bundled up into an array. Well, the same thing works in reverse.

When you call a method, you can explode an array, so that each of its members is taken as a separate parameter. Do this by prefixing the array argument (which must follow all the regular arguments) with an asterisk.

def five(a, b, c, d, e)

  "I was passed #{a} #{b} #{c} #{d} #{e}"

end

five(1, 2, 3, 4, 5 )

»

"I was passed 1 2 3 4 5"

five(1, 2, 3, *['a', 'b'])

»

"I was passed 1 2 3 a b"

five(*(10..14).to_a)

»

"I was passed 10 11 12 13 14"

Making Blocks More Dynamic

We've already seen how you can associate a block with a method call.

listBones("aardvark") do |aBone|

  # ...

end

Normally, this is perfectly good enough---you associate a fixed block of code with a method, in the same way you'd have a chunk of code after an iforwhilestatement.

Sometimes, however, you'd like to be more flexible. For example, we may be teaching math skills.[Of course, Andy and Dave would have to learn math skills first. Conrad Schneiker reminded us that there are three kinds of people: those who can count and those who can't.]The student could ask for ann-plus table or ann-times table. If the student asked for a 2-times table, we'd output 2, 4, 6, 8, and so on. (This code does not check its inputs for errors.)

print "(t)imes or (p)lus: "

times = gets

print "number: "

number = gets.to_i

if times =~ /^t/

  puts((1..10).collect { |n| n*number }.join(", "))

else

  puts((1..10).collect { |n| n+number }.join(", "))

end

produces:

(t)imes or (p)lus: t

number: 2

2, 4, 6, 8, 10, 12, 14, 16, 18, 20

This works, but it's ugly, with virtually identical code on each branch of the ifstatement. If would be nice if we could factor out the block that does the calculation.

print "(t)imes or (p)lus: "

times = gets

print "number: "

number = gets.to_i

if times =~ /^t/

  calc = proc { |n| n*number }

else

  calc = proc { |n| n+number }

end

puts((1..10).collect(&calc).join(", "))

produces:

(t)imes or (p)lus: t

number: 2

2, 4, 6, 8, 10, 12, 14, 16, 18, 20

If the last argument to a method is preceded by an ampersand, Ruby assumes that it is a Procobject. It removes it from the parameter list, converts theProcobject into a block, and associates it with the method.

This technique can also be used to add some syntactic sugar to block usage. For example, you sometimes want to take an iterator and store each value it yields into an array. We'll reuse our Fibonacci number generator from page 40.

a = []

fibUpTo(20) { |val| a << val }

»

nil

a.inspect

»

"[1, 1, 2, 3, 5, 8, 13]"

This works, but our intention isn't quite as transparent as we may like. Instead, we'll define a method called into, which returns the block that fills the array. (Notice at the same time that the block returned really is a closure---it references the parameteranArrayeven after methodintohas returned.)

def into(anArray)

  return proc { |val| anArray << val }

end

fibUpTo 20, &into(a = [])

a.inspect

»

"[1, 1, 2, 3, 5, 8, 13]"

Соседние файлы в папке Ruby