solargraph 0.14.2 → 0.14.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ca2ed2f74501e75cb81ff97f3db0a8553800887f
4
- data.tar.gz: 1c9299750fb4c356ef8239f59fa37c7742e4dcb6
3
+ metadata.gz: 9b19cc5d128d5ad59344c60240530466594888a3
4
+ data.tar.gz: db5e6a4c0f05e070c1b14d1c22d6ae32f1ac61e6
5
5
  SHA512:
6
- metadata.gz: b25e723d7e22460204e71c48552f54bbc586abd088d9244f93a60496cfab37e2fce9fe1810c9d3cfec321ea956cd9fbd97ab9c0a6d5bb207dae220c6f6a4f0f7
7
- data.tar.gz: 5384d1df973aa083e140b0e877d112d639ddcc5e38c18eddc7d9d1e4a17ecb9fea2773853d04967a085d09aeb8cbadf7805bf14065556b88e45c1a019852fdc8
6
+ metadata.gz: 12d90c3ac837e6a3669e91dbdcc3101edfac58010f1dde7471caf7f6808529c64fbfcb31cf28859e6f11d52b91040cbd4929124295016e999a03627f6e2295af
7
+ data.tar.gz: 3fe26bbd2699603487702b765734ae63df345d4afced95b1139e7bafdb2eef419fcd19e1778268b91b84193ea30da0b96ef609aabcb95a26abce46545f8e4e34
@@ -11,7 +11,6 @@ module Solargraph
11
11
  autoload :Snippets, 'solargraph/snippets'
12
12
  autoload :Server, 'solargraph/server'
13
13
  autoload :YardMap, 'solargraph/yard_map'
14
- autoload :YardMethods, 'solargraph/yard_methods'
15
14
  autoload :Pin, 'solargraph/pin'
16
15
  autoload :LiveMap, 'solargraph/live_map'
17
16
  autoload :ServerMethods, 'solargraph/server_methods'
@@ -23,7 +23,6 @@ module Solargraph
23
23
  ].freeze
24
24
 
25
25
  include NodeMethods
26
- include YardMethods
27
26
 
28
27
  # The root directory of the project. The ApiMap will search here for
29
28
  # additional files to parse and analyze.
@@ -35,20 +34,14 @@ module Solargraph
35
34
  def initialize workspace = nil
36
35
  @workspace = workspace.gsub(/\\/, '/') unless workspace.nil?
37
36
  clear
38
- # @todo Instead of requiring extensions to be listed in the config,
39
- # we're experimenting with automatically loading them.
40
- #self.config.extensions.each do |ext|
41
- # require ext
42
- #end
43
37
  require_extensions
44
- @workspace_files = []
45
38
  unless @workspace.nil?
46
- @workspace_files.concat (self.config.included - self.config.excluded)
47
- @workspace_files.each do |wf|
39
+ workspace_files.concat (self.config.included - self.config.excluded)
40
+ workspace_files.each do |wf|
48
41
  begin
49
42
  @@source_cache[wf] ||= Source.load(wf)
50
- rescue
51
- STDERR.puts "Failed to load #{wf}"
43
+ rescue Exception => e
44
+ STDERR.puts "Failed to load #{wf}: #{e.message}"
52
45
  end
53
46
  end
54
47
  end
@@ -60,10 +53,21 @@ module Solargraph
60
53
  yard_map
61
54
  end
62
55
 
63
- def config
64
- @config ||= ApiMap::Config.new(@workspace)
56
+ # @return [Solargraph::ApiMap::Config]
57
+ def config reload = false
58
+ @config = ApiMap::Config.new(@workspace) if @config.nil? or reload
59
+ @config
65
60
  end
66
61
 
62
+ # An array of all workspace files included in the map.
63
+ #
64
+ # @return[Array<String>]
65
+ def workspace_files
66
+ @workspace_files ||= []
67
+ end
68
+
69
+ # An array of required paths in the workspace.
70
+ #
67
71
  # @return [Array<String>]
68
72
  def required
69
73
  @required ||= []
@@ -83,16 +87,36 @@ module Solargraph
83
87
  @live_map ||= Solargraph::LiveMap.new(self)
84
88
  end
85
89
 
90
+ # @todo Get rid of the cursor parameter. Tracking stubbed lines is the
91
+ # better option.
92
+ #
93
+ # @param code [String]
94
+ # @param filename [String]
86
95
  # @return [Solargraph::ApiMap::Source]
