Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Keep your code fresh smelling: generate "bad code smells" specs2 specifications for any source language.

branch: master

license file

latest commit 317fdc2e27
Adam Rosien authored February 24, 2013
Octocat-spinner-32 app start of app conf spec November 13, 2012
Octocat-spinner-32 core fix tests February 22, 2013
Octocat-spinner-32 notes notes February 22, 2013
Octocat-spinner-32 project Cross-build to 2.9.1, 2.9.2, 2.10.0; 2.9.0-1 build removed. Fixes #10. February 15, 2013
Octocat-spinner-32 src ls info for 0.7 September 18, 2012
Octocat-spinner-32 .gitignore Small refactorings. February 02, 2012
Octocat-spinner-32 .travis.yml update travis CI scala versions February 15, 2013
Octocat-spinner-32 LICENSE-2.0.txt license file February 24, 2013
Octocat-spinner-32 README.md license file February 24, 2013
Octocat-spinner-32 version.sbt Setting version to 0.12-SNAPSHOT February 22, 2013
README.md

Keeps your code fresh smelling: generate bad code smells specs2 specifications for any source language.

Installation

sniff is available via the Maven Central repository and current supports Scala 2.9.1, 2.9.2 and 2.10.0.

sbt:

libraryDependencies ++= Seq(
  "net.rosien" %% "sniff" % "0.10" % "test"
) 

maven:

 <dependency>
  <groupId>net.rosien</groupId>
  <artifactId>sniff_2.9.2</artifactId> 
  <version>0.10</version>
  <scope>test</scope>
</dependency>

Build Status

Usage

import org.specs2.Specification

class SniffSpec extends Specification { 
  import net.rosien.sniff._

  def is = "Scala code shouldn't smell" ^ Language.Scala.snippets.sniff("src/main/scala", "src/test/scala")
}

Running this spec in sbt scans the directories src/main/scala and src/test/scala for bad code smells described by regular expressions:

> test
[info] Compiling 1 Scala source to /Users/arosien/asr/sniff/target/scala-2.9.1.final/test-classes...
[info] SniffSpec
[info] 
[info] Code shouldn't smell
[info] + /Users/arosien/asr/sniff/src/main/scala/sniff.scala smells ok
[info] + /Users/arosien/asr/sniff/src/test/scala/SniffSpec.scala smells ok
[info]  
[info] Total for specification SniffSpec
[info] Finished in 504 ms
[info] 2 examples, 0 failure, 0 error
[info] 
[info] Passed: : Total 2, Failed 0, Errors 0, Passed 2, Skipped 0
[success] Total time: 4 s, completed Jan 22, 2012 7:13:31 PM

If I add the string "java.net.URL" to the above code (to make the smell spec fail) I get:

> test
[info] SniffSpec
[info] 
[info] Code shouldn't smell
[info] + /Users/arosien/asr/sniff/src/main/scala/sniff.scala smells ok
[error] x /Users/arosien/asr/sniff/src/test/scala/SniffSpec.scala smells ok
[error]     /Users/arosien/asr/sniff/src/test/scala/SniffSpec.scala:8: failed snippet 'java\.net\.URL' (URL actually resolves hostnames over the network, use java.net.URI instead) '  // java.net.URL' matches '.*java\.net\.URL.*' (sniff.scala:40)
[info]  
[info] Total for specification SniffSpec
[info] Finished in 277 ms
[info] 2 examples, 1 failure, 0 error
[info] 
[error] Failed: : Total 2, Failed 1, Errors 0, Passed 1, Skipped 0
[error] Failed tests:
[error]   net.rosien.sniff.SniffSpec
[error] {file:/Users/arosien/asr/sniff/}default-28e91d/test:test: Tests unsuccessful
[error] Total time: 1 s, completed Jan 23, 2012 9:46:05 AM

If there are bad smells that you temporarily want to ignore you can define an implicit Ignores value:

// snippets.sniff() uses this implicit
implicit val ignore = Ignores(
      Ignore('NoURL, "src/test/scala/SniffSpec.scala"),
      ...)

Defining your own smells

import org.specs2.Specification
import net.rosien.sniff._

val mySmells = 
  Smell('NoMutableCollections, """scala\.collection\.mutable""".r, rationale = "Immutable is better than mutable. - El Jefe", Scala, 'movieReferences) ::
  // more smells
  Nil
}

class SniffSpec extends Specification { 
  def is = "Die smells die" ^ CodeSnippets(Language.Scala, mySmells: _*).sniff("src/main/scala", "src/test/scala")
}

There is a growing list of default smells for various languages defined at https://github.com/arosien/sniff/blob/master/src/main/scala/smells.scala. Please fork and send me a pull request to have yours included.

To define a new language just create a singleton object extending net.rosien.sniff.Language.

Regular Expressions? WTF!?

There are lots of ways to model "bad code smells", from simple rules to deep language parsing. sniff emphasizes:

  • smells as regular expressions, because they are easy to write and test for any source language
  • broadly scoped smells rather than complex predicates ("never use X")
  • a simple exception mechanism to ignore false positives

For more complex rules and deeper analysis, try these great tools:

Credits

TODO

  • Magic token to ignore smells on a line or in a region, e.g., for use in commented-out code.
  • Executable jar to sniff stuff from the command-line, e.g., for use in continuous integration systems.
  • Sniff helper method for maven-style paths (src/main/scala, etc.)

License

The license is Apache 2.0, see LICENSE-2.0.txt.

Something went wrong with that request. Please try again.