Je veux passer un argument optionnel (n'importe quel type de données, même un Hash) suivi d'une liste d'arguments de mot-clé (qui peuvent être vides) à une méthode.
Voici ce que j'ai obtenu:
my_method({foo: 'foo'}) # => [nil, {:foo=>"foo"}]
Le résultat de la méthode est comme prévu dans les cas suivants:
rien
my_method({foo: 'foo'}) # => [{:foo=>"foo"}, {}]
un sujet
my_method(bar: 'bar') # => [nil, {:bar=>"bar"}]
un sujet littéral avec des options
my_method({foo: 'foo'}, bar: 'bar') # => [{:foo=>"foo"}, {:bar=>"bar"}]
un Hash
comme sujet avec des options
my_method('foo', bar: 'bar') # => ["foo", {:bar=>"bar"}]
pas de sujet, seulement des options
my_method('foo') # => ["foo", {}]
Lorsque vous passez un Hash
comme sujet et aucune option, le résultat souhaité est:
my_method() # => [nil, {}]
Mais j'obtiens ce qui suit; Je n'obtiens pas le bon sujet:
def my_method(subject = nil, **options) [subject, options] end
Est my_method (foo: 'foo')
équivalent à my_method ({foo: 'foo'})
? Des idées sur la façon dont je pourrais obtenir le résultat souhaité?
3 Réponses :
Autant que je sache, c'est une limitation de la façon dont Ruby passe les arguments. Il ne peut pas faire la différence entre my_method ({foo: 'foo'})
et my_method (foo: 'foo')
Pourquoi ne pas pirater avec ceci?
if subject.is_a?(Hash) && options.empty? subject, options = nil, subject end
Cela suppose que subject
ne devrait pas être un hachage.
Merci pour votre réponse. Malheureusement, je dois parfois passer un hachage à subject
.
@Taschetto Ok ... mais comment distinguerais-tu un sujet nul et juste des options d'un sujet Hash et aucune option?
my_method ({foo: 'foo'})
doit être un objet de hachage et aucune option; my_method (foo: 'foo')
devrait être un sujet nul et juste des options. Mais peut-être que je me trompe.
@Taschetto Je suis presque sûr que c'est une limitation de Ruby. Il ne peut pas faire la distinction entre ces deux cas. Je voudrais simplement rendre subject
non facultatif dans ce cas.
Peut-être pas la meilleure réponse, mais vous pouvez essayer avec argument de mot clé :
my_method({foo: 'foo'}, {})
Puis
my_method(subject: {foo: 'foo'}) => [{:foo=>"foo"}, {}]
Vous pouvez utiliser
def my_method(subject: nil, **options) [ subject, options ] end
Merci pour votre réponse. Oui, ça marche. Mais dans mon cas, je devrais refactoriser un grand nombre d'appels de méthode. J'ai besoin de maintenir l'interface de la méthode.
@Taschetto alors my_method ({foo: 'foo'}, {}) peut être une solution?
Vous voyez, vous avez des ** options
comme argument qui n'ont pas de valeur par défaut et le premier argument a une valeur par défaut. Donc, comprenez bien le cas d'un seul argument ,
Chaque fois qu'un seul argument est passé, il est tenté d'assigner au deuxième argument (car le premier a la valeur par défaut nil) et s'il échoue en raison d'une incompatibilité de type, il attribue au premier argument. C'est ainsi que fonctionne my_method (4)
.
Supposons maintenant que vous ayez un seul argument passé comme hachage, qui correspond à attribuer au deuxième argument, puis bien sûr, il est affecté au deuxième argument est défini par défaut sur nil.
Si vous voulez le faire fonctionner, vous pouvez faire ce qui suit,
> my_method(subject: {sd: 4}) => [{:sd=>4}, {}]
Ou vous pouvez fournir le nom de l'argument en passant,
> my_method({sd: 4}, {}) => [{:sd=>4}, {}]
J'ai mis à jour dans ma réponse pourquoi il a été attribué au deuxième argument.