2

Is there a better way to do this in Ruby?

if params.has_key?(:comentario_page)
  gon.position = 0
elsif params.has_key?(:avaliacao_page)
  gon.position = 1
elsif params.has_key?(:seguindo_page)
  gon.position = 2
elsif params.has_key?(:seguidores_page)
  gon.position = 3
[and go on...]
else 
  gon.position = 0
end

Let's say that I have 10 if/else.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Vitor Vezani
  • 846
  • 2
  • 8
  • 24

6 Answers6

3

Suppose keys is an array of the given keys:

keys = [:comentario_page, :avaliacao_page, :seguindo_page, :seguidores_page]

Then you could write:

def gon_position(keys, params)
  keys.index { |k| params.has_key?(k) }.to_i
end

Note that if index returns nil, nil.to_i #=> 0.

For example:

params = { :a=>1, :avaliacao_page=>2, :seguindo_page=>3, :b=>4 }
gon_position(keys, params)
  #=> 1

params = { :a=>1, :b=>4 }
gon_position(keys, params)
  #=> 0
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
0

You might want to use a case statement.

http://ruby-doc.org/docs/keywords/1.9/Object.html#method-i-case

Here's an article that explains what a case statement is and what you can do with it.

Andrew Hendrie
  • 6,205
  • 4
  • 40
  • 71
0

The obvious answer is to use a case statement. The less obvious answer is to use a bare case statement with no comparator value; this is a less-known syntax choice which allows you to test on true/false in each when case.

gon.position = case
               when params.has_key?(:a) then 1
               when params.has_key?(:b) then 2
               when params.has_key?(:c) then 3
               else 0
               end

I don't love the repetition that remains (or the excessive indent in this formatting style), but I would probably refactor whatever methodology I'm using that led me to case over hash keys in the first place, rather than fussing over the rest too much.

user513951
  • 12,445
  • 7
  • 65
  • 82
0

Can't fully test this since I don't have your surrounding code with params, but my testing of the following using a made-up hash seemed to work:

key_set = [:key0, :key2, :key3, :key9]
gon.position = key_set.map.with_index { |k, i| i if params.has_key? k }.compact.first || 0

The || 0 at the end corresponds to the desired else value.

This assumes the desired value is a sequential integer. If not, create a hash key_hash of target values to replace the array key_set, lose the .with_index, and replace i if params.has_key? k with key_hash[k] if params.has_key? k.

The bad news is that this doesn't short-circuit. It will go through the entire candidate set of keys even if it's already found one.

pjs
  • 18,696
  • 4
  • 27
  • 56
0

Similarly to @pjs, I would use a data structure to hold mine. However, it's not clear to me that you are actually talking about sequential numbers. For that, we can use a hash:

 pages = {:comentario_page => 1,
      :avaliacao_page => 2,
      .....
 }

That way, you can grab whatever value makes sense based on the passed parameter. Since you are using the class gon, you could instantiate it like so

 gon = Gon.new(params)
 ...
 gon.position = [value]

Case statements and if / else constructs are poor choices here.

jjk
  • 536
  • 7
  • 15
0
keys = %i[comentario_page avaliacao_page seguindo_page seguidores_page ...]
gon.position =
case (keys & params.keys).first
when :comentario_page then 0
when :avaliacao_page then 1
when :seguindo_page then 2
when :seguidores_page then 3
...
else 0
end
sawa
  • 165,429
  • 45
  • 277
  • 381