solargraph 0.15.4 → 0.16.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 24b597ba06561ddd1bc1a8b4552b7d3bb1ee3867
4
- data.tar.gz: 37bc48eabc24b26b736b64f451402faa0cce7624
3
+ metadata.gz: b84e595d8f1d4042f81bbfb7c27dc56913a0de8c
4
+ data.tar.gz: 0ddfb700d7f1a8e10ec74f021954e1b9fa1375ce
5
5
  SHA512:
6
- metadata.gz: 9bdf2c98784584111834a166a87daab38c94aa9158db3efd05e655651b5b050afdcf488a7d33b78704f9cb04274a137ca047855df93dd1e91a9b010ce69b0b4a
7
- data.tar.gz: e7de68f3751c3a86cd7ed7c3ea3003a902ad72cf6fab8cac6f05a13190118b360e0da4926c707ffdaf5a7075a54a23c12e5e6b665d82279653cb3d5335020c80
6
+ metadata.gz: 171c19a787d30924b510b21d08c443c348d96d8c551fbefd03535dacc8e22fd289ace4f4f270e9469d61d813dc3c640e7ffed21d093826ef787173d0c80e5703
7
+ data.tar.gz: 88637fc48b37ef6bc2c7e3e5f4051fc87fa8901c829bf94bffc877d884f7e47fca750182241cb3d2cf539811e7c9275358a0792a42e6ea666815b59bb94a24c8
@@ -34,16 +34,18 @@ module Solargraph
34
34
 
35
35
  # @param workspace [String]
36
36
  def initialize workspace = nil
37
+ @@source_cache.clear
37
38
  @workspace = workspace.gsub(/\\/, '/') unless workspace.nil?
38
39
  clear
39
40
  require_extensions
40
41
  unless @workspace.nil?
41
- workspace_files.concat (self.config.included - self.config.excluded)
42
+ workspace_files.concat config.calculated
42
43
  workspace_files.each do |wf|
43
44
  begin
44
45
  @@source_cache[wf] ||= Source.load(wf)
45
46
  rescue Parser::SyntaxError => e
46
47
  STDERR.puts "Failed to load #{wf}: #{e.message}"
48
+ @@source_cache[wf] = Source.virtual('', wf)
47
49
  end
48
50
  end
49
51
  end
@@ -132,6 +134,21 @@ module Solargraph
132
134
  process_maps if @stale or force
133
135
  end
134
136
 
137
+ def changed?
138
+ current = config.calculated
139
+ unless (Set.new(current) ^ workspace_files).empty?
140
+ STDERR.puts "Change based on difference in file list"
141
+ return true
142
+ end
143
+ current.each do |f|
144
+ if !File.exist?(f) or File.mtime(f) != source_file_mtime(f)
145
+ STDERR.puts "Change based on file #{f}"
146
+ return true
147
+ end
148
+ end
149
+ false
150
+ end
151
+
135
152
  # Get the docstring associated with a node.
136
153
  #
137
154
  # @param node [AST::Node]
@@ -468,9 +485,9 @@ module Solargraph
468
485
  end
469
486
  end
470
487
  strings = meths.map(&:to_s)
471
- live_map.get_methods(fqns, '', 'class', visibility.include?(:private)).each do |m|
472
- next if strings.include?(m) or !m.match(/^[a-z]/i)
473
- meths.push Suggestion.new(m, kind: Suggestion::METHOD, docstring: YARD::Docstring.new('(defined at runtime)'), path: "#{fqns}.#{m}")
488
+ live_map.get_methods(fqns, '', 'class', visibility.include?(:private)).each do |ls|
489
+ next if strings.include?(ls.to_s)
490
+ meths.push ls
474
491
  end
475
492
  meths
476
493
  end
@@ -507,9 +524,9 @@ module Solargraph
507
524
  end
508
525
  end
509
526
  strings = meths.map(&:to_s)
510
- live_map.get_methods(namespace, root, 'instance', visibility.include?(:private)).each do |m|
511
- next if strings.include?(m) or !m.match(/^[a-z]/i)
512
- meths.push Suggestion.new(m, kind: Suggestion::METHOD, docstring: YARD::Docstring.new('(defined at runtime)'), path: "#{fqns}##{m}")
527
+ live_map.get_methods(fqns, '', 'class', visibility.include?(:private)).each do |ls|
528
+ next if strings.include?(ls.to_s)
529
+ meths.push ls
513
530
  end
514
531
  meths
515
532
  end
@@ -539,6 +556,8 @@ module Solargraph
539
556
  if @workspace_files.include?(filename)
540
557
  eliminate filename
541
558
  @@source_cache[filename] = Source.load(filename)
559
+ @sources.delete filename
560
+ @sources[filename] = @@source_cache[filename]
542
561
  rebuild_local_yardoc #if @workspace_files.include?(filename)
543
562
  @stale = true
544
563
  else
@@ -845,6 +864,7 @@ module Solargraph
845
864
  if scope == :class and part == 'new'
846
865
  scope = :instance
847
866
  elsif !METHODS_RETURNING_SELF.include?(part)
867
+ type = nil
848
868
  visibility = [:public]
849
869
  visibility.concat [:private, :protected] if top
850
870
  if scope == :instance || namespace == ''
@@ -860,7 +880,7 @@ module Solargraph
860
880
  end
861
881
  top = false
862
882
  end
863
- if scope == :class
883
+ if scope == :class and !type.nil?
864
884
  type = "Class<#{type}>"
865
885
  end
866
886
  type
@@ -957,5 +977,13 @@ module Solargraph
957
977
  end
958
978
  result
959
979
  end
980
+
981
+ def source_file_mtime(filename)
982
+ # @todo This is naively inefficient.
983
+ sources.each do |s|
984
+ return s.mtime if s.filename == filename
985
+ end
986
+ nil
987
+ end
960
988
  end
961
989
  end
@@ -40,7 +40,8 @@ module Solargraph
40
40
  # @return [Array<String>]
41
41
  def included
42
42
  return [] if workspace.nil?
43
- @included ||= process_globs(@raw_data['include'])
43
+ #@included ||= process_globs(@raw_data['include'])
44
+ process_globs(@raw_data['include'])
44
45
  end
45
46
 
46
47
  # An array of files excluded from the workspace.
@@ -48,14 +49,16 @@ module Solargraph
48
49
  # @return [Array<String>]
49
50
  def excluded
50
51
  return [] if workspace.nil?
51
- @excluded ||= process_globs(@raw_data['exclude'])
52
+ #@excluded ||= process_globs(@raw_data['exclude'])
53
+ process_globs(@raw_data['exclude'])
52
54
  end
53
55
 
54
56
  # The calculated array of (included - excluded) files in the workspace.
55
57
  #
56
58
  # @return [Array<String>]
57
59
  def calculated
58
- @calculated ||= (included - excluded)
60
+ #@calculated ||= (included - excluded)
61
+ included - excluded
59
62
  end
60
63
 
61
64
  # @return [Array<String>]
@@ -77,7 +80,7 @@ module Solargraph
77
80
  result = []
78
81
  globs.each do |glob|
79
82
  Dir[File.join workspace, glob].each do |f|
80
- result.push File.realdirpath(f)
83
+ result.push File.realdirpath(f).gsub(/\\/, '/')
81
84
  end
82
85
  end
83
86
  result
@@ -15,6 +15,8 @@ module Solargraph
15
15
  # @return [String]
16
16
  attr_reader :filename
17
17
 
18
+ attr_reader :mtime
19
+
18
20
  # @return [Array<Integer>]
19
21
  attr_reader :stubbed_lines
20
22
 
@@ -29,6 +31,7 @@ module Solargraph
29
31
  @directives = {}
30
32
  @docstring_hash = associate_comments(node, comments)
31
33
  @filename = filename
34
+ @mtime = (!filename.nil? and File.exist?(filename) ? File.mtime(filename) : nil)
32
35
  @namespace_nodes = {}
33
36
  @all_nodes = []
34
37
  @node_stack = []
@@ -391,6 +394,11 @@ module Solargraph
391
394
  stubs = []
392
395
  fixed_position = false
393
396
  tmp = code
