Recherche…


Introduction

Les fonctions de Ruby fournissent un code organisé et réutilisable pour préparer un ensemble d'actions. Les fonctions simplifient le processus de codage, empêchent la logique redondante et facilitent le suivi du code. Cette rubrique décrit la déclaration et l'utilisation des fonctions, des arguments, des paramètres, des instructions de rendement et de la portée dans Ruby.

Remarques

Une méthode est un bloc de code nommé, associé à un ou plusieurs objets et généralement identifié par une liste de paramètres en plus du nom.

def hello(name)
  "Hello, #{name}"
end

Un appel de méthode spécifie le nom de la méthode, l'objet sur lequel il doit être appelé (parfois appelé récepteur) et zéro ou plusieurs valeurs d'argument affectées aux paramètres de la méthode nommée. La valeur de la dernière expression évaluée dans la méthode devient la valeur de l'expression d'invocation de la méthode.

hello("World")
# => "Hello, World"

Lorsque le récepteur n'est pas explicite, il est self .

self
# => main

self.hello("World")
# => "Hello, World"

Comme expliqué dans le manuel Ruby Programming Language , de nombreux langages distinguent les fonctions sans objet associé et les méthodes appelées sur un objet récepteur. Ruby étant un langage purement orienté objet, toutes les méthodes sont des méthodes vraies et sont associées à au moins un objet.

Vue d'ensemble des paramètres de la méthode

Type Signature de méthode Exemple d'appel Les devoirs
R Évalué def fn(a,b,c) fn(2,3,5) a=2, b=3, c=5
V ariadic def fn(*rest) fn(2,3,5) rest=[2, 3, 5]
D efault def fn(a=0,b=1) fn(2,3) a=2, b=3
K eyword def fn(a:0,b:1) fn(a:2,b:3) a=2, b=3

Ces types d'arguments peuvent être combinés de presque toutes les manières possibles pour créer des fonctions variadiques. Le nombre minimum d'arguments de la fonction sera égal à la quantité d'arguments requis dans la signature. Les arguments supplémentaires seront d'abord affectés aux paramètres par défaut, puis au paramètre *rest .

Type Signature de méthode Exemple d'appel Les devoirs
R, D, V, R def fn(a,b=1,*mid,z) fn(2,97) a=2, b=1, mid=[], z=97
fn(2,3,97) a=2, b=3, mid=[], z=97
fn(2,3,5,97) a=2, b=3, mid=[5], z=97
fn(2,3,5,7,97) a=2, b=3, mid=[5,7], z=97
R, K, K def fn(a,g:6,h:7) fn(2) a=2, g=6, h=7
fn(2,h:19) a=2, g=6, h=19
fn(2,g:17,h:19) a=2, g=17, h=19
VK def fn(**ks) fn(a:2,g:17,h:19) ks={a:2, g:17, h:19}
fn(four:4,five:5) ks={four:4, five:5}

Paramètre unique requis

def say_hello_to(name)
    puts "Hello #{name}"
end

say_hello_to('Charles')    # Hello Charles

Plusieurs paramètres requis

def greet(greeting, name)
    puts "#{greeting} #{name}"
end

greet('Hi', 'Sophie')    # Hi Sophie

Paramètres par défaut

def make_animal_sound(sound = 'Cuack')
    puts sound
end

make_animal_sound('Mooo') # Mooo
make_animal_sound         # Cuack

Il est possible d'inclure des valeurs par défaut pour plusieurs arguments:

def make_animal_sound(sound = 'Cuack', volume = 11)
    play_sound(sound, volume)
end

make_animal_sound('Mooo') # Spinal Tap cow

Cependant, il n'est pas possible de fournir le second sans fournir le premier. Au lieu d'utiliser des paramètres de position, essayez les paramètres de mot clé:

def make_animal_sound(sound: 'Cuack', volume: 11)
    play_sound(sound, volume)
end

make_animal_sound(volume: 1) # Duck whisper

Ou un paramètre de hachage qui stocke les options:

def make_animal_sound(options = {})
    options[:sound]  ||= 'Cuak'
    options[:volume] ||= 11
    play_sound(sound, volume)
end

make_animal_sound(:sound => 'Mooo') 

Les valeurs de paramètres par défaut peuvent être définies par n'importe quelle expression ruby. L'expression s'exécutera dans le contexte de la méthode, vous pouvez même déclarer des variables locales ici. Notez que vous ne passerez pas en revue les codes. Gracieuseté de caius pour l' avoir signalé .

def make_animal_sound( sound = ( raise 'TUU-too-TUU-too...' ) ); p sound; end

make_animal_sound 'blaaaa' # => 'blaaaa'
make_animal_sound          # => TUU-too-TUU-too... (RuntimeError)

Paramètre (s) facultatif (opérateur splat)

def welcome_guests(*guests)
    guests.each { |guest| puts "Welcome #{guest}!" }
end

welcome_guests('Tom')    # Welcome Tom!
welcome_guests('Rob', 'Sally', 'Lucas') # Welcome Rob!
                                        # Welcome Sally!
                                        # Welcome Lucas!

Notez que welcome_guests(['Rob', 'Sally', 'Lucas']) affichera Welcome ["Rob", "Sally", "Lucas"]!
Au lieu de cela, si vous avez une liste, vous pouvez faire welcome_guests(*['Rob', 'Sally', 'Lucas']) et cela fonctionnera comme welcome_guests('Rob', 'Sally', 'Lucas') .

Mélange de paramètres facultatif par défaut requis

def my_mix(name,valid=true, *opt)
    puts name
    puts valid
    puts opt
end

Appelez comme suit:

my_mix('me')
# 'me'
# true
# []

my_mix('me', false)
# 'me'
# false
# []

my_mix('me', true, 5, 7) 
# 'me'
# true
# [5,7]

Les définitions de méthode sont des expressions

Définir une méthode dans Ruby 2.x renvoie un symbole représentant le nom:

class Example
  puts def hello
  end
end

#=> :hello

Cela permet des techniques de métaprogrammation intéressantes. Par exemple, les méthodes peuvent être encapsulées par d'autres méthodes:

class Class
  def logged(name)
    original_method = instance_method(name)
    define_method(name) do |*args|
      puts "Calling #{name} with #{args.inspect}."
      original_method.bind(self).call(*args)
      puts "Completed #{name}."
    end
  end
end

class Meal
  def initialize
    @food = []
  end
  
  logged def add(item)
    @food << item
  end
end

meal = Meal.new
meal.add "Coffee"
# Calling add with ["Coffee"].
# Completed add.

Capture d'arguments de mots clés non déclarés (double splat)

L'opérateur ** fonctionne de la même manière que l'opérateur * mais il s'applique aux paramètres de mot-clé.

def options(required_key:, optional_key: nil, **other_options)
  other_options
end

options(required_key: 'Done!', foo: 'Foo!', bar: 'Bar!')
#> { :foo => "Foo!", :bar => "Bar!" }

Dans l'exemple ci-dessus, si **other_options n'est pas utilisé, un ArgumentError: unknown keyword: foo, bar erreur de ArgumentError: unknown keyword: foo, bar serait **other_options .

def without_double_splat(required_key:, optional_key: nil)
  # do nothing
end

without_double_splat(required_key: 'Done!', foo: 'Foo!', bar: 'Bar!')
#> ArgumentError: unknown keywords: foo, bar

C'est pratique lorsque vous avez un hachage d'options que vous souhaitez transmettre à une méthode et que vous ne souhaitez pas filtrer les clés.

def options(required_key:, optional_key: nil, **other_options)
  other_options
end

my_hash = { required_key: true, foo: 'Foo!', bar: 'Bar!' }

options(my_hash)
#> { :foo => "Foo!", :bar => "Bar!" }

Il est également possible de déballer un hash en utilisant l'opérateur ** . Cela vous permet de fournir un mot-clé directement à une méthode en plus des valeurs d'autres hachages:

my_hash = { foo: 'Foo!', bar: 'Bar!' }

options(required_key: true, **my_hash)
#> { :foo => "Foo!", :bar => "Bar!" }

Céder aux blocs

Vous pouvez envoyer un bloc à votre méthode et il peut appeler ce bloc plusieurs fois. Cela peut être fait en envoyant un proc / lambda ou autre, mais c'est plus facile et plus rapide avec le yield :

def simple(arg1,arg2)
  puts "First we are here:  #{arg1}"
  yield
  puts "Finally we are here:  #{arg2}"
  yield
end
simple('start','end') { puts "Now we are inside the yield" }

#> First we are here:  start
#> Now we are inside the yield
#> Finally we are here:  end
#> Now we are inside the yield

Notez que le { puts ... } n'est pas entre parenthèses, il vient implicitement après. Cela signifie également que nous ne pouvons avoir qu'un seul bloc de yield . Nous pouvons transmettre des arguments au yield :

def simple(arg)
  puts "Before yield"
  yield(arg)
  puts "After yield"
end
simple('Dave') { |name| puts "My name is #{name}" }

#> Before yield
#> My name is Dave
#> After yield

Avec le rendement, nous pouvons facilement créer des itérateurs ou des fonctions fonctionnant sur d'autres codes:

def countdown(num)
  num.times do |i|
    yield(num-i)
  end
end

countdown(5) { |i| puts "Call number #{i}" }

#> Call number 5
#> Call number 4
#> Call number 3
#> Call number 2
#> Call number 1

En fait, c'est avec le yield que des choses comme foreach , each et les times sont généralement implémentées dans les classes.

Si vous voulez savoir si un bloc vous a été donné ou non, utilisez block_given? :

class Employees
  def names
    ret = []
    @employees.each do |emp|
      if block_given?
        yield(emp.name)
      else
        ret.push(emp.name) 
      end
    end

    ret
  end
end

Cet exemple suppose que la classe Employees possède une liste @employees pouvant être itérée avec each pour obtenir des objets ayant des noms d'employés à l'aide de la méthode name . Si on nous donne un bloc, alors nous yield le nom au bloc, sinon nous le pousserons simplement dans un tableau que nous renverrons.

Tuple Arguments

Une méthode peut prendre un paramètre de tableau et le déstructurer immédiatement en variables locales nommées. Trouvé sur le blog de Mathias Meyer .

def feed( amount, (animal, food) )

    p "#{amount} #{animal}s chew some #{food}"

end

feed 3, [ 'rabbit', 'grass' ] # => "3 rabbits chew some grass"

Définir une méthode

Les méthodes sont définies avec le mot-clé def , suivi du nom de la méthode et d'une liste facultative de noms de paramètre entre parenthèses. Le code Ruby entre def et end représente le corps de la méthode.

def hello(name)
  "Hello, #{name}"
end

Un appel de méthode spécifie le nom de la méthode, l'objet sur lequel il doit être appelé (parfois appelé récepteur) et zéro ou plusieurs valeurs d'argument affectées aux paramètres de la méthode nommée.

hello("World")
# => "Hello, World"

Lorsque le récepteur n'est pas explicite, il est self .

Les noms de paramètre peuvent être utilisés comme variables dans le corps de la méthode et les valeurs de ces paramètres nommés proviennent des arguments d'une invocation de méthode.

hello("World")
# => "Hello, World"
hello("All")
# => "Hello, All"

Utiliser une fonction comme un bloc

De nombreuses fonctions de Ruby acceptent un bloc comme argument. Par exemple:

[0, 1, 2].map {|i| i + 1}
 => [1, 2, 3]

Si vous avez déjà une fonction qui fait ce que vous voulez, vous pouvez la transformer en un bloc en utilisant &method(:fn) :

def inc(num)
   num + 1
end

[0, 1, 2].map &method(:inc)
 => [1, 2, 3]


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow