solargraph 0.1.0 → 0.2.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: acab722ec6710f43f14625320985dbcd30dd2e19
4
- data.tar.gz: c19b6542c62b928a4b585df460a131e70ab58912
3
+ metadata.gz: e99bdc143ca29ca298dc48668e2eab23a73fb338
4
+ data.tar.gz: a2c8fc45842f2d30f30c964f427962992223315e
5
5
  SHA512:
6
- metadata.gz: e310d1270047cd3dbd9f21c4249efeaf3342417233bf1484f0e4cb86d944b1a6c24bf900a4a00580c86413f9b130f51289a705579e533f5bbdeab02958b13b49
7
- data.tar.gz: 6815c3a16e85e7246e86ca3fe7358b4732b91fac3a09867fd149c32d9be7903436ac10f72650ddfb472164ca0be7bd322822da8be43385261844a9c581f109c5
6
+ metadata.gz: e7eee90d32b54be8ed26faa90c55794c68981e90e6fae4dfafba8a226847bb06fe90485876a82be679d83bca3fac5eb33c63072d98a517418c6437ba91956873
7
+ data.tar.gz: c8b992d21569e07e36db02c08c332c7309ee206daf81ff5489ce440a308b50d1e6cdabc337b728ecd37403e745f1f6fc4ffbb1562e3d486908f8372b2cafcd5d
@@ -15,14 +15,20 @@ module Solargraph
15
15
  MAPPABLE_METHODS = [
16
16
  :include, :require, :autoload, :attr_reader, :attr_writer, :attr_accessor, :private, :public, :protected
17
17
  ]
18
+
18
19
  include NodeMethods
19
20
 
20
21
  attr_reader :workspace
21
22
 
22
23
  def initialize workspace = nil
23
24
  @workspace = workspace
24
- #process_workspace
25
25
  clear
26
+ unless @workspace.nil? #or has_yardoc?
27
+ files = Dir[File.join workspace, 'lib', '**', '*.rb'] + Dir[File.join workspace, 'app', '**', '*.rb']
28
+ files.each { |f|
29
+ append_file f
30
+ }
31
+ end
26
32
  end
27
33
 
28
34
  def clear
@@ -31,17 +37,12 @@ module Solargraph
31
37
  @parent_stack = {}
32
38
  @namespace_map = {}
33
39
  @namespace_tree = {}
34
- #@pending_requires = []
35
40
  @required = []
36
41
  end
37
42
 
38
- #def process_workspace
39
- # clear
40
- # return if @workspace.nil?
41
- # process_files
42
- # process_requires
43
- # process_maps
44
- #end
43
+ def has_yardoc?
44
+ workspace and File.exist?(File.join(workspace, '.yardoc'))
45
+ end
45
46
 
46
47
  def append_file filename
47
48
  append_source File.read(filename), filename
@@ -53,22 +54,21 @@ module Solargraph
53
54
  end
54
55
 
55
56
  def append_node node, comments, filename = nil
56
- mapified = mapify(node)
57
+ @file_comments[filename] = associate_comments(node, comments)
58
+ mapified = reduce(node, @file_comments[filename])
57
59
  root = AST::Node.new(:begin, [filename])
58
60
  mapified.children.each { |c|
59
61
  root = root.append c
60
62
  }
61
63
  @file_nodes[filename] = root
62
- @file_comments[filename] = associate_comments(mapified, comments)
63
64
  @required.uniq!
64
65
  process_maps
65
66
  end
66
67
 
67
68
  def associate_comments node, comments
68
- comment_hash = Parser::Source::Comment.associate(node, comments)
69
+ comment_hash = Parser::Source::Comment.associate_locations(node, comments)
69
70
  yard_hash = {}
70
71
  comment_hash.each_pair { |k, v|
71
- #ctxt = v.map(&:text).join("\r\n")
72
72
  ctxt = ''
73
73
  v.each { |l|
74
74
  ctxt += l.text.gsub(/^#/, '') + "\n"
@@ -81,7 +81,8 @@ module Solargraph
81
81
 
82
82
  def get_comment_for node
83
83
  filename = get_filename_for(node)
84
- @file_comments[filename][node] unless @file_comments[filename].nil?
84
+ return nil if @file_comments[filename].nil?
85
+ @file_comments[filename][node.loc]
85
86
  end
86
87
 
87
88
  def self.get_keywords without_snippets: false
@@ -142,7 +143,17 @@ module Solargraph
142
143
  }
143
144
  unless cursor.nil?
144
145
  cursor.keys.each { |k|
145
- result.push Suggestion.new(k, kind: Suggestion::CLASS)
146
+ type = get_namespace_type(k, fqns)
147
+ kind = nil
148
+ detail = nil
149
+ if type == :class
150
+ kind = Suggestion::CLASS
151
+ detail = 'Class'
152
+ elsif type == :module
153
+ kind = Suggestion::MODULE
154
+ detail = 'Module'
155
+ end
156
+ result.push Suggestion.new(k, kind: kind, detail: detail)
146
157
  }
147
158
  nodes = get_namespace_nodes(fqns)
148
159
  nodes.each { |n|
@@ -225,7 +236,6 @@ module Solargraph
225
236
  if node.kind_of?(AST::Node)
226
237
  node.children.each { |c|
227
238
  if c.kind_of?(AST::Node)
228
- #next if [:class, :module].include?(c.type)
229
239
  is_inst = !find_parent(c, :def).nil?
230
240
  if c.type == :ivasgn and ( (scope == :instance and is_inst) or (scope != :instance and !is_inst) )
231
241
  arr.push Suggestion.new(c.children[0], kind: Suggestion::VARIABLE)
@@ -266,7 +276,7 @@ module Solargraph
266
276
  end
267
277
 
268
278
  def get_global_variables
269
- # TODO I bet these aren't getting mapped at all. Damn.
279
+ # TODO: Get them
270
280
  []
271
281
  end
272
282
 
@@ -323,19 +333,25 @@ module Solargraph
323
333
  end
324
334
 
325
335
  def get_instance_methods(namespace, root = '')
326
- meths = inner_get_instance_methods(namespace, root, [])
336
+ meths = []
337
+ meths += inner_get_instance_methods(namespace, root, []) unless has_yardoc?
327
338
  yard = YardMap.new(required: @required, workspace: @workspace)
328
- type = get_namespace_type(namespace, root)
329
- if type == :class
330
- meths += yard.get_instance_methods('Object')
331
- elsif type == :module
332
- meths += yard.get_instance_methods('Module')
333
- end
334
- meths += yard.get_instance_methods(namespace, root)
335
- sc = get_superclass(namespace, root)
336
- until sc.nil?
337
- meths += yard.get_instance_methods(sc, root)
338
- sc = get_superclass(sc)
339
+ yard_meths = yard.get_instance_methods(namespace, root)
340
+ if yard_meths.any?
341
+ meths.concat yard_meths
342
+ else
343
+ type = get_namespace_type(namespace, root)
344
+ if type == :class
345
+ meths += yard.get_instance_methods('Object')
346
+ elsif type == :module
347
+ meths += yard.get_instance_methods('Module')
348
+ end
349
+ # TODO: Look out for repeats. Consider not doing this at all.
350
+ sc = get_superclass(namespace, root)
351
+ until sc.nil?
352
+ meths += yard.get_instance_methods(sc, root)
353
+ sc = get_superclass(sc)
354
+ end
339
355
  end
340
356
  meths
341
357
  end
@@ -374,7 +390,7 @@ module Solargraph
374
390
  elsif current_scope == :public
375
391
  if c.kind_of?(AST::Node) and c.type == :def
376
392
  cmnt = get_comment_for(c)
377
- meths.push Suggestion.new(c.children[0], kind: Suggestion::METHOD, documentation: cmnt) if c.children[0].to_s[0].match(/[a-z]/i)
393
+ meths.push Suggestion.new(c.children[0], kind: Suggestion::METHOD, documentation: cmnt, detail: fqns) if c.children[0].to_s[0].match(/[a-z]/i)
378
394
  elsif c.kind_of?(AST::Node) and c.type == :send and c.children[1] == :attr_reader
379
395
  c.children[2..-1].each { |x|
380
396
  meths.push Suggestion.new(x.children[0], kind: Suggestion::METHOD) if x.type == :sym
@@ -421,15 +437,6 @@ module Solargraph
421
437
 
422
438
  private
423
439
 
424
- def mapify node
425
- root = node
426
- if !root.kind_of?(AST::Node) or root.type != :begin
427
- root = AST::Node.new(:begin, [node], {})
428
- end
429
- root = reduce root
430
- root
431
- end
432
-
433
440
  def mappable?(node)
434
441
  # TODO Add node.type :casgn (constant assignment)
435
442
  if node.kind_of?(AST::Node) and (node.type == :class or node.type == :module or node.type == :def or node.type == :defs or node.type == :ivasgn or node.type == :gvasgn or node.type == :or_asgn)
@@ -441,42 +448,42 @@ module Solargraph
441
448
  end
442
449
  end
443
450
 
444
- def reduce node
445
- mappable = get_mappable_nodes(node.children)
451
+ def reduce node, comment_hash
452
+ mappable = get_mappable_nodes(node.children, comment_hash)
446
453
  result = node.updated nil, mappable
447
454
  result
448
455
  end
449
456
 
450
- def get_mappable_nodes arr
457
+ def get_mappable_nodes arr, comment_hash
451
458
  result = []
452
459
  arr.each { |n|
453
460
  if mappable?(n)
454
- min = minify(n)
461
+ min = minify(n, comment_hash)
455
462
  result.push min
456
463
  else
457
464
  next unless n.kind_of?(AST::Node)
458
- result += get_mappable_nodes(n.children)
465
+ result += get_mappable_nodes(n.children, comment_hash)
459
466
  end
460
467
  }
461
468
  result
462
469
  end
463
470
 
464
- def minify node
471
+ def minify node, comment_hash
465
472
  return node if node.type == :args
466
473
  type = node.type
467
474
  children = []
468
475
  if node.type == :class
469
476
  children += node.children[0, 2]
470
- children += get_mappable_nodes(node.children[2..-1])
477
+ children += get_mappable_nodes(node.children[2..-1], comment_hash)
471
478
  elsif node.type == :def
472
479
  children += node.children[0, 2]
473
- children += get_mappable_nodes(node.children[2..-1])
480
+ children += get_mappable_nodes(node.children[2..-1], comment_hash)
474
481
  elsif node.type == :defs
475
482
  children += node.children[0, 3]
476
- children += get_mappable_nodes(node.children[3..-1])
483
+ children += get_mappable_nodes(node.children[3..-1], comment_hash)
477
484
  elsif node.type == :module
478
485
  children += node.children[0, 1]
479
- children += get_mappable_nodes(node.children[1..-1])
486
+ children += get_mappable_nodes(node.children[1..-1], comment_hash)
480
487
  elsif node.type == :ivasgn or node.type == :gvasgn
481
488
  children += node.children
482
489
  elsif node.type == :send and node.children[1] == :include
@@ -500,7 +507,7 @@ module Solargraph
500
507
  end
501
508
 
502
509
  def map_parents node, tree = []
503
- if node.kind_of?(AST::Node) #and (node.type == :class or node.type == :module)
510
+ if node.kind_of?(AST::Node)
504
511
  @parent_stack[node] = tree
505
512
  node.children.each { |c|
506
513
  map_parents c, [node] + tree
@@ -7,26 +7,30 @@ module Solargraph
7
7
 
8
8
  include NodeMethods
9
9
 
10
- def initialize code: '', filename: nil
11
- workspace = nil
12
- unless filename.nil?
13
- filename.gsub!(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
10
+ def initialize code: '', filename: nil, workspace: nil
11
+ if workspace.nil? and !filename.nil?
12
+ filename = filename.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
14
13
  workspace = CodeMap.find_workspace(filename)
15
14
  end
16
- @api_map = ApiMap.new(workspace)
17
- unless workspace.nil?
18
- files = Dir[File.join workspace, '**', '*.rb']
19
- files.each { |f|
20
- unless filename == f
21
- @api_map.append_file f
15
+ if workspace.nil?
16
+ @api_map = ApiMap.new(workspace)
17
+ else
18
+ ser_file = File.join(workspace, '.solargraph.ser')
19
+ if File.exist?(ser_file)
20
+ begin
21
+ @api_map = Marshal.load(File.read(ser_file))
22
+ rescue Exception => e
23
+ @api_map = ApiMap.new(workspace)
22
24
  end
23
- }
25
+ else
26
+ @api_map = ApiMap.new(workspace)
27
+ end
24
28
  end
25
29
 
26
30
  @code = code.gsub(/\r/, '')
27
31
  tries = 0
28
32
  # Hide incomplete code to avoid syntax errors
29
- tmp = "#{code}\nX".gsub(/[\.@]([\s])/, '#\1').gsub(/([\A\s]?)def([\s]*?[\n\Z])/, '\1#ef\2')
33
+ tmp = "#{@code}\nX".gsub(/[\.@]([\s])/, '#\1').gsub(/([\A\s]?)def([\s]*?[\n\Z])/, '\1#ef\2')
30
34
  #tmp = code
31
35
  begin
32
36
  @node, comments = Parser::CurrentRuby.parse_with_comments(tmp)
@@ -36,7 +40,6 @@ module Solargraph
36
40
  tries += 1
37
41
  spot = e.diagnostic.location.begin_pos
38
42
  if spot == tmp.length
39
- puts e.message
40
43
  tmp = tmp[0..-2] + '#'
41
44
  else
42
45
  tmp = tmp[0..spot] + '#' + tmp[spot+2..-1].to_s
@@ -181,20 +184,7 @@ module Solargraph
181
184
  result = @api_map.namespaces_in(ns)
182
185
  end
183
186
  elsif phrase.include?('.')
184
- # It's a method call
185
- # TODO: For now we're assuming only one period. That's obviously a bad assumption.
186
- #base = phrase[0..phrase.index('.')-1]
187
- #ns_here = namespace_at(index)
188
- #result = @api_map.get_methods(base, ns_here)
189
- #scope = parent_node_from(index, :class, :module, :def, :defs) || @node
190
- #var = find_local_variable_node(base, scope)
191
- #unless var.nil?
192
- # obj = infer(var.children[1])
193
- # result = @api_map.get_instance_methods(obj) unless obj.nil?
194
- #end
195
-
196
- # TODO: Alternate version that resolves signature
197
- result = resolve_signature_at index
187
+ result = resolve_signature_at @code[0, index].rindex('.')
198
188
  else
199
189
  current_namespace = namespace_at(index)
200
190
  parts = current_namespace.to_s.split('::')
@@ -14,7 +14,7 @@ module Solargraph
14
14
  rescue Exception => e
15
15
  STDERR.puts e
16
16
  STDERR.puts e.backtrace.join("\n")
17
- { "status" => "err", "message" => e.message }.to_json
17
+ { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
18
18
  end
19
19
  end
20
20
  end
@@ -54,6 +54,18 @@ module Solargraph
54
54
  Solargraph::Server.run!
55
55
  end
56
56
 
57
+ desc 'serialize DIRECTORY', 'Cache an API map of DIRECTORY'
58
+ def serialize directory
59
+ api_map = ApiMap.new directory
60
+ files = Dir[File.join directory, 'lib', '**', '*.rb'] + Dir[File.join directory, 'app', '**', '*.rb']
61
+ files.each { |f|
62
+ api_map.append_file f
63
+ }
64
+ File.open(File.join(directory, '.solargraph.ser'), 'wb') { |file|
65
+ file << Marshal.dump(api_map)
66
+ }
67
+ end
68
+
57
69
  desc 'suggest', 'Get code suggestions for the provided input'
58
70
  long_desc <<-LONGDESC
59
71
  Analyze a Ruby file and output a list of code suggestions in JSON format.
@@ -76,7 +88,8 @@ module Solargraph
76
88
  rescue Exception => e
77
89
  STDERR.puts e
78
90
  STDERR.puts e.backtrace.join("\n")
79
- result = { "status" => "err", "message" => e.message }.to_json
91
+ #result = { "status" => "err", "message" => e.message }.to_json
92
+ result = { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
80
93
  STDOUT.puts result
81
94
  end
82
95
  end
@@ -10,15 +10,16 @@ module Solargraph
10
10
  VARIABLE = 'Variable'
11
11
  SNIPPET = 'Snippet'
12
12
 
13
- attr_reader :label, :kind, :insert, :detail, :documentation
13
+ attr_reader :label, :kind, :insert, :detail, :documentation, :code_object, :location
14
14
 
15
- def initialize label, kind: KEYWORD, insert: nil, detail: nil, documentation: nil, code_object: nil
15
+ def initialize label, kind: KEYWORD, insert: nil, detail: nil, documentation: nil, code_object: nil, location: nil
16
16
  @label = label.to_s
17
17
  @kind = kind
18
18
  @insert = insert || @label
19
19
  @detail = detail
20
20
  @code_object = code_object
21
21
  @documentation = documentation
22
+ @location = location
22
23
  end
23
24
 
24
25
  def to_s
@@ -26,14 +27,19 @@ module Solargraph
26
27
  end
27
28
 
28
29
  def to_json args={}
29
- {
30
+ obj = {
30
31
  label: @label,
31
32
  kind: @kind,
32
33
  insert: @insert,
33
34
  detail: @detail,
34
- #documentation: (@documentation.nil? ? nil : @documentation.all)
35
- documentation: (@code_object.nil? ? nil : YARD::Templates::Engine.render(format: :text, object: @code_object))
36
- }.to_json(args)
35
+ location: (@location.nil? ? nil : @location.to_s)
36
+ }
37
+ if @code_object.nil?
38
+ obj[:documentation] = @documentation.all unless @documentation.nil?
39
+ else
40
+ obj[:documentation] = @code_object.docstring.all unless @code_object.docstring.nil?
41
+ end
42
+ obj.to_json(args)
37
43
  end
38
44
  end
39
45
 
@@ -1,3 +1,3 @@
1
1
  module Solargraph
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -10,12 +10,20 @@ module Solargraph
10
10
  wsy = File.join(workspace, '.yardoc')
11
11
  yardocs.push wsy if File.exist?(wsy)
12
12
  end
13
+ used = []
13
14
  required.each { |r|
14
- gy = YARD::Registry.yardoc_file_for_gem(r)
15
- yardocs.push gy unless gy.nil?
15
+ if workspace.nil? or !File.exist?(File.join workspace, 'lib', "#{r}.rb")
16
+ g = r.split('/').first
17
+ unless used.include?(g)
18
+ used.push g
19
+ gy = YARD::Registry.yardoc_file_for_gem(g)
20
+ yardocs.push gy unless gy.nil?
21
+ end
22
+ end
16
23
  }
17
24
  yardocs.push File.join(Dir.home, '.solargraph', 'cache', '2.0.0', 'yardoc')
18
25
  #yardocs.push File.join(Dir.home, '.solargraph', 'cache', '2.0.0', 'yardoc-stdlib')
26
+ yardocs.uniq!
19
27
  end
20
28
 
21
29
  def yardocs
@@ -38,7 +46,16 @@ module Solargraph
38
46
  end
39
47
  }
40
48
  consts.each { |c|
41
- result.push Suggestion.new(c.to_s.split('::').last, kind: Suggestion::CLASS)
49
+ detail = nil
50
+ kind = nil
51
+ if c.kind_of?(YARD::CodeObjects::ClassObject)
52
+ detail = 'Class'
53
+ kind = Suggestion::CLASS
54
+ elsif c.kind_of?(YARD::CodeObjects::ModuleObject)
55
+ detail = 'Module'
56
+ kind = Suggestion::MODULE
57
+ end
58
+ result.push Suggestion.new(c.to_s.split('::').last, detail: detail, kind: kind)
42
59
  }
43
60
  result
44
61
  end
@@ -79,7 +96,7 @@ module Solargraph
79
96
  unless ns.nil?
80
97
  ns.meths(scope: :class, visibility: [:public]).each { |m|
81
98
  n = m.to_s.split('.').last
82
- meths.push Suggestion.new("#{n}", kind: Suggestion::METHOD) if n.to_s.match(/^[a-z]/i)
99
+ meths.push Suggestion.new("#{n}", kind: Suggestion::METHOD, detail: "#{ns}") if n.to_s.match(/^[a-z]/i)
83
100
  }
84
101
  if ns.kind_of?(YARD::CodeObjects::ClassObject) and namespace != 'Class'
85
102
  meths += get_instance_methods('Class')
@@ -104,7 +121,9 @@ module Solargraph
104
121
  unless ns.nil?
105
122
  ns.meths(scope: :instance, visibility: [:public]).each { |m|
106
123
  n = m.to_s.split('#').last
107
- meths.push Suggestion.new("#{n}", kind: Suggestion::METHOD, documentation: m.docstring, code_object: m) if n.to_s.match(/^[a-z]/i) and !m.to_s.start_with?('Kernel#') and !m.docstring.to_s.include?(':nodoc:')
124
+ if n.to_s.match(/^[a-z]/i) and !m.to_s.start_with?('Kernel#') and !m.docstring.to_s.include?(':nodoc:')
125
+ meths.push Suggestion.new("#{n}", kind: Suggestion::METHOD, documentation: m.docstring, code_object: m, detail: "#{ns}", location: "#{m.file}:#{m.line}")
126
+ end
108
127
  }
109
128
  if ns.kind_of?(YARD::CodeObjects::ClassObject) and namespace != 'Object'
110
129
  meths += get_instance_methods('Object')
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.1.0
4
+ version: 0.2.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: 2017-03-18 00:00:00.000000000 Z
11
+ date: 2017-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser