Why?
====
After the introduction of:
safeReadFile :: FilePath -> IO (Either E.IOException String)
There were places who needed to repack data into the appropriate type.
This is an extra step and, while in these situations not necessarily
*slow*, should be removed.
This introduces a Readable typeclass which dictates implementation of
`readFile'` based on the resulting requested type. This means `safeReadFile`
can be used in various situations without having to `pack`.
This replaces readIfFileExists, which has a race-condition and may raise
an exception, with safeReadFile, which safely reads a file and includes
the IOException if something goes wrong.
Unused is not a tool where you can remove code without verifying
behavior still works, since it's most valuable in dynamic languages like
Ruby, Elixir, JavaScript, etc.
Common scenarios right now seem to be:
* Issues with the cache, and specifically find
* Seeing no results when results are expected
This discusses a few different reasons for those issues, and ideas of
how a developer might address them.
This introduces behavior searching for an available program to calculate
digests across directories. OS X ships with md5, but on *nix-based
systems, it's md5sum. The output is largely the same, apart from the
final digest calculation, which includes a "file path":
da52a1a5d5a3c9672371746e4d32708a -
This strips the trailing whitespace and dash:
da52a1a5d5a3c9672371746e4d32708a
Closes#49
This creates a new "list" output format that includes a certain number
of git SHAs per token. This allows for perusal of the most recent
changes for a given token to understand what changed.
Why?
====
With multiple calls to `parallel`, `stopGlobalPool` stops working
correctly.
This moves `stopGlobalPool` higher up, and executes it once, allowing
multiple calls to `parallel` to happen without causing issues.
This introduces a monad transformer stack to cover our reader (options
from the CLI) and except (for handling failure cases, initially missing
tags or invalid config).
This ensures errors are bubbled up appropriately (and halt program
execution) and the Options are available in the correct locations within
the app.
This also separates options parsing (which remains in app/Main.) from
translating those options into the correctly executed runner and
generated output.
This enables per-user and per-project configs, located in:
* ~/.unused.yml
* APP_ROOT/.unused.yml
Configurations stack upon each other, not replace; unused provides a
very base config, but additional configurations can be defined.
Per-user configs are best used to suit common types of projects at a
generic level. For example, a developer commonly working in Rails
applications might have a config at ~/.unused.yml for patterns like
Policy objects from Pundit, ActiveModel::Serializers, etc.
Per-project config would be less-generic patterns, ones where re-use
isn't likely or applicable.
See unused's global config:
https://github.com/joshuaclayton/unused/blob/master/data/config.yml
The structure is as follows:
- name: Rails
autoLowLikelihood:
- name: Pundit
pathStartsWith: app/policies
pathEndsWith: .rb
termEndsWith: Policy
classOrModule: true
- name: Pundit Helpers
pathStartsWith: app/policies
allowedTerms:
- Scope
- index?
- new?
- create?
- show?
- edit?
- destroy?
- resolve
- name: Other Language
autoLowLikelihood:
- name: Thing
pathEndsWith: .ex
classOrModule: true
Name each item, and include an autoLowLikelihood key with multiple named
matchers. Each matcher can look for various formatting aspects,
including termStartsWith, termEndsWith, pathStartsWith, pathEndsWith,
classOrModule, and allowedTerms.
Why?
====
In cases where no matchers are present, a language config should not
auto-classify every match as low-likelihood; instead, it should return
False so subsequent checks can operate on the match itself.
This is related to 9bf9499e67f52bcde2420bfe3945f73cfdaa06d7; both are
handling cases where less configuration data than ideal is present and
the program still needs to operate correctly.
Why?
====
If parsing options fails, the program will exit; if
withoutCursor has been called prior to execParser, the program may exit
without any way to re-enable the cursor. This can cause confusion and
frustration for users.
Why?
With SHA fingerprinting speeds improved drastically by
f618d8a796, we can now re-enable
caching by default.
This introduces a -C flag to disable the cache for a run.
Note that the cache is always invalidated when files are modified.
Why?
====
Dynamic languages, and Rails in particular, support some fun method
creation. One common pattern is, within RSpec, to create matchers
dynamically based on predicate methods. Two common examples are:
* `#admin?` gets converted to the matcher `#be_admin`
* `#has_active_todos?` gets converted to the matcher `#have_active_todos`
This especially comes into play when writing page objects with predicate
methods.
This change introduces the concept of aliases, a way to describe the
before/after for these transformations. This introduces a direct swap
with a wildcard value (%s), although this may change in the future to
support other transformations for pluralization, camel-casing, etc.
Externally, aliases are not grouped together by term; however, the
underlying counts are summed together, increasing the total occurrences
and likely pushing the individual method out of "high" likelihood into
"medium" or "low" likelihood.
Closes#19.