Rubocop Offense:使用条件的 return 进行变量赋值和比较

Rubocop Offense: Use the return of the conditional for variable assignment and comparison

我的 Rubocop 攻击告诉我我需要 'Use the return of the conditional for variable assignment and comparison'

虽然我尝试修复它,但它又冒犯了我 'method line is too long'。

我尝试重构为另一种方法,但我的代码出错了。

如何缩短或重构此代码?

HSH = { 'a' => 'z', 'b' => 'y', 'c' => 'x', 'd' => 'w', 'e' => 'v', \
        'f' => 'u', 'g' => 't', 'h' => 's', \
        'i' => 'r', 'j' => 'q', 'k' => 'p', 'l' => 'o', 'm' => 'n' }.freeze


def encoder(str)
  encoded_string = ''
  str.chars.each do |char|
    encoded_string = if HSH.key?(char) then encoded_string += HSH[char]
                     elsif HSH.invert.key?(char) then encoded_string += HSH.invert[char]
                     else encoded_string += char
                     end
  end
  encoded_string
end

当我 运行 我的测试套件时,一切正常。

但是 rubocop offense 给我的方法行太长了。

HSH = {
  'a' => 'z', 'b' => 'y', 'c' => 'x',
  'd' => 'w', 'e' => 'v', 'f' => 'u',
  'g' => 't', 'h' => 's', 'i' => 'r',
  'j' => 'q', 'k' => 'p', 'l' => 'o',
  'm' => 'n'
}.freeze

def encoder(str)
  str.chars.map { |char| HSH[char] || HSH.invert[char] || char }.join
end

我会继续将你的散列扩展到所有 26 个字母,这样你就可以避免反向查找。这通过删除一个案例来简化您的代码,这可能会安抚 Rubocop……但更重要的是,您将使用哈希索引来提高效率和性能。反向散列查找很昂贵,因为它必须读取(最多)每个值。

考虑编码“1+2”。它将进行三个快速索引扫描,然后进行三个全数组扫描,只是 return 原始字符串。

使用完全填充的哈希,只需快速扫描三次。

这是您的原始代码,经过最少的更改即可实现您的目标:(有更短的方法可以做到这一点(提示:trmap),但更短不如简单重要对使用代码的程序员来说很舒服。)

translation = { 
  'a' => 'z', 'b' => 'y', 'c' => 'x', 'd' => 'w', 'e' => 'v', 'f' => 'u', 'g' => 't', 
  'h' => 's', 'i' => 'r', 'j' => 'q', 'k' => 'p', 'l' => 'o', 'm' => 'n', 'n' => 'm', 
  'o' => 'l', 'p' => 'k', 'q' => 'j', 'r' => 'i', 's' => 'h', 't' => 'g', 'u' => 'f', 
  'v' => 'e', 'w' => 'd', 'x' => 'c', 'y' => 'b', 'z' => 'a'
}.freeze

def encoder(str)
  encoded_string = ''

  str.chars.each do |char|
    encoded_string << translation[char] || char
  end
  encoded_string
end

您甚至可以考虑将散列扩展为大小写字母,甚至所有 256 个字符值,具体取决于您要解决的问题。但是让我们同意忽略 Unicode 字符!

回到 Rubocop... 任何类型的 "too long/too complex" 警告的最简单、可靠的解决方案是将代码提取到新方法中。编写 def charswap 并将其用作循环体。这将使编写测试更容易启动。但是,通过将翻译数组扩展到所有 26 个字母,代码变得非常简单,实际上不需要重构。

注意!不要使用这个答案! @steenslag .

提供了正确的方法

使用具有所有字母的散列显式映射默认过程:

HSH =
  (?a..?z).zip((?a..?z).to_a.reverse).to_h.
  tap { |h| h.default_proc = ->(_, k) { k }}.
  freeze

def encoder(str)
  str.chars.map(&HSH.method(:[])).join
end

无哈希:

ALPHABET = ("a".."z").to_a.join

def encoder(str)
  str.tr(ALPHABET, ALPHABET.reverse)
end

与@Steenslag 的回答一样,无需将字符串转换为数组、映射数组的每个元素并将结果连接回字符串。通过避免对每个字母进行线性搜索的需要,以下定义是有效的。

def encode_decode(str)
  rng = 'a'..'z'       
  str.gsub(/./) { |c| rng.cover?(c) ? (219-c.ord).chr : c }
end

plain_text = "The launch code is 'Bal3De8Rd0asH'."
  #=> "Tsv ozfmxs xlwv rh 'Bzo3Dv8Rw0zhH'."
coded_text = encode_decode(plain_text)
  #=> "Tsv ozfmxs xlwv rh 'Bzo3Dv8Rw0zhH'." 
encode_decode(coded_text)
  #=> "The launch code is 'Bal3De8Rd0asH'." 

我们中的一些人提出了更好的方法来实施您的 encoder 方法。但是我们所有人(包括我自己)并没有真正回答您的问题,也没有在您的代码中看到一个核心问题:

My Rubocop offense is telling me I need to 'Use the return of the conditional for variable assignment and comparison'

While I tried fixing it, it gave me another offense that my 'method line is too long'.

encoded_string = if HSH.key?(char) then encoded_string += HSH[char]
                 elsif HSH.invert.key?(char) then encoded_string += HSH.invert[char]
                 else encoded_string += char
                 end

您有点听从了 Rubocop 的建议……您将条件结果分配给了一个值……但我认为您没有达到目的。我什至不确定这是它所指的条件结果。我假设您添加了 encoded_string = ... 作业。

这是一个无用的赋值,因为您已经在 if 块中将字符附加到 encoded_string。您不必再次分配它。

回到我猜你的第 1 版代码,这是遵循 Rubocop 的建议的更有效的方法。不要在每个条件下进行赋值...只进行一次赋值,条件的结果为:

encoded_string += if HSH.key?(char) then HSH[char]
                  elsif HSH.invert.key?(char) then HSH.invert[char]
                  else char
                  end

最终代码更少,并且与您原来的编码风格和方法相匹配。它甚至可能会让 Rubocop 开心。可爱代码的下一步是消除过多的 key? 测试:

encoded_string += if HSH[char] then HSH[char]
                  elsif HSH.invert[char] then HSH.invert[char]
                  else char
                  end

从那里开始,这是用 || 消除 if/elsif 块的一小步。当我们这样做时,我们会将 += 更改为 << 以避免“产生大量不必要的中间 String 实例”。 (感谢@Aleksei Matiushkin 的建议)

encoded_string << HSH[char] || HSH.invert[char] || char

对于您解决此问题的方法,这是生产代码应力求达到的最低程度的简洁性和可读性。任何人都可以理解它,而无需认真思考或点击 Stack Overflow。