📜 ⬆️ ⬇️

Using send for convenience, from despair and for fun


One of the methods of the Sidekiq library. Smile Explanation


send to Ruby calls object methods by name. Here is the obvious way to use it:


# :   . ,        . user.name = "" user.age = 29 # :    .    . def set(field, value) send("#{field}=", value) end user.set(:name, "") user.set(:age, 29) 

And you probably also saw these lines:


 after_create :send_email 

Yes, callbacks in the rails inside are also implemented using send .



Even through send, when testing, private methods are called. Sandi Metz, author of Practical Object-Oriented Design in Ruby (on private methods from 10:58), talks about whether to test them at all.


Short translation-retelling

She considers testing of private methods to be superfluous: the correct set of input data when testing public methods will provide 100% coverage. But periodically, with the active development of unstable Sandi code, this rule is violated so as not to delve into the traces, but catch an error in the place of origin. She considers such tests temporary and readily deletes when the code stabilizes. She is aware of the approach "If you need to test a private method, put it into a separate class," but she believes that the code will not become more stable from such a selection.


Sometimes you can't do without send:


 data_point = OpenStruct.new(:queued? => true) data_point.queued? # -> true data_point.send("queued?=",false) #      data_point.queued? # -> false 

This is an example from the OpenStruct documentation. The example is contrived, but there are also more strange names: take at least the same method from the picture at the beginning of the post.


Continuing the theme of unusual method names.


Often try to quit irb with a better command? Just add the following code to ~/.irbrc :


 module Kernel def  exit end end 

It occurred to me while mulling over examples for the article; added for the sake of the test itself in .irbrc - works. I was going to delete it, then I think: "But it’s convenient the same." While left, let it lie for a week.


For the desperate: why dwell only on the translation of a higher-exit?
 module Kernel def method_missing(method_name, *arguments, &block) return(super) unless contains_russian_letters?(method_name.to_s) possible_meaning = translit(method_name.to_s) send(possible_meaning, *arguments) end private def translit(string) string.chars.map do |char| russian_to_english_mapping[char] || char end.join end def contains_russian_letters?(string) !(string.chars & russian_symbols).empty? end def russian_symbols "".chars end def russian_to_english_mapping english = "qwertyuiop[]asdfghjkl;'zxcvbnm,.".chars russian_symbols.zip(english).to_h end end # : puts(1.inspect) #  1 (1.) #  . ! 

Leave it did not dare.


disadvantages


Inaccurate use of send degrades readability. Compare:


 #  1. ,    if params[:sort_by] == "age" users.sort_by_age else users.sort_by_name end #  2. ,   (    ) sorting_method = "sort_by_#{params[:sort_by]}" users.send(sorting_method) #    ,     #  ,  : users.sort_by(params[:sort_by]) 

Let's sum up


Use send if you need:



Do not use send unnecessarily.


')

Source: https://habr.com/ru/post/318546/


All Articles