Is there a better alternative to this Ruby idiom?

巧了我就是萌 提交于 2019-12-10 09:34:32

问题


I'm finding myself writing this bit of code in my controllers a lot:

params[:task][:completed_at] = Time.parse(params[:task][:completed_at]) if params[:task][:completed_at]

Don't get hung up on what I'm doing here specifically, because the reasons change every time; but there are many circumstances where I need to check for a value in params and change it before handing it off to create or update_attributes.

Repeating params[:task][:completed_at] three times feels very bad. Is there a better way to do this?


回答1:


One way to shorten this slightly is:

if c = params[:task][:completed_at]
  params[:task][:completed_at] = Time.parse(c)
end

Or, you might prefer this:

params[:task][:completed_at] &&= Time.parse(params[:task][:completed_at])

In the second case, the assignment will only happen if the left side is "truthy".




回答2:


I suppose you could consider doing something like this.

Implement #to_time on String and NilClass, perhaps in a extensions.rb (as recommended in Ruby Best Practices, e.g.

require 'time'
class String
  def to_time
    Time.parse(self) # add error/exception handling to taste
  end
end

class NilClass
  def to_time
    nil
  end
end

Then you can just call params[:task][:created_at].to_time and the duplication is gone.

I'm not at all sure that this necessarily constitutes "best practice", but IMHO it meets the objective of the question...




回答3:


I am not incredibly familiar with Ruby, but since it has Perl roots, there may be a construct that allows you to write it like this:

$_ = Time->parse($_) for params[:task][:completed_at] || ();

basically exploiting the for loop to create an alias to the variable, if it exists

maybe something like:

(params[:task][:completed_at] || ()).each { |i| i = Time.parse(i) }

edit:

I see that Ruby has an alias keyword. I am not familiar enough with it to give a Ruby example, but in Perl, the above could also be written:

local *_ = \$params[$task][$completed_at];

$_ = Time->parse($_) if defined;

which specifies that $_ will be an alias for $params[$task][$completed_at]

I tried playing around with it breifly in Ruby, but didn't see a way to alias an identifier, just global variables.



来源:https://stackoverflow.com/questions/2068165/is-there-a-better-alternative-to-this-ruby-idiom

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!