inch 0.0.1 → 0.1.0

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