397
+ if !offset.nil? and offset > 0
398
+ if tmp[offset - 1] == '.'
399
+ tmp = tmp[0..offset-2] + '_' + tmp[offset..-1]
400
+ end
401
+ end
394
402
  begin
395
403
  node, comments = Parser::CurrentRuby.parse_with_comments(tmp)
396
404
  Source.new(code, node, comments, filename, stubs)
@@ -25,6 +25,10 @@ module Solargraph
25
25
 
26
26
  include NodeMethods
27
27
 
28
+ METHODS_WITH_YIELDPARAM_SUBTYPES = %w[
29
+ Array#each Hash#each_pair Array#map
30
+ ]
31
+
28
32
  def initialize code: '', filename: nil, api_map: nil, cursor: nil
29
33
  # HACK: Adjust incoming filename's path separator for yardoc file comparisons
30
34
  filename = filename.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless filename.nil? or File::ALT_SEPARATOR.nil?
@@ -346,7 +350,11 @@ module Solargraph
346
350
  yp = get_yieldparams_at(index).keep_if{|s| s.to_s == parts[0]}.first
347
351
  unless yp.nil?
348
352
  if parts[1].nil? or parts[1].empty?
349
- result = yp.return_type
353
+ if yp.return_type.nil?
354
+ STDERR.puts "Here is where we try to get the stupid, you know, the yieldparam type"
355
+ else
356
+ result = yp.return_type
357
+ end
350
358
  else
351
359
  newsig = parts[1..-1].join('.')
352
360
  result = api_map.infer_signature_type(newsig, yp.return_type, scope: :instance)
@@ -405,7 +413,7 @@ module Solargraph
405
413
  end
406
414
  unless signature.include?('.')
407
415
  fqns = api_map.find_fully_qualified_namespace(signature, ns_here)
408
- return "Class<#{fqns}>" unless fqns.nil?
416
+ return "Class<#{fqns}>" unless fqns.nil? or fqns.empty?
409
417
  end
410
418
  start = parts[0]
411
419
  return nil if start.nil?
@@ -626,7 +634,16 @@ module Solargraph
626
634
  end
627
635
  i = 0
628
636
  block_node.children[1].children.each do |a|
629
- rt = (yps[i].nil? ? nil : yps[i].types[0])
637
+ rt = nil
638
+ if yps[i].nil? or yps[i].types.nil? or yps[i].types.empty?
639
+ zsig = api_map.resolve_node_signature(block_node.children[0])
640
+ vartype = infer_signature_from_node(zsig.split('.').first, scope_node)
641
+ subtypes = get_subtypes(vartype)
642
+ zpath = infer_path_from_signature_and_node(zsig, scope_node)
643
+ rt = subtypes[i] if METHODS_WITH_YIELDPARAM_SUBTYPES.include?(zpath)
644
+ else
645
+ rt = yps[i].types[0]
646
+ end
630
647
  result.push Suggestion.new(a.children[0], kind: Suggestion::PROPERTY, return_type: rt)
631
648
  i += 1
632
649
  end
@@ -777,5 +794,19 @@ module Solargraph
777
794
  cursor = nil if cursor < 0
778
795
  cursor
779
796
  end
797
+
798
+ def infer_path_from_signature_and_node signature, node
799
+ # @todo Improve this method
800
+ parts = signature.split('.')
801
+ last = parts.pop
802
+ type = infer_signature_from_node(parts.join('.'), node)
803
+ "#{type.gsub(/<[a-z0-9:, ]*>/i, '')}##{last}"
804
+ end
805
+
806
+ def get_subtypes type
807
+ match = type.match(/<([a-z0-9_:, ]*)>/i)
808
+ return [] if match.nil?
809
+ match[1].split(',').map(&:strip)
810
+ end
780
811
  end
781
812
  end
@@ -15,6 +15,7 @@ module Solargraph
15
15
  end
16
16
 
17
17
  def get_methods(namespace, root = '', scope = 'instance', with_private = false)
18
+ fqns = api_map.find_fully_qualified_namespace(namespace, root)
18
19
  params = {
19
20
  namespace: namespace, root: root, scope: scope, with_private: with_private
20
21
  }
