solargraph 0.14.2 → 0.14.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,50 +5,65 @@ module Solargraph
5
5
  class Config
6
6
  # @return [String]
7
7
  attr_reader :workspace
8
- attr_reader :raw_data
9
-
10
- # @return [Array<String>]
11
- attr_reader :included
12
-
13
- # @return [Array<String>]
14
- attr_reader :excluded
15
8
 
16
- # @return [Array<String>]
17
- attr_reader :domains
9
+ # @return [Hash]
10
+ attr_reader :raw_data
18
11
 
19
12
  def initialize workspace = nil
20
13
  @workspace = workspace
21
14
  include_globs = ['**/*.rb']
22
15
  exclude_globs = ['spec/**/*', 'test/**/*']
23
- @included = []
24
- @excluded = []
25
- @domains = []
26
16
  unless @workspace.nil?
27
- include_globs = ['**/*.rb']
28
- exclude_globs = ['spec/**/*', 'test/**/*']
29
17
  sfile = File.join(@workspace, '.solargraph.yml')
30
18
  if File.file?(sfile)
31
- @raw_data = YAML.load(File.read(sfile))
32
- conf = YAML.load(File.read(sfile))
33
- include_globs = conf['include'] || include_globs
34
- exclude_globs = conf['exclude'] || []
35
- @domains = conf['domains'] || []
19
+ begin
20
+ @raw_data = YAML.load(File.read(sfile))
21
+ conf = YAML.load(File.read(sfile))
22
+ include_globs = conf['include'] || include_globs
23
+ exclude_globs = conf['exclude'] || []
24
+ rescue Exception => e
25
+ STDERR.puts "Unable to read .solargraph.yml: #{e.class} #{e.message}"
26
+ @raw_data = {}
27
+ end
36
28
  end
37
- @included.concat process_globs(include_globs)
38
- @excluded.concat process_globs(exclude_globs)
39
29
  end
40
30
  @raw_data ||= {}
41
- @raw_data['include'] = @raw_data['include'] || include_globs
42
- @raw_data['exclude'] = @raw_data['exclude'] || exclude_globs
43
- # @todo If the domains config goes stable, add it to @raw_data
31
+ @raw_data['include'] ||= include_globs
32
+ @raw_data['exclude'] ||= exclude_globs
33
+ @raw_data['domains'] ||= []
34
+ @raw_data['required'] ||= []
44
35
  end
45
36
 
37
+ # An array of files included in the workspace (before calculating excluded files).
38
+ #
39
+ # @return [Array<String>]
46
40
  def included
47
- process_globs @raw_data['include']
41
+ return [] if workspace.nil?
42
+ @included ||= process_globs(@raw_data['include'])
48
43
  end
49
44
 
45
+ # An array of files excluded from the workspace.
46
+ #
47
+ # @return [Array<String>]
50
48
  def excluded
51
- process_globs @raw_data['exclude']
49
+ return [] if workspace.nil?
50
+ @excluded ||= process_globs(@raw_data['exclude'])
51
+ end
52
+
53
+ # The calculated array of (included - excluded) files in the workspace.
54
+ #
55
+ # @return [Array<String>]
56
+ def calculated
57
+ @calculated ||= (included - excluded)
58
+ end
59
+
60
+ # @return [Array<String>]
61
+ def domains
62
+ raw_data['domains']
63
+ end
64
+
65
+ def required
66
+ raw_data['required']
52
67
  end
53
68
 
54
69
  private
@@ -70,46 +70,63 @@ module Solargraph
70
70
  @superclasses ||= {}
71
71
  end
72
72
 
73
+ # @return [Array<Solargraph::Pin::Method>]
73
74
  def method_pins
74
75
  @method_pins ||= []
75
76
  end
76
77
 
78
+ # @return [Array<Solargraph::Pin::Attribute>]
77
79
  def attribute_pins
78
80
  @attribute_pins ||= []
79
81
  end
80
82
 
83
+ # @return [Array<Solargraph::Pin::InstanceVariable>]
81
84
  def instance_variable_pins
82
85
  @instance_variable_pins ||= []
83
86
  end
84
87
 
88
+ # @return [Array<Solargraph::Pin::ClassVariable>]
85
89
  def class_variable_pins
86
90
  @class_variable_pins ||= []
87
91
  end
88
92
 
93
+ # @return [Array<Solargraph::Pin::LocalVariable>]
89
94
  def local_variable_pins
90
95
  @local_variable_pins ||= []
91
96
  end
92
97
 
98
+ # @return [Array<Solargraph::Pin::GlobalVariable>]
93
99
  def global_variable_pins
94
100
  @global_variable_pins ||= []
95
101
  end
96
102
 
103
+ # @return [Array<Solargraph::Pin::Constant>]
97
104
  def constant_pins
98
105
  @constant_pins ||= []
99
106
  end
100
107
 
108
+ # @return [Array<Solargraph::Pin::Symbol>]
101
109
  def symbol_pins
102
110
  @symbol_pins ||= []
103
111
  end
104
112
 
113
+ # @return [Array<Solargraph::Pin::Namespace>]
114
+ def namespace_pins
115
+ @namespace_pins ||= []
116
+ end
117
+
118
+ # @return [Array<String>]
105
119
  def required
106
120
  @required ||= []
107
121
  end
108
122
 
123
+ # @return [YARD::Docstring]
109
124
  def docstring_for node
110
- @docstring_hash[node.loc]
125
+ return @docstring_hash[node.loc] if node.respond_to?(:loc)
126
+ nil
111
127
  end
112
128
 
129
+ # @return [String]
113
130
  def code_for node
114
131
  b = node.location.expression.begin.begin_pos
115
132
  e = node.location.expression.end.end_pos
@@ -121,6 +138,7 @@ module Solargraph
121
138
  @node_tree[node] || []
122
139
  end
123
140
 
141
+ # @return [String]
124
142
  def namespace_for node
125
143
  parts = []
126
144
  ([node] + (@node_tree[node] || [])).each do |n|
@@ -188,6 +206,7 @@ module Solargraph
188
206
  fqn = tree.join('::')
189
207
  @namespace_nodes[fqn] ||= []
190
208
  @namespace_nodes[fqn].push node
209
+ namespace_pins.push Solargraph::Pin::Namespace.new(self, node, tree[0..-2].join('::') || '')
191
210
  if node.type == :class and !node.children[1].nil?
192
211
  sc = unpack_name(node.children[1])
193
212
  superclasses[fqn] = sc
@@ -205,6 +224,7 @@ module Solargraph
205
224
  unless ora.nil?
206
225
  u = c.updated(:ivasgn, c.children + ora.children[1..-1], nil)
207
226
  @node_tree[u] = @node_stack.clone
227
+ @docstring_hash[u.loc] = docstring_for(ora)
208
228
  instance_variable_pins.push Solargraph::Pin::InstanceVariable.new(self, u, fqn || '', local_scope)
209
229
  end
210
230
  else
@@ -216,6 +236,7 @@ module Solargraph
216
236
  unless ora.nil?
217
237
  u = c.updated(:cvasgn, c.children + ora.children[1..-1], nil)
218
238
  @node_tree[u] = @node_stack.clone
239
+ @docstring_hash[u.loc] = docstring_for(ora)
219
240
  class_variable_pins.push Solargraph::Pin::ClassVariable.new(self, u, fqn || '')
220
241
  end
221
242
  else
@@ -241,38 +262,34 @@ module Solargraph
241
262
  elsif c.type == :casgn
242
263
  constant_pins.push Solargraph::Pin::Constant.new(self, c, fqn)
243
264
  else
244
- #unless fqn.nil?
245
- if c.kind_of?(AST::Node)
246
- if c.type == :def and c.children[0].to_s[0].match(/[a-z]/i)
247
- method_pins.push Solargraph::Pin::Method.new(source, c, fqn || '', scope, visibility)
248
- #inner_map_node c, tree, visibility, scope, fqn, stack
249
- #next
250
- elsif c.type == :defs
251
- method_pins.push Solargraph::Pin::Method.new(source, c, fqn || '', :class, :public)
252
- inner_map_node c, tree, :public, :class, fqn, stack
253
- next
254
- elsif c.type == :send and [:public, :protected, :private].include?(c.children[1])
255
- visibility = c.children[1]
256
- elsif c.type == :send and c.children[1] == :include #and node.type == :class
257
- namespace_includes[fqn] ||= []
258
- c.children[2..-1].each do |i|
259
- namespace_includes[fqn].push unpack_name(i)
265
+ if c.kind_of?(AST::Node)
266
+ if c.type == :def and c.children[0].to_s[0].match(/[a-z]/i)
267
+ method_pins.push Solargraph::Pin::Method.new(source, c, fqn || '', scope, visibility)
268
+ elsif c.type == :defs
269
+ method_pins.push Solargraph::Pin::Method.new(source, c, fqn || '', :class, :public)
270
+ inner_map_node c, tree, :public, :class, fqn, stack
271
+ next
272
+ elsif c.type == :send and [:public, :protected, :private].include?(c.children[1])
273
+ visibility = c.children[1]
274
+ elsif c.type == :send and c.children[1] == :include #and node.type == :class
275
+ namespace_includes[fqn] ||= []
276
+ c.children[2..-1].each do |i|
277
+ namespace_includes[fqn].push unpack_name(i)
278
+ end
279
+ elsif c.type == :send and [:attr_reader, :attr_writer, :attr_accessor].include?(c.children[1])
280
+ c.children[2..-1].each do |a|
281
+ if c.children[1] == :attr_reader or c.children[1] == :attr_accessor
282
+ attribute_pins.push Solargraph::Pin::Attribute.new(self, a, fqn || '', :reader, docstring_for(c)) #AttrPin.new(c)
260
283
  end
261
- elsif c.type == :send and [:attr_reader, :attr_writer, :attr_accessor].include?(c.children[1])
262
- c.children[2..-1].each do |a|
263
- if c.children[1] == :attr_reader or c.children[1] == :attr_accessor
264
- attribute_pins.push Solargraph::Pin::Attribute.new(self, a, fqn || '', :reader, docstring_for(c)) #AttrPin.new(c)
265
- end
266
- if c.children[1] == :attr_writer or c.children[1] == :attr_accessor
267
- attribute_pins.push Solargraph::Pin::Attribute.new(self, a, fqn || '', :writer, docstring_for(c)) #AttrPin.new(c)
268
- end
284
+ if c.children[1] == :attr_writer or c.children[1] == :attr_accessor
285
+ attribute_pins.push Solargraph::Pin::Attribute.new(self, a, fqn || '', :writer, docstring_for(c)) #AttrPin.new(c)
269
286
  end
270
- elsif c.type == :sclass and c.children[0].type == :self
271
- inner_map_node c, tree, :public, :class, fqn || '', stack
272
- next
273
287
  end
288
+ elsif c.type == :sclass and c.children[0].type == :self
289
+ inner_map_node c, tree, :public, :class, fqn || '', stack
290
+ next
274
291
  end
275
- #end
292
+ end
276
293
  if c.type == :send and c.children[1] == :require
277
294
  if c.children[2].kind_of?(AST::Node) and c.children[2].type == :str
278
295
  required.push c.children[2].children[0].to_s
@@ -316,8 +333,8 @@ module Solargraph
316
333
  fixed_cursor = false
317
334
  begin
318
335
  # HACK: The current file is parsed with a trailing underscore to fix
319
- # incomplete trees resulting from short scripts (e.g., a lone variable
320
- # assignment).
336
+ # incomplete trees resulting from short scripts (e.g., an unfinished
337
+ # variable assignment).
321
338
  node, comments = Parser::CurrentRuby.parse_with_comments(tmp + "\n_")
322
339
  Source.new(code, node, comments, filename)
323
340
  rescue Parser::SyntaxError => e
@@ -25,6 +25,7 @@ module Solargraph
25
25
 
26
26
  # The root directory of the project. The ApiMap will search here for
27
27
  # additional files to parse and analyze.
28
+ # @deprecated CodeMap will be server-agnostic in a future version.
28
29
  #
29
30
  # @return [String]
30
31
  attr_reader :workspace
@@ -32,6 +33,7 @@ module Solargraph
32
33
  include NodeMethods
33
34
 
34
35
  def initialize code: '', filename: nil, workspace: nil, api_map: nil, cursor: nil
36
+ STDERR.puts "WARNING: the `workspace` parameter in Solargraph::CodeMap#new is deprecated and will be removed in a future version." unless workspace.nil?
35
37
  @workspace = workspace
36
38
  # HACK: Adjust incoming filename's path separator for yardoc file comparisons
37
39
  filename = filename.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless filename.nil? or File::ALT_SEPARATOR.nil?
@@ -225,7 +227,7 @@ module Solargraph
225
227
  if signature.include?('::')
226
228
  parts = signature.split('::', -1)
227
229
  ns = parts[0..-2].join('::')
228
- result = api_map.namespaces_in(ns, namespace)
230
+ result = api_map.get_constants(ns, namespace)
229
231
  else
230
232
  type = infer_literal_node_type(node_at(index - 2))
231
233
  if type.nil?
