yardstick 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. data/.document +5 -0
  2. data/.gitignore +10 -0
  3. data/LICENSE +20 -0
  4. data/README.markdown +117 -0
  5. data/Rakefile +24 -0
  6. data/VERSION +1 -0
  7. data/bin/yardstick +7 -0
  8. data/deps.rip +1 -0
  9. data/lib/yardstick/autoload.rb +16 -0
  10. data/lib/yardstick/cli.rb +76 -0
  11. data/lib/yardstick/core_ext/object.rb +13 -0
  12. data/lib/yardstick/measurable.rb +78 -0
  13. data/lib/yardstick/measurement.rb +217 -0
  14. data/lib/yardstick/measurement_set.rb +130 -0
  15. data/lib/yardstick/method.rb +111 -0
  16. data/lib/yardstick/ordered_set.rb +115 -0
  17. data/lib/yardstick/processor.rb +65 -0
  18. data/lib/yardstick/rake/measurement.rb +101 -0
  19. data/lib/yardstick/rake/verify.rb +179 -0
  20. data/lib/yardstick/rule.rb +61 -0
  21. data/lib/yardstick/rule_set.rb +18 -0
  22. data/lib/yardstick/yard_ext.rb +20 -0
  23. data/lib/yardstick.rb +52 -0
  24. data/spec/public/yardstick/cli_spec.rb +108 -0
  25. data/spec/public/yardstick/measurement_set_spec.rb +265 -0
  26. data/spec/public/yardstick/measurement_spec.rb +256 -0
  27. data/spec/public/yardstick/method_spec.rb +356 -0
  28. data/spec/public/yardstick/rake/measurement_spec.rb +173 -0
  29. data/spec/public/yardstick/rake/verify_spec.rb +229 -0
  30. data/spec/public/yardstick_spec.rb +70 -0
  31. data/spec/rcov.opts +6 -0
  32. data/spec/semipublic/yardstick/rule_spec.rb +28 -0
  33. data/spec/spec.opts +4 -0
  34. data/spec/spec_helper.rb +45 -0
  35. data/tasks/ci.rake +1 -0
  36. data/tasks/heckle.rake +52 -0
  37. data/tasks/metrics.rake +5 -0
  38. data/tasks/rdoc.rake +15 -0
  39. data/tasks/spec.rake +22 -0
  40. data/tasks/yardstick.rake +9 -0
  41. data/yardstick.gemspec +90 -0
  42. metadata +113 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.markdown
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ *.sw?
2
+ .DS_Store
3
+ .yardoc
4
+ coverage
5
+ profiling
6
+ measurements
7
+ rdoc
8
+ doc
9
+ pkg
10
+ tmp
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Dan Kubb
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,117 @@
1
+ Yardstick 0.1.0
2
+ ===============
3
+
4
+ * [Homepage](http://yardstick.rubyforge.org/)
5
+ * [Git](http://github.com/dkubb/yardstick)
6
+ * [Bug Tracker](http://github.com/dkubb/yardstick/issues)
7
+ * [Mailing List](http://groups.google.com/group/yardstick)
8
+ * [IRC](irc://irc.freenode.net/yardstick)
9
+
10
+ Synopsis
11
+ --------
12
+
13
+ Yardstick is a tool that verifies YARD coverage of ruby code.
14
+
15
+ It will measure the source and provide feedback on what is missing from
16
+ the documentation and what can be improved.
17
+
18
+ Installation
19
+ ------------
20
+
21
+ With Rubygems:
22
+
23
+ $ sudo gem install dkubb-yardstick --source http://gems.github.com/
24
+ $ irb -rubygems
25
+ >> require 'yardstick'
26
+ => true
27
+
28
+ With the [Rip package manager](http://hellorip.com/):
29
+
30
+ $ rip install git://github.com/dkubb/yardstick.git
31
+ $ irb -rrip
32
+ >> require 'yardstick'
33
+ => true
34
+
35
+ With git and local working copy:
36
+
37
+ $ git clone git://github.com/dkubb/yardstick.git
38
+ $ cd yardstick
39
+ $ rake build && sudo rake install
40
+ $ irb -rubygems
41
+ >> require 'yardstick'
42
+ => true
43
+
44
+ Usage
45
+ -----
46
+
47
+ Yardstick may be used three ways:
48
+
49
+ **1. Command-line Tool**
50
+
51
+ This is the simplest way to run yardstick. Provide it a list of files
52
+ and it will measure all of them and output suggestions for improvement,
53
+ eg:
54
+
55
+ $ yardstick 'lib/**/*.rb' 'app/**/*.rb' ...etc...
56
+
57
+ **2. Rake task**
58
+
59
+ Yardstick may be integrated with existing Rakefile and build processes,
60
+ and is especially useful when used with a continuous integration system.
61
+ You can set thresholds, as well as check that the threshold matches the
62
+ actual coverage, forcing you to bump it up if the actual coverage has
63
+ increased. It uses a simple DSL to configure the task eg:
64
+
65
+ # measure coverage
66
+
67
+ require 'yardstick/rake/measurement'
68
+
69
+ Yardstick::Rake::Measurement.new(:yardstick_measure) do |measurement|
70
+ measurement.output = 'measurement/report.txt'
71
+ end
72
+
73
+
74
+ # verify coverage
75
+
76
+ require 'yardstick/rake/verify'
77
+
78
+ Yardstick::Rake::Verify.new do |verify|
79
+ verify.threshold = 100
80
+ end
81
+
82
+
83
+ **3. Libraries**
84
+
85
+ Yardstick comes with several libraries that will allow you to process
86
+ lists of files, or String code fragments, eg:
87
+
88
+ require 'yardstick'
89
+
90
+ # measure a list of file paths
91
+ measurements = Yardstick.measure(paths)
92
+
93
+ # measure a code fragment
94
+ measurements = Yardstick.measure_string <<-RUBY
95
+ # Displays the message provided to stdout
96
+ #
97
+ # @param [#to_str] message
98
+ # the message to display
99
+ #
100
+ # @return [undefined]
101
+ #
102
+ # @api public
103
+ def display(message)
104
+ puts message.to_str
105
+ end
106
+ RUBY
107
+
108
+ TODO
109
+ ----
110
+
111
+ - Add more measurements, especially for @param, @yield and type
112
+ validation
113
+ - Update yardstick_measure task to use the Yardstick::CLI library
114
+ underneath.
115
+ - Output results as HTML from command line tool and Rake task
116
+
117
+ Copyright (c) 2009 Dan Kubb. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'pathname'
4
+
5
+ Pathname.glob('tasks/**/*.rake').each { |task| load task.expand_path }
6
+
7
+ begin
8
+ require 'jeweler'
9
+
10
+ Jeweler::Tasks.new do |gem|
11
+ gem.name = 'yardstick'
12
+ gem.summary = 'A tool for verifying YARD documentation coverage'
13
+ gem.email = 'dan.kubb@gmail.com'
14
+ gem.homepage = 'http://github.com/dkubb/yardstick'
15
+ gem.authors = [ 'Dan Kubb' ]
16
+ gem.rubyforge_project = 'yardstick'
17
+
18
+ gem.add_dependency('yard', '~>0.2')
19
+ end
20
+
21
+ Jeweler::RubyforgeTasks.new
22
+ rescue LoadError
23
+ puts 'Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler'
24
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/yardstick ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby -KU
2
+
3
+ require 'rubygems'
4
+ require 'pathname'
5
+ require Pathname(__FILE__).dirname.expand_path.parent.join('lib', 'yardstick')
6
+
7
+ Yardstick::CLI.run(*ARGV)
data/deps.rip ADDED
@@ -0,0 +1 @@
1
+ git://github.com/lsegal/yard.git 0.2.3.3
@@ -0,0 +1,16 @@
1
+ module Yardstick
2
+ autoload :CLI, 'yardstick/cli'
3
+ autoload :Measurable, 'yardstick/measurable'
4
+ autoload :Measurement, 'yardstick/measurement'
5
+ autoload :MeasurementSet, 'yardstick/measurement_set'
6
+ autoload :Method, 'yardstick/method'
7
+ autoload :OrderedSet, 'yardstick/ordered_set'
8
+ autoload :Processor, 'yardstick/processor'
9
+ autoload :Rule, 'yardstick/rule'
10
+ autoload :RuleSet, 'yardstick/rule_set'
11
+
12
+ module Rake
13
+ autoload :Measurement, 'yardstick/rake/measurement'
14
+ autoload :Verify, 'yardstick/rake/verify'
15
+ end # module Rake
16
+ end # module Yardstick
@@ -0,0 +1,76 @@
1
+ require 'optparse'
2
+
3
+ module Yardstick
4
+ class CLI
5
+
6
+ # Parse the command line options, and run the command
7
+ #
8
+ # @example
9
+ # Yardstick::CLI.run(%w[ article.rb ]) # => [ Measurement ]
10
+ #
11
+ # @param [Array] *args
12
+ # arguments passed in from the command line
13
+ #
14
+ # @return [MeasurementSet]
15
+ # the measurement for each file
16
+ #
17
+ # @api public
18
+ def self.run(*args)
19
+ measurements = Yardstick.measure(*parse_options(args))
20
+ measurements.puts
21
+ measurements
22
+ end
23
+
24
+ # Parse the options provided from the command-line
25
+ #
26
+ # @param [Array<String>] args
27
+ # the command-line options
28
+ #
29
+ # @return [Array(Array<String>, Hash)]
30
+ # the list of files, and options parsed from the command-line
31
+ #
32
+ # @api private
33
+ def self.parse_options(args)
34
+ args << '--help' if args.empty?
35
+ options = {}
36
+ option_parser(options).parse!(args)
37
+ [ args, options ]
38
+ rescue OptionParser::InvalidOption => error
39
+ display_exit(error.message)
40
+ end
41
+
42
+ # Return an OptionParser instance for the command-line app
43
+ #
44
+ # @param [Hash] options
45
+ # the options to set when parsing the command-line arguments
46
+ #
47
+ # @return [OptionParser]
48
+ # the option parser instance
49
+ #
50
+ # @api private
51
+ def self.option_parser(options)
52
+ opts = OptionParser.new
53
+ opts.on_tail('-v', '--version', 'print version information and exit') { display_exit("#{opts.program_name} #{Yardstick::VERSION}") }
54
+ opts.on_tail('-h', '--help', 'display this help and exit') { display_exit(opts.to_s) }
55
+ opts
56
+ end
57
+
58
+ # Display a message and exit
59
+ #
60
+ # @param [#to_str] message
61
+ # the message to display
62
+ #
63
+ # @return [undefined]
64
+ #
65
+ # @api private
66
+ def self.display_exit(message)
67
+ puts message.to_str
68
+ exit
69
+ end
70
+
71
+ class << self
72
+ private :option_parser, :parse_options, :display_exit
73
+ end
74
+
75
+ end # module CLI
76
+ end # module Yardstick
@@ -0,0 +1,13 @@
1
+ class Object #:nodoc:
2
+
3
+ # Return the meta class for this instance
4
+ #
5
+ # @return [Class]
6
+ # the meta class
7
+ #
8
+ # @api private
9
+ def meta_class
10
+ class << self; self end
11
+ end
12
+
13
+ end # class Object
@@ -0,0 +1,78 @@
1
+ module Yardstick
2
+ module Measurable
3
+ include Measurement::UtilityMethods
4
+
5
+ module ClassMethods
6
+
7
+ # List of rules for this class
8
+ #
9
+ # @return [RuleSet<Rule>]
10
+ # the rules for this class
11
+ #
12
+ # @api private
13
+ def rules
14
+ @rules ||= RuleSet.new
15
+ end
16
+
17
+ # Set the description for the rule
18
+ #
19
+ # @param [#to_str] description
20
+ # the rule description
21
+ #
22
+ # @yield []
23
+ # the rule to perform
24
+ #
25
+ # @yieldreturn [Boolean]
26
+ # return true if successful, false if not
27
+ #
28
+ # @return [undefined]
29
+ #
30
+ # @api private
31
+ def rule(description, &block)
32
+ rules << Rule.new(description, &block)
33
+ end
34
+
35
+ private
36
+
37
+ # Include the class or module with measurable class methods
38
+ #
39
+ # @param [Module] mod
40
+ # the module to include within
41
+ #
42
+ # @return [undefined]
43
+ #
44
+ # @api private
45
+ def included(mod)
46
+ mod.extend(ClassMethods).rules.merge(rules)
47
+ end
48
+
49
+ # Extend the docstring meta class with measurable class methods
50
+ #
51
+ # @param [YARD::Docstring] docstring
52
+ # the docstring to extend
53
+ #
54
+ # @return [undefined]
55
+ #
56
+ # @api private
57
+ def extended(docstring)
58
+ included(docstring.meta_class)
59
+ end
60
+ end # module ClassMethods
61
+
62
+ extend ClassMethods
63
+
64
+ # Return a list of measurements for this docstring instance
65
+ #
66
+ # @example
67
+ # docstring.measure # => [ Measurement ]
68
+ #
69
+ # @return [MeasurementSet]
70
+ # a collection of measurements
71
+ #
72
+ # @api public
73
+ def measure
74
+ meta_class.rules.measure(self)
75
+ end
76
+
77
+ end # module Measurable
78
+ end # module Yardstick
@@ -0,0 +1,217 @@
1
+ module Yardstick
2
+ class Measurement
3
+
4
+ # Return the Measurement description
5
+ #
6
+ # @example
7
+ # measurement.description # => "The description"
8
+ #
9
+ # @return [String]
10
+ # the description
11
+ #
12
+ # @api public
13
+ attr_reader :description
14
+
15
+ # Return a Measurement instance
16
+ #
17
+ # @example
18
+ # measurement = Measurement.new('The description', docstring, :successful_method)
19
+ #
20
+ # @param [#to_str] description
21
+ # the measurement description
22
+ # @param [YARD::Docstring] docstring
23
+ # the docstring to measure
24
+ #
25
+ # @yield []
26
+ # the measurement to perform
27
+ #
28
+ # @return [Yardstick::Measurement]
29
+ # the measurement instance
30
+ #
31
+ # @api public
32
+ def initialize(description, docstring, &block)
33
+ @description = description.to_str
34
+ @docstring = docstring
35
+ @block = block
36
+ @result = measure
37
+ end
38
+
39
+ # Return true if the measurement was successful
40
+ #
41
+ # @example Measurement successful
42
+ # measurement.ok? # => true
43
+ #
44
+ # @example Measurement unsuccessful
45
+ # measurement.ok? # => false
46
+ #
47
+ # @return [Boolean]
48
+ # true if the measurement was successful, false if not
49
+ #
50
+ # @api public
51
+ def ok?
52
+ @result == true || skip?
53
+ end
54
+
55
+ # Return true if the measurement was skipped
56
+ #
57
+ # @example Measurement skipped
58
+ # measurement.skip? # => true
59
+ #
60
+ # @example Measurement not skipped
61
+ # measurement.skip? # => false
62
+ #
63
+ # @return [Boolean]
64
+ # true if the measurement was skipped, false if not
65
+ #
66
+ # @api public
67
+ def skip?
68
+ @result == :skip
69
+ end
70
+
71
+ # Return true if the measurement is not implemented
72
+ #
73
+ # @example Measurement not implemented
74
+ # measurement.todo? # => true
75
+ #
76
+ # @example Measurement implemented
77
+ # measurement.todo? # => false
78
+ #
79
+ # @return [Boolean]
80
+ # true if the measurement is not implemented, false if not
81
+ #
82
+ # @api public
83
+ def todo?
84
+ @result == :todo
85
+ end
86
+
87
+ # Warns the results the measurement if it was not successful
88
+ #
89
+ # @example
90
+ # measurement.puts # (outputs results if not successful)
91
+ #
92
+ # @param [#puts] io
93
+ # optional object to puts the summary
94
+ #
95
+ # @return [undefined]
96
+ #
97
+ # @api public
98
+ def puts(io = $stdout)
99
+ unless ok?
100
+ io.puts("#{file}:#{line}: #{path}: #{@description}")
101
+ end
102
+ end
103
+
104
+ # Test if Measurement is equal to another measurement
105
+ #
106
+ # @example
107
+ # measurement == equal_measurement # => true
108
+ #
109
+ # @param [Measurement] other
110
+ # the other Measurement
111
+ #
112
+ # @return [Boolean]
113
+ # true if the Measurement is equal to the other, false if not
114
+ #
115
+ # @api semipublic
116
+ def eql?(other)
117
+ @description.eql?(other.instance_variable_get(:@description)) &&
118
+ @docstring.eql?(other.instance_variable_get(:@docstring))
119
+ end
120
+
121
+ # Return hash identifier for the Measurement
122
+ #
123
+ # @return [Integer]
124
+ # the hash identifier
125
+ #
126
+ # @api private
127
+ def hash
128
+ [ @description, @docstring ].hash
129
+ end
130
+
131
+ private
132
+
133
+ # Measure the docstring using the method provided to the constructor
134
+ #
135
+ # @return [Boolean, Symbol]
136
+ # true if the test is successful, false if not
137
+ # :todo if the test is not implemented
138
+ # :skip if the test does not apply
139
+ #
140
+ # @api private
141
+ def measure
142
+ catch :measurement do
143
+ @docstring.instance_eval(&@block)
144
+ end
145
+ end
146
+
147
+ # The code object for the docstring
148
+ #
149
+ # @return [YARD::CodeObjects::Base]
150
+ # the code object
151
+ #
152
+ # @api private
153
+ def object
154
+ @docstring.object
155
+ end
156
+
157
+ # The filename for the code
158
+ #
159
+ # @return [Pathname]
160
+ # the filename
161
+ #
162
+ # @api private
163
+ def file
164
+ Pathname(object.file)
165
+ end
166
+
167
+ # The line number for the code
168
+ #
169
+ # @return [Integer]
170
+ # the line number
171
+ #
172
+ # @api private
173
+ def line
174
+ object.line
175
+ end
176
+
177
+ # The class and method name for the code
178
+ #
179
+ # @return [String]
180
+ # the class and method name
181
+ #
182
+ # @api private
183
+ def path
184
+ object.path
185
+ end
186
+
187
+ module UtilityMethods #:nodoc:
188
+ private
189
+
190
+ # Throw a :skip measurement message to the caller
191
+ #
192
+ # This method allows you to short-circuit measurement methods when
193
+ # the measurement does not apply due to specific object states.
194
+ #
195
+ # @return [undefined]
196
+ #
197
+ # @api private
198
+ def skip
199
+ throw :measurement, :skip
200
+ end
201
+
202
+ # Throw a :todo measurement message to the caller
203
+ #
204
+ # This method allows you to short-circuit measurement methods when
205
+ # the measurement is not implemented.
206
+ #
207
+ # @return [undefined]
208
+ #
209
+ # @api private
210
+ def todo
211
+ throw :measurement, :todo
212
+ end
213
+
214
+ end # module UtilityMethods
215
+
216
+ end # class Measurement
217
+ end # module Yardstick