@@ -24,7 +25,9 @@ module Solargraph
24
25
  result = []
25
26
  runners.each do |p|
26
27
  next if did_runtime and p.runtime?
27
- result.concat p.get_methods(namespace: namespace, root: root, scope: scope, with_private: with_private)
28
+ p.get_methods(namespace: namespace, root: root, scope: scope, with_private: with_private).each do |m|
29
+ result.push Suggestion.new(m['name'], kind: Suggestion::METHOD, docstring: YARD::Docstring.new('(defined at runtime)'), path: "#{fqns}.#{m['name']}", arguments: m['parameters'])
30
+ end
28
31
  did_runtime = true if p.runtime?
29
32
  end
30
33
  cache.set_methods(params, result)
@@ -71,7 +71,14 @@ module Solargraph
71
71
  result.concat con.public_instance_methods(false)
72
72
  end
73
73
  end
74
- respond_ok result.uniq
74
+ respond_ok (result.uniq.sort.map do |name|
75
+ # @type [Method]
76
+ meth = con.method(name)
77
+ {
78
+ name: name,
79
+ parameters: build_parameter_array(meth.parameters)
80
+ }
81
+ end)
75
82
  end
76
83
 
77
84
  def get_constants args
@@ -138,6 +145,26 @@ module Solargraph
138
145
  data: []
139
146
  }.to_json
140
147
  end
148
+
149
+ def build_parameter_array parameters
150
+ an = 1
151
+ parameters.map do |p|
152
+ if p[0] == :rest
153
+ str = (p[1] ? "*#{p[1]}" : "*args")
154
+ else
155
+ str = (p[1] ? p[1].to_s : "arg#{an}")
156
+ if p[0] == :opt
157
+ str += ' = ?'
158
+ elsif p[0] == :key
159
+ str += ':'
160
+ elsif p[0] == :keyreq
161
+ str += ': ?'
162
+ end
163
+ end
164
+ an += 1
165
+ str
166
+ end
167
+ end
141
168
  end
142
169
  end
143
170
  end
@@ -172,6 +172,30 @@ module Solargraph
172
172
  end
173
173
  end
174
174
 
175
+ def run!
176
+ Thread.new do
177
+ while true
178
+ watch_workspaces
179
+ sleep 1
180
+ end
181
+ end
182
+ super
183
+ end
184
+
185
+ def watch_workspaces
186
+ @@semaphore.synchronize do
187
+ changed = {}
188
+ @@api_hash.each_pair do |w, a|
189
+ next unless a.changed?
190
+ STDERR.puts "Reloading changed workspace #{w}"
191
+ n = Solargraph::ApiMap.new(w)
192
+ changed[w] = n
193
+ end
194
+ changed.each_pair do |w, a|
195
+ @@api_hash[w] = a
196
+ end
197
+ end
198
+ end
175
199
  end
176
200
 
177
201
  class Helpers
@@ -21,8 +21,7 @@ module Solargraph
21
21
  option :files, type: :string, aliases: :f, desc: 'The public files directory', default: nil
22
22
  def server
23
23
  port = options[:port]
24
- # This line should not be necessary with WEBrick
25
- #port = available_port if port.zero?
24
+ port = available_port if port.zero?
26
25
  Solargraph::Server.set :port, port
27
26
  Solargraph::Server.set :views, options[:views] unless options[:views].nil?
28
27
  Solargraph::Server.set :public_folder, options[:files] unless options[:files].nil?
@@ -1,3 +1,3 @@
1
1
  module Solargraph
2
- VERSION = '0.15.4'
2
+ VERSION = '0.16.0'
3
3
  end
@@ -225,7 +225,7 @@ module Solargraph
225
225
  end
226
226
 
227
227
  def find_fully_qualified_namespace namespace, scope
228
- unless scope.empty?
228
+ unless scope.nil? or scope.empty?
229
229
  parts = scope.split('::')
230
230
  while parts.length > 0
231
231
  here = "#{parts.join('::')}::#{namespace}"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solargraph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.4
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-02 00:00:00.000000000 Z
11
+ date: 2018-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser