Is there a clean way to fill param which may not be needed for hash param in ruby method?

StackOverflow https://stackoverflow.com/questions/20976267

  •  25-09-2022
  •  | 
  •  

Domanda

Assuming we have a function, called mail, it can receive a Hash object, containing from, to, subject, body and so on to send mail, so we often call it like

mail(from: 'from@source.com', to: 'to@destination.com', subject: 'hello', body: 'world')

but sometimes we needn't supply from address, and this function has a default value, so we will call like this in this situation:

mail(to: 'to@destination.com', subject: 'hello', body: 'world')

But wait, if we will determine whether we should supply value for from depending on the environment, say we have a piece of code like this:

if user == me
    mail(to: 'to@destination.com', subject: 'hello', body: 'world')
else
    mail(from: 'from@source.com', to: 'to@destination.com', subject: 'hello', body: 'world')

It's not clean, and if we have more than one value, then? So I come to this:

params = { subject: 'hello', body: 'world' }
params[:from] = 'from@source.com' unless user == me
params[:to] = 'to@destination.com' unless custom == me
mail(params)

So, at last, my question is my title, any suggestions?

È stato utile?

Soluzione

Another option would be to use Object#tap. This might be better than PinnyM's solution in cases where you're using has_key? to determine whether to assign a default value (rather than just checking whether the hash returns a truthy value for that key):

def mail(options={})
  puts "From: " + (options[:from] || "default@source.com")
  puts "To: "   + (options[:to]   || "other@source.com")
  puts "Subject: " + options[:subject]
  puts "Body: " + options[:body]
end

me = "Ajedi32"
user = me
custom = "Other Guy"

mail(
  {
    subject: 'hello',
    body: 'world'
  }.tap { |opts|
    opts[:from] = 'from@source.com' unless user == me
    opts[:to] = 'to@destination.com' unless custom == me
  }
)

Output:

From: default@source.com
To: to@destination.com
Subject: hello
Body: world

I'm not really sure that's much cleaner than your current solution though...

Altri suggerimenti

mail(
  from: ('from@source.com' unless user == me),
  to: ('to@destination.com' unless custom == me), 
  subject: 'hello', 
  body: 'world' 
)

This will result in passing nil as the values of the conditional params, should they not be needed. This should work just fine in most cases, since evaluating a missing key would generally result in nil as well. Should this be a problem for you, you can strip out the nil values:

params = { ... }.reject{|k,v| v.nil?}
mail params
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top