87
96
  def virtualize code, filename = nil, cursor = nil
88
- unless @virtual_source.nil? or @virtual_filename == filename or @workspace_files.include?(@virtual_filename)
89
- eliminate @virtual_filename
97
+ workspace_files.delete_if do |f|
98
+ if File.exist?(f)
99
+ false
100
+ else
101
+ eliminate f
102
+ true
103
+ end
104
+ end
105
+ if filename.nil? or filename.end_with?('.rb')
106
+ eliminate @virtual_filename unless @virtual_source.nil? or @virtual_filename == filename or workspace_files.include?(@virtual_filename)
107
+ @virtual_filename = filename
108
+ @virtual_source = Source.fix(code, filename, cursor)
109
+ unless filename.nil? or workspace_files.include?(filename)
110
+ current_files = @workspace_files
111
+ @workspace_files = config(true).calculated
112
+ (current_files - @workspace_files).each { |f| eliminate f }
113
+ end
114
+ process_virtual
115
+ else
116
+ unless filename.nil?
117
+ # @todo Handle special files like .solargraph.yml
118
+ end
90
119
  end
91
- #refresh
92
- @virtual_filename = filename
93
- @virtual_source = Source.fix(code, filename, cursor)
94
- process_virtual
95
- #@stale = true
96
120
  @virtual_source
97
121
  end
98
122
 
@@ -109,12 +133,17 @@ module Solargraph
109
133
  #
110
134
  # @param node [AST::Node]
111
135
  # @return [YARD::Docstring]
112
- def get_comment_for node
136
+ def get_docstring_for node
113
137
  filename = get_filename_for(node)
114
138
  return nil if @sources[filename].nil?
115
139
  @sources[filename].docstring_for(node)
116
140
  end
117
141
 
142
+ # @deprecated Use get_docstring_for instead.
143
+ def get_comment_for node
144
+ get_docstring_for node
145
+ end
146
+
118
147
  # @return [Array<Solargraph::Suggestion>]
119
148
  def self.get_keywords
120
149
  @keyword_suggestions ||= KEYWORDS.map{ |s|
@@ -122,6 +151,7 @@ module Solargraph
122
151
  }.freeze
123
152
  end
124
153
 
154
+ # @return [Array<String>]
125
155
  def namespaces
126
156
  refresh
127
157
  namespace_map.keys
@@ -131,14 +161,9 @@ module Solargraph
131
161
  !find_fully_qualified_namespace(name, root).nil?
132
162
  end
133
163
 
164
+ # @deprecated Use get_constants instead.
134
165
  def namespaces_in name, root = ''
135
- refresh
136
- result = []
137
- result += inner_namespaces_in(name, root, [])
138
- result += yard_map.get_constants name, root
139
- strings = result.map(&:to_s)
140
- result.concat live_map.get_constants(name, root)
141
- result
166
+ get_constants name, root
142
167
  end
143
168
 
144
169
  # @return [Array<Solargraph::Pin::Constant>]
@@ -148,16 +173,32 @@ module Solargraph
148
173
  end
149
174
 
150
175
  # @return [Array<Solargraph::Suggestion>]
151
- def get_constants namespace, root
176
+ def get_constants namespace, root = ''
152
177
  result = []
178
+ skip = []
153
179
  fqns = find_fully_qualified_namespace(namespace, root)
154
- cp = @const_pins[fqns]
155
- unless cp.nil?
156
- cp.each do |pin|
157
- result.push pin_to_suggestion(pin)
180
+ if fqns.empty?
181
+ result.concat inner_get_constants('', skip, false)
182
+ else
183
+ parts = fqns.split('::')
184
+ resolved = find_namespace_pins(parts.join('::'))
185
+ resolved.each do |pin|
186
+ result.concat inner_get_constants(pin.path, skip, true)
158
187
  end
159
188
  end
160
189
  result.concat yard_map.get_constants(fqns)
190
+ result
191
+ end
192
+
193
+ def find_namespace_pins fqns
194
+ set = nil
195
+ if fqns.include?('::')
196
+ set = @namespace_pins[fqns.split('::')[0..-2].join('::')]
197
+ else
198
+ set = @namespace_pins['']
199
+ end
200
+ return [] if set.nil?
201
+ set.select{|p| p.path == fqns}
161
202
  end
162
203
 
163
204
  # @return [String]
@@ -218,9 +259,7 @@ module Solargraph
218
259
  result = []
219
260
  ip = @ivar_pins[namespace]
220
261
  unless ip.nil?
221
- ip.select{ |pin| pin.scope == scope }.each do |pin|
222
- result.push pin_to_suggestion(pin)
223
- end
262
+ result.concat suggest_unique_variables(ip.select{ |pin| pin.scope == scope })
224
263
  end
225
264
  result
226
265
  end
@@ -235,11 +274,9 @@ module Solargraph
235
274
  def get_class_variables(namespace)
236
275
  refresh
237
276
  result = []
238
- ip = @cvar_pins[namespace]
239
- unless ip.nil?
240
- ip.each do |pin|
241
- result.push pin_to_suggestion(pin)
242
- end
277
+ cp = @cvar_pins[namespace]
278
+ unless cp.nil?
279
+ result.concat suggest_unique_variables(cp)
243
280
  end
244
281
  result
245
282
  end
@@ -258,6 +295,14 @@ module Solargraph
258
295
  nil
259
296
  end
260
297
 
298
+ # @return [Solargraph::ApiMap::Source]
299
+ def get_source_for(node)
300
+ @sources.each do |filename, source|
301
+ return source if source.include?(node)
302
+ end
303
+ nil
304
+ end
305
+
261
306
  # @return [String]
262
307
  def infer_instance_variable(var, namespace, scope)
263
308
  refresh
@@ -281,20 +326,18 @@ module Solargraph
281
326
 
282
327
  # @return [Array<Solargraph::Suggestion>]
283
328
  def get_global_variables
284
- result = []
329
+ globals = []
285
330
  @sources.values.each do |s|
286
- s.global_variable_pins.each do |p|
287
- result.push pin_to_suggestion(p)
288
- end
331
+ globals.concat s.global_variable_pins
289
332
  end
290
- result
333
+ suggest_unique_variables globals
291
334
  end
292
335
 
293
336
  # @return [String]
294
337
  def infer_assignment_node_type node, namespace
295
338
  type = cache.get_assignment_node_type(node, namespace)
296
339
  if type.nil?
297
- cmnt = get_comment_for(node)
340
+ cmnt = get_docstring_for(node)
298
341
  if cmnt.nil?
299
342
  name_i = (node.type == :casgn ? 1 : 0)
300
343
  sig_i = (node.type == :casgn ? 2 : 1)
@@ -321,6 +364,7 @@ module Solargraph
321
364
 
322
365
  # @return [String]
323
366
  def infer_signature_type signature, namespace, scope: :class
367
+ namespace ||= ''
324
368
  if cache.has_signature_type?(signature, namespace, scope)
325
369
  return cache.get_signature_type(signature, namespace, scope)
326
370
  end
@@ -453,13 +497,14 @@ module Solargraph
453
497
  meths
454
498
  end
455
499
 
500
+ # @return [Array<String>]
456
501
  def get_include_strings_from *nodes
457
502
  arr = []
458
503
  nodes.each { |node|
459
504
  next unless node.kind_of?(AST::Node)
460
505
  arr.push unpack_name(node.children[2]) if (node.type == :send and node.children[1] == :include)
461
506
  node.children.each { |n|
462
- arr += get_include_strings_from(n) if n.kind_of?(AST::Node) and n.type != :class and n.type != :module
507
+ arr += get_include_strings_from(n) if n.kind_of?(AST::Node) and n.type != :class and n.type != :module and n.type != :sclass
463
508
  }
464
509
  }
465
510
  arr
@@ -467,16 +512,27 @@ module Solargraph
467
512
 
468
513
  def update filename
469
514
  filename.gsub!(/\\/, '/')
470
- eliminate filename
471
- @@source_cache[filename] = Source.load(filename)
472
- rebuild_local_yardoc #if @workspace_files.include?(filename)
473
- @stale = true
515
+ if filename.end_with?('.rb')
516
+ if @workspace_files.include?(filename)
517
+ eliminate filename
518
+ @@source_cache[filename] = Source.load(filename)
519
+ rebuild_local_yardoc #if @workspace_files.include?(filename)
520
+ @stale = true
521
+ else
522
+ @workspace_files = config(true).calculated
523
+ update filename if @workspace_files.include?(filename)
524
+ end
525
+ elsif File.basename(filename) == '.solargraph.yml'
526
+ # @todo Finish refreshing the map
527
+ @workspace_files = config(true).calculated
528
+ end
474
529
  end
475
530
 
476
531
  def sources
477
532
  @sources.values
478
533
  end
479
534
 
535
+ # @return [Array<String>]
480
536
  def get_path_suggestions path
481
537
  refresh
482
538
  result = []
@@ -490,9 +546,10 @@ module Solargraph
490
546
  result = get_methods(parts[0], '', visibility: [:public, :private, :protected]).select{|s| s.label == parts[1]}
491
547
  else
492
548
  # It's a class or module
493
- get_namespace_nodes(path).each do |node|
494
- # TODO This is way underimplemented
495
- result.push Suggestion.new(path, kind: Suggestion::CLASS)
549
+ parts = path.split('::')
550
+ np = @namespace_pins[parts[0..-2].join('::')]
551
+ unless np.nil?
552
+ result.concat np.select{|p| p.name == parts.last}.map{|p| pin_to_suggestion(p)}
496
553
  end
497
554
  result.concat yard_map.objects(path)
498
555
  end
@@ -506,17 +563,10 @@ module Solargraph
506
563
  @namespace_map ||= {}
507
564
  end
508
565
 
509
- # @return [Hash]
510
- def namespace_tree
511
- @namespace_tree ||= {}
512
- end
513
-
514
566
  def clear
515
567
  @stale = false
516
- @parent_stack = {}
517
568
  namespace_map.clear
518
- namespace_tree.clear
519
- required.clear
569
+ @required = config.required.clone
520
570
  end
521
571
 
522
572
  def process_maps
@@ -530,10 +580,9 @@ module Solargraph
530
580
  @attr_pins = {}
531
581
  @namespace_includes = {}
532
582
  @superclasses = {}
533
- @parent_stack = {}
583
+ @namespace_pins = {}
534
584
  namespace_map.clear
535
- namespace_tree.clear
536
- @required = []
585
+ @required = config.required.clone
537
586
  @pin_suggestions = {}
538
587
  unless @virtual_source.nil?
539
588
  @sources[@virtual_filename] = @virtual_source
@@ -542,7 +591,6 @@ module Solargraph
542
591
  s.namespace_nodes.each_pair do |k, v|
543
592
  namespace_map[k] ||= []
544
593
  namespace_map[k].concat v
545
- add_to_namespace_tree k.split('::')
546
594
  end
547
595
  end
