inch 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +170 -56
  3. data/TODOS.md +0 -6
  4. data/config/defaults.rb +82 -0
  5. data/lib/inch/cli/command/base.rb +9 -0
  6. data/lib/inch/cli/command/base_list.rb +8 -8
  7. data/lib/inch/cli/command/base_object.rb +1 -1
  8. data/lib/inch/cli/command/list.rb +6 -1
  9. data/lib/inch/cli/command/options/base.rb +1 -1
  10. data/lib/inch/cli/command/options/suggest.rb +3 -1
  11. data/lib/inch/cli/command/output/list.rb +6 -6
  12. data/lib/inch/cli/command/output/show.rb +3 -3
  13. data/lib/inch/cli/command/output/stats.rb +52 -33
  14. data/lib/inch/cli/command/output/suggest.rb +7 -7
  15. data/lib/inch/cli/command/show.rb +5 -0
  16. data/lib/inch/cli/command/stats.rb +6 -1
  17. data/lib/inch/cli/command/suggest.rb +31 -12
  18. data/lib/inch/cli/command.rb +7 -14
  19. data/lib/inch/cli/command_parser.rb +2 -9
  20. data/lib/inch/cli/sparkline_helper.rb +13 -13
  21. data/lib/inch/cli/weighted_list.rb +85 -0
  22. data/lib/inch/cli.rb +2 -1
  23. data/lib/inch/code_object/nodoc_helper.rb +2 -0
  24. data/lib/inch/code_object/proxy/base.rb +36 -13
  25. data/lib/inch/code_object/proxy/method_object.rb +29 -0
  26. data/lib/inch/code_object/proxy/namespace_object.rb +6 -0
  27. data/lib/inch/config.rb +30 -37
  28. data/lib/inch/evaluation/base.rb +53 -1
  29. data/lib/inch/evaluation/constant_object.rb +8 -11
  30. data/lib/inch/evaluation/file.rb +1 -1
  31. data/lib/inch/evaluation/grade.rb +41 -0
  32. data/lib/inch/evaluation/grade_list.rb +32 -0
  33. data/lib/inch/evaluation/method_object.rb +10 -51
  34. data/lib/inch/evaluation/namespace_object.rb +8 -49
  35. data/lib/inch/evaluation/{criteria.rb → object_schema.rb} +12 -22
  36. data/lib/inch/evaluation/read_write_methods.rb +21 -0
  37. data/lib/inch/evaluation/role/method.rb +8 -0
  38. data/lib/inch/evaluation.rb +5 -2
  39. data/lib/inch/version.rb +1 -1
  40. data/lib/inch.rb +3 -1
  41. data/test/fixtures/simple/lib/broken.rb +15 -0
  42. data/test/fixtures/simple/lib/role_methods.rb +15 -0
  43. data/test/inch/cli/weighted_list_test.rb +55 -0
  44. data/test/inch/code_object/proxy/method_object_test.rb +42 -0
  45. data/test/integration/stats_options_test.rb +1 -1
  46. metadata +11 -5
  47. data/lib/inch/evaluation/score_range.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a3d046495aa235b1de7a7b672064aa637bd234a9
4
- data.tar.gz: 8c1f011bbae79bebace8b24652bc8d4a91e03423
3
+ metadata.gz: 76a30cfdd0b22157bc5ef102e9f15cc96ec40147
4
+ data.tar.gz: 21d1a3ecb2c12294579f4406059a322e25fb15ff
5
5
  SHA512:
6
- metadata.gz: da0b420bda2854141896e838ab0cb399110415370ceffdc026e686017a796389bd29f66fb4e085d617e42fc30c5e234e436f49b234270b7690fe67000121a549
7
- data.tar.gz: a56f9672e84f23952719ea7c2087aa08ae736ed5b7e20c24f612066abc5fed6dc145e252c11cceae797c4fcb7a138a37a3a04373534ad5b9f1147d47a81580de
6
+ metadata.gz: e60ae99656807e6731978c0b3bd29534ad313bcda1f8aabae5407dc062bb8aa3f1e589f3599b900f917973608047d1e6909bdfc52e872792d07e281b18cda16f
7
+ data.tar.gz: 5bd8e9097b64d1cb9e454ef47e052e1d96ca1d2f562d2c12c9ae470b26de4db456e6c901563f5c9b9267eb013a6976ee25c2f31f768577806e826d6bf6be3b79
data/README.md CHANGED
@@ -1,9 +1,16 @@
1
1
  # Inch [![Build Status](https://travis-ci.org/rrrene/inch.png)](https://travis-ci.org/rrrene/inch)
2
2
 
3
- Take a look at the project page for an [introduction with screenshots (live and in full color)](http://rrrene.github.io/inch/).
3
+ `inch` gives you hints where to improve your docs. One Inch at a time.
4
4
 
5
- Inch is a documentation measurement tool for the Ruby programming language
6
- that gives you hints where to improve your docs. One Inch at a time.
5
+ Take a look at the [project page with screenshots (live and in full color)](http://rrrene.github.io/inch/).
6
+
7
+ ## What can it do?
8
+
9
+ `inch` is a little bit like Code Climate, but for your inline code documentation (and not a webservice).
10
+
11
+ It is a command-line utility that suggests places in your codebase where documentation can be improved.
12
+
13
+ If there are no inline-docs yet, `inch` can tell you where to start.
7
14
 
8
15
 
9
16
 
@@ -31,93 +38,126 @@ To run Inch, simply type
31
38
 
32
39
  Given a `lib` directory with the following code inside:
33
40
 
34
- class Foo
35
- # A complicated method
36
- def complicated(o, i, *args, &block)
37
- # ... snip ...
38
- end
39
-
40
- # An example of a method that takes a parameter (+param1+)
41
- # and does nothing.
42
- #
43
- # Returns nil
44
- def nothing(param1)
45
- end
46
-
47
- def filename
48
- "#{self.class}_#{id}.foo"
49
- end
50
- end
41
+ ```ruby
42
+ class Foo
43
+ # A complicated method
44
+ def complicated(o, i, *args, &block)
45
+ # ... snip ...
46
+ end
47
+
48
+ # An example of a method that takes a parameter (+param1+)
49
+ # and does nothing.
50
+ #
51
+ # Returns nil
52
+ def nothing(param1)
53
+ end
54
+
55
+ def filename
56
+ "#{self.class}_#{id}.foo"
57
+ end
58
+ end
59
+ ```
51
60
 
52
61
  Inch will suggest that the docs could be improved:
53
62
 
54
63
  # Properly documented, could be improved:
55
-
64
+
56
65
  ┃ B ↑ Foo#complicated
57
-
66
+
58
67
  # Undocumented:
59
-
68
+
60
69
  ┃ U ↑ Foo
61
70
  ┃ U ↗ Foo#filename
62
-
71
+
63
72
  You might want to look at these files:
64
-
73
+
65
74
  ┃ lib/foo.rb
66
-
75
+
67
76
  Grade distribution (undocumented, C, B, A): █ ▁ ▄ ▄
68
-
77
+
69
78
  Only considering priority objects: ↑ ↗ → (use `--help` for options).
70
79
 
71
- Inch does not report coverage scores for code objects. It assigns grades and shows you the grade distribution rather then an overall grade.
72
80
 
73
- The grades (A, B, C) show how good the present documentation seems. The grade `U` is assigned to all undocumented objects. The arrows (↑ ↗ → ↘ ↓) hint at the importance of the object being documented.
81
+ ## Philosophy
82
+
83
+ Inch was created to help people document their code, therefore it may be more important to look at **what it does not** do than at what it does.
84
+
85
+ * It does not aim for "fully documented" or "100% documentation coverage".
86
+ * It does not tell you to document all your code (neither does it tell you not to).
87
+ * It does not impose rules on how your documentation should look like.
88
+ * It does not require that, e.g."every method's documentation should be a single line under 80 characters not ending in a period" or that "every class and module should provide a code example of their usage".
89
+
90
+ Inch takes a more relaxed approach towards documentation measurement and tries to show you places where your codebase *could* use more documentation.
91
+
92
+
93
+
94
+ ### The Grade System
95
+
96
+ Inch assigns grades to each class, module, constant or method in a codebase, based on how complete the docs are.
97
+
98
+ The grades are:
99
+
100
+ * `A` - Seems really good
101
+ * `B` - Properly documented, but could be improved
102
+ * `C` - Needs work
103
+ * `U` - Undocumented
104
+
105
+ Using this system has some advantages compared to plain coverage scores:
106
+
107
+ * You can get an `A` even if you "only" get 90 out of 100 possible points.
108
+ * Getting a `B` is basically good enough.
109
+ * Undocumented objects are assigned a special grade, instead of scoring 0%.
110
+
111
+ The last point might be the most important one: If objects are undocumented, there is nothing to evaluate. Therefore you can not simply give them a bad rating, because they might be left undocumented intentionally.
112
+
113
+
114
+
115
+ ### Priorities ↑ ↓
116
+
117
+ Every class, module, constant and method in a codebase is assigned a priority which reflects how important Inch thinks it is to be documented.
74
118
 
119
+ This process follows some reasonable rules, like
75
120
 
76
- ### Inch does not judge
121
+ * it is more important to document public methods than private ones
122
+ * it is more important to document methods with many parameters than methods without parameters
123
+ * it is not important to document objects marked as `:nodoc:`
77
124
 
78
- Inch uses grades instead of scores to take a more relaxed approach. You can
79
- get an `A` without employing every trick from a predetermined list of checks.
125
+ Priorities are displayed as arrows. Arrows pointing north mark high priority objects, arrows pointing south mark low priority objects.
80
126
 
81
- The reason for using the grade distribution instead of an overall score is
82
- that the distribution says more about your codebase than a coverage percentage
83
- ever could:
127
+
128
+
129
+ ### No overall scores or grades
130
+
131
+ Inch does not give you a grade for your whole codebase.
132
+
133
+ "Why?" you might ask. Look at the example below:
84
134
 
85
135
  Grade distribution (undocumented, C, B, A): ▄ ▁ ▄ █
86
136
 
87
- In this example we have a good chunk of code that is still undocumented, but
88
- the vast majority of code is rated A or B. This tells you three things:
137
+ In this example there is a part of code that is still undocumented, but
138
+ the vast majority of code is rated A or B.
139
+
140
+ This tells you three things:
89
141
 
90
142
  * There is a significant amount of documentation present.
91
143
  * The present documentation seems good.
92
144
  * There are still undocumented methods.
93
145
 
94
146
  Inch does not really tell you what to do from here. It suggests objects and
95
- files that could be improved to get a better rating, but that is all.
147
+ files that could be improved to get a better rating, but that is all. This
148
+ way, it is perfectly reasonable to leave parts of your codebase
149
+ undocumented.
96
150
 
97
- This way, it is perfectly reasonable to leave parts of your codebase
98
- undocumented. Instead of reporting
151
+ Instead of reporting
99
152
 
100
153
  coverage: 67.1% 46 ouf of 140 checks failed
101
154
 
102
155
  and leaving you with a bad feeling, Inch tells you there are still
103
156
  undocumented objects without judging.
104
157
 
105
- Inch does not tell you to document all your methods. Neither does it tell you
106
- not to. It does not tell you "a method's documentation should be a single line
107
- under 80 characters not ending in a period".
108
-
109
-
110
-
111
- ### Limitations
112
-
113
- How you document your code is up to you and Inch can't actually tell you how good your docs are.
114
-
115
- It can't tell if your code examples work or if you described parameters
116
- correctly or if you have just added `# TODO: write docs` to each and every
117
- method.
158
+ This provides a lot more insight than an overall grade could, because an overall grade for the above example would either be an `A` (if the evaluation ignores undocumented objects) or a weak `C` (if the evaluation includes them).
118
159
 
119
- It is just a tool, that you can use to find parts of a codebase lacking
120
- documentation.
160
+ The grade distribution does a much better job of painting the bigger picture.
121
161
 
122
162
 
123
163
 
@@ -128,8 +168,67 @@ Inch is build to parse [YARD](http://yardoc.org/),
128
168
  style documentation comments, but works reasonably well with unstructured
129
169
  comments.
130
170
 
131
- It comes with four sub-commands: `suggest`, `stats`, `show`, and `list`
171
+ These inline-docs below all score an `A` despite being written in different styles:
172
+
173
+ ```ruby
174
+ # Detects the size of the blob.
175
+ #
176
+ # @example
177
+ # blob_size(filename, blob) # => some value
178
+ #
179
+ # @param filename [String] the filename
180
+ # @param blob [String] the blob data
181
+ # @param mode [String, nil] optional String mode
182
+ # @return [Fixnum,nil]
183
+ def blob_size(filename, blob, mode = nil)
184
+ ```
185
+
186
+ ```ruby
187
+ # Detects the size of the blob.
188
+ #
189
+ # blob_size(filename, blob) # => some value
190
+ #
191
+ # Params:
192
+ # +filename+:: String filename
193
+ # +blob+:: String blob data
194
+ # +mode+:: Optional String mode (defaults to nil)
195
+ def blob_size(filename, blob, mode = nil)
196
+ ```
197
+
198
+ ```ruby
199
+ # Public: Detects the size of the blob.
200
+ #
201
+ # filename - String filename
202
+ # blob - String blob data
203
+ # mode - Optional String mode (defaults to nil)
204
+ #
205
+ # Examples
206
+ #
207
+ # blob_size(filename, blob)
208
+ # # => some value
209
+ #
210
+ # Returns Fixnum or nil.
211
+ def blob_size(filename, blob, mode = nil)
212
+ ```
213
+
214
+
215
+ But you don't have to adhere to any specific syntax. This gets an `A` as well:
216
+
217
+ ```ruby
218
+ # Returns the size of a +blob+ for a given +filename+.
219
+ #
220
+ # blob_size(filename, blob)
221
+ # # => some value
222
+ #
223
+ def blob_size(filename, blob, mode = nil)
224
+ ```
225
+
226
+ Inch *let's you write your documentation the way you want*.
227
+
228
+
229
+ ## Subcommands
132
230
 
231
+ It comes with four sub-commands: `suggest`, `stats`, `show`, and `list`
133
232
 
134
233
 
135
234
  ### inch suggest
@@ -278,6 +377,21 @@ This creates a rake task named `inch`. Change the name by passing it to the cons
278
377
 
279
378
 
280
379
 
380
+
381
+
382
+ ## Limitations
383
+
384
+ How you document your code is up to you and Inch can't actually tell you how good your docs are.
385
+
386
+ It can't tell if your code examples work or if you described parameters
387
+ correctly or if you have just added `# TODO: write docs` to each and every
388
+ method.
389
+
390
+ It is just a tool, that you can use to find parts in your codebase that are
391
+ lacking documentation.
392
+
393
+
394
+
281
395
  ## How is this different from ...?
282
396
 
283
397
  ### Documentation coverage
data/TODOS.md CHANGED
@@ -9,10 +9,4 @@
9
9
  (realized via the @overload tag in YARD)
10
10
 
11
11
  * Think about implicit cases in terms of evaluation:
12
- * constructors and ?-methods are automatically assigned a @return tag
13
12
  * attr_* methods are automatically assigned a docstring and @param tag
14
-
15
- * Think about limiting the number of `B`-objects in `inch suggest`
16
- `inch suggest` shows too many `B`s even though there are still undocumented
17
- objects in the codebase. this becomes a problem, when one thinks of `B` as
18
- "good enough", which Inch itself suggests.
@@ -0,0 +1,82 @@
1
+ Inch::Config.run do
2
+ # development!
3
+
4
+ evaluation do
5
+ grade(:A) do
6
+ scores 80..100
7
+ label "Seems really good"
8
+ color :green
9
+ end
10
+
11
+ grade(:B) do
12
+ scores 50...80
13
+ label "Proper documentation present"
14
+ color :yellow
15
+ end
16
+
17
+ grade(:C) do
18
+ scores 1...50
19
+ label "Needs work"
20
+ color :red
21
+ end
22
+
23
+ grade(:U) do
24
+ scores 0..0
25
+ label "Undocumented"
26
+ color :color141
27
+ bg_color :color105
28
+ end
29
+
30
+ schema(:ConstantObject) do
31
+ docstring 1.0
32
+
33
+ # optional:
34
+ unconsidered_tag 0.2
35
+ end
36
+
37
+ schema(:ClassObject) do
38
+ docstring 1.0
39
+
40
+ # optional:
41
+ code_example_single 0.1
42
+ code_example_multi 0.2
43
+ unconsidered_tag 0.2
44
+ end
45
+
46
+ schema(:ModuleObject) do
47
+ docstring 1.0
48
+
49
+ # optional:
50
+ code_example_single 0.1
51
+ code_example_multi 0.2
52
+ unconsidered_tag 0.2
53
+ end
54
+
55
+ schema(:MethodObject) do
56
+ docstring 0.5
57
+ parameters 0.4
58
+ return_type 0.1
59
+ return_description 0.3
60
+
61
+ if object.constructor? || object.questioning_name?
62
+ parameters parameters + return_type
63
+ return_type 0.0
64
+ end
65
+
66
+ if object.constructor?
67
+ return_description 0.0
68
+ end
69
+
70
+ if !object.has_parameters? || object.setter?
71
+ return_description docstring + parameters
72
+ docstring docstring + parameters
73
+ parameters 0.0
74
+ end
75
+
76
+ # optional:
77
+ code_example_single 0.1
78
+ code_example_multi 0.25
79
+ unconsidered_tag 0.2
80
+ end
81
+ end
82
+ end
@@ -50,6 +50,15 @@ module Inch
50
50
  command
51
51
  end
52
52
 
53
+ # Registers the current Command in the CommandParser
54
+ #
55
+ # @param name [Symbol] name of the Command
56
+ # @return [void]
57
+ def self.register_command_as(name, default = false)
58
+ CLI::CommandParser.default_command = name if default
59
+ CLI::CommandParser.commands[name] = self
60
+ end
61
+
53
62
  def initialize
54
63
  options_class = "Command::Options::#{self.class.to_s.split('::').last}"
55
64
  @options = eval(options_class).new
@@ -14,10 +14,10 @@ module Inch
14
14
 
15
15
  def initialize
16
16
  super
17
- @ranges = Evaluation.new_score_ranges
17
+ @grade_lists = Evaluation.new_grade_lists
18
18
  end
19
19
 
20
- # Prepares the list of objects and ranges, parsing arguments and
20
+ # Prepares the list of objects and grade_lists, parsing arguments and
21
21
  # running the source parser.
22
22
  #
23
23
  # @param *args [Array<String>] the list of arguments.
@@ -27,17 +27,17 @@ module Inch
27
27
  @options.verify
28
28
  run_source_parser(@options.paths, @options.excluded)
29
29
  filter_objects
30
- assign_objects_to_ranges
30
+ assign_objects_to_grade_lists
31
31
  end
32
32
 
33
33
  private
34
34
 
35
- # Assigns the objects returned by {#objects} to the score ranges in
36
- # +@ranges+ based on their score
35
+ # Assigns the objects returned by {#objects} to the grade_lists
36
+ # based on their score
37
37
  #
38
- def assign_objects_to_ranges
39
- @ranges.each do |range|
40
- list = objects.select { |o| range.range.include?(o.score) }
38
+ def assign_objects_to_grade_lists
39
+ @grade_lists.each do |range|
40
+ list = objects.select { |o| range.scores.include?(o.score) }
41
41
  range.objects = sort_by_priority(list)
42
42
  end
43
43
  end
@@ -15,7 +15,7 @@ module Inch
15
15
 
16
16
  def initialize
17
17
  super
18
- @ranges = Evaluation.new_score_ranges
18
+ @grade_lists = Evaluation.new_grade_lists
19
19
  end
20
20
 
21
21
  # Prepares the given objects, parsing arguments and
@@ -1,7 +1,12 @@
1
+ require_relative 'options/list'
2
+ require_relative 'output/list'
3
+
1
4
  module Inch
2
5
  module CLI
3
6
  module Command
4
7
  class List < BaseList
8
+ register_command_as :list
9
+
5
10
  def description
6
11
  'Lists all objects with their results'
7
12
  end
@@ -17,7 +22,7 @@ module Inch
17
22
  # @return [void]
18
23
  def run(*args)
19
24
  prepare_list(*args)
20
- Output::List.new(@options, objects, @ranges)
25
+ Output::List.new(@options, objects, @grade_lists)
21
26
  end
22
27
  end
23
28
  end
@@ -101,7 +101,7 @@ module Inch
101
101
  #
102
102
  # @return [String]
103
103
  def description_hint_grades
104
- grades = Evaluation.new_score_ranges.map(&:grade)
104
+ grades = Evaluation::Grade.all
105
105
  "School grades (#{grades.join(', ')}) are assigned and " +
106
106
  "displayed with each object."
107
107
  end
@@ -8,6 +8,7 @@ module Inch
8
8
 
9
9
  attribute :proper_grades, [:A, :B]
10
10
  attribute :grades_to_display, [:B, :C, :U]
11
+ attribute :grade_weights, [0.2, 0.4, 0.4]
11
12
  attribute :object_min_priority, 0
12
13
  attribute :object_max_score, ::Inch::Evaluation::Base::MAX_SCORE
13
14
 
@@ -49,7 +50,8 @@ module Inch
49
50
  @object_max_score = object_max_score - 1
50
51
  # only A-listers are regarded as 'proper'
51
52
  @proper_grades = [:A]
52
- @grades_to_display = [:A, :B, :C]
53
+ @grades_to_display = [:A, :B, :C, :U]
54
+ @grade_weights = [0.3, 0.3, 0.2, 0.2]
53
55
  @object_count = 30
54
56
  @pedantic = true
55
57
  end
@@ -7,10 +7,10 @@ module Inch
7
7
 
8
8
  PER_RANGE = 10
9
9
 
10
- def initialize(options, objects, ranges)
10
+ def initialize(options, objects, grade_lists)
11
11
  @options = options
12
12
  @objects = objects
13
- @ranges = ranges
13
+ @grade_lists = grade_lists
14
14
  @omitted = 0
15
15
 
16
16
  display_list
@@ -19,13 +19,13 @@ module Inch
19
19
  private
20
20
 
21
21
  def display_list
22
- @ranges.each do |range|
22
+ @grade_lists.each do |range|
23
23
  if range.objects.empty?
24
24
  # pass
25
25
  else
26
26
  trace
27
- trace_header(range.description, range.color, range.bg_color)
28
- display_range(range)
27
+ trace_header(range.label, range.color, range.bg_color)
28
+ display_grade_list(range)
29
29
  end
30
30
  end
31
31
 
@@ -36,7 +36,7 @@ module Inch
36
36
  end
37
37
  end
38
38
 
39
- def display_range(range)
39
+ def display_grade_list(range)
40
40
  display_count = @options.show_all? ? range.objects.size : PER_RANGE
41
41
  list = range.objects[0...display_count]
42
42
  list.each do |o|
@@ -68,9 +68,9 @@ module Inch
68
68
  end
69
69
 
70
70
  def grade(score)
71
- ranges ||= Evaluation.new_score_ranges
72
- r = ranges.detect { |r| r.range.include?(score) }
73
- "#{r.grade} - #{r.description}".color(r.color)
71
+ grade_lists ||= Evaluation.new_grade_lists
72
+ r = grade_lists.detect { |r| r.scores.include?(score) }
73
+ "#{r.grade} - #{r.label}".color(r.color)
74
74
  end
75
75
  end
76
76
  end