inch 0.2.3 → 0.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +7 -0
  3. data/TODOS.md +0 -5
  4. data/config/defaults.rb +26 -1
  5. data/inch.gemspec +1 -0
  6. data/lib/inch.rb +2 -1
  7. data/lib/inch/api.rb +34 -0
  8. data/lib/inch/api/filter.rb +17 -0
  9. data/lib/inch/api/get.rb +30 -0
  10. data/lib/inch/api/list.rb +10 -0
  11. data/lib/inch/api/options/base.rb +45 -0
  12. data/lib/inch/api/options/filter.rb +25 -0
  13. data/lib/inch/api/options/suggest.rb +36 -0
  14. data/lib/inch/api/stats.rb +7 -0
  15. data/lib/inch/api/suggest.rb +110 -0
  16. data/lib/inch/cli.rb +4 -1
  17. data/lib/inch/cli/command/base.rb +1 -17
  18. data/lib/inch/cli/command/base_list.rb +3 -63
  19. data/lib/inch/cli/command/base_object.rb +6 -28
  20. data/lib/inch/cli/command/list.rb +3 -2
  21. data/lib/inch/cli/command/options/base.rb +1 -1
  22. data/lib/inch/cli/command/options/base_list.rb +4 -2
  23. data/lib/inch/cli/command/options/suggest.rb +9 -8
  24. data/lib/inch/cli/command/output/base.rb +9 -11
  25. data/lib/inch/cli/command/output/list.rb +2 -2
  26. data/lib/inch/cli/command/output/show.rb +2 -10
  27. data/lib/inch/cli/command/output/stats.rb +4 -3
  28. data/lib/inch/cli/command/output/suggest.rb +5 -5
  29. data/lib/inch/cli/command/stats.rb +4 -3
  30. data/lib/inch/cli/command/suggest.rb +4 -94
  31. data/lib/inch/code_object.rb +2 -2
  32. data/lib/inch/code_object/converter.rb +89 -0
  33. data/lib/inch/code_object/provider.rb +36 -0
  34. data/lib/inch/code_object/provider/yard.rb +19 -0
  35. data/lib/inch/code_object/provider/yard/docstring.rb +106 -0
  36. data/lib/inch/code_object/provider/yard/nodoc_helper.rb +93 -0
  37. data/lib/inch/code_object/provider/yard/object.rb +55 -0
  38. data/lib/inch/code_object/provider/yard/object/base.rb +262 -0
  39. data/lib/inch/code_object/provider/yard/object/class_object.rb +12 -0
  40. data/lib/inch/code_object/provider/yard/object/constant_object.rb +12 -0
  41. data/lib/inch/code_object/provider/yard/object/method_object.rb +126 -0
  42. data/lib/inch/code_object/provider/yard/object/method_parameter_object.rb +88 -0
  43. data/lib/inch/code_object/provider/yard/object/module_object.rb +12 -0
  44. data/lib/inch/code_object/provider/yard/object/namespace_object.rb +47 -0
  45. data/lib/inch/code_object/provider/yard/parser.rb +54 -0
  46. data/lib/inch/code_object/proxy.rb +5 -3
  47. data/lib/inch/code_object/proxy/base.rb +103 -110
  48. data/lib/inch/code_object/proxy/class_object.rb +0 -1
  49. data/lib/inch/code_object/proxy/method_object.rb +20 -99
  50. data/lib/inch/code_object/proxy/method_parameter_object.rb +15 -39
  51. data/lib/inch/code_object/proxy/namespace_object.rb +7 -18
  52. data/lib/inch/codebase.rb +19 -0
  53. data/lib/inch/codebase/objects.rb +73 -0
  54. data/lib/inch/codebase/objects_filter.rb +61 -0
  55. data/lib/inch/codebase/proxy.rb +22 -0
  56. data/lib/inch/config.rb +8 -1
  57. data/lib/inch/evaluation.rb +5 -7
  58. data/lib/inch/evaluation/file.rb +1 -1
  59. data/lib/inch/evaluation/grade.rb +1 -1
  60. data/lib/inch/evaluation/object_schema.rb +3 -1
  61. data/lib/inch/evaluation/priority_range.rb +44 -0
  62. data/lib/inch/evaluation/proxy.rb +25 -0
  63. data/lib/inch/evaluation/proxy/base.rb +146 -0
  64. data/lib/inch/evaluation/proxy/class_object.rb +8 -0
  65. data/lib/inch/evaluation/proxy/constant_object.rb +19 -0
  66. data/lib/inch/evaluation/proxy/method_object.rb +65 -0
  67. data/lib/inch/evaluation/proxy/module_object.rb +8 -0
  68. data/lib/inch/evaluation/proxy/namespace_object.rb +27 -0
  69. data/lib/inch/evaluation/role/base.rb +19 -0
  70. data/lib/inch/evaluation/role/constant.rb +16 -0
  71. data/lib/inch/evaluation/role/method.rb +22 -0
  72. data/lib/inch/evaluation/role/method_parameter.rb +31 -1
  73. data/lib/inch/evaluation/role/namespace.rb +15 -0
  74. data/lib/inch/evaluation/role/object.rb +24 -0
  75. data/lib/inch/rake/suggest.rb +1 -0
  76. data/lib/inch/utils/read_write_methods.rb +44 -0
  77. data/lib/inch/{cli → utils}/weighted_list.rb +1 -1
  78. data/lib/inch/version.rb +1 -1
  79. data/test/fixtures/simple/lib/broken.rb +8 -0
  80. data/test/inch/api/filter_test.rb +51 -0
  81. data/test/inch/api/get_test.rb +22 -0
  82. data/test/inch/api/list_test.rb +15 -0
  83. data/test/inch/api/options/base_test.rb +30 -0
  84. data/test/inch/api/stats_test.rb +15 -0
  85. data/test/inch/api/suggest_test.rb +26 -0
  86. data/test/inch/cli/command/list_test.rb +2 -1
  87. data/test/inch/code_object/converter_test.rb +29 -0
  88. data/test/inch/code_object/{docstring_test.rb → provider/yard/docstring_test.rb} +13 -13
  89. data/test/inch/code_object/{nodoc_helper_test.rb → provider/yard/nodoc_helper_test.rb} +6 -6
  90. data/test/inch/code_object/provider/yard_test.rb +11 -0
  91. data/test/inch/code_object/provider_test.rb +9 -0
  92. data/test/inch/code_object/proxy/method_object_test.rb +22 -22
  93. data/test/inch/code_object/proxy_test.rb +10 -10
  94. data/test/inch/codebase/objects_test.rb +28 -0
  95. data/test/inch/codebase/proxy_test.rb +17 -0
  96. data/test/inch/evaluation/role/base_test.rb +71 -0
  97. data/test/inch/{cli → utils}/weighted_list_test.rb +2 -2
  98. data/test/shared/base_list.rb +73 -0
  99. data/test/test_helper.rb +0 -95
  100. metadata +89 -24
  101. data/lib/inch/code_object/docstring.rb +0 -102
  102. data/lib/inch/code_object/nodoc_helper.rb +0 -107
  103. data/lib/inch/evaluation/base.rb +0 -157
  104. data/lib/inch/evaluation/class_object.rb +0 -6
  105. data/lib/inch/evaluation/constant_object.rb +0 -33
  106. data/lib/inch/evaluation/method_object.rb +0 -105
  107. data/lib/inch/evaluation/module_object.rb +0 -6
  108. data/lib/inch/evaluation/namespace_object.rb +0 -52
  109. data/lib/inch/evaluation/read_write_methods.rb +0 -21
  110. data/lib/inch/source_parser.rb +0 -62
  111. data/test/inch/source_parser_test.rb +0 -23
@@ -3,6 +3,6 @@ module Inch
3
3
  end
4
4
  end
5
5
 
6
- require_relative 'code_object/docstring'
7
- require_relative 'code_object/nodoc_helper'
6
+ require_relative 'code_object/converter'
7
+ require_relative 'code_object/provider'
8
8
  require_relative 'code_object/proxy'
@@ -0,0 +1,89 @@
1
+ module Inch
2
+ module CodeObject
3
+ # The Converter takes code object representations from a provider and
4
+ # converts them into attributes hashes.
5
+ # These attributes can then be used to initialize a CodeObject::Proxy.
6
+ #
7
+ # @see CodeObject::Proxy.for
8
+ module Converter
9
+ OBJECT_ATTRIBUTES = %w(
10
+ name
11
+ fullname
12
+ files
13
+ filename
14
+
15
+ children_fullnames
16
+ parent_fullname
17
+
18
+ api_tag?
19
+ attributes
20
+ bang_name?
21
+ constant?
22
+ constructor?
23
+ depth
24
+ docstring
25
+ getter?
26
+ has_alias?
27
+ has_children?
28
+ has_code_example?
29
+ has_doc?
30
+ has_multiple_code_examples?
31
+ has_unconsidered_tags?
32
+ method?
33
+ nodoc?
34
+ namespace?
35
+ overridden?
36
+ overridden_method_fullname
37
+ parameters
38
+ private?
39
+ private_api_tag?
40
+ private_tag?
41
+ protected?
42
+ public?
43
+ questioning_name?
44
+ return_described?
45
+ return_mentioned?
46
+ return_typed?
47
+ in_root?
48
+ setter?
49
+ source
50
+ unconsidered_tag_count
51
+ undocumented?
52
+ visibility
53
+ ).map(&:to_sym)
54
+
55
+ PARAMETER_ATTRIBUTES = %w(
56
+ name
57
+ block?
58
+ described?
59
+ mentioned?
60
+ splat?
61
+ typed?
62
+ wrongly_mentioned?
63
+ ).map(&:to_sym)
64
+
65
+ # Returns an attributes Hash for a given code object
66
+ #
67
+ # @param o [Provider::YARD::Object::Base]
68
+ # @return [Hash]
69
+ def self.to_hash(o)
70
+ attributes = {}
71
+ OBJECT_ATTRIBUTES.each do |name|
72
+ if o.respond_to?(name)
73
+ attributes[name] = o.method(name).call
74
+ end
75
+ end
76
+ attributes[:parameters] = o.parameters.map do |parameter|
77
+ hash = {}
78
+ PARAMETER_ATTRIBUTES.each do |pname|
79
+ if parameter.respond_to?(pname)
80
+ hash[pname] = parameter.method(pname).call
81
+ end
82
+ end
83
+ hash
84
+ end
85
+ attributes
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,36 @@
1
+ module Inch
2
+ module CodeObject
3
+ # Provider modules "provide" a Codebase object with code objects.
4
+ # They are the intermediary between the raw representation that tools
5
+ # like YARD deliver and the "interface" that Inch expects.
6
+ #
7
+ # YARD Example:
8
+ #
9
+ # YARD's SourceParser returns ::YARD::CodeObject objects, which are
10
+ # cast to Provider::YARD::Object::Base objects that can ensure naming
11
+ # conventions et al. follow certain rules. These objects are then again
12
+ # converted into CodeObject::Proxy::Base objects that form the codebase:
13
+ #
14
+ # ::YARD::CodeObject
15
+ # ↓
16
+ # ::Inch::CodeObject::Provider::YARD::Object::Base
17
+ # ↓
18
+ # (Hash)
19
+ # ↓
20
+ # ::Inch::CodeObject::Proxy::Base
21
+ #
22
+ #
23
+ module Provider
24
+ def self.parse(dir, paths, excluded, type = :YARD)
25
+ provider_for(type).parse(dir, paths, excluded)
26
+ end
27
+
28
+ # @return [Module]
29
+ def self.provider_for(type)
30
+ eval("::Inch::CodeObject::Provider::#{type}")
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ require_relative 'provider/yard'
@@ -0,0 +1,19 @@
1
+ module Inch
2
+ module CodeObject
3
+ module Provider
4
+ # Parses the source tree (using YARD)
5
+ module YARD
6
+
7
+ def self.parse(dir, paths, excluded)
8
+ Parser.parse(dir, paths, excluded)
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ require_relative 'yard/parser'
17
+ require_relative 'yard/docstring'
18
+ require_relative 'yard/nodoc_helper'
19
+ require_relative 'yard/object'
@@ -0,0 +1,106 @@
1
+ module Inch
2
+ module CodeObject
3
+ module Provider
4
+ module YARD
5
+ class Docstring
6
+ def initialize(text)
7
+ @text = text.to_s
8
+ end
9
+
10
+ def empty?
11
+ @text.strip.empty?
12
+ end
13
+
14
+ def contains_code_example?
15
+ !code_examples.empty?
16
+ end
17
+
18
+ def code_examples
19
+ @code_examples ||= parse_code_examples
20
+ end
21
+
22
+ def describes_parameter?(name)
23
+ describe_parameter_regexps(name).any? do |pattern|
24
+ @text.index(pattern)
25
+ end
26
+ end
27
+
28
+ def mentions_parameter?(name)
29
+ mention_parameter_regexps(name).any? do |pattern|
30
+ @text.index(pattern)
31
+ end
32
+ end
33
+
34
+ def mentions_return?
35
+ @text.lines.to_a.last =~ /^Returns\ /
36
+ end
37
+
38
+ def describes_return?
39
+ @text.lines.to_a.last =~ /^Returns\ (\w+\s){2,}/
40
+ end
41
+
42
+ def parse_code_examples
43
+ code_examples = []
44
+ example = nil
45
+ @text.lines.each_with_index do |line, index|
46
+ if line =~/^\s*+$/
47
+ code_examples << example if example
48
+ example = []
49
+ elsif line =~/^\ {2,}\S+/
50
+ example << line if example
51
+ else
52
+ code_examples << example if example
53
+ example = nil
54
+ end
55
+ end
56
+ code_examples << example if example
57
+ code_examples.delete_if(&:empty?).map(&:join)
58
+ end
59
+
60
+ private
61
+
62
+ def mention_parameter_patterns(name)
63
+ [
64
+ "+#{name}+",
65
+ "+#{name}+::",
66
+ "<tt>#{name}</tt>",
67
+ "<tt>#{name}</tt>::",
68
+ "#{name}::",
69
+ /^#{Regexp.escape(name)}\ \-\ /
70
+ ]
71
+ end
72
+
73
+ def describe_parameter_extra_regexps(name)
74
+ [
75
+ "#{name}::",
76
+ "+#{name}+::",
77
+ "<tt>#{name}</tt>::",
78
+ ].map do |pattern|
79
+ r = pattern.is_a?(Regexp) ? pattern : Regexp.escape(pattern)
80
+ /#{r}\n\ {2,}.+/m
81
+ end
82
+ end
83
+
84
+ def describe_parameter_regexps(name)
85
+ same_line_regexps = mention_parameter_patterns(name).map do |pattern|
86
+ r = pattern.is_a?(Regexp) ? pattern : Regexp.escape(pattern)
87
+ /^#{r}\s?\S+/
88
+ end
89
+ same_line_regexps + describe_parameter_extra_regexps(name)
90
+ end
91
+
92
+ def mention_parameter_regexps(name)
93
+ mention_parameter_patterns(name).map do |pattern|
94
+ if pattern.is_a?(Regexp)
95
+ pattern
96
+ else
97
+ r = Regexp.escape(pattern)
98
+ /\W#{r}\W/
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,93 @@
1
+ module Inch
2
+ module CodeObject
3
+ module Provider
4
+ module YARD
5
+ module NodocHelper
6
+
7
+ # Returns true if the code object is somehow marked not to be
8
+ # documented.
9
+ #
10
+ # @note Doesnot recognize ":startdoc:" and ":stopdoc:"
11
+ #
12
+ def nodoc?
13
+ private_tag? || nodoc_comment?
14
+ end
15
+
16
+ NO_DOC_REGEX = /#\s*\:nodoc\:/
17
+ NO_DOC_ALL_REGEX = /#\s*\:nodoc\:\s*all/
18
+ DOC_REGEX = /#\s*\:doc\:/
19
+
20
+ def nodoc_comment?
21
+ explicit_nodoc_comment? || implicit_nodoc_comment?
22
+ end
23
+
24
+ def explicit_nodoc_comment?
25
+ declarations.any? { |str| str =~ NO_DOC_REGEX }
26
+ end
27
+
28
+ def explicit_nodoc_all_comment?
29
+ declarations.any? { |str| str =~ NO_DOC_ALL_REGEX }
30
+ end
31
+
32
+ def explicit_doc_comment?
33
+ declarations.any? { |str| str =~ DOC_REGEX }
34
+ end
35
+
36
+ def implicit_nodoc_all_comment?
37
+ if parent
38
+ parent.explicit_nodoc_all_comment? ||
39
+ parent.implicit_nodoc_all_comment?
40
+ end
41
+ end
42
+
43
+ def implicit_nodoc_comment?
44
+ return false if explicit_doc_comment?
45
+
46
+ if parent
47
+ return false if parent.explicit_doc_comment?
48
+
49
+ if namespace?
50
+ if parent.explicit_nodoc_all_comment?
51
+ return true
52
+ else
53
+ return parent.implicit_nodoc_all_comment?
54
+ end
55
+ else
56
+ if parent.explicit_nodoc_comment?
57
+ return true
58
+ else
59
+ return parent.implicit_nodoc_all_comment?
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ # Returns all lines in all files declaring the object
66
+ #
67
+ # @example
68
+ # declarations # => ["class Base # :nodoc:", "class Foo < Base"]
69
+ #
70
+ # @return [Array<String>]
71
+ def declarations
72
+ @declarations ||= files.map do |f|
73
+ get_line_no(f.filename, f.line_no)
74
+ end
75
+ end
76
+
77
+ # Returns a +line_number+ from a file
78
+ #
79
+ # @param filename [String]
80
+ # @param line_number [Fixnum]
81
+ # @return [String]
82
+ def get_line_no(filename, line_number)
83
+ f = File.open(filename)
84
+ line_number.times{f.gets}
85
+ result = $_
86
+ f.close
87
+ result
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,55 @@
1
+ module Inch
2
+ module CodeObject
3
+ module Provider
4
+ module YARD
5
+ # CodeObject::Provider::YARD::Object object represent code objects.
6
+ #
7
+ module Object
8
+ class << self
9
+ # Returns a Proxy object for the given +yard_object+
10
+ #
11
+ # @param yard_object [YARD::CodeObject]
12
+ # @return [Provider::YARD::Object]
13
+ def for(yard_object)
14
+ @cache ||= {}
15
+ if proxy_object = @cache[cache_key(yard_object)]
16
+ proxy_object
17
+ else
18
+ @cache[cache_key(yard_object)] = class_for(yard_object).new(yard_object)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ # Returns a Proxy class for the given +yard_object+
25
+ #
26
+ # @param yard_object [YARD::CodeObject]
27
+ # @return [Class]
28
+ def class_for(yard_object)
29
+ class_name = yard_object.class.to_s.split('::').last
30
+ eval("::Inch::CodeObject::Provider::YARD::Object::#{class_name}")
31
+ rescue
32
+ Base
33
+ end
34
+
35
+ # Returns a cache key for the given +yard_object+
36
+ #
37
+ # @param yard_object [YARD::CodeObject]
38
+ # @return [String]
39
+ def cache_key(yard_object)
40
+ yard_object.path
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ require_relative 'object/base'
50
+ require_relative 'object/namespace_object'
51
+ require_relative 'object/class_object'
52
+ require_relative 'object/constant_object'
53
+ require_relative 'object/method_object'
54
+ require_relative 'object/method_parameter_object'
55
+ require_relative 'object/module_object'
@@ -0,0 +1,262 @@
1
+ require 'forwardable'
2
+
3
+ module Inch
4
+ module CodeObject
5
+ module Provider
6
+ module YARD
7
+ module Object
8
+ # @abstract
9
+ class Base
10
+ extend Forwardable
11
+ include YARD::NodocHelper
12
+
13
+ # @return [YARD::CodeObjects::Base] the actual (YARD) code object
14
+ attr_reader :object
15
+
16
+ # @return [String] the codebase's directory
17
+ attr_accessor :base_dir
18
+
19
+ # Tags considered by wrapper methods like {#has_code_example?}
20
+ CONSIDERED_YARD_TAGS = %w(api example param private return)
21
+
22
+ # convenient shortcuts to (YARD) code object
23
+ def_delegators :object, :type, :namespace, :source, :source_type, :signature, :group, :dynamic, :visibility
24
+
25
+ # @param object [YARD::CodeObjects::Base] the actual (YARD) code object
26
+ def initialize(object)
27
+ @object = object
28
+ end
29
+
30
+ def api_tag?
31
+ !api_tag.nil?
32
+ end
33
+
34
+ def api_tag
35
+ tag(:api) || (parent && parent.api_tag)
36
+ end
37
+
38
+ # To be overridden
39
+ # @see Proxy::NamespaceObject
40
+ # @return [CodeObject::Proxy::Base,nil] the child inside the current object or +nil+
41
+ def child(name)
42
+ nil
43
+ end
44
+
45
+ # @return [Array,nil] the full names of the children of the current object
46
+ def children_fullnames
47
+ []
48
+ end
49
+
50
+ # To be overridden
51
+ # @see Proxy::NamespaceObject
52
+ def children
53
+ []
54
+ end
55
+
56
+ RUBY_CORE = %w(Array Bignum BasicObject Object Module Class Complex NilClass Numeric String Float Fiber FiberError Continuation Dir File Encoding Enumerator StopIteration Enumerator::Generator Enumerator::Yielder Exception SystemExit SignalException Interrupt StandardError TypeError ArgumentError IndexError KeyError RangeError ScriptError SyntaxError LoadError NotImplementedError NameError NoMethodError RuntimeError SecurityError NoMemoryError EncodingError SystemCallError Encoding::CompatibilityError File::Stat IO Hash ENV IOError EOFError ARGF RubyVM RubyVM::InstructionSequence Math::DomainError ZeroDivisionError FloatDomainError Integer Fixnum Data TrueClass FalseClass Mutex Thread Proc LocalJumpError SystemStackError Method UnboundMethod Binding Process::Status Random Range Rational RegexpError Regexp MatchData Symbol Struct ThreadGroup ThreadError Time Encoding::UndefinedConversionError Encoding::InvalidByteSequenceError Encoding::ConverterNotFoundError Encoding::Converter RubyVM::Env) +
57
+ %w(Comparable Kernel File::Constants Enumerable Errno FileTest GC ObjectSpace GC::Profiler IO::WaitReadable IO::WaitWritable Marshal Math Process Process::UID Process::GID Process::Sys Signal)
58
+ def core?
59
+ RUBY_CORE.include?(name.to_s)
60
+ end
61
+
62
+ # @return [Docstring]
63
+ def docstring
64
+ @docstring ||= Docstring.new(object.docstring)
65
+ end
66
+
67
+ # Returns all files declaring the object in the form of an Array of
68
+ # Arrays containing the filename and the line number of their
69
+ # declaration.
70
+ #
71
+ # @example
72
+ # files # => [["lib/inch.rb", 3],
73
+ # ["lib/inch/cli.rb", 1],
74
+ # ["lib/inch/version.rb", 1],
75
+ #
76
+ # @return [Array<Array(String, Fixnum)>]
77
+ def files
78
+ object.files.map do |(filename, line_no)|
79
+ CodeLocation.new(base_dir, filename, line_no)
80
+ end
81
+ rescue ::YARD::CodeObjects::ProxyMethodError
82
+ # this error is raised by YARD
83
+ # see broken.rb in test fixtures
84
+ []
85
+ end
86
+
87
+ # CodeLocation is a utility class to find declarations of objects in files
88
+ class CodeLocation < Struct.new(:base_dir, :relative_path, :line_no)
89
+ def filename
90
+ File.join(base_dir, relative_path)
91
+ end
92
+ end
93
+
94
+ # Returns the name of the file where the object is declared first
95
+ # @return [String] a filename
96
+ def filename
97
+ # just checking the first file (which is the file where an object
98
+ # is first declared)
99
+ files.first && files.first.filename
100
+ end
101
+
102
+ def fullname
103
+ object.path
104
+ end
105
+
106
+ def name
107
+ object.name
108
+ end
109
+
110
+ def has_alias?
111
+ false
112
+ end
113
+
114
+ def has_children?
115
+ !children.empty?
116
+ end
117
+
118
+ def has_code_example?
119
+ !tags(:example).empty? ||
120
+ docstring.contains_code_example?
121
+ end
122
+
123
+ def has_doc?
124
+ !docstring.empty?
125
+ end
126
+
127
+ def has_multiple_code_examples?
128
+ if tags(:example).size > 1 || docstring.code_examples.size > 1
129
+ true
130
+ else
131
+ if tag = tag(:example)
132
+ multi_code_examples?(tag.text)
133
+ elsif text = docstring.code_examples.first
134
+ multi_code_examples?(text)
135
+ else
136
+ false
137
+ end
138
+ end
139
+ end
140
+
141
+ def has_unconsidered_tags?
142
+ !unconsidered_tags.empty?
143
+ end
144
+
145
+ def in_in_root?
146
+ depth == 1
147
+ end
148
+
149
+ # The depth of the following is 4:
150
+ #
151
+ # Foo::Bar::Baz#initialize
152
+ # ^ ^ ^ ^
153
+ # 1 << 2 << 3 << 4
154
+ #
155
+ # +depth+ answers the question "how many layers of code objects are
156
+ # above this one?"
157
+ #
158
+ # @note top-level counts, that's why Foo has depth 1!
159
+ #
160
+ # @param i [Fixnum] a counter for recursive method calls
161
+ # @return [Fixnum] the depth of the object in terms of namespace
162
+ def depth(i = 0)
163
+ if parent
164
+ parent.depth(i+1)
165
+ else
166
+ i
167
+ end
168
+ end
169
+
170
+ # @return [Boolean] +true+ if the object represents a method
171
+ def method?
172
+ false
173
+ end
174
+
175
+ # @return [Boolean] +true+ if the object represents a namespace
176
+ def namespace?
177
+ false
178
+ end
179
+
180
+ def parameters
181
+ []
182
+ end
183
+
184
+ # @return [Array,nil] the parent of the current object or +nil+
185
+ def parent
186
+ YARD::Object.for(object.parent) if object.parent
187
+ end
188
+
189
+ def private?
190
+ visibility == :private
191
+ end
192
+
193
+ # @return [Boolean]
194
+ # +true+ if the object or its parent is tagged as @private
195
+ def private_tag?
196
+ !private_tag.nil?
197
+ end
198
+
199
+ def private_tag
200
+ tag(:private) || (parent && parent.private_tag)
201
+ end
202
+
203
+ def private_api_tag?
204
+ api_tag && api_tag.text == 'private'
205
+ end
206
+
207
+ def protected?
208
+ visibility == :protected
209
+ end
210
+
211
+ def public?
212
+ visibility == :public
213
+ end
214
+
215
+ def in_root?
216
+ depth == 1
217
+ end
218
+
219
+ # @return [Boolean] +true+ if the object has no documentation at all
220
+ def undocumented?
221
+ docstring.empty? && tags.empty?
222
+ end
223
+
224
+ def unconsidered_tag_count
225
+ unconsidered_tags.size
226
+ end
227
+
228
+ def inspect
229
+ "#<#{self.class.to_s}: #{path}>"
230
+ end
231
+
232
+ protected
233
+
234
+ def multi_code_examples?(text)
235
+ text.scan(/\b(#{Regexp.escape(name)})[^_0-9\!\?]/m).size > 1
236
+ end
237
+
238
+ def tag(name)
239
+ tags(name).first
240
+ end
241
+
242
+ def tags(name = nil)
243
+ object.tags(name)
244
+ rescue ::YARD::CodeObjects::ProxyMethodError
245
+ # this error is raised by YARD
246
+ # see broken.rb in test fixtures
247
+ []
248
+ end
249
+
250
+ # @return [Array]
251
+ # YARD tags that are not already covered by other wrapper methods
252
+ def unconsidered_tags
253
+ @unconsidered_tags ||= tags.reject do |tag|
254
+ CONSIDERED_YARD_TAGS.include?(tag.tag_name)
255
+ end
256
+ end
257
+ end
258
+ end
259
+ end
260
+ end
261
+ end
262
+ end