= An Introduction to cleanr
:Author: Andreas Dominik Cullmann
:Date: 2020-01-09, 12:03:36
:toc2:

////
    %\VignetteIndexEntry{An Introduction to cleanr}
    %\VignetteEngine{rasciidoc::rasciidoc}
    %\VignetteEncoding{UTF-8}
////
== The Intro to the Intro
Coding is an art, but most of the code we write is more or less dreadful.
Many tried to teach us how to write code less dreadful, be it implicitly as
<<KR>> did,
be it explicitly as
<<CC>>
did.

If you are concerned about your coding style, you will probably want to lint 
your codes with  https://CRAN.R-project.org/package=lintr[lintr] or even 
reformat it using https://CRAN.R-project.org/package=formatR[formatR] or
 https://CRAN.R-project.org/package=styler[styler] 
(the latter gives better results in my opinion).

This package tries to help you with your code's layout:
it checks our code for files too long or wide, functions with too
many lines, too wide lines, too many arguments or too many levels of nesting.
Note that it's *not* a static code analyser like 
 https://CRAN.R-project.org/package=lintr[lintr].

== A first example
//begin.rcode, echo = FALSE
cleanr::set_cleanr_options(reset = TRUE)
//end.rcode
You can use *cleanr* to check the layout of a file:
//begin.rcode
path <- system.file("runit_tests", "runit_wrappers.R", package = "cleanr")
print(cleanr::check_file_layout(path))
//end.rcode
Okay, looks good. Let's make it look worse.  

== Options
*cleanr* is controlled by a list of options named "cleanr". You can retrieve 
it either via +options("cleanr")+ or via a convenience function:
//begin.rcode
cleanr::get_cleanr_options(flatten_list = FALSE)
//end.rcode

=== Arguments to Check Functions
You can change any of those options on the fly (leaving the options set 
                                                untouched). 
The real life
//begin.rcode, eval = FALSE
cleanr::check_file_layout(path, max_file_width = 79)
//end.rcode
produces conditions that would stop this vignette from getting compiled, this is
why we here assert these conditions:

//begin.rcode
print(tools::assertCondition(cleanr::check_file_layout(path, 
                                                     max_file_width = 79), 
                             c("cleanr", "error",  "condition"))
)
//end.rcode
=== Setting Options
You can set options using the convenience function:
//begin.rcode
cleanr::set_cleanr_options(max_file_width = 75, 
                           max_file_length = 20)
//end.rcode
//begin.rcode
print(tools::assertCondition(cleanr::check_file_layout(path), 
                             c("cleanr", "error",  "condition"))
)
//end.rcode

== Checking for File Layout
Files too long or too wide are hard to read.
You can check for a file's layout, i.e. for its lines' width and for the number 
of its lines.
You have already seen how to check for file layout:
//begin.rcode
cleanr::set_cleanr_options(reset = TRUE)
path <- system.file("source", "R", "checks.R", package = "cleanr")
print(cleanr::check_file_layout(path)) 
//end.rcode

We override some option by argument:
//begin.rcode
print(tools::assertCondition(cleanr::check_file_layout(path, 
                                                       max_file_length = 100), 
                             c("cleanr", "error",  "condition"))
)
//end.rcode


== Checking for Function Layout
Functions should

 - not have too many arguments,
 - not have too many levels of nesting,
 - neither have too many lines nor
 - have too many lines of code,
 - not have lines too wide and
 - explicitly return an object.

You can check all functions defined in a file:
//begin.rcode
print(suppressWarnings(cleanr::check_functions_in_file(path)))
//end.rcode
And again we override some option by argument:

//begin.rcode
print(tools::assertCondition(suppressWarnings(cleanr::check_functions_in_file(path,
                                                                        max_num_arguments = 1)), 
                       c("cleanr", "error",  "condition"))
)
//end.rcode

== Checking for File and Function Layout 
*cleanr* comes with wrappers to check for file and function layout in one go:
+check_file+ runs the file and function layout checks on a file,
+check_directory+ runs them on all files (matching a given pattern) in a 
directory and 
+check_package+ runs them on a package source 
(you may find it helpful when developing a package).
//begin.rcode
print(suppressWarnings(cleanr::check_file(path)))
//end.rcode

//begin.rcode
path <- system.file("runit_tests", package = "cleanr")
print(suppressWarnings(cleanr::check_directory(path,
                                               check_return = FALSE)))
//end.rcode
To run *cleanr* on its own codes, we need to load its internal functions first:
//begin.rcode
path <- system.file("source", "R", package = "cleanr")
cleanr::load_internal_functions("cleanr")
print(tools::assertCondition(suppressWarnings(cleanr::check_directory(path)), 
                       c("cleanr", "error",  "condition"))
)
//end.rcode
== Disabling checks
To disable any check, set the corresponding option or argument to +NULL+ or 
+FALSE+. 
//begin.rcode
cleanr::set_cleanr_options(reset = TRUE)
cleanr::load_internal_functions("cleanr")
path <- system.file("source", "R", "wrappers.R", package = "cleanr")

# will produce a condition:
r <- tools::assertCondition(cleanr::check_functions_in_file(path, 
                                                            check_return = FALSE),
                            c("cleanr", "error",  "condition"))
print(r)
# set argument to disable the check causing the condition:
r <- cleanr::check_functions_in_file(path, check_return = FALSE, 
                                     max_num_arguments = FALSE)
print(r)
//end.rcode



To completely disable all checks use:
//begin.rcode
co <- get_cleanr_options(flatten_list = FALSE)
co <- lapply(co, function(x) x == FALSE)
options("cleanr" = list(cleanr = co))
get_cleanr_options() 
//end.rcode
Now run on any directory, +check_directory+ will always return +TRUE+:
//begin.rcode
path <- system.file("source", "R", package = "cleanr")
cleanr::load_internal_functions("cleanr")
print(cleanr::check_directory(path)) 
//end.rcode




[bibliography]
== References
- [[[KR]]] B. W. Kernighan and D. M. Ritchie. 
   The C Programming Language, Second Edition.
   Prentice-Hall, Englewood Cliffs, New Jersey.
   1988.

- [[[CC]]] R.C. Martin.
  Clean Code: A Handbook of Agile Software Craftsmanship.
  Pearson Education.
  2008.