@@ -235,10 +237,10 @@ module Solargraph
235
237
  result += ApiMap.get_keywords
236
238
  while parts.length > 0
237
239
  ns = parts.join('::')
238
- result += api_map.namespaces_in(ns, namespace)
240
+ result += api_map.get_constants(ns, namespace)
239
241
  parts.pop
240
242
  end
241
- result += api_map.namespaces_in('')
243
+ result += api_map.get_constants('')
242
244
  result += api_map.get_instance_methods('Kernel')
243
245
  result += api_map.get_methods('')
244
246
  result += api_map.get_instance_methods('')
@@ -434,8 +436,9 @@ module Solargraph
434
436
  return type unless type.nil?
435
437
  else
436
438
  # Signature starts with a local variable
437
- type = get_type_comment(var)
438
- type = infer_literal_node_type(var.children[1]) if type.nil?
439
+ type = nil
440
+ lvp = source.local_variable_pins.select{|p| p.name == var.children[0].to_s and p.visible_from?(node) and (!p.nil_assignment? or p.return_type)}.first
441
+ type = lvp.return_type unless lvp.nil?
439
442
  if type.nil?
440
443
  vsig = resolve_node_signature(var.children[1])
441
444
  type = infer_signature_from_node vsig, node
@@ -458,16 +461,6 @@ module Solargraph
458
461
  inferred
459
462
  end
460
463
 
461
- def get_type_comment node
462
- obj = nil
463
- cmnt = @source.docstring_for(node)
464
- unless cmnt.nil?
465
- tag = cmnt.tag(:type)
466
- obj = tag.types[0] unless tag.nil? or tag.types.empty?
467
- end
468
- obj
469
- end
470
-
471
464
  # Get the signature at the specified index.
472
465
  # A signature is a method call that can start with a constant, method, or
473
466
  # variable and does not include any method arguments. Examples:
@@ -513,7 +506,6 @@ module Solargraph
513
506
  def get_local_variables_and_methods_at(index)
514
507
  result = []
515
508
  local = parent_node_from(index, :class, :module, :def, :defs) || @node
516
- #result += get_local_variables_from(local)
517
509
  result += get_local_variables_from(node_at(index))
518
510
  scope = namespace_at(index) || @node
519
511
  if local.type == :def
@@ -580,7 +572,7 @@ module Solargraph
580
572
  def get_method_arguments_from node
581
573
  return [] unless node.type == :def or node.type == :defs
582
574
  param_hash = {}
583
- cmnt = api_map.get_comment_for(node)
575
+ cmnt = api_map.get_docstring_for(node)
584
576
  unless cmnt.nil?
585
577
  tags = cmnt.tags(:param)
586
578
  tags.each do |tag|
@@ -649,9 +641,20 @@ module Solargraph
649
641
  node ||= @node
650
642
  namespace = namespace_from(node)
651
643
  arr = []
644
+ nil_pins = []
645
+ val_names = []
652
646
  @source.local_variable_pins.select{|p| p.visible_from?(node) }.each do |pin|
653
- #arr.push Suggestion.new(pin.name, kind: Suggestion::VARIABLE, return_type: api_map.infer_assignment_node_type(pin.node, namespace))
654
- arr.push Suggestion.new(pin.name, kind: Suggestion::VARIABLE, location: pin.location)
647
+ if pin.nil_assignment? and pin.return_type.nil?
648
+ nil_pins.push pin
649
+ else
650
+ unless val_names.include?(pin.name)
651
+ arr.push Suggestion.pull(pin)
652
+ val_names.push pin.name
653
+ end
654
+ end
655
+ end
656
+ nil_pins.reject{|p| val_names.include?(p.name)}.each do |pin|
657
+ arr.push Suggestion.pull(pin)
655
658
  end
656
659
  arr
657
660
  end
@@ -44,13 +44,14 @@ module Solargraph
44
44
  end
45
45
  suggestions = []
46
46
  result.uniq.each do |r|
47
+ path = (r['namespace'].empty? ? '' : "#{r['namespace']}::") + r['name']
47
48
  kind = Suggestion::CONSTANT
48
49
  if r['class'] == 'Class'
49
50
  kind = Suggestion::CLASS
50
51
  elsif r['class'] == 'Module'
51
52
  kind = Suggestion::MODULE
52
53
  end
53
- suggestions.push(Suggestion.new(r['name'], kind: kind))
54
+ suggestions.push(Suggestion.new(r['name'], kind: kind, path: path))
54
55
  end
55
56
  cache.set_constants(namespace, root, suggestions)
56
57
  suggestions
@@ -1,15 +1,16 @@
1
1
  module Solargraph
2
2
  module Pin
3
- autoload :Base, 'solargraph/pin/base'
4
- autoload :Method, 'solargraph/pin/method'
5
- autoload :Attribute, 'solargraph/pin/attribute'
6
- autoload :BaseVariable, 'solargraph/pin/base_variable'
3
+ autoload :Base, 'solargraph/pin/base'
4
+ autoload :Method, 'solargraph/pin/method'
5
+ autoload :Attribute, 'solargraph/pin/attribute'
6
+ autoload :BaseVariable, 'solargraph/pin/base_variable'
7
7
  autoload :InstanceVariable, 'solargraph/pin/instance_variable'
8
- autoload :ClassVariable, 'solargraph/pin/class_variable'
9
- autoload :LocalVariable, 'solargraph/pin/local_variable'
10
- autoload :GlobalVariable, 'solargraph/pin/global_variable'
11
- autoload :Constant, 'solargraph/pin/constant'
12
- autoload :Symbol, 'solargraph/pin/symbol'
13
- autoload :Directed, 'solargraph/pin/directed'
8
+ autoload :ClassVariable, 'solargraph/pin/class_variable'
9
+ autoload :LocalVariable, 'solargraph/pin/local_variable'
10
+ autoload :GlobalVariable, 'solargraph/pin/global_variable'
11
+ autoload :Constant, 'solargraph/pin/constant'
12
+ autoload :Symbol, 'solargraph/pin/symbol'
13
+ autoload :Directed, 'solargraph/pin/directed'
14
+ autoload :Namespace, 'solargraph/pin/namespace'
14
15
  end
15
16
  end
@@ -19,6 +19,10 @@ module Solargraph
19
19
  @return_type ||= literal_from_assignment
20
20
  end
21
21
 
22
+ def nil_assignment?
23
+ node.children[(node.type == :casgn ? 2 : 1)].type == :nil
24
+ end
25
+
22
26
  def signature
23
27
  @signature ||= resolve_node_signature(node.children[(node.type == :casgn ? 2 : 1)])
24
28
  end
@@ -0,0 +1,23 @@
1
+ module Solargraph
2
+ module Pin
3
+ class Namespace < Pin::Base
4
+ include Solargraph::NodeMethods
5
+
6
+ def name
7
+ @name ||= pack_name(node.children[0]).last.to_s
8
+ end
9
+
10
+ def path
11
+ @path ||= (namespace.empty? ? '' : "#{namespace}::") + name
12
+ end
13
+
14
+ def kind
15
+ @kind ||= (node.type == :class ? Solargraph::Suggestion::CLASS : Solargraph::Suggestion::MODULE)
16
+ end
17
+
18
+ def return_type
19
+ @return_type ||= (node.type == :class ? 'Class' : 'Module') + "<#{path}>"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -32,6 +32,8 @@ module Solargraph
32
32
  end
33
33
  rescue JSON::ParserError => e
34
34
  STDOUT.puts respond_err "Error parsing input: #{e.message}"
35
+ rescue Exception => e
36
+ STDOUT.puts respond_err "Error processing input: #{e.message}"
35
37
  end
36
38
  STDOUT.flush
37
39
  end
@@ -63,15 +65,15 @@ module Solargraph
63
65
  unless con.nil?
64
66
  if (args['scope'] == 'class')
65
67
  if args['with_private']
66
- result.concat con.methods
68
+ result.concat con.methods(false)
67
69
  else
68
- result.concat con.public_methods
70
+ result.concat con.public_methods(false)
69
71
  end
70
72
  elsif (args['scope'] == 'instance')
71
73
  if args['with_private']
72
- result.concat con.instance_methods
74
+ result.concat con.instance_methods(false)
73
75
  else
74
- result.concat con.public_instance_methods
76
+ result.concat con.public_instance_methods(false)
75
77
  end
76
78
  end
77
79
  end
@@ -85,8 +87,8 @@ module Solargraph
85
87
  #result.concat con.constants
86
88
  con.constants.each do |c|
87
89
  next if c == :Solargraph and !@required.include?('solargraph')
88
- item = { name: c }
89
90
  here = con.const_get(c)
91
+ item = { namespace: con.to_s, name: c.to_s }
90
92
  item[:class] = here.class.to_s
91
93
  result.push item
92
94
  end