dkubb-yardstick 0.0.1 → 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.
data/.document CHANGED
@@ -1,4 +1,4 @@
1
- README.rdoc
1
+ README.markdown
2
2
  lib/**/*.rb
3
3
  bin/*
4
4
  features/**/*.feature
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  .DS_Store
3
3
  .yardoc
4
4
  coverage
5
+ profiling
5
6
  rdoc
6
7
  doc
7
8
  pkg
@@ -0,0 +1,69 @@
1
+ Yardstick 0.0.1
2
+ ===============
3
+
4
+ Synopsis
5
+ --------
6
+
7
+ Yardstick is a tool that verifies YARD coverage of ruby code.
8
+
9
+ It will measure the source and provide feedback on what is missing from
10
+ the documentation and what can be improved.
11
+
12
+ Installation
13
+ ------------
14
+
15
+ From Gem:
16
+
17
+ $ sudo gem install dkubb-yardstick --source http://gems.github.com/
18
+
19
+ With a local working copy:
20
+
21
+ $ git clone git://github.com/dkubb/yardstick.git
22
+ $ cd yardstick
23
+ $ rake build && sudo rake install
24
+
25
+ Usage
26
+ -----
27
+
28
+ Yardstick may be used two ways:
29
+
30
+ **1. yardstick Command-line Tool**
31
+
32
+ This is the simplest way to run yardstick. Provide it a list of files
33
+ and it will measure all of them and output suggestions for improvement,
34
+ eg:
35
+
36
+ $ yardstick lib/**/*.rb
37
+
38
+ **2. Yardstick Libraries**
39
+
40
+ Yardstick comes with several libraries that will allow you to process
41
+ lists of files, or String code fragments, eg:
42
+
43
+ # measure a list of file paths
44
+ measurements = Yardstick.measure(paths)
45
+
46
+ # measure a code fragment
47
+ measurements = Yardstick.measure_string <<-RUBY
48
+ # Displays the message provided to stdout
49
+ #
50
+ # @param [#to_str] message
51
+ # the message to display
52
+ #
53
+ # @return [undefined]
54
+ #
55
+ # @api public
56
+ def display(message)
57
+ puts message.to_str
58
+ end
59
+ RUBY
60
+
61
+ TODO
62
+ ----
63
+
64
+ - Add more measurements, especially for @param, @yield and type
65
+ validation
66
+ - Create a Rake task to allow integration of Yardstick into build
67
+ processes more easily
68
+
69
+ Copyright (c) 2009 Dan Kubb. See LICENSE for details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.1.0
@@ -2,7 +2,7 @@ require 'pathname'
2
2
  require 'yard'
3
3
 
4
4
  module Yardstick
5
- VERSION = '0.0.1'.freeze
5
+ VERSION = '0.1.0'.freeze
6
6
  ROOT = Pathname(__FILE__).dirname.parent.expand_path.freeze
7
7
 
8
8
  # Measure a list of files
@@ -10,17 +10,17 @@ module Yardstick
10
10
  # @example
11
11
  # Yardstick.measure('article.rb') # => [ Measurement ]
12
12
  #
13
- # @param [Array<#to_str>, #to_str] files
13
+ # @param [Array<#to_s>, #to_s] path
14
14
  # optional list of paths to measure
15
15
  # @param [Hash] options
16
16
  # optional configuration
17
17
  #
18
- # @return [Array<Measurement>]
18
+ # @return [MeasurementSet]
19
19
  # the measurements for each file
20
20
  #
21
21
  # @api public
22
- def self.measure(files = 'lib/**/*.rb', options = {})
23
- Yardstick::Processor.process_files(files)
22
+ def self.measure(path = 'lib/**/*.rb', options = {})
23
+ Yardstick::Processor.process_path(path)
24
24
  end
25
25
 
26
26
  # Measure a string of code and YARD documentation
@@ -35,7 +35,7 @@ module Yardstick
35
35
  # @param [Hash] options
36
36
  # optional configuration
37
37
  #
38
- # @return [Array<Measurement>]
38
+ # @return [MeasurementSet]
39
39
  # the measurements for the string
40
40
  #
41
41
  # @api public
@@ -45,7 +45,7 @@ module Yardstick
45
45
 
46
46
  end # module Yardstick
47
47
 
48
- $LOAD_PATH << Yardstick::ROOT + 'lib'
48
+ $LOAD_PATH.unshift(Yardstick::ROOT + 'lib')
49
49
 
50
50
  require 'yardstick/core_ext/object'
51
51
  require 'yardstick/yard_ext'
@@ -1,7 +1,11 @@
1
1
  module Yardstick
2
- autoload :CLI, 'yardstick/cli'
3
- autoload :Measurable, 'yardstick/measurable'
4
- autoload :Measurement, 'yardstick/measurement'
5
- autoload :Method, 'yardstick/method'
6
- autoload :Processor, 'yardstick/processor'
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'
7
11
  end # module Yardstick
@@ -11,14 +11,14 @@ module Yardstick
11
11
  # @param [Array] *args
12
12
  # arguments passed in from the command line
13
13
  #
14
- # @return [Array(Measurement)]
14
+ # @return [MeasurementSet]
15
15
  # the measurement for each file
16
16
  #
17
- # @api private
17
+ # @api public
18
18
  def self.run(*args)
19
- Yardstick.measure(*parse_options(args)).each do |measurement|
20
- measurement.warn
21
- end
19
+ measurements = Yardstick.measure(*parse_options(args))
20
+ measurements.warn
21
+ measurements
22
22
  end
23
23
 
24
24
  # Parse the options provided from the command-line
@@ -36,7 +36,7 @@ module Yardstick
36
36
  option_parser(options).parse!(args)
37
37
  [ args, options ]
38
38
  rescue OptionParser::InvalidOption => error
39
- display_exit(error.message << "\n" << args.inspect)
39
+ display_exit(error.message)
40
40
  end
41
41
 
42
42
  # Return an OptionParser instance for the command-line app
@@ -51,7 +51,7 @@ module Yardstick
51
51
  def self.option_parser(options)
52
52
  opts = OptionParser.new
53
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) }
54
+ opts.on_tail('-h', '--help', 'display this help and exit') { display_exit(opts.to_s) }
55
55
  opts
56
56
  end
57
57
 
@@ -69,9 +69,7 @@ module Yardstick
69
69
  end
70
70
 
71
71
  class << self
72
- private :option_parser
73
- private :parse_options
74
- private :display_exit
72
+ private :option_parser, :parse_options, :display_exit
75
73
  end
76
74
 
77
75
  end # module CLI
@@ -4,23 +4,23 @@ module Yardstick
4
4
 
5
5
  module ClassMethods
6
6
 
7
- # List of measurement types for this class
7
+ # List of rules for this class
8
8
  #
9
- # @return [Array<Array(String, Symbol)>]
10
- # the measurements for this class
9
+ # @return [RuleSet<Rule>]
10
+ # the rules for this class
11
11
  #
12
12
  # @api private
13
- def measurements
14
- @measurements ||= []
13
+ def rules
14
+ @rules ||= RuleSet.new
15
15
  end
16
16
 
17
- # Set the description for the measurement
17
+ # Set the description for the rule
18
18
  #
19
19
  # @param [#to_str] description
20
- # the measurement description
20
+ # the rule description
21
21
  #
22
22
  # @yield []
23
- # the measurement to perform
23
+ # the rule to perform
24
24
  #
25
25
  # @yieldreturn [Boolean]
26
26
  # return true if successful, false if not
@@ -28,8 +28,8 @@ module Yardstick
28
28
  # @return [undefined]
29
29
  #
30
30
  # @api private
31
- def measurement(description, &block)
32
- measurements << [ description, block ]
31
+ def rule(description, &block)
32
+ rules << Rule.new(description, &block)
33
33
  end
34
34
 
35
35
  private
@@ -43,8 +43,7 @@ module Yardstick
43
43
  #
44
44
  # @api private
45
45
  def included(mod)
46
- mod.extend(ClassMethods)
47
- copy_measurements(mod)
46
+ mod.extend(ClassMethods).rules.merge(rules)
48
47
  end
49
48
 
50
49
  # Extend the docstring meta class with measurable class methods
@@ -56,21 +55,7 @@ module Yardstick
56
55
  #
57
56
  # @api private
58
57
  def extended(docstring)
59
- meta_class = docstring.meta_class
60
- meta_class.extend(ClassMethods)
61
- copy_measurements(meta_class)
62
- end
63
-
64
- # Copy measurements from the ancestor to the descendant
65
- #
66
- # @param [Module] descendant
67
- # the descendant module or class
68
- #
69
- # @return [undefined]
70
- #
71
- # @api private
72
- def copy_measurements(descendant)
73
- descendant.measurements.concat(measurements).uniq!
58
+ included(docstring.meta_class)
74
59
  end
75
60
  end # module ClassMethods
76
61
 
@@ -81,14 +66,12 @@ module Yardstick
81
66
  # @example
82
67
  # docstring.measure # => [ Measurement ]
83
68
  #
84
- # @return [Array<Measurement>]
69
+ # @return [MeasurementSet]
85
70
  # a collection of measurements
86
71
  #
87
72
  # @api public
88
73
  def measure
