Commit 8d72f33b authored by Coraline Ehmke's avatar Coraline Ehmke

Cleaned up CLI; updated README; version bump

parent df97977f
......@@ -2,13 +2,18 @@
Snuffle analyzes source code to identify "data clumps", clusters of attributes
that are often used together. It uses this analysis to propose objects that
may be extracted from a given class.
may be extracted from a given class. It also looks for objects that are hinted
at by method names and identifies them as "latent objects". For example, if you
have `home_address` and `work_address` methods in a User class, Snuffle will
tell you that you might want to extract those methods to a latent Address class.
Please note that Snuffle is still pre-release and will not be ready for serious
use until it hits version 1.0.0.
## TODO
* Ignore data clumps called in "loose" class methods (e.g. attr_accessor)
* Match on string concatenation
* Consider weighting based on match type
* Output files in folder hierarchy that mirrors source files
## Installation
......@@ -26,13 +31,10 @@ Or install it yourself as:
## Usage
$ snuffle check example.rb
$ snuffle check lib/example.rb
+----------------------------+------------+-----------------------------+
| Filename | Host Class | Candidate Object Attributes |
+----------------------------+------------+-----------------------------+
| example.rb | Customer | company_name, customer_name |
+----------------------------+------------+-----------------------------+
Checking lib/example.rb...
Results written to doc/snuffle/index.htm
## Contributing
......
......@@ -5,21 +5,17 @@ module Snuffle
class CLI < Thor
desc_text = "Formats are text (default, to STDOUT), html, and csv. "
desc_text << "Example: snuffle check foo/ -f html"
desc "check PATH_TO_FILE [-f FORMAT] [-t MAX_COMPLEXITY_ALLOWED]", desc_text
method_option :format, :type => :string, :default => 'text', :aliases => "-f"
desc "snuffle check PATH_TO_FILES", "Example: snuffle app/models/"
def check(path="./")
summaries = []
file_list(path).each do |path_to_file|
puts "Checking #{path_to_file}..."
summary = Snuffle::SourceFile.new(path_to_file: path_to_file).summary
report(summary, summary.source)
html_report(summary, summary.source)
summaries << summary
end
create_html_index(summaries, path)
puts results_files.join("\n")
puts "Results written to #{results_files.last}"
end
default_task :check
......@@ -39,32 +35,18 @@ module Snuffle
def report(summary, source)
text_report(summary)
cvs_report(summary)
html_report(summary, source)
end
def create_html_index(summaries, start_path)
return unless options['format'] == 'html'
results_files << Snuffle::Formatters::HtmlIndex.new(summaries, start_path).export
end
def cvs_report(summary)
return unless options['format'] == 'csv'
return unless summary.cohorts.count > 0 || summary.latent_objects.count > 0
results_files << Snuffle::Formatters::Csv.new(summary).export
end
def html_report(summary, source)
return unless options['format'] == 'html'
return unless summary.cohorts.count > 0 || summary.latent_objects.count > 0
results_files << Snuffle::Formatters::Html.new(summary, source).export
end
def text_report(summary)
return unless options['format'] == 'text'
puts
puts Snuffle::Formatters::Text.new(summary).export
end
def results_files
@results_files ||= []
end
......
......@@ -5,31 +5,57 @@
Snuffle
%link{href: "http://cdn.datatables.net/1.10.0/css/jquery.dataTables.css", rel: "stylesheet"}
%style{media: "screen", type: "text/css"}
body { background: #49525a; color: #fff; font-family: arial, sans-serif; padding: 2em; }
table { width: 100%; box-shadow: 0 5px 0 rgba(0,0,0,.8); border-spacing: 0; border: 5px solid #000; border-radius: 5px; border-collapse: collapse; min-width: 50%; }
tr.header th:first-child { border-radius: 5px 0 0 0; }
tr.header th:last-child { border-radius: 0 5px 0 0; }
tr.header th:only-child { border-radius: 5px 5px 0 0; }
tr.header { background-color: #222; }
tr.even { background: rgba(128, 128, 128, 0.5) !important;}
tr.odd { background: rgba(128, 128, 128, 0.25) !important}
tr.even:hover, tr.odd:hover { background: rgba(128, 128, 128, 0.75) !important;}
tr.faint td { opacity: 0.5; font-style: italic; }
th { background: #000; text-align: left; padding: .5em; }
td { text-align: left; padding: .5em; padding-left: 1.25em !important;}
td.center { text-align: center; }
tfoot { background: #000; border-top: 10px solid #000; font-family: courier; margin-top: 4em; font-size: .75em; }
:css
#{Rouge::Theme.find('thankful_eyes').render(scope: '.highlight')}
a:link, a:visited { color: #fff }
body { line-height: 1.5em; background: #49525a; color: #fff; font-family: arial, sans-serif; font-size: 14px; padding: 2em; }
div.column { float: left; width: 45%; }
div.file_listing { padding: .1em; border-radius: 5px; background: #000; width: 100%; border: 1px solid #000;}
div.file_meta { padding: 1em; border-radius: 5px; background: #440013; width: 98%; border: .5em solid #000;}
h1 { color:#fff; font-size: 1.25em; margin-top: .25em; }
h2 { color:#fff; font-size: .75em; margin-top: -1em; }
h3 { color:#fff; font-size: 1.1em;margin-top: 1em; }
h3.highlighted { background: rgba(170, 161, 57, .6); border-radius: 100px; padding: .25em; padding-left: 1em; color: #000;}
h3.highlighted-method { background: rgba(153, 51, 80, .6); border-radius: 100px; padding-left: 1em; }
li { margin-bottom: 1em;}
div.file_meta { padding: 1em; border-radius: 5px; background: #444; height: 3.5em; width: 98%; border: .5em solid #000;}
div.file_listing { padding: .5em; border-radius: 5px; background: #222; width: 100%; border: 1px solid #000;}
= ".summary {padding: 1em; border-radius: 5px; background: #4c5d62; width: 98%; border: .5em solid #000;}"
= ".clear { clear: both; }"
= ".indented {margin-left: 1em; }"
pre { line-height: 1.75em;}
pre.lineno { margin-top: -1.4em !important;}
span.highlighted { padding-left: 1em; display: inline-block; position: absolute; left: 0px; padding-right: 90%}
table { width: 100%; box-shadow: 0 5px 0 rgba(0,0,0,.8); border-spacing: 0; border: 5px solid #000; border-radius: 5px; border-collapse: collapse; min-width: 50%; }
td { text-align: left; padding: .5em; padding-left: 1.25em !important;}
tfoot { background: #000; border-top: 10px solid #000; font-family: courier; margin-top: 4em; font-size: .75em; }
th { background: #000; text-align: left; padding: .5em; }
tr.even { background: rgba(128, 128, 128, 0.5) !important;}
tr.even:hover, tr.odd:hover { background: rgba(128, 128, 128, 0.75) !important;}
tr.faint td { opacity: 0.5; font-style: italic; }
tr.header { background-color: #222; }
tr.header th:first-child { border-radius: 5px 0 0 0; }
tr.header th:last-child { border-radius: 0 5px 0 0; }
tr.header th:only-child { border-radius: 5px 5px 0 0; }
tr.odd { background: rgba(128, 128, 128, 0.25) !important}
.center { text-align: center; }
.clear { clear: both; }
.highlighted { background: rgba(170, 161, 57, .6); border-radius: 100px; }
.highlighted-method { background: rgba(153, 51, 80, .6); padding: .25em; border-radius: 100px; color: #fff; }
.indented {margin-left: 1em; }
.summary {padding: 1em; border-radius: 5px; background: rgb(41, 80, 109); width: 98%; border: .5em solid #000;}
.btn {
-webkit-border-radius: 28;
-moz-border-radius: 28;
border: none;
border-radius: 28px;
color: #ffffff;
background: #7d99af;
padding: 10px 20px 10px 20px;
text-decoration: none;
}
.btn:hover {
background: #4c708c;
border: none;
text-decoration: none;
}
%body
......@@ -50,16 +76,19 @@
%th
Host Module/Class
%th
Object Candidates
Data Clumps
%th
Latent Objects
%tbody
- summaries.each_with_index do |summary, i|
%tr{class: "#{i % 2 == 1 ? 'odd' : 'even'} #{summary.cohorts.count == 0 ? 'faint' : ''}"}
%tr{class: "#{i % 2 == 1 ? 'odd' : 'even'} #{summary.has_results? ? 'faint' : ''}"}
%td
- if summary.cohorts.count == 0
= summary.path_to_file
- else
- if summary.has_results?
%a{href: "source/#{summary.class_filename}.htm"}
= summary.path_to_file
- else
= summary.path_to_file
%td
- if summary.class_name.size > 30
= "..."
......@@ -68,10 +97,12 @@
= summary.class_name
%td
= summary.cohorts.count
%td
= summary.latent_objects.count
%br.clear
%div.summary.center
%p.center
%em
Analyzed on
= date
......
......@@ -8,6 +8,10 @@ module Snuffle
self.class_name.downcase.gsub(' ', '_')
end
def has_results?
self.cohorts.count != 0 || self.latent_objects.count != 0
end
end
end
\ No newline at end of file
module Snuffle
VERSION = "0.9.1"
VERSION = "0.10.1"
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment