troessner / reek Goto Github PK
View Code? Open in Web Editor NEWCode smell detector for Ruby
Home Page: https://github.com/troessner/reek
License: MIT License
Code smell detector for Ruby
Home Page: https://github.com/troessner/reek
License: MIT License
I get the following code smell with a DataMapper model:
"app/models/response.rb" -- 1 warnings:
Response has at least 27 methods (Large Class)
I'm sure you'll agree the class doesn't have that many methods...
class Response
include DataMapper::Resource
property :id, Serial
property :response, Integer, :nullable => false
property :made_at, Time, :nullable => false, :default => lambda { Clock.current_time }
belongs_to :proposed_question
def correct?
question.accepts_as_correct?(response)
end
def <=>(other)
other.made_at <=> made_at
end
def ==(other)
made_at == other.made_at &&
response == other.response
end
end
Similarly wacky numbers come out of all my other DM models, 37 being the highest...
This entails moving to ruby_parser too -- #4
Sorry for any duplication - can't find a ticket for the --quiet option anywhere. I think the RSpec matcher should be quiet by default, and certainly configurable: showing a huge list of "0 warnings" makes it much harder to work through and fix code issues.
The methods in a class may be defined in multiple batches, possibly in multiple source files. So Reek needs to remember what it sees over the whole file set, and add methods and ivars to an existing class where necessary.
Check for repeated identical conditional expressions within the same class or module.
Add a config option to set the number of occurrences of the expressions that will trigger a warning. Set it to 3 by default.
New smell: More than 8 calls to require
in a single source file.
A class has a field that is not set in the constructor, but is used in some method that doesn't also set it.
Or a class provides an attr_writer.
A bit like a method on a class, the following should presumably not trigger Utility Function?
module MyModule
def reset!
# ...
end
module_function :reset!
end
Currently the default behaviour is to complain about any block that's nested inside another. Add a config option to allow the user to raise this threshhold above 1.
Tools such as metric_fu currently parse Reek's text output. It would be easier for them to load a YAML file produced by Reek. So I propose a new option --format taking one of (initially) three values: none
, yaml
, or text
; the last would produce the current output, and would be the default.
The following method is envious
def func
@other.a
@other.b
@nother.c
end
because it could be moved to @other, creating a method like tthis:
def other.func(me)
a
b
me.nother_c
end
But FeatureEnvy doesn't pick this up.
I'd like to be able to configure Reek so that, for example, some methods are allowed to have upto 5 parameters, while the rest must keep within the standard 3.
[Raised originally by dbalatero]
Given an ActiveRecord model with a number of validations and associations added, and no extra methods, the method count can balloon to larger than the max count really fast.
I believe this is because validates*of-type methods in Rails add methods to the class itself, so they don't get seen as separate modules / inherited methods.
Would there be a way to whitelist some of these generated methods?
When I just define a method at the top level in a script, it has no "instance state" to ignore, and will therefore always be a UtilityFunction. Doesn't make sense.
Examine the parameters to the parsed methods and look for clumps of common names.
Configure by minimum clump size and min repetition threshold.
(This is a special case of Dead Code.)
The following code includes 3 nested assignments, yet none of these contribute to the method's "length":
def parse(arg, argv, &error)
if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
return nil, block, nil
end
opt = (val = parse_arg(val, &error))[1]
val = conv_arg(*val)
if opt and !arg
argv.shift
else
val[0] = nil
end
val
end
The metho'ds length is reported as 6, but should be 9.
Any name ending in a number (eg. pane1, pane2) could be more communicative.
Fix by adding another pattern to the config.
If a command-line argument is a dir, reek should examine dir/**/*.rb
I'd love it if there was some way of configuring long method to not count logging statements, but maybe too many logging statements is also a code smell?
A call to super represents an implicit dependency on being in an instance of the right class in the hierarchy. So UtilityFunction shouldn't complain; and FeatureEnvy should count it when considering moving the code elsewhere.
The plug-in should mark up source files in the editor view, showing where the smells are.
The plug-in should mark up source files in the editor view, showing where the smells are.
I don't think Uncommunicative Name should apply to Enumerable methods. The following is (to me, at least) perfectly understandable:
users.map { |u| u.name }
WDYT?
GitHub issues working for me again :)
How about two options to reek:
% reek --include-masked-smells
% reek --only-masked-smells
That let you identify smells that config files have disabled compared to the defaults. (eg FeatureEnvy if it was disabled, LongMethod if it was set to 20 and it found a method of length 7-19)
This would provide a way to put really awkward bits on the back burner, but give a way to go back to them later.
Add an optino to write a YAML report into an output folder.
(Could look at metric_fu for the report's format?)
In a Hexagonal Architectural view of an app, the code style in the Adapters is special. So any name matching /Adapter/ should be exempted from certain smells (particularly those related to conditional code).
The name Large Class is a hangover from Martin Fowler's original Java smells; in Ruby it should probably be renamed to Large Module.
A method that uses super and then modifying the return value will get reported as a utility method (IMHO) incorrectly, eg:
def docstring
super.extend(Yardstick::Method)
end
Currently smell warnings describe the code element in which the smell sits, but this can be ambiguous or vague (for example, nested iterators in a large method can be hard to identify). Reek should offer %f (filename) and %l (line number) in smell reports.
Would be nice to be able to disable smells for specific bits of code instead of using the config file. for example...
def my_method #:nosmell[utility_function]
...
end
[Raised by S. Brent Faulkner]
See http://gist.github.com/107726 for an example.
For example, it should be a fatal error if the max_allowed_calls setting for Duplication is set to < 2.
Every class and module should have a brief description of its responsibilities in the comments just ahead of its definition
[Raised by Ashley Moran]
Say you have the following config file:
---
FeatureEnvy:
exclude:
- view
but the view method that gets analysed does not have Feature Envy. Should this be considered an error? It seems that exclusions could persist after the code smells have been removed, silently ignoring the smell being introduced.
I've done a few refactorings now that removed code smells, and had to remember to manually take them out of the configs.
Similar idea to code coverage failing if your coverage percentage increases on the basis that you want to maintain any improvements you make.
Possibly the sanest behaviour would be to fail if the config is in the same directory as the file affected, so that global excludes don't raise loads of errors.
Ryan Davis, author of both ParseTree and ruby_parser, says ParseTree will be end-of-lifed at the same time as Ruby 1.8 And even now it is no longer actively supported.
For example, the following method reports Feature Envy (I think - I'd have to check). But Utility Function is the most common one that gets reported.
class ProposedQuestion
class << self
def new_for_facts_with_format(times_table_facts, question_format)
times_table_facts.map { |fact| ProposedQuestion.new(:times_table_fact => fact, :question_format => question_format) }
end
end
end
New smell detector.
Add a detector for the Law of Demeter. This should at least report methods called on a value returned from a method.
Attempt to detect when a method has been added to a core class.
When Reek is asked to examine an in-memory object, via
MyClass.should_not reek
for example, certain smells should be disabled. Most obvious of these is LargeClass.
This came up today. We have a file of ugly monkey-patching hacks to workaround framework bugs, and we wanted to turn reek off for this. But we couldn't control the smells on a per-file basis, so we had to put them in one by one.
Being able to configure smells per-file or per-class/module would have made this easier.
WDYT?
There's an Open Secret when a method returns multiple values. For example:
url, url_title = check_refs( url )
Or is it a kind of Data Clump?
Add a command-line option that disables all but the named smell. This should be a rake option too.
Tools such as perlcritic categorise the smells they report with a "severity". Good idea.
Got this in spec_helper.rb:
gem 'kevinrutherford-reek'
require 'reek'
require 'reek/spec'
You get this error:
/opt/local/lib/ruby/vendor_ruby/1.8/rubygems.rb:149:in `activate': can't activate kevinrutherford-reek (= 1.1.3.10, runtime), already activated kevinrutherford-reek-1.1.3.13 (Gem::Exception)
from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/custom_require.rb:35:in `require'
Removing old gems solves it, but it should be able to load?
Feature Envy currently applies only to whole methods. It would be great to find a way to have it report a block, or the else-clause of a conditional, or any branch of a switch.
Store a variety of profiles as profile.reek files in config/, and allow the user to pick which one is used as the base for the run's config. Start with relaxed | strict.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.