yardstick 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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