inch 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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/README.md +335 -3
  4. data/Rakefile +8 -0
  5. data/TODOS.md +12 -0
  6. data/bin/inch +17 -0
  7. data/inch.gemspec +7 -2
  8. data/lib/inch.rb +6 -1
  9. data/lib/inch/cli.rb +24 -0
  10. data/lib/inch/cli/arguments.rb +45 -0
  11. data/lib/inch/cli/command.rb +29 -0
  12. data/lib/inch/cli/command/base.rb +62 -0
  13. data/lib/inch/cli/command/base_list.rb +75 -0
  14. data/lib/inch/cli/command/base_object.rb +40 -0
  15. data/lib/inch/cli/command/console.rb +22 -0
  16. data/lib/inch/cli/command/inspect.rb +20 -0
  17. data/lib/inch/cli/command/list.rb +25 -0
  18. data/lib/inch/cli/command/options/base.rb +137 -0
  19. data/lib/inch/cli/command/options/base_list.rb +84 -0
  20. data/lib/inch/cli/command/options/base_object.rb +47 -0
  21. data/lib/inch/cli/command/options/console.rb +26 -0
  22. data/lib/inch/cli/command/options/inspect.rb +25 -0
  23. data/lib/inch/cli/command/options/list.rb +30 -0
  24. data/lib/inch/cli/command/options/show.rb +27 -0
  25. data/lib/inch/cli/command/options/stats.rb +20 -0
  26. data/lib/inch/cli/command/options/suggest.rb +61 -0
  27. data/lib/inch/cli/command/output/base.rb +32 -0
  28. data/lib/inch/cli/command/output/console.rb +45 -0
  29. data/lib/inch/cli/command/output/inspect.rb +129 -0
  30. data/lib/inch/cli/command/output/list.rb +87 -0
  31. data/lib/inch/cli/command/output/show.rb +79 -0
  32. data/lib/inch/cli/command/output/stats.rb +111 -0
  33. data/lib/inch/cli/command/output/suggest.rb +104 -0
  34. data/lib/inch/cli/command/show.rb +20 -0
  35. data/lib/inch/cli/command/stats.rb +20 -0
  36. data/lib/inch/cli/command/suggest.rb +104 -0
  37. data/lib/inch/cli/command_parser.rb +82 -0
  38. data/lib/inch/cli/sparkline_helper.rb +31 -0
  39. data/lib/inch/cli/trace_helper.rb +42 -0
  40. data/lib/inch/cli/yardopts_helper.rb +49 -0
  41. data/lib/inch/code_object.rb +8 -0
  42. data/lib/inch/code_object/docstring.rb +97 -0
  43. data/lib/inch/code_object/nodoc_helper.rb +84 -0
  44. data/lib/inch/code_object/proxy.rb +37 -0
  45. data/lib/inch/code_object/proxy/base.rb +194 -0
  46. data/lib/inch/code_object/proxy/class_object.rb +9 -0
  47. data/lib/inch/code_object/proxy/constant_object.rb +8 -0
  48. data/lib/inch/code_object/proxy/method_object.rb +118 -0
  49. data/lib/inch/code_object/proxy/method_parameter_object.rb +81 -0
  50. data/lib/inch/code_object/proxy/module_object.rb +8 -0
  51. data/lib/inch/code_object/proxy/namespace_object.rb +38 -0
  52. data/lib/inch/core_ext.rb +2 -0
  53. data/lib/inch/core_ext/string.rb +3 -0
  54. data/lib/inch/core_ext/yard.rb +4 -0
  55. data/lib/inch/evaluation.rb +35 -0
  56. data/lib/inch/evaluation/base.rb +60 -0
  57. data/lib/inch/evaluation/class_object.rb +6 -0
  58. data/lib/inch/evaluation/constant_object.rb +34 -0
  59. data/lib/inch/evaluation/file.rb +66 -0
  60. data/lib/inch/evaluation/method_object.rb +127 -0
  61. data/lib/inch/evaluation/module_object.rb +6 -0
  62. data/lib/inch/evaluation/namespace_object.rb +94 -0
  63. data/lib/inch/evaluation/role/base.rb +49 -0
  64. data/lib/inch/evaluation/role/constant.rb +43 -0
  65. data/lib/inch/evaluation/role/method.rb +60 -0
  66. data/lib/inch/evaluation/role/method_parameter.rb +46 -0
  67. data/lib/inch/evaluation/role/missing.rb +20 -0
  68. data/lib/inch/evaluation/role/namespace.rb +58 -0
  69. data/lib/inch/evaluation/role/object.rb +64 -0
  70. data/lib/inch/evaluation/score_range.rb +26 -0
  71. data/lib/inch/rake.rb +1 -0
  72. data/lib/inch/rake/suggest.rb +26 -0
  73. data/lib/inch/source_parser.rb +36 -0
  74. data/lib/inch/version.rb +1 -1
  75. data/test/fixtures/code_examples/lib/foo.rb +87 -0
  76. data/test/fixtures/readme/lib/foo.rb +17 -0
  77. data/test/fixtures/simple/README +25 -0
  78. data/test/fixtures/simple/lib/broken.rb +10 -0
  79. data/test/fixtures/simple/lib/foo.rb +214 -0
  80. data/test/fixtures/simple/lib/role_methods.rb +78 -0
  81. data/test/fixtures/simple/lib/role_namespaces.rb +68 -0
  82. data/test/fixtures/visibility/lib/foo.rb +18 -0
  83. data/test/fixtures/yardopts/.yardopts +1 -0
  84. data/test/fixtures/yardopts/foo/bar.rb +6 -0
  85. data/test/inch/cli/arguments_test.rb +70 -0
  86. data/test/inch/cli/command/console_test.rb +59 -0
  87. data/test/inch/cli/command/inspect_test.rb +59 -0
  88. data/test/inch/cli/command/list_test.rb +61 -0
  89. data/test/inch/cli/command/show_test.rb +59 -0
  90. data/test/inch/cli/command/stats_test.rb +57 -0
  91. data/test/inch/cli/command/suggest_test.rb +57 -0
  92. data/test/inch/cli/command_parser_test.rb +33 -0
  93. data/test/inch/cli/yardopts_helper_test.rb +84 -0
  94. data/test/inch/code_object/docstring_test.rb +204 -0
  95. data/test/inch/code_object/nodoc_helper_test.rb +38 -0
  96. data/test/inch/code_object/proxy_test.rb +188 -0
  97. data/test/inch/source_parser_test.rb +23 -0
  98. data/test/integration/stats_options_test.rb +34 -0
  99. data/test/integration/visibility_options_test.rb +79 -0
  100. data/test/test_helper.rb +21 -0
  101. metadata +184 -7
@@ -0,0 +1,24 @@
1
+ module Inch
2
+ module CLI
3
+ class << self
4
+ # Returns the columns of the terminal window
5
+ # (defaults to 80)
6
+ # @return [Fixnum]
7
+ def get_term_columns
8
+ str = `stty size`
9
+ rows_cols = str.split(' ').map(&:to_i)
10
+ rows_cols[1]
11
+ rescue
12
+ 80
13
+ end
14
+ end
15
+ COLUMNS = get_term_columns
16
+ end
17
+ end
18
+
19
+ require_relative 'cli/arguments'
20
+ require_relative 'cli/sparkline_helper'
21
+ require_relative 'cli/trace_helper'
22
+ require_relative 'cli/yardopts_helper'
23
+ require_relative 'cli/command'
24
+ require_relative 'cli/command_parser'
@@ -0,0 +1,45 @@
1
+ module Inch
2
+ module CLI
3
+ class Arguments
4
+ attr_reader :files, :object_names, :switches
5
+
6
+ def initialize(args)
7
+ @files = []
8
+ @object_names = []
9
+ @switches = []
10
+ parse(args)
11
+ end
12
+
13
+ private
14
+
15
+ def parse(args)
16
+ if first_non_file = args.find_index { |e| !file_or_glob?(e) }
17
+ @files = args[0...first_non_file]
18
+ rest = args[first_non_file..-1]
19
+ if first_switch = rest.find_index { |e| switch?(e) }
20
+ @object_names = rest[0...first_switch]
21
+ @switches = rest[first_switch..-1]
22
+ else
23
+ # object_names only
24
+ @object_names = rest
25
+ end
26
+ else
27
+ # files only
28
+ @files = args
29
+ end
30
+ end
31
+
32
+ def file_or_glob?(f)
33
+ if f =~ /[\*\{]/
34
+ true
35
+ else
36
+ File.file?(f) || File.directory?(f)
37
+ end
38
+ end
39
+
40
+ def switch?(f)
41
+ f =~ /^\-/
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ require_relative 'command/base'
2
+ require_relative 'command/base_list'
3
+ require_relative 'command/base_object'
4
+
5
+ require_relative 'command/console'
6
+ require_relative 'command/inspect'
7
+ require_relative 'command/list'
8
+ require_relative 'command/show'
9
+ require_relative 'command/stats'
10
+ require_relative 'command/suggest'
11
+
12
+ require_relative 'command/options/base'
13
+ require_relative 'command/options/base_list'
14
+ require_relative 'command/options/base_object'
15
+
16
+ require_relative 'command/options/console'
17
+ require_relative 'command/options/inspect'
18
+ require_relative 'command/options/list'
19
+ require_relative 'command/options/show'
20
+ require_relative 'command/options/stats'
21
+ require_relative 'command/options/suggest'
22
+
23
+ require_relative 'command/output/base'
24
+ require_relative 'command/output/console'
25
+ require_relative 'command/output/inspect'
26
+ require_relative 'command/output/list'
27
+ require_relative 'command/output/show'
28
+ require_relative 'command/output/stats'
29
+ require_relative 'command/output/suggest'
@@ -0,0 +1,62 @@
1
+ module Inch
2
+ module CLI
3
+ module Command
4
+ # Abstract base class for CLI utilities. Provides some helper methods for
5
+ # the option parser
6
+ #
7
+ # @abstract
8
+ # @note This was adapted from YARD.
9
+ # @see https://github.com/lsegal/yard/blob/master/lib/yard/cli/command.rb
10
+ class Base
11
+ include TraceHelper
12
+
13
+ attr_reader :source_parser
14
+
15
+ # Helper method to run the utility on an instance.
16
+ # @see #run
17
+ def self.run(*args)
18
+ command = new
19
+ command.run(*args)
20
+ command
21
+ end
22
+
23
+ def initialize
24
+ options_class = "Command::Options::#{self.class.to_s.split('::').last}"
25
+ @options = eval(options_class).new
26
+ @options.usage = usage
27
+ end
28
+
29
+ # Returns a description of the command
30
+ # @return [String]
31
+ def description
32
+ ""
33
+ end
34
+
35
+ # Returns the name of the command by which it is referenced
36
+ # in the command list.
37
+ # @return [String]
38
+ def name
39
+ CommandParser.commands.each do |name, klass|
40
+ return name if klass == self.class
41
+ end
42
+ end
43
+
44
+ # Returns a description of the command's usage pattern
45
+ # @return [String]
46
+ def usage
47
+ "Usage: inch #{name} [options]"
48
+ end
49
+
50
+ private
51
+
52
+ def run_source_parser(paths, excluded)
53
+ debug "Parsing:\n" \
54
+ " files: #{paths.inspect}\n" \
55
+ " excluded: #{excluded.inspect}"
56
+
57
+ @source_parser = SourceParser.run(paths, excluded)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,75 @@
1
+ module Inch
2
+ module CLI
3
+ module Command
4
+ class BaseList < Base
5
+ attr_writer :objects
6
+
7
+ def initialize
8
+ super
9
+ @ranges = Evaluation.new_score_ranges
10
+ end
11
+
12
+ # Prepares the list of objects and ranges, parsing arguments and
13
+ # running the source parser.
14
+ #
15
+ # @param [Array<String>] args the list of arguments.
16
+ # @return [void]
17
+ def prepare_list(*args)
18
+ @options.parse(args)
19
+ @options.verify
20
+ run_source_parser(@options.paths, @options.excluded)
21
+ filter_objects
22
+ assign_objects_to_ranges
23
+ end
24
+
25
+ private
26
+
27
+ # Assigns the objects returned by {#objects} to the score ranges in
28
+ # @ranges based on their score
29
+ #
30
+ def assign_objects_to_ranges
31
+ @ranges.each do |range|
32
+ list = objects.select { |o| range.range.include?(o.score) }
33
+ range.objects = sort_by_priority(list)
34
+ end
35
+ end
36
+
37
+ def filter_objects
38
+ if @options.namespaces == :only
39
+ self.objects = objects.select(&:namespace?)
40
+ end
41
+ if @options.namespaces == :none
42
+ self.objects = objects.reject(&:namespace?)
43
+ end
44
+ if @options.undocumented == :only
45
+ self.objects = objects.select(&:undocumented?)
46
+ end
47
+ if @options.undocumented == :none
48
+ self.objects = objects.reject(&:undocumented?)
49
+ end
50
+ if @options.depth
51
+ self.objects = objects.select { |o| o.depth <= @depth }
52
+ end
53
+ self.objects = objects.select do |o|
54
+ @options.visibility.include?(o.visibility)
55
+ end
56
+ if !@options.visibility.include?(:private)
57
+ self.objects = objects.reject do |o|
58
+ o.private_tag?
59
+ end
60
+ end
61
+ end
62
+
63
+ def objects
64
+ @objects ||= sort_by_priority(source_parser.all_objects)
65
+ end
66
+
67
+ def sort_by_priority(objects)
68
+ objects.sort_by do |o|
69
+ [o.priority, o.score, o.path.size]
70
+ end.reverse
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,40 @@
1
+ module Inch
2
+ module CLI
3
+ module Command
4
+ class BaseObject < Base
5
+ attr_accessor :object, :objects
6
+
7
+ def initialize
8
+ super
9
+ @ranges = Evaluation.new_score_ranges
10
+ end
11
+
12
+ # Prepares the (list of) objects, parsing arguments and
13
+ # running the source parser.
14
+ #
15
+ # @param [Array<String>] args the list of arguments.
16
+ # @return [void]
17
+ def prepare_objects(*args)
18
+ @options.parse(args)
19
+ @options.verify
20
+ run_source_parser(@options.paths, @options.excluded)
21
+
22
+ self.objects = find_object_names(@options.object_names)
23
+ self.object = @objects.first
24
+ end
25
+
26
+ private
27
+
28
+ def find_object_names(object_names)
29
+ object_names.map do |object_name|
30
+ if object = source_parser.find_object(object_name)
31
+ object
32
+ else
33
+ source_parser.find_objects(object_name)
34
+ end
35
+ end.flatten
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,22 @@
1
+ require 'pry'
2
+
3
+ module Inch
4
+ module CLI
5
+ module Command
6
+ class Console < BaseObject
7
+ def description
8
+ 'Shows a console'
9
+ end
10
+
11
+ def usage
12
+ 'Usage: inch console [paths] [OBJECT_NAME] [options]'
13
+ end
14
+
15
+ def run(*args)
16
+ prepare_objects(*args)
17
+ Output::Console.new(@options, @object, @objects, source_parser)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ module Inch
2
+ module CLI
3
+ module Command
4
+ class Inspect < BaseObject
5
+ def description
6
+ 'Inspects an object'
7
+ end
8
+
9
+ def usage
10
+ 'Usage: inch inspect [paths] OBJECT_NAME [[OBJECT_NAME2] ...] [options]'
11
+ end
12
+
13
+ def run(*args)
14
+ prepare_objects(*args)
15
+ Output::Inspect.new(@options, objects)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ module Inch
2
+ module CLI
3
+ module Command
4
+ class List < BaseList
5
+ def description
6
+ 'Lists all objects with their results'
7
+ end
8
+
9
+ def usage
10
+ 'Usage: inch list [paths] [options]'
11
+ end
12
+
13
+ # Runs the commandline utility, parsing arguments and displaying a
14
+ # list of objects
15
+ #
16
+ # @param [Array<String>] args the list of arguments.
17
+ # @return [void]
18
+ def run(*args)
19
+ prepare_list(*args)
20
+ Output::List.new(@options, objects, @ranges)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,137 @@
1
+ require 'optparse'
2
+
3
+ module Inch
4
+ module CLI
5
+ module Command
6
+ module Options
7
+ # Abstract base class for CLI options. Provides some helper methods for
8
+ # the option parser
9
+ #
10
+ class Base
11
+ include TraceHelper
12
+ include YardoptsHelper
13
+
14
+ class << self
15
+ def attribute(name, default = nil)
16
+ define_method(name) do
17
+ instance_variable_get("@#{name}") || default
18
+ end
19
+ define_method("#{name}=") do |value|
20
+ instance_variable_set("@#{name}", value)
21
+ end
22
+ end
23
+ end
24
+
25
+ attribute :usage, ""
26
+ attribute :paths, []
27
+ attribute :excluded, []
28
+
29
+ def parse(args)
30
+ opts = OptionParser.new
31
+ opts.banner = usage
32
+
33
+ descriptions.each do |text|
34
+ opts.separator " " + text
35
+ end
36
+
37
+ set_options(opts)
38
+ parse_options(opts, args)
39
+ end
40
+
41
+ def set_options(opts)
42
+ common_options(opts)
43
+ end
44
+
45
+ # Override and fill with validations
46
+ def verify
47
+ end
48
+
49
+ protected
50
+
51
+ # Override and fill with an array of descriptions that will be
52
+ # shown via the help switch.
53
+ def descriptions
54
+ []
55
+ end
56
+
57
+ def description_arrows
58
+ arrows = Output::Base::PRIORITY_ARROWS.join(' ')
59
+ "Arrows (#{arrows}) hint at the importance of the object " +
60
+ "being documented."
61
+ end
62
+
63
+ def description_grades
64
+ grades = Evaluation.new_score_ranges.map(&:grade)
65
+ "School grades (#{grades.join(', ')}) are assigned and " +
66
+ "displayed with each object."
67
+ end
68
+
69
+ DEFAULT_PATHS = ["{lib,app}/**/*.rb", "ext/**/*.c"]
70
+
71
+ # @yard_files is assigned by YardoptsHelper#parse_yardopts_options
72
+ def get_paths(args)
73
+ paths = @yard_files ? @yard_files : args.dup
74
+ if paths.empty?
75
+ DEFAULT_PATHS
76
+ else
77
+ paths
78
+ end
79
+ end
80
+
81
+ # Adds a set of common options to the tail of the OptionParser
82
+ #
83
+ # @param [OptionParser] opts the option parser object
84
+ # @return [void]
85
+ def common_options(opts)
86
+ opts.separator ""
87
+ opts.separator "Other options:"
88
+ opts.on("--[no-]color", "Run without color") do |v|
89
+ Term::ANSIColor::coloring = v
90
+ end
91
+ opts.on_tail('-v', '--version', 'Show version.') do
92
+ trace "inch #{Inch::VERSION}"
93
+ exit
94
+ end
95
+ opts.on_tail('-h', '--help', 'Show this help.') do
96
+ trace opts
97
+ exit
98
+ end
99
+ end
100
+
101
+ def kill(msg = nil)
102
+ warn usage
103
+ warn msg.red unless msg.nil?
104
+ warn "Try `--help' for more information."
105
+ exit 1
106
+ end
107
+
108
+ # Parses the option and handles invalid switches
109
+ #
110
+ # @param [OptionParser] opts the option parser object
111
+ # @param [Array<String>] args the arguments passed from input. This
112
+ # array will be modified.
113
+ # @return [void]
114
+ def parse_options(opts, args)
115
+ reset
116
+ opts.parse!(args)
117
+ rescue OptionParser::ParseError => err
118
+ kill unrecognized_option(err)
119
+ end
120
+
121
+ def reset
122
+ # color is enabled by default, can be turned of by switch --no-color
123
+ Term::ANSIColor::coloring = true
124
+ end
125
+
126
+ # Callback when an unrecognize option is parsed
127
+ #
128
+ # @param [OptionParser::ParseError] err the exception raised by the
129
+ # option parser
130
+ def unrecognized_option(err)
131
+ trace "Unrecognized/#{err.message}".red
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end