inch 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/README.md +335 -3
- data/Rakefile +8 -0
- data/TODOS.md +12 -0
- data/bin/inch +17 -0
- data/inch.gemspec +7 -2
- data/lib/inch.rb +6 -1
- data/lib/inch/cli.rb +24 -0
- data/lib/inch/cli/arguments.rb +45 -0
- data/lib/inch/cli/command.rb +29 -0
- data/lib/inch/cli/command/base.rb +62 -0
- data/lib/inch/cli/command/base_list.rb +75 -0
- data/lib/inch/cli/command/base_object.rb +40 -0
- data/lib/inch/cli/command/console.rb +22 -0
- data/lib/inch/cli/command/inspect.rb +20 -0
- data/lib/inch/cli/command/list.rb +25 -0
- data/lib/inch/cli/command/options/base.rb +137 -0
- data/lib/inch/cli/command/options/base_list.rb +84 -0
- data/lib/inch/cli/command/options/base_object.rb +47 -0
- data/lib/inch/cli/command/options/console.rb +26 -0
- data/lib/inch/cli/command/options/inspect.rb +25 -0
- data/lib/inch/cli/command/options/list.rb +30 -0
- data/lib/inch/cli/command/options/show.rb +27 -0
- data/lib/inch/cli/command/options/stats.rb +20 -0
- data/lib/inch/cli/command/options/suggest.rb +61 -0
- data/lib/inch/cli/command/output/base.rb +32 -0
- data/lib/inch/cli/command/output/console.rb +45 -0
- data/lib/inch/cli/command/output/inspect.rb +129 -0
- data/lib/inch/cli/command/output/list.rb +87 -0
- data/lib/inch/cli/command/output/show.rb +79 -0
- data/lib/inch/cli/command/output/stats.rb +111 -0
- data/lib/inch/cli/command/output/suggest.rb +104 -0
- data/lib/inch/cli/command/show.rb +20 -0
- data/lib/inch/cli/command/stats.rb +20 -0
- data/lib/inch/cli/command/suggest.rb +104 -0
- data/lib/inch/cli/command_parser.rb +82 -0
- data/lib/inch/cli/sparkline_helper.rb +31 -0
- data/lib/inch/cli/trace_helper.rb +42 -0
- data/lib/inch/cli/yardopts_helper.rb +49 -0
- data/lib/inch/code_object.rb +8 -0
- data/lib/inch/code_object/docstring.rb +97 -0
- data/lib/inch/code_object/nodoc_helper.rb +84 -0
- data/lib/inch/code_object/proxy.rb +37 -0
- data/lib/inch/code_object/proxy/base.rb +194 -0
- data/lib/inch/code_object/proxy/class_object.rb +9 -0
- data/lib/inch/code_object/proxy/constant_object.rb +8 -0
- data/lib/inch/code_object/proxy/method_object.rb +118 -0
- data/lib/inch/code_object/proxy/method_parameter_object.rb +81 -0
- data/lib/inch/code_object/proxy/module_object.rb +8 -0
- data/lib/inch/code_object/proxy/namespace_object.rb +38 -0
- data/lib/inch/core_ext.rb +2 -0
- data/lib/inch/core_ext/string.rb +3 -0
- data/lib/inch/core_ext/yard.rb +4 -0
- data/lib/inch/evaluation.rb +35 -0
- data/lib/inch/evaluation/base.rb +60 -0
- data/lib/inch/evaluation/class_object.rb +6 -0
- data/lib/inch/evaluation/constant_object.rb +34 -0
- data/lib/inch/evaluation/file.rb +66 -0
- data/lib/inch/evaluation/method_object.rb +127 -0
- data/lib/inch/evaluation/module_object.rb +6 -0
- data/lib/inch/evaluation/namespace_object.rb +94 -0
- data/lib/inch/evaluation/role/base.rb +49 -0
- data/lib/inch/evaluation/role/constant.rb +43 -0
- data/lib/inch/evaluation/role/method.rb +60 -0
- data/lib/inch/evaluation/role/method_parameter.rb +46 -0
- data/lib/inch/evaluation/role/missing.rb +20 -0
- data/lib/inch/evaluation/role/namespace.rb +58 -0
- data/lib/inch/evaluation/role/object.rb +64 -0
- data/lib/inch/evaluation/score_range.rb +26 -0
- data/lib/inch/rake.rb +1 -0
- data/lib/inch/rake/suggest.rb +26 -0
- data/lib/inch/source_parser.rb +36 -0
- data/lib/inch/version.rb +1 -1
- data/test/fixtures/code_examples/lib/foo.rb +87 -0
- data/test/fixtures/readme/lib/foo.rb +17 -0
- data/test/fixtures/simple/README +25 -0
- data/test/fixtures/simple/lib/broken.rb +10 -0
- data/test/fixtures/simple/lib/foo.rb +214 -0
- data/test/fixtures/simple/lib/role_methods.rb +78 -0
- data/test/fixtures/simple/lib/role_namespaces.rb +68 -0
- data/test/fixtures/visibility/lib/foo.rb +18 -0
- data/test/fixtures/yardopts/.yardopts +1 -0
- data/test/fixtures/yardopts/foo/bar.rb +6 -0
- data/test/inch/cli/arguments_test.rb +70 -0
- data/test/inch/cli/command/console_test.rb +59 -0
- data/test/inch/cli/command/inspect_test.rb +59 -0
- data/test/inch/cli/command/list_test.rb +61 -0
- data/test/inch/cli/command/show_test.rb +59 -0
- data/test/inch/cli/command/stats_test.rb +57 -0
- data/test/inch/cli/command/suggest_test.rb +57 -0
- data/test/inch/cli/command_parser_test.rb +33 -0
- data/test/inch/cli/yardopts_helper_test.rb +84 -0
- data/test/inch/code_object/docstring_test.rb +204 -0
- data/test/inch/code_object/nodoc_helper_test.rb +38 -0
- data/test/inch/code_object/proxy_test.rb +188 -0
- data/test/inch/source_parser_test.rb +23 -0
- data/test/integration/stats_options_test.rb +34 -0
- data/test/integration/visibility_options_test.rb +79 -0
- data/test/test_helper.rb +21 -0
- metadata +184 -7
@@ -0,0 +1,82 @@
|
|
1
|
+
# This was adapted from https://github.com/lsegal/yard/blob/master/lib/yard/cli/command_parser.rb
|
2
|
+
module Inch
|
3
|
+
module CLI
|
4
|
+
# This class parses a command name out of the +inch+ CLI command and calls
|
5
|
+
# that command in the form:
|
6
|
+
#
|
7
|
+
# $ inch command_name [options]
|
8
|
+
#
|
9
|
+
# If no command or arguments are specified, or if the arguments immediately
|
10
|
+
# begin with a +--opt+ (not +--help+), the {default_command} will be used
|
11
|
+
# (which itself defaults to +:doc+).
|
12
|
+
#
|
13
|
+
class CommandParser
|
14
|
+
include TraceHelper
|
15
|
+
|
16
|
+
class << self
|
17
|
+
# @return [Hash{Symbol => Command}] the mapping of command names to
|
18
|
+
# command classes to parse the user command.
|
19
|
+
attr_accessor :commands
|
20
|
+
|
21
|
+
# @return [Symbol] the default command name to use when no options
|
22
|
+
# are specified or
|
23
|
+
attr_accessor :default_command
|
24
|
+
end
|
25
|
+
|
26
|
+
self.commands = {
|
27
|
+
:console => Command::Console,
|
28
|
+
:inspect => Command::Inspect,
|
29
|
+
:list => Command::List,
|
30
|
+
:show => Command::Show,
|
31
|
+
:stats => Command::Stats,
|
32
|
+
:suggest => Command::Suggest,
|
33
|
+
}
|
34
|
+
|
35
|
+
self.default_command = :suggest
|
36
|
+
|
37
|
+
# Convenience method to create a new CommandParser and call {#run}
|
38
|
+
# @return (see #run)
|
39
|
+
def self.run(*args)
|
40
|
+
new.run(*args)
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize
|
44
|
+
#log.show_backtraces = false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Runs the {Command} object matching the command name of the first
|
48
|
+
# argument.
|
49
|
+
# @return [void]
|
50
|
+
def run(*args)
|
51
|
+
unless ['--help', '-h'].include?(args.join)
|
52
|
+
if args.size == 0 || args.first =~ /^-/
|
53
|
+
command_name = self.class.default_command
|
54
|
+
else
|
55
|
+
command_name = args.first.to_sym
|
56
|
+
args.shift
|
57
|
+
end
|
58
|
+
if commands.has_key?(command_name)
|
59
|
+
return commands[command_name].run(*args)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
list_commands
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def commands
|
68
|
+
self.class.commands
|
69
|
+
end
|
70
|
+
|
71
|
+
def list_commands
|
72
|
+
trace "Usage: inch <command> [options]"
|
73
|
+
trace
|
74
|
+
trace "Commands:"
|
75
|
+
commands.keys.sort_by {|k| k.to_s }.each do |command_name|
|
76
|
+
command = commands[command_name].new
|
77
|
+
trace " %-8s %s" % [command_name, command.description]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Inch
|
2
|
+
module CLI
|
3
|
+
module SparklineHelper
|
4
|
+
def ranges_sparkline(_ranges)
|
5
|
+
ranges = _ranges.reverse
|
6
|
+
list = ranges.map { |r| r.objects.size }
|
7
|
+
sparkline = Sparkr::Sparkline.new(list)
|
8
|
+
sparkline.format do |tick, count, index|
|
9
|
+
t = tick.color(ranges[index].color)
|
10
|
+
index == 0 ? t + ' ' : t
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def grades_sparkline(objects)
|
15
|
+
grades = {}
|
16
|
+
objects.each do |o|
|
17
|
+
grades[o.grade] ||= 0
|
18
|
+
grades[o.grade] += 1
|
19
|
+
end
|
20
|
+
ranges = Evaluation.new_score_ranges.reverse
|
21
|
+
order = ranges.map(&:grade)
|
22
|
+
list = order.map { |g| grades[g] }
|
23
|
+
sparkline = Sparkr::Sparkline.new(list)
|
24
|
+
sparkline.format do |tick, count, index|
|
25
|
+
t = tick.color(ranges[index].color)
|
26
|
+
index == 0 ? t + ' ' : t
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Inch
|
2
|
+
module CLI
|
3
|
+
module TraceHelper
|
4
|
+
def debug(msg)
|
5
|
+
return unless ENV['DEBUG']
|
6
|
+
msg.to_s.lines.each do |line|
|
7
|
+
trace edged :dark, line.gsub(/\n$/,'').dark
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Writes the given +text+ to stdout
|
12
|
+
# @param text [String]
|
13
|
+
# @return [void]
|
14
|
+
def trace(text = "")
|
15
|
+
puts text
|
16
|
+
end
|
17
|
+
|
18
|
+
def trace_header(text, color, bg_color = nil)
|
19
|
+
trace header(text, color, bg_color)
|
20
|
+
trace if !use_color?
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def edged(color, msg, edge = "┃ ")
|
26
|
+
edge.color(color) + msg
|
27
|
+
end
|
28
|
+
|
29
|
+
def header(text, color, bg_color = nil)
|
30
|
+
bg_color ||= "intense_#{color}"
|
31
|
+
bar = " #{text}".ljust(CLI::COLUMNS-1)
|
32
|
+
.on_color(bg_color).color(:color16)
|
33
|
+
"#".color(color).on_color(color) + bar
|
34
|
+
end
|
35
|
+
|
36
|
+
def use_color?
|
37
|
+
Term::ANSIColor::coloring?
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Inch
|
2
|
+
module CLI
|
3
|
+
module YardoptsHelper
|
4
|
+
# @return [Array<String>] list of Ruby source files to process
|
5
|
+
attr_accessor :yard_files
|
6
|
+
|
7
|
+
# @return [Array<String>] list of excluded paths (regexp matches)
|
8
|
+
attr_accessor :excluded
|
9
|
+
|
10
|
+
VALID_YARD_SWITCHES = %w(--private --no-private --protected --no-public
|
11
|
+
--plugin --load --safe --yardopts --no-yardopts --document --no-document)
|
12
|
+
|
13
|
+
# Parses the option and gracefully handles invalid switches
|
14
|
+
#
|
15
|
+
# @param [OptionParser] opts the option parser object
|
16
|
+
# @param [Array<String>] args the arguments passed from input. This
|
17
|
+
# array will be modified.
|
18
|
+
# @return [void]
|
19
|
+
def parse_yardopts_options(opts, args)
|
20
|
+
wrapper = YardoptsWrapper.new()
|
21
|
+
|
22
|
+
dupped_args = args.dup
|
23
|
+
dupped_args.delete("--help")
|
24
|
+
dupped_args.delete_if do |arg|
|
25
|
+
arg =~ /^\-/ && !VALID_YARD_SWITCHES.include?(arg)
|
26
|
+
end
|
27
|
+
|
28
|
+
debug "Sending args to YARD:\n" \
|
29
|
+
" args: #{dupped_args}"
|
30
|
+
|
31
|
+
wrapper.parse_arguments(*dupped_args)
|
32
|
+
|
33
|
+
self.yard_files = wrapper.files
|
34
|
+
self.excluded = wrapper.excluded
|
35
|
+
end
|
36
|
+
|
37
|
+
def yardopts_options(opts)
|
38
|
+
wrapper = YardoptsWrapper.new()
|
39
|
+
wrapper.add_yardoc_options(opts)
|
40
|
+
end
|
41
|
+
|
42
|
+
class YardoptsWrapper < YARD::CLI::Yardoc
|
43
|
+
def add_yardoc_options(opts)
|
44
|
+
yardopts_options(opts)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Inch
|
2
|
+
module CodeObject
|
3
|
+
class Docstring
|
4
|
+
def initialize(text)
|
5
|
+
@text = text.to_s
|
6
|
+
end
|
7
|
+
|
8
|
+
def empty?
|
9
|
+
@text.strip.empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
def contains_code_example?
|
13
|
+
!code_examples.empty?
|
14
|
+
end
|
15
|
+
|
16
|
+
def code_examples
|
17
|
+
@code_examples ||= parse_code_examples
|
18
|
+
end
|
19
|
+
|
20
|
+
def describes_parameter?(name)
|
21
|
+
describe_parameter_regexps(name).any? do |pattern|
|
22
|
+
@text.index(pattern)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def mentions_parameter?(name)
|
27
|
+
mention_parameter_regexps(name).any? do |pattern|
|
28
|
+
@text.index(pattern)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def mentions_return?
|
33
|
+
@text.lines.last =~ /^Returns\ /
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_code_examples
|
37
|
+
code_examples = []
|
38
|
+
example = nil
|
39
|
+
@text.lines.each_with_index do |line, index|
|
40
|
+
if line =~/^\s*+$/
|
41
|
+
code_examples << example if example
|
42
|
+
example = []
|
43
|
+
elsif line =~/^\ {2,}\S+/
|
44
|
+
example << line if example
|
45
|
+
else
|
46
|
+
code_examples << example if example
|
47
|
+
example = nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
code_examples << example if example
|
51
|
+
code_examples.delete_if(&:empty?).map(&:join)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def mention_parameter_patterns(name)
|
57
|
+
[
|
58
|
+
"+#{name}+",
|
59
|
+
"+#{name}+::",
|
60
|
+
"<tt>#{name}</tt>",
|
61
|
+
"<tt>#{name}</tt>::",
|
62
|
+
"#{name}::",
|
63
|
+
/^#{name}\ \-\ /
|
64
|
+
]
|
65
|
+
end
|
66
|
+
|
67
|
+
def describe_parameter_extra_regexps(name)
|
68
|
+
[
|
69
|
+
"#{name}::",
|
70
|
+
"+#{name}+::",
|
71
|
+
"<tt>#{name}</tt>::",
|
72
|
+
].map do |pattern|
|
73
|
+
r = pattern.is_a?(Regexp) ? pattern : Regexp.escape(pattern)
|
74
|
+
/#{r}\n\ {2,}.+/m
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def describe_parameter_regexps(name)
|
79
|
+
mention_parameter_patterns(name).map do |pattern|
|
80
|
+
r = pattern.is_a?(Regexp) ? pattern : Regexp.escape(pattern)
|
81
|
+
/^#{r}\s?\S+/
|
82
|
+
end + describe_parameter_extra_regexps(name)
|
83
|
+
end
|
84
|
+
|
85
|
+
def mention_parameter_regexps(name)
|
86
|
+
mention_parameter_patterns(name).map do |pattern|
|
87
|
+
if pattern.is_a?(Regexp)
|
88
|
+
pattern
|
89
|
+
else
|
90
|
+
r = Regexp.escape(pattern)
|
91
|
+
/\W#{r}\W/
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Inch
|
2
|
+
module CodeObject
|
3
|
+
module NodocHelper
|
4
|
+
|
5
|
+
# Returns true if the code object is somehow marked not to be
|
6
|
+
# documented.
|
7
|
+
#
|
8
|
+
# @note Doesnot recognize ":startdoc:" and ":stopdoc:"
|
9
|
+
#
|
10
|
+
def nodoc?
|
11
|
+
object.tag(:private) || nodoc_comment?
|
12
|
+
end
|
13
|
+
|
14
|
+
NO_DOC_REGEX = /#\s*\:nodoc\:/
|
15
|
+
NO_DOC_ALL_REGEX = /#\s*\:nodoc\:\s*all/
|
16
|
+
DOC_REGEX = /#\s*\:doc\:/
|
17
|
+
|
18
|
+
def nodoc_comment?
|
19
|
+
explicit_nodoc_comment? || implicit_nodoc_comment?
|
20
|
+
end
|
21
|
+
|
22
|
+
def explicit_nodoc_comment?
|
23
|
+
declarations.any? { |str| str =~ NO_DOC_REGEX }
|
24
|
+
end
|
25
|
+
|
26
|
+
def explicit_nodoc_all_comment?
|
27
|
+
declarations.any? { |str| str =~ NO_DOC_ALL_REGEX }
|
28
|
+
end
|
29
|
+
|
30
|
+
def explicit_doc_comment?
|
31
|
+
declarations.any? { |str| str =~ DOC_REGEX }
|
32
|
+
end
|
33
|
+
|
34
|
+
def implicit_nodoc_all_comment?
|
35
|
+
if parent
|
36
|
+
parent.explicit_nodoc_all_comment? ||
|
37
|
+
parent.implicit_nodoc_all_comment?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def implicit_nodoc_comment?
|
42
|
+
return false if explicit_doc_comment?
|
43
|
+
|
44
|
+
if parent
|
45
|
+
return false if parent.explicit_doc_comment?
|
46
|
+
|
47
|
+
if namespace?
|
48
|
+
if parent.explicit_nodoc_all_comment?
|
49
|
+
return true
|
50
|
+
else
|
51
|
+
return parent.implicit_nodoc_all_comment?
|
52
|
+
end
|
53
|
+
else
|
54
|
+
if parent.explicit_nodoc_comment?
|
55
|
+
return true
|
56
|
+
else
|
57
|
+
return parent.implicit_nodoc_all_comment?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def declarations
|
64
|
+
@declarations ||= files.map do |(filename, line_no)|
|
65
|
+
get_line_no(filename, line_no)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def files
|
70
|
+
object.files
|
71
|
+
rescue YARD::CodeObjects::ProxyMethodError
|
72
|
+
[]
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_line_no(filename, n)
|
76
|
+
f = File.open(filename)
|
77
|
+
n.times{f.gets}
|
78
|
+
result = $_
|
79
|
+
f.close
|
80
|
+
result
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Inch
|
2
|
+
module CodeObject
|
3
|
+
module Proxy
|
4
|
+
class << self
|
5
|
+
def for(code_object)
|
6
|
+
@cache ||= {}
|
7
|
+
if proxy_object = @cache[cache_key(code_object)]
|
8
|
+
proxy_object
|
9
|
+
else
|
10
|
+
@cache[cache_key(code_object)] = class_for(code_object).new(code_object)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def class_for(code_object)
|
17
|
+
class_name = code_object.class.to_s.split('::').last
|
18
|
+
eval("::Inch::CodeObject::Proxy::#{class_name}")
|
19
|
+
rescue
|
20
|
+
Base
|
21
|
+
end
|
22
|
+
|
23
|
+
def cache_key(o)
|
24
|
+
o.path
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
require_relative 'proxy/base'
|
32
|
+
require_relative 'proxy/namespace_object'
|
33
|
+
require_relative 'proxy/class_object'
|
34
|
+
require_relative 'proxy/constant_object'
|
35
|
+
require_relative 'proxy/method_object'
|
36
|
+
require_relative 'proxy/method_parameter_object'
|
37
|
+
require_relative 'proxy/module_object'
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Inch
|
4
|
+
module CodeObject
|
5
|
+
module Proxy
|
6
|
+
class Base
|
7
|
+
extend Forwardable
|
8
|
+
include NodocHelper
|
9
|
+
|
10
|
+
# the actual (YARD) code object
|
11
|
+
attr_accessor :object
|
12
|
+
|
13
|
+
# @return [Symbol]
|
14
|
+
# when objects are assigned to ScoreRanges, this grade is set to
|
15
|
+
# enable easier querying for objects of a certain grade
|
16
|
+
attr_writer :grade
|
17
|
+
|
18
|
+
# Tags considered by wrapper methods like {#has_code_example?}
|
19
|
+
CONSIDERED_YARD_TAGS = %w(example param private return)
|
20
|
+
|
21
|
+
# convenient shortcuts to (YARD) code object
|
22
|
+
def_delegators :object, :type, :path, :name, :namespace, :source, :source_type, :signature, :group, :dynamic, :visibility, :docstring
|
23
|
+
|
24
|
+
# convenient shortcuts to evalution object
|
25
|
+
def_delegators :evaluation, :score, :roles, :priority
|
26
|
+
|
27
|
+
def initialize(object)
|
28
|
+
self.object = object
|
29
|
+
end
|
30
|
+
|
31
|
+
# To be overridden
|
32
|
+
# @see Proxy::NamespaceObject
|
33
|
+
# @return [Array,nil] the children of the current object or +nil+
|
34
|
+
def children
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def docstring
|
39
|
+
@docstring ||= Docstring.new(object.docstring)
|
40
|
+
end
|
41
|
+
|
42
|
+
def evaluation
|
43
|
+
@evaluation ||= Evaluation.for(self)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the name of the file where the object is declared first
|
47
|
+
# @return [String] a filename
|
48
|
+
def filename
|
49
|
+
# just checking the first file (which is the file where an object
|
50
|
+
# is first declared)
|
51
|
+
files.size > 0 ? files[0][0] : nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def grade
|
55
|
+
@grade ||= Evaluation.new_score_ranges.detect { |range|
|
56
|
+
range.range.include?(score)
|
57
|
+
}.grade
|
58
|
+
end
|
59
|
+
|
60
|
+
def has_alias?
|
61
|
+
!object.aliases.empty?
|
62
|
+
end
|
63
|
+
|
64
|
+
def has_code_example?
|
65
|
+
!object.tags(:example).empty? ||
|
66
|
+
docstring.contains_code_example?
|
67
|
+
end
|
68
|
+
|
69
|
+
def has_doc?
|
70
|
+
!docstring.empty?
|
71
|
+
end
|
72
|
+
|
73
|
+
def has_multiple_code_examples?
|
74
|
+
if object.tags(:example).size > 1 || docstring.code_examples.size > 1
|
75
|
+
true
|
76
|
+
else
|
77
|
+
if tag = object.tag(:example)
|
78
|
+
multi_code_examples?(tag.text)
|
79
|
+
elsif text = docstring.code_examples.first
|
80
|
+
multi_code_examples?(text)
|
81
|
+
else
|
82
|
+
false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def has_unconsidered_tags?
|
88
|
+
!unconsidered_tags.empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
def in_root?
|
92
|
+
depth == 1
|
93
|
+
end
|
94
|
+
|
95
|
+
# The depth of the following is 4:
|
96
|
+
#
|
97
|
+
# Foo::Bar::Baz#initialize
|
98
|
+
# ^ ^ ^ ^
|
99
|
+
# 1 << 2 << 3 << 4
|
100
|
+
#
|
101
|
+
# +depth+ answers the question "how many layers of code objects are
|
102
|
+
# above this one?"
|
103
|
+
#
|
104
|
+
# @note top-level counts, that's why Foo has depth 1!
|
105
|
+
#
|
106
|
+
# @param i [Fixnum] a counter for recursive method calls
|
107
|
+
# @return [Fixnum] the depth of the object in terms of namespace
|
108
|
+
def depth(i = 0)
|
109
|
+
if parent
|
110
|
+
parent.depth(i+1)
|
111
|
+
else
|
112
|
+
i
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# In the following example, the height of +Foo+ is 3
|
117
|
+
# (the height of the top-level is 4):
|
118
|
+
#
|
119
|
+
# Foo::Bar::Baz#initialize
|
120
|
+
# ^ ^ ^ ^
|
121
|
+
# 0 >> 1 >> 2 >> 3
|
122
|
+
#
|
123
|
+
# +height+ answers the question "how many layers of code objects are
|
124
|
+
# underneath this one?"
|
125
|
+
#
|
126
|
+
# @param i [Fixnum] a counter for recursive method calls
|
127
|
+
# @return [Fixnum] the height of the object in terms of namespace
|
128
|
+
def height(i = 0)
|
129
|
+
if children && !children.empty?
|
130
|
+
children.map do |child|
|
131
|
+
child.height(i+1)
|
132
|
+
end.max
|
133
|
+
else
|
134
|
+
i
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# @return [Boolean] +true+ if the object represents a method
|
139
|
+
def method?
|
140
|
+
false
|
141
|
+
end
|
142
|
+
|
143
|
+
# @return [Boolean] +true+ if the object represents a namespace
|
144
|
+
def namespace?
|
145
|
+
false
|
146
|
+
end
|
147
|
+
|
148
|
+
# @return [Array,nil] the parent of the current object or +nil+
|
149
|
+
def parent
|
150
|
+
Proxy.for(object.parent) if object.parent
|
151
|
+
end
|
152
|
+
|
153
|
+
def private?
|
154
|
+
visibility == :private
|
155
|
+
end
|
156
|
+
|
157
|
+
def private_tag?
|
158
|
+
!!object.tag(:private)
|
159
|
+
end
|
160
|
+
|
161
|
+
def protected?
|
162
|
+
visibility == :protected
|
163
|
+
end
|
164
|
+
|
165
|
+
def public?
|
166
|
+
visibility == :public
|
167
|
+
end
|
168
|
+
|
169
|
+
# @return [Boolean] +true+ if the object has no documentation at all
|
170
|
+
def undocumented?
|
171
|
+
docstring.empty? && object.tags.empty?
|
172
|
+
end
|
173
|
+
|
174
|
+
# @return [Array]
|
175
|
+
# YARD tags that are not already covered by other wrapper methods
|
176
|
+
def unconsidered_tags
|
177
|
+
@unconsidered_tags ||= object.tags.reject do |tag|
|
178
|
+
CONSIDERED_YARD_TAGS.include?(tag.tag_name)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def inspect
|
183
|
+
"#<#{self.class.to_s}: #{path}>"
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
def multi_code_examples?(text)
|
189
|
+
text =~ /\b#{Regexp.escape(name)}[^_0-9\!\?]/
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|