89
- meta_class.measurements.map do |(description, block)|
90
- Measurement.new(description, self, &block)
91
- end
74
+ meta_class.rules.measure(self)
92
75
  end
93
76
 
94
77
  end # module Measurable
@@ -1,6 +1,17 @@
1
1
  module Yardstick
2
2
  class Measurement
3
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
+
4
15
  # Return a Measurement instance
5
16
  #
6
17
  # @example
@@ -87,6 +98,33 @@ module Yardstick
87
98
  end
88
99
  end
89
100
 
101
+ # Test if Measurement is equal to another measurement
102
+ #
103
+ # @example
104
+ # measurement == equal_measurement # => true
105
+ #
106
+ # @param [Measurement] other
107
+ # the other Measurement
108
+ #
109
+ # @return [Boolean]
110
+ # true if the Measurement is equal to the other, false if not
111
+ #
112
+ # @api semipublic
113
+ def eql?(other)
114
+ @description.eql?(other.instance_variable_get(:@description)) &&
115
+ @docstring.eql?(other.instance_variable_get(:@docstring))
116
+ end
117
+
118
+ # Return hash identifier for the Measurement
119
+ #
120
+ # @return [Integer]
121
+ # the hash identifier
122
+ #
123
+ # @api private
124
+ def hash
125
+ [ @description, @docstring ].hash
126
+ end
127
+
90
128
  private
91
129
 
92
130
  # Measure the docstring using the method provided to the constructor
@@ -0,0 +1,123 @@
1
+ require 'rational'
2
+
3
+ module Yardstick
4
+ class MeasurementSet < OrderedSet
5
+
6
+ # The total number of measurements
7
+ #
8
+ # @example
9
+ # measurements.total # => 570
10
+ #
11
+ # @return [Integer]
12
+ # total measurements
13
+ #
14
+ # @api public
15
+ def total
16
+ length
17
+ end
18
+
19
+ # The number of successful measurements
20
+ #
21
+ # @example
22
+ # measurements.successful # => 561
23
+ #
24
+ # @return [Integer]
25
+ # successful measurements
26
+ #
27
+ # @api public
28
+ def successful
29
+ select { |measurement| measurement.ok? }.length
30
+ end
31
+
32
+ # The number of failed measurements
33
+ #
34
+ # @example
35
+ # measurements.failed # => 9
36
+ #
37
+ # @return [Integer]
38
+ # failed measurements
39
+ #
40
+ # @api public
41
+ def failed
42
+ total - successful
43
+ end
44
+
45
+ # The percentage of successful measurements
46
+ #
47
+ # @example
48
+ # measurements.coverage # => Rational(561, 570).to_f # => 98.4%
49
+ #
50
+ # @return [Integer, Rational]
51
+ # the coverage percentage
52
+ #
53
+ # @api public
54
+ def coverage
55
+ empty? ? 0 : Rational(successful, total)
56
+ end
57
+
58
+ # Warn the unsuccessful measurements and a summary
59
+ #
60
+ # @example
61
+ # measurements.warn # (outputs measurements results and summary)
62
+ #
63
+ # @return [undefined]
64
+ #
65
+ # @api public
66
+ def warn
67
+ each { |measurement| measurement.warn }
68
+ warn_summary
69
+ end
70
+
71
+ private
72
+
73
+ # Warn the summary of all measurements
74
+ #
75
+ # @return [undefined]
76
+ #
77
+ # @api private
78
+ def warn_summary
79
+ Kernel.warn("\n#{[ coverage_text, successful_text, failed_text, total_text ].join(' ')}")
80
+ end
81
+
82
+ # The text for the coverage percentage to include in the summary
83
+ #
84
+ # @return [String]
85
+ # the coverage text
86
+ #
87
+ # @api private
88
+ def coverage_text
89
+ 'Coverage: %.1f%%' % (coverage * 100)
90
+ end
91
+
92
+ # The text for the successful measurements to include in the summary
93
+ #
94
+ # @return [String]
95
+ # the successful text
96
+ #
97
+ # @api private
98
+ def successful_text
99
+ 'Success: %d' % successful
100
+ end
101
+
102
+ # The text for the failed measurements to include in the summary
103
+ #
104
+ # @return [String]
105
+ # the failed text
106
+ #
107
+ # @api private
108
+ def failed_text
109
+ 'Failed: %d' % failed
110
+ end
111
+
112
+ # The text for the total measurements to include in the summary
113
+ #
114
+ # @return [String]
115
+ # the total text
116
+ #
117
+ # @api private
118
+ def total_text
119
+ 'Total: %d' % total
120
+ end
121
+
122
+ end # class MeasurementSet
123
+ end # module Yardstick