
目录

Reek是一种研究Ruby类,模块和方法的工具,并报告了发现的任何代码气味。
为了很好地介绍代码气味,请查看此博客文章或该文章。 RubyConfby也有此谈话(如果您喜欢的话,还有一个幻灯片)。
通过RubyGems安装它:
gem install reek并这样运行:
reek [options] [dir_or_source_file] * 想象一个源文件demo.rb包含:
# Smelly class
class Smelly
# This will reek of UncommunicativeMethodName
def x
y = 10 # This will reek of UncommunicativeVariableName
end
endREEK将报告此文件中以下代码闻到:
$ reek --no-documentation demo.rb
Inspecting 1 file(s):
S
demo.rb -- 2 warnings:
[4]:UncommunicativeMethodName: Smelly#x has the name 'x'
[5]:UncommunicativeVariableName: Smelly#x has the variable name 'y'
Reek正式支持Crouby 3.0至3.3和Jruby 9.4。其他红宝石实施(例如Rubinius)不得到正式支持,但也应该工作。
请注意,在每个Ruby版本上,Reek将使用解析器作为Ruby。因此,您应该始终使用项目的目标红宝石版本之一运行Reek。
Reek专注于高级代码的气味,因此我们无法告诉您如何以通用方式修复警告;这是并且将始终完全取决于您的领域语言和业务逻辑。
也就是说,一个例子可能会帮助您开始。看看Ruby在Rails模型上的样本(请注意,这是被截断的,而不是工作代码):
class ShoppingCart < ActiveRecord :: Base
has_many :items
def gross_price
items . sum { | item | item . net + item . tax }
end
end
class Item < ActiveRecord :: Base
belongs_to :shopping_cart
end这样的文件上运行reek:
reek app/models/shopping_cart.rb
将报告:
[5, 5]:ShoppingCart#gross_price refers to item more than self (FeatureEnvy)
解决此问题非常简单。将其属于单一项目的总价计算,这将是Item类:
class ShoppingCart < ActiveRecord :: Base
has_many :items
def gross_price
items . sum { | item | item . gross_price }
end
end
class Item < ActiveRecord :: Base
belongs_to :shopping_cart
def gross_price
net + tax
end
end代码闻到的文档可能会给您进一步的提示 - 当您有警告时,请务必先检查一下这些内容。
您可以通过多种方式在来源上工作,最常见的方法只是
reek lib/如果您没有通过任何源参数来撤销,则只需将当前的工作目录作为源。
所以
reek与明确的完全相同:
reek .此外,您可以将代码管传送到这样:
echo " class C; def m; end; end " | reek这将打印出来:
$stdin -- 3 warnings:
[1]:C has no descriptive comment (IrresponsibleModule)
[1]:C has the name ' C ' (UncommunicativeModuleName)
[1]:C#m has the name ' m ' (UncommunicativeMethodName)Reek当前包括检查控制夫妇的某些方面,数据集团,特征嫉妒,大型班级,长参数列表,模拟多态性,过多的语句,不传奇的名称,未使用的参数等等。请参阅代码气味,以获取最新的详细信息REEK将在您的代码中检查哪些内容。
有争议的探测器的特殊配置:
默认情况下未使用的私人方法被禁用,因为它是有争议的,这意味着您必须通过配置中的配置明确激活它
UnusedPrivateMethod :
enabled : true公用事业功能也是一个有争议的探测器,可能确实是不受欢迎的。结果,我们可以将其禁用以这样的非公共方法:
---
UtilityFunction :
public_methods_only : true 对于基本概述,运行
reek -- help有关这些CLI选项的摘要,请参阅命令行选项。
通过配置文件配置Reek是迄今为止最强大的方法。 Reek希望该文件名是.reek.yml ,但您可以通过CLI -c开关覆盖此名称(请参见下文)。
通过三种方法,可以将Reek传递给配置文件:
-c开关(请参阅上面的命令行接口)Reek试图找到此类配置文件的顺序正是上述:首先,它通过CLI明确地检查了它是否给了配置文件;然后,它检查了当前的工作目录中是否有一个文件,如果找不到一个文件,它会遍历目录,直到登录根目录。最后,它检查您的主目录。
Reek一旦检测到配置文件就会立即停止搜索,这意味着从Reek的角度来看,就完全存在一个配置文件和一种配置,无论您在文件系统上可能有多少个*.reek文件。
我们付出了很多努力,使Reek的配置尽可能地自我解释,因此了解它的最佳方法是通过查看一个简单的示例(例如,您的项目目录中的.reek.yml ):
---
# ## Generic smell configuration
detectors :
# You can disable smells completely
IrresponsibleModule :
enabled : false
# You can use filters to silence Reek warnings.
# Either because you simply disagree with Reek (we are not the police) or
# because you want to fix this at a later point in time.
NestedIterators :
exclude :
- " MyWorker#self.class_method " # should be refactored
- " AnotherWorker#instance_method " # should be refactored as well
# A lot of smells allow fine tuning their configuration. You can look up all available options
# in the corresponding smell documentation in /docs. In most cases you probably can just go
# with the defaults as documented in defaults.reek.yml.
DataClump :
max_copies : 3
min_clump_size : 3
# ## Directory specific configuration
# You can configure smells on a per-directory base.
# E.g. the classic Rails case: controllers smell of NestedIterators (see /docs/Nested-Iterators.md) and
# helpers smell of UtilityFunction (see docs/Utility-Function.md)
#
# Note that we only allow configuration on a directory level, not a file level,
# so all paths have to point to directories.
# A Dir.glob pattern can be used.
directories :
" web_app/app/controllers " :
NestedIterators :
enabled : false
" web_app/app/helpers** " :
UtilityFunction :
enabled : false
" web_app/lib/**/test/** " :
UtilityFunction :
enabled : false
# ## Excluding directories
# Directories and files below will not be scanned at all
exclude_paths :
- lib/legacy
- lib/rake/legacy_tasks
- lib/smelly.rb如上所述,Reek的配置包括3个不同的部分,由3个不同的键表示:
无论您在配置中添加的任何内容都应在其中一个密钥下范围范围。
如果您有一个目录指令,默认指令的目录指令(目录指令)将优先。
例如,此配置:
---
detectors :
IrresponsibleModule :
enabled : false
TooManyStatements :
max_statements : 5
directories :
" app/controllers " :
TooManyStatements :
max_statements : 10转换为:
每个气味探测器都支持我们的基本气味选择。如上所述,某些气味类型提供的配置超出了基本气味选项的配置,例如数据集团。超出基本气味选项的所有选项都记录在“相应气味类型 /文档”页面中(如果您想对所有可能的配置进行快速概述,也可以在此存储库中查看defaults.reek.yml文件。
请注意,您根本不需要配置文件。如果您对所有默认设置都很好,则可以完全跳过。
不用担心在配置文件中引入一个错误可能不会引起注意的错误 - Reek使用模式来验证您的配置在启动时对您的配置进行验证,并且如果您拼写错误或使用错误的数据类型,则会大声失败。
Error: We found some problems with your configuration file: [/detectors/DetectorWithTypo] key 'DetectorWithTypo:' is undefined.
Reek仅使用一个配置文件和一个配置文件,而.reek.yml为默认名称。
如果您必须在目录中有一个或多个配置文件(例如,您要使用不同的,相互排斥的设置在玩耍),则需要明确告诉Reek哪个文件可以通过reek -c config.reek使用。
如果您需要抑制气味警告,并且由于某种原因,您也不能或不想使用配置文件,您也可以使用类似的特殊源代码注释:
# This method smells of :reek:NestedIterators
def smelly_method foo
foo . each { | bar | bar . each { | baz | baz . qux } }
end您甚至可以传递特定的配置设置:
# :reek:NestedIterators { max_allowed_nesting: 2 }
def smelly_method foo
foo . each { | bar | bar . each { | baz | baz . qux } }
end这是一个非常强大的功能,并在气味抑制下进一步解释。
使用Reeks的动态机制,可以找到一个配置文件,您可能会遇到您无法100%确定使用什么配置文件REEK使用的情况。例如,您的项目根中有一个特定项目的配置文件,还有您用于所有其他项目的主目录中的另一种REEK配置,无论出于何种原因,Reek似乎都使用了其他配置文件,而不是您假设的文件。
在这种情况下,您可以将标志--show-configuration-path传递给Reek,这将使Reek输出其使用的配置文件的路径。
当您必须首先修复数百或数千个气味警告时,将Reek等工具集成到现有的较大代码库中可能会令人生畏。当然,您可以手动禁用如上图所示的气味警告,但根据代码库的大小,这可能不是一个选择。幸运的是,Reek提供了一个“ todo”标志,您可以用来生成一种配置,该配置将抑制当前代码库的所有气味警告:
reek --todo lib/这将在您当前的工作目录中创建文件'.reek.yml'。
然后,您可以将其用作您的配置 - 由于您的工作目录可能是您的项目根,因此在大多数情况下,您不必明确地告诉Reek使用'.reek.yml',因为Reek会自动将其拾取并将其用作配置文件。请参阅上面的配置加载。
如果出于任何原因,您决定将“ .reek.yml”放置在其他地方,那么Reek不会自动捡起它,则需要明确告诉Reek才能通过:
reek -c whatever/.reek.yml lib/重要的是要了解--todo标志的第一用例应在引入Reek的开头时一次运行以简化过渡。如果您发现自己想用--todo Flag重新运行Reek,以使许多新警告保持沉默,那么您将击败--todo国旗和Reek本身的目的。
结果,再次使用--todo标志运行Reek不会覆盖现有的“ .reek.yml”,而不是中止执行。它也不会考虑您可能考虑的任何其他配置文件。
这意味着当您运行时
reek -c other_configuration.reek --todo lib/ other_configuration.reek将被简单地忽略。
当然,您始终可以删除现有的.reek.yml文件,然后使用--todo标志运行Reek,但请记住,这不是此功能的预期用例。
除了显而易见
reek [options] [dir_or_source_file] *在项目中使用Reek还有很多其他方法:
查看源代码后要做的第一件事是运行Bundler:
bundle install
然后运行测试:
bundle exec rspec spec/your/file_spec.rb # Runs all tests in spec/your/file_spec.rb
bundle exec rspec spec/your/file_spec.rb:23 # Runs test in line 23
bundle exec cucumber features/your_file.feature # Runs all scenarios in your_file.feature
bundle exec cucumber features/your_file.feature:23 # Runs scenario at line 23或者只是运行整个测试套件:
bundle exec rake
这将运行测试(RSPEC和Cucumber),Rubocop和Reek本身。
另一个有用的耙子任务是console任务。这将使您直接进入一个可以使用Reeks模块和课程来玩耍的环境:
bundle exec rake console
irb(main):001> Reek::Examiner
=> Reek::Examiner
您还可以在要开始调试的点上添加以下内容来使用IRB时使用IRB:
binding . irb看看我们的开发人员API以获取更多灵感。
从那时起,您应该退房:
如果您不想用代码弄脏双手,您还有其他方法可以帮助我们:
如果您遇到代码气候问题(例如,浏览代码重复阈值),您可能希望能够在本地使用REEK代码库来运行代码气候。为此,您需要执行以下操作:
gem install codeclimatecodeclimate engines:install现在,您可以运行各种代码气候引擎,例如, codeclimate analyze -e duplication
REEK支持6种输出格式:
--format html )--format yaml ,另请参见YAML报告)--format json )--format xml )--format github ) 使reek“ rails” - 友好型非常简单,因为我们支持目录特定的配置(Reek Talk中的directory directives )。只需将其添加到您的配置文件中:
directories :
" app/controllers " :
IrresponsibleModule :
enabled : false
NestedIterators :
max_allowed_nesting : 2
UnusedPrivateMethod :
enabled : false
InstanceVariableAssumption :
enabled : false
" app/helpers " :
IrresponsibleModule :
enabled : false
UtilityFunction :
enabled : false
" app/mailers " :
InstanceVariableAssumption :
enabled : false
" app/models " :
InstanceVariableAssumption :
enabled : false不过,请注意,Reek不要合并您的配置条目,因此,如果您已经有针对“应用程序/控制器”或“应用程序/帮助者”的目录指令,则需要更新这些指令,而不是将上述YAML示例复制到配置文件中。
您可能想研究的其他静态代码分析仪的非排量列表:
REEK核心团队由:
Reek的原始作者是Kevin Rutherford。
Reek徽标的作者是Sonja Heinen。
值得注意的贡献来自: