Несколько вещей, которые я заметил:
При использовании блоков идиоматично использовать { ... }
для одной строки и do ... end
для нескольких строк.Вы склонны их немного смешивать.
if results.include?(name) == false
будет выглядеть лучше, так как unless results.include? name
if (details.include? 'Prerequisites') && (details['Prerequisites'] != nil)
можно сократить доif details['Prerequisites']
Читайте о "правдивости" в Ruby, если вы не понимаете, почему.Аналогичным образом, results.reject {|x| (spec[x].include? 'Private') && (spec[x]['Private'] == true)}
может стать results.reject { |x| spec[x]['Private'] }
Я думаю, что ситуация с вложенными лямбда-мишенями выглядит немного беспорядочно и выглядит созревшей для того, чтобы ее можно было разделить на несколько методов.Я также не стал бы пытаться распутать это без некоторых тестов.
Попробуйте использовать более описательные имена переменных / методов.Например, calc_remaining_sp
может быть лучше представлено простым remaining_skillpoints
.
Как правило, больше строк более чистого кода предпочтительнее, чем меньше строк более плотного кода.Пример:
results.reject {|x| (spec[x].include? 'Private') && (spec[x]['Private'] == true)}.to_a().sort_by {|x|x[1][:remaining_sp]} \
.each { |x, y| puts "#{x} = #{y[:remaining_sp]} sp left\n" }
Это можно переписать примерно так:
results.reject! { |skill| spec[skill]['Private'] }
results.sort_by! { |skill| skill[1][:remaining_sp] } # sort_by! requires 1.9 - for 1.8 use results = results.sort_by...
results.each { |x, y| puts "#{x} = #{y[:remaining_sp]} sp left\n" }
Наконец, когда вы начнете писать больше методов, попробуйте дать им легко используемый API.Например, метод оставшихся точек навыка:
def calc_remaining_sp(rank, from_level, to_level)
sp = BASE_SKILLPOINTS.map { |x| x * rank }
[sp[to_level] - sp[from_level], 0].max
end
Если кто-то еще захочет использовать этот метод, ему придется запомнить сокращения, которые вы использовали в имени метода, и порядок, в котором аргументы должныпоявляются в, что не весело.Более похожая на ruby альтернатива была бы:
def remaining_skillpoints(options)
skillpoints = BASE_SKILLPOINTS.map { |x| x * options[:rank] }
difference = skillpoints[options[:to]] - skillpoints[options[:from]]
[difference, 0].max
end
Это позволило бы другому Rubyist сделать что-то вроде:
points_needed = remaining_skillpoints :rank => 6, :from => 3, :to => 5
Или, с новым синтаксисом Hash в Ruby 1.9, это может бытьеще более приятный:
points_needed = remaining_skillpoints rank: 6, from: 3, to: 5
Но в любом случае, вы чувствуете себя намного лучше, чем я с Руби после четырех дней.Если вы планируете строить этот фрагмент кода в будущем, я бы определенно попытался добавить несколько тестов, прежде чем начать рефакторинг.Посмотрите на RSpec .Хорошим введением в это будет глава 1 Ruby Best Practices (бесплатный PDF).
Наслаждайтесь Ruby!