inch 0.2.3 → 0.3.0.rc1

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 (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
@@ -2,7 +2,6 @@ module Inch
2
2
  module CodeObject
3
3
  module Proxy
4
4
  class ClassObject < NamespaceObject
5
- def_delegators :object, :superclass
6
5
  end
7
6
  end
8
7
  end
@@ -3,31 +3,16 @@ module Inch
3
3
  module Proxy
4
4
  # Proxy class for methods
5
5
  class MethodObject < Base
6
-
7
6
  def constructor?
8
- name == :initialize
9
- end
10
-
11
- def comment_and_abbrev_source
12
- comments.join('') + abbrev_source
7
+ self[:constructor?]
13
8
  end
14
9
 
15
10
  def bang_name?
16
- name =~ /\!$/
11
+ self[:bang_name?]
17
12
  end
18
13
 
19
14
  def getter?
20
- attr_info = object.attr_info || {}
21
- read_info = attr_info[:read]
22
- if read_info
23
- read_info.path == path
24
- else
25
- parent.child(:"#{name}=")
26
- end
27
- end
28
-
29
- def has_doc?
30
- super && !implicit_docstring?
15
+ self[:getter?]
31
16
  end
32
17
 
33
18
  def has_parameters?
@@ -42,7 +27,7 @@ module Inch
42
27
  MANY_LINES_THRESHOLD = 20
43
28
  def has_many_lines?
44
29
  # for now, this includes the 'def' line and comments
45
- if source = object.source
30
+ if source
46
31
  size = source.lines.count
47
32
  size > MANY_LINES_THRESHOLD
48
33
  else
@@ -50,110 +35,46 @@ module Inch
50
35
  end
51
36
  end
52
37
 
53
- def method?
54
- true
38
+ def parameter(name)
39
+ parameters.detect { |p| p.name == name.to_s }
55
40
  end
56
41
 
57
42
  def parameters
58
- @parameters ||= all_parameter_names.map do |name|
59
- in_signature = signature_parameter_names.include?(name)
60
- tag = parameter_tag(name)
61
- MethodParameterObject.new(self, name, tag, in_signature)
43
+ @parameters ||= self[:parameters].map do |param_attr|
44
+ MethodParameterObject.new(param_attr)
62
45
  end
63
46
  end
64
47
 
65
- def parameter(name)
66
- parameters.detect { |p| p.name == name.to_s }
67
- end
68
-
69
48
  def overridden?
70
- !!object.overridden_method
49
+ self[:overridden?]
71
50
  end
72
51
 
73
52
  def overridden_method
74
- @overridden_method ||= Proxy.for(object.overridden_method)
53
+ @overridden_method ||= object_lookup.find(self[:overridden_method_fullname])
75
54
  end
76
55
 
77
56
  def return_mentioned?
78
- !!return_tag || docstring.mentions_return?
57
+ self[:return_mentioned?]
79
58
  end
80
59
 
81
60
  def return_described?
82
- (return_tag && !return_tag.text.empty?) || docstring.describes_return?
83
- end
84
-
85
- def setter?
86
- name =~ /\=$/ && parameters.size == 1
87
- end
88
-
89
- def questioning_name?
90
- name =~ /\?$/
91
- end
92
-
93
- private
94
-
95
- def all_parameter_names
96
- names = signature_parameter_names
97
- names.concat parameter_tags.map(&:name)
98
- names.compact.uniq
99
- end
100
-
101
- def abbrev_source
102
- lines = object.source.to_s.lines.to_a
103
- if lines.size >= 5
104
- indent = lines[1].scan(/^(\s+)/).flatten.join('')
105
- lines = lines[0..1] +
106
- ["#{indent}# ... snip ...\n"] +
107
- lines[-2..-1]
108
- end
109
- lines.join('')
61
+ self[:return_described?]
110
62
  end
111
63
 
112
- def comments
113
- @comments ||= files.map do |(filename, line_no)|
114
- get_lines_up_while(filename, line_no - 1) do |line|
115
- line =~ /^\s*#/
116
- end.flatten.join('')
117
- end
64
+ def return_typed?
65
+ self[:return_typed?]
118
66
  end
119
67
 
120
- def get_lines_up_while(filename, line_no, &block)
121
- lines = []
122
- line = get_line_no(filename, line_no)
123
- if yield(line) && line_no > 0
124
- lines << line.gsub(/^(\s+)/, '')
125
- lines << get_lines_up_while(filename, line_no - 1, &block)
126
- end
127
- lines.reverse
128
- end
129
-
130
- def implicit_docstring?
131
- if getter?
132
- docstring == "Returns the value of attribute #{name}"
133
- elsif setter?
134
- basename = name.to_s.gsub(/(\=)$/, '')
135
- docstring == "Sets the attribute #{basename}"
136
- else
137
- false
138
- end
139
- end
140
-
141
- def signature_parameter_names
142
- object.parameters.map(&:first)
143
- end
144
-
145
- def parameter_tag(param_name)
146
- parameter_tags.detect do |tag|
147
- tag.name == param_name
148
- end
68
+ def setter?
69
+ self[:setter?]
149
70
  end
150
71
 
151
- def parameter_tags
152
- object.tags(:param)
72
+ def source
73
+ self[:source?]
153
74
  end
154
75
 
155
- def return_tag
156
- object.tags(:return).first
76
+ def questioning_name?
77
+ self[:questioning_name?]
157
78
  end
158
79
  end
159
80
  end
@@ -3,17 +3,12 @@ module Inch
3
3
  module Proxy
4
4
  # Proxy class for method parameters
5
5
  class MethodParameterObject
6
- attr_reader :name # @return [String]
6
+ def initialize(attributes)
7
+ @attributes = attributes
8
+ end
7
9
 
8
- # @param method [Inch::CodeObject::Proxy::MethodObject] the method the parameter belongs_to
9
- # @param name [String] the name of the parameter
10
- # @param tag [YARD::Tags::Tag] the Tag object for the parameter
11
- # @param in_signature [Boolean] +true+ if the method's signature contains the parameter
12
- def initialize(method, name, tag, in_signature)
13
- @method = method
14
- @name = name
15
- @tag = tag
16
- @in_signature = in_signature
10
+ def [](key)
11
+ @attributes[key]
17
12
  end
18
13
 
19
14
  BAD_NAME_EXCEPTIONS = %w(id)
@@ -27,57 +22,38 @@ module Inch
27
22
 
28
23
  # @return [Boolean] +true+ if the parameter is a block
29
24
  def block?
30
- name =~ /^\&/
25
+ self[:block?]
31
26
  end
32
27
 
33
28
  # @return [Boolean] +true+ if an additional description given?
34
29
  def described?
35
- described_by_tag? || described_by_docstring?
30
+ self[:described?]
36
31
  end
37
32
 
38
33
  # @return [Boolean] +true+ if the parameter is mentioned in the docs
39
34
  def mentioned?
40
- !!@tag || mentioned_by_docstring?
35
+ self[:mentioned?]
36
+ end
37
+
38
+ def name
39
+ self[:name]
41
40
  end
42
41
 
43
42
  # @return [Boolean] +true+ if the parameter is a splat argument
44
43
  def splat?
45
- name =~ /^\*/
44
+ self[:splat?]
46
45
  end
47
46
 
48
47
  # @return [Boolean] +true+ if the type of the parameter is defined
49
48
  def typed?
50
- @tag && @tag.types && !@tag.types.empty?
49
+ self[:typed?]
51
50
  end
52
51
 
53
52
  # @return [Boolean] +true+ if the parameter is mentioned in the docs, but not present in the method's signature
54
53
  def wrongly_mentioned?
55
- mentioned? && !@in_signature
54
+ self[:wrongly_mentioned?]
56
55
  end
57
56
 
58
- private
59
-
60
- def described_by_tag?
61
- @tag && !@tag.text.empty?
62
- end
63
-
64
- def described_by_docstring?
65
- if @method.docstring.describes_parameter?(name)
66
- true
67
- else
68
- unsplatted = name.gsub(/^[\&\*]/, '')
69
- @method.docstring.describes_parameter?(unsplatted)
70
- end
71
- end
72
-
73
- def mentioned_by_docstring?
74
- if @method.docstring.mentions_parameter?(name)
75
- true
76
- else
77
- unsplatted = name.gsub(/^[\&\*]/, '')
78
- @method.docstring.mentions_parameter?(unsplatted)
79
- end
80
- end
81
57
  end
82
58
  end
83
59
  end
@@ -4,22 +4,15 @@ module Inch
4
4
  # a namespace object can have methods and other namespace objects
5
5
  # inside itself (e.g. classes and modules)
6
6
  class NamespaceObject < Base
7
- def child(name)
8
- if children
9
- children.detect { |child| child.name == name }
10
- end
11
- end
12
-
13
- def children
14
- object.children.map do |o|
15
- Proxy.for(o)
16
- end
7
+ # The wording is a bit redundant, but this means the class and
8
+ # instance attributes of the namespace
9
+ def attributes
10
+ self[:attributes]
17
11
  end
18
12
 
19
13
  MANY_ATTRIBUTES_THRESHOLD = 5
20
14
  def has_many_attributes?
21
- n = object.class_attributes.size + object.instance_attributes.size
22
- n > MANY_ATTRIBUTES_THRESHOLD
15
+ attributes.size > MANY_ATTRIBUTES_THRESHOLD
23
16
  end
24
17
 
25
18
  MANY_CHILDREN_THRESHOLD = 20
@@ -27,12 +20,8 @@ module Inch
27
20
  children.size > MANY_CHILDREN_THRESHOLD
28
21
  end
29
22
 
30
- def namespace?
31
- true
32
- end
33
-
34
- def no_methods?
35
- !children.any?(&:method?)
23
+ def has_methods?
24
+ children.any?(&:method?)
36
25
  end
37
26
 
38
27
  def pure_namespace?
@@ -0,0 +1,19 @@
1
+ module Inch
2
+ # Codebases are one of the building blocks of Inch's analysis (the other
3
+ # being "code objects" inside these "codebases").
4
+ module Codebase
5
+ # Parses a codebase
6
+ #
7
+ # @param dir [String]
8
+ # @param paths [Array<String>]
9
+ # @param excluded [Array<String>]
10
+ # @return [Codebase::Proxy]
11
+ def self.parse(dir, paths = nil, excluded = nil)
12
+ Proxy.new(dir, paths, excluded)
13
+ end
14
+ end
15
+ end
16
+
17
+ require_relative 'codebase/proxy'
18
+ require_relative 'codebase/objects'
19
+ require_relative 'codebase/objects_filter'
@@ -0,0 +1,73 @@
1
+ module Inch
2
+ module Codebase
3
+ class Objects
4
+ include Enumerable
5
+ extend Forwardable
6
+
7
+ def_delegators :@list, :each, :empty?, :size
8
+
9
+ # @param objects [Array<CodeObject::Proxy::Base>]
10
+ # @return [Array<CodeObject::Proxy::Base>]
11
+ def self.sort_by_priority(objects)
12
+ objects.sort_by do |o|
13
+ [o.priority, o.score, o.fullname.size]
14
+ end.reverse
15
+ end
16
+
17
+ def initialize(objects)
18
+ list = objects.map do |o|
19
+ proxy = CodeObject::Proxy.for(o)
20
+ proxy.object_lookup = self
21
+ proxy
22
+ end
23
+ @list = list
24
+ # the @list has to be set for the priority sorting
25
+ # since the priority needs the object_lookup, which
26
+ # in turn depends on @list - it's a crazy world
27
+ @list = self.class.sort_by_priority(@list)
28
+ end
29
+
30
+ # Returns all parsed objects as code object proxies
31
+ #
32
+ # @see CodeObject::Proxy.for
33
+ # @return [Array<CodeObject::Proxy::Base>]
34
+ def all
35
+ @list
36
+ end
37
+
38
+ # Returns the object with the given +fullname+
39
+ #
40
+ # @example
41
+ #
42
+ # find("Foo#bar")
43
+ # # => returns the code object proxy for Foo#bar
44
+ #
45
+ # @param fullname [String] partial fullname/name of an object
46
+ # @return [CodeObject::Proxy::Base]
47
+ def find(fullname)
48
+ all.detect { |o| o.fullname == fullname }
49
+ end
50
+
51
+ # Returns all objects where the +fullname+ starts_with the given
52
+ # +partial_name+
53
+ #
54
+ # @example
55
+ #
56
+ # find("Foo#")
57
+ # # => returns the code object proxies for all instance methods of Foo
58
+ #
59
+ # @param partial_name [String] partial name of an object
60
+ # @return [Array<CodeObject::Proxy::Base>]
61
+ def starting_with(partial_name)
62
+ all.select { |o| o.fullname.start_with?(partial_name) }
63
+ end
64
+
65
+ # Filters the list based on the settings in +options+
66
+ #
67
+ # @return [void]
68
+ def filter!(options)
69
+ @list = ObjectsFilter.new(all, options).objects
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,61 @@
1
+ module Inch
2
+ module Codebase
3
+ # ObjectsFilter can be used to filter a list of objects by given a set of
4
+ # given +options+
5
+ class ObjectsFilter
6
+ attr_reader :options
7
+
8
+ def initialize(list, options)
9
+ @list = list
10
+ @options = options
11
+ filter
12
+ end
13
+
14
+ def objects
15
+ @list
16
+ end
17
+
18
+ private
19
+
20
+ def filter
21
+ filter_namespaces
22
+ filter_undocumented
23
+ filter_depth
24
+ filter_visibility
25
+ end
26
+
27
+ def filter_namespaces
28
+ if options.namespaces == :only
29
+ @list = @list.select(&:namespace?)
30
+ elsif options.namespaces == :none
31
+ @list = @list.reject(&:namespace?)
32
+ end
33
+ end
34
+
35
+ def filter_undocumented
36
+ if options.undocumented == :only
37
+ @list = @list.select(&:undocumented?)
38
+ elsif options.undocumented == :none
39
+ @list = @list.reject(&:undocumented?)
40
+ end
41
+ end
42
+
43
+ def filter_depth
44
+ if options.depth
45
+ @list = @list.select { |o| o.depth <= options.depth }
46
+ end
47
+ end
48
+
49
+ def filter_visibility
50
+ @list = @list.select do |o|
51
+ options.visibility.include?(o.visibility)
52
+ end
53
+ if !options.visibility.include?(:private)
54
+ @list = @list.reject do |o|
55
+ o.private_tag?
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end