2016-12-15 4 views
4

У меня есть def в рубине, как показано ниже. Могу ли я сделать что-то, чтобы сделать его сухим? например:DRY для рубиновых переменных петель

[e,t,l,te,le,le].each |xxx| do 
    if xxx 
end 

Это означает, что циклы для «переменных», а не только «Перечислитель».

код:

def findLogs (obj) 
    if e=obj['E'] 
    e=obj['E']['pkg'] ? "@E = #{obj['E']['pkg']},":nil 
    else nil 
    end 
    if t=obj['T'] 
    t=obj['T']['pkg'] ? "@T = #{obj['T']['pkg']},":nil 
    else nil 
    end 
    if l=obj['L'] 
    l=obj['L']['pkg'] ? "@L = #{obj['L']['pkg']},":nil 
    else nil 
    end 
    if te=obj['Te'] 
    te=obj['Te']['pkg'] ? "@Te = #{obj['Te']['pkg']},":nil 
    else nil 
    end 
    if le=obj['Le'] 
    le=obj['Le']['pkg'] ? "@Le = #{obj['Le']['pkg']},":nil 
    else nil 
    end 
end 
+0

возможно, если вы удалите переменные и сделайте их ключами в хеше, или что-то в этом роде. Ключи хэша намного проще перебирать. поэтому 'te = obj [...]' становится 'my_hash ['te'] = obj [...]' –

+2

Вы тоже можете делать это для локальных варов, но не должны. –

+4

Что должен делать ваш код? Локальные переменные бессмысленны, если вы их не используете. – Stefan

ответ

4
e, t, l, te, le = %w|E T L Te Le|.map do |s| 
    obj[s] && obj[s]['pkg'] ? "@#{s} = #{obj[s]['pkg']}," : nil 
end 

Для Серхио Tulentsev:

b = binding 
%w|E T L Te Le|.each do |s| 
    b.local_variable_set(
    s.downcase.to_sym, 
    obj[s] && obj[s]['pkg'] ? "@#{s} = #{obj[s]['pkg']}," : nil 
) 
end 
+0

Не совсем DRY, не так ли? :) но да, есть +1 –

+0

@SergioTulentsev это СУХОЙ, почему? Помимо 'obj [s] && obj [s] ['pkg']' нет никакого повторения. Это не образец хорошего кода, ни надежный фрагмент качества продукции. Но ** это DRYed **. – mudasobwa

+0

Если вы хотите добавить еще один элемент, вам придется вводить его дважды. –

2

Как Стефан упоминается в комментарии, определения локальных переменных в findLogs бессмысленно, если вы не используете их. Даже если вы определяете их дважды;).

Это неясно из вашего кода. Если вы хотите определить переменные экземпляра, написав код Ruby внутри строки, а затем: eval: пожалуйста, не надо!

obj = { 
    'E' => nil, 
    'T' => { 'pkg' => 't_pkg' }, 
    'L' => { 'not_pkg' => 'x' }, 
    'Te' => { 'pkg' => 'te_pkg' } 
} 

%w(E T L Te Le).each do |var_name| 
    instance_variable_set("@#{var_name}", obj.dig(var_name, 'pkg')) 
end 

p [@E, @T, @L, @Te, @Le] # => [nil, "t_pkg", nil, "te_pkg", nil] 
1

это выглядит как функция JS, чем Руби :)

Несколько вещей, чтобы заметить:

  1. переменные не используются, так что вы можете избавиться от них
  2. Есть целый лот else nil, который может быть удален как метод Ruby, возвратит nil по умолчанию
  3. Вы используете тернарный оператор только для возврата nil, опять же, вы можете избежать его
  4. Этот метод делает слишком много вещей: Это проверка, какой журнал это, а также отображать/форматирования
  5. Стиль Примечание: В Ruby мы используем snake_case, поэтому метод должен быть называется find_logs

Вы можете избежать повторения, как уже было сказано, и заменить его чем-то вроде:

def find_logs(obj) 
    log_type = ["E", "T", "L", "Te", "Le"].detect do |type| 
    obj[type] && obj[type]["pkg"] 
    end 

    "@#{log_type} = #{obj[log_type]['pkg']}," if log_type 
end 

Теперь, это не особенно красива и она по-прежнему делать две разные вещи, но это может быть достаточно хорошим , и я t удалили дублирование.

Я не знаю проблемы, которую вы пытаетесь решить, но поскольку мы в Ruby, вероятно, лучше решить ее с помощью класса, например. что-то вроде этого (не проверял, поэтому он не может работать):

class LogFormatter 
    LOG_TYPES = ["E", "T", "L", "Te", "Le"] 

    def initialize(obj:) 
    @obj = obj 
    end 

    def format 
    "@#{log_type} = #{pkg}," if log_type 
    end 

    private 

    attr_reader :obj 

    def pkg 
    @pkg ||= obj[log_type]["pkg"] 
    end 

    def log_type 
    @log_type ||= LOG_TYPES.detect { |type| obj[type] && obj[type]["pkg"] } 
    end 

end 

Теперь, имейте в виду, что в зависимости от того, что вы пытаетесь сделать, это может быть немного излишним - но лично я предпочитаю иметь а не иметь этот «сложный» метод в каком-то другом классе с совершенно несвязанной ответственностью.

+0

Спасибо за советы, подумайте. –