548
596
  @sources.values.each { |s|
@@ -561,13 +609,13 @@ module Solargraph
561
609
 
562
610
  def process_workspace_files
563
611
  @sources.clear
564
- @workspace_files.each do |f|
612
+ workspace_files.each do |f|
565
613
  if File.file?(f)
566
614
  begin
567
615
  @@source_cache[f] ||= Source.load(f)
568
616
  @sources[f] = @@source_cache[f]
569
- rescue
570
- STDERR.puts "Failed to load #{f}"
617
+ rescue Exception => e
618
+ STDERR.puts "Failed to load #{f}: #{e.message}"
571
619
  end
572
620
  end
573
621
  end
@@ -577,13 +625,11 @@ module Solargraph
577
625
  unless @virtual_source.nil?
578
626
  cache.clear
579
627
  namespace_map.clear
580
- namespace_tree.clear
581
628
  @sources[@virtual_filename] = @virtual_source
582
629
  @sources.values.each do |s|
583
630
  s.namespace_nodes.each_pair do |k, v|
584
631
  namespace_map[k] ||= []
585
632
  namespace_map[k].concat v
586
- add_to_namespace_tree k.split('::')
587
633
  end
588
634
  end
589
635
  eliminate @virtual_filename
@@ -592,7 +638,7 @@ module Solargraph
592
638
  end
593
639
 
594
640
  def eliminate filename
595
- [@ivar_pins.values, @cvar_pins.values, @const_pins.values, @method_pins.values, @attr_pins.values].each do |pinsets|
641
+ [@ivar_pins.values, @cvar_pins.values, @const_pins.values, @method_pins.values, @attr_pins.values, @namespace_pins.values].each do |pinsets|
596
642
  pinsets.each do |pins|
597
643
  pins.delete_if{|pin| pin.filename == filename}
598
644
  end
@@ -632,6 +678,10 @@ module Solargraph
632
678
  source.superclasses.each_pair do |cls, sup|
633
679
  @superclasses[cls] = sup
634
680
  end
681
+ source.namespace_pins.each do |pin|
682
+ @namespace_pins[pin.namespace] ||= []
683
+ @namespace_pins[pin.namespace].push pin
684
+ end
635
685
  source.required.each do |r|
636
686
  required.push r
637
687
  end
@@ -707,50 +757,6 @@ module Solargraph
707
757
  meths.uniq
708
758
  end
709
759
 
710
- def inner_namespaces_in name, root, skip
711
- result = []
712
- fqns = find_fully_qualified_namespace(name, root)
713
- unless fqns.nil? or skip.include?(fqns)
714
- skip.push fqns
715
- nodes = get_namespace_nodes(fqns)
716
- unless nodes.empty?
717
- cursor = namespace_tree
718
- parts = fqns.split('::')
719
- parts.each { |p|
720
- cursor = cursor[p]
721
- }
722
- unless cursor.nil?
723
- cursor.keys.each { |k|
724
- type = get_namespace_type("#{fqns == '' ? '' : fqns + '::'}#{k}")
725
- kind = nil
726
- detail = nil
727
- if type == :class
728
- kind = Suggestion::CLASS
729
- detail = 'Class'
730
- elsif type == :module
731
- kind = Suggestion::MODULE
732
- detail = 'Module'
733
- end
734
- result.push Suggestion.new(k, kind: kind, detail: detail)
735
- }
736
- cp = @const_pins[fqns]
737
- unless cp.nil?
738
- cp.each do |pin|
739
- result.push pin_to_suggestion(pin)
740
- end
741
- end
742
- inc = @namespace_includes[fqns]
743
- unless inc.nil?
744
- inc.each do |i|
745
- result.concat inner_namespaces_in(i, fqns, skip)
746
- end
747
- end
748
- end
749
- end
750
- end
751
- result
752
- end
753
-
754
760
  # Get a fully qualified namespace for the given signature.
755
761
  # The signature should be in the form of a method chain, e.g.,
756
762
  # method1.method2
@@ -804,12 +810,31 @@ module Solargraph
804
810
  type
805
811
  end
806
812
 
807
- def add_to_namespace_tree tree
808
- cursor = namespace_tree
809
- tree.each { |t|
810
- cursor[t.to_s] ||= {}
811
- cursor = cursor[t.to_s]
812
- }
813
+ def inner_get_constants here, skip = [], deep = true
814
+ return [] if skip.include?(here)
815
+ skip.push here
816
+ result = []
817
+ cp = @const_pins[here]
818
+ unless cp.nil?
819
+ cp.each do |pin|
820
+ result.push pin_to_suggestion(pin)
821
+ end
822
+ end
823
+ np = @namespace_pins[here]
824
+ unless np.nil?
825
+ np.each do |pin|
826
+ result.push pin_to_suggestion(pin)
827
+ if deep
828
+ get_include_strings_from(pin.node).each do |i|
829
+ result.concat inner_get_constants(i, skip, false)
830
+ end
831
+ end
832
+ end
833
+ end
834
+ get_include_strings_from(*get_namespace_nodes(here)).each do |i|
835
+ result.concat inner_get_constants(i, skip, false)
836
+ end
837
+ result
813
838
  end
814
839
 
815
840
  def file_nodes
@@ -837,5 +862,25 @@ module Solargraph
837
862
  require n.match(/^(solargraph\-[a-z0-9_\-]*?\-ext)\-[0-9\.]*$/)[1]
838
863
  end
839
864
  end
865
+
866
+ def suggest_unique_variables pins
867
+ result = []
868
+ nil_pins = []
869
+ val_names = []
870
+ pins.each do |pin|
871
+ if pin.nil_assignment? and pin.return_type.nil?
872
+ nil_pins.push pin
873
+ else
874
+ unless val_names.include?(pin.name)
875
+ result.push pin_to_suggestion(pin)
876
+ val_names.push pin.name
877
+ end
878
+ end
879
+ end
880
+ nil_pins.reject{|p| val_names.include?(p.name)}.each do |pin|
881
+ result.push pin_to_suggestion(pin)
882
+ end
883
+ result
884
+ end
840
885
  end
841
886
  end