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,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,8 @@
1
+ module Inch
2
+ module CodeObject
3
+ end
4
+ end
5
+
6
+ require_relative 'code_object/docstring'
7
+ require_relative 'code_object/nodoc_helper'
8
+ require_relative 'code_object/proxy'
@@ -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