solargraph 0.34.3 → 0.35.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
  SHA256:
3
- metadata.gz: 19d601d06fae9aedf33e93d09172bb9257757aaf7323f6f6a355c82fc7b67223
4
- data.tar.gz: 5a5d073284cd8034b710dbb22169a30478e490e8561b4e2be56b59a52c79b757
3
+ metadata.gz: 02a0b8dd485332480c292f17a1cae69217cf9cb4e5f3aa9c29bd94ac55d57ab8
4
+ data.tar.gz: f74891d9e13561d6a1ece0fb64fd014af2b1504e412e9d51b4e83d8d6a9aa089
5
5
  SHA512:
6
- metadata.gz: 0071a0c809fae4043ea2ffa35ef811f575d1c9027f199c47d344692ce0e7a641a10f94af240220959a5ef924f92985511afebd8b502cc35ed023bbffe2b27a62
7
- data.tar.gz: 0076f43c9ae828ead40ec6d64a6409fa96d3631a290673baf026aa65e8f72fbdc8103cd073a7f5919945cd8a7f598f233889ef38ea173f3e58cd27cbb03f8812
6
+ metadata.gz: f3c8574a741707ef88be3f6ec1e1287b4a67b091d0c12634e65d563e93510ba135c193b55f9f4d05af5a5f8b1d9a6c661f691e571811281cd523c6a62eec5513
7
+ data.tar.gz: 13a013bcc7738c449696207a3622e1b3d3b7bed626fd2e39fe2a89c08eb42776fd19a32c7d65642b4ada6535a94af0f3f0a6ea3aee303eba1c2407daff9d4ad9
@@ -73,6 +73,8 @@ module Solargraph
73
73
  @items.any?(&:selfy?)
74
74
  end
75
75
 
76
+ # @param dst [String]
77
+ # @return [ComplexType]
76
78
  def self_to dst
77
79
  return self unless selfy?
78
80
  red = reduce_class(dst)
@@ -86,6 +88,8 @@ module Solargraph
86
88
  # to reference an instance of their class and never the class itself.
87
89
  # This behavior may change depending on which result is expected
88
90
  # from YARD conventions. See https://github.com/lsegal/yard/issues/1257
91
+ # @param dst [String]
92
+ # @return [String]
89
93
  def reduce_class dst
90
94
  while dst =~ /^(Class|Module)\<(.*?)\>$/
91
95
  dst = dst.sub(/^(Class|Module)\</, '').sub(/\>$/, '')
@@ -21,10 +21,14 @@ module Solargraph
21
21
  ]
22
22
 
23
23
  OVERRIDES = [
24
- Override.method_return('Array#select', 'self'),
25
- Override.method_return('Array#reject', 'self'),
26
24
  Override.method_return('Array#keep_if', 'self'),
27
25
  Override.method_return('Array#delete_if', 'self'),
26
+ Override.from_comment('Array#reject', %(
27
+ @overload reject(&block)
28
+ @return [self]
29
+ @overload reject()
30
+ @return [Enumerator]
31
+ )),
28
32
  Override.method_return('Array#reverse', 'self', delete: ['overload']),
29
33
  Override.from_comment('Array#select', %(
30
34
  @overload select(&block)
@@ -76,6 +80,7 @@ module Solargraph
76
80
  Override.method_return('Object#dup', 'self'),
77
81
  Override.method_return('Object#freeze', 'self'),
78
82
  Override.method_return('Object#taint', 'self'),
83
+ Override.method_return('Object#to_s', 'String'),
79
84
  Override.method_return('Object#untaint', 'self'),
80
85
  Override.from_comment('Object#tap', %(
81
86
  @return [self]
@@ -9,6 +9,8 @@ require 'cgi'
9
9
  module Solargraph
10
10
  class Page
11
11
  class Binder < OpenStruct
12
+ # @param locals [Hash]
13
+ # @param render_method [Proc]
12
14
  def initialize locals, render_method
13
15
  super(locals)
14
16
  define_singleton_method :render do |template, layout: false, locals: {}|
@@ -19,6 +21,8 @@ module Solargraph
19
21
  end
20
22
  end
21
23
 
24
+ # @param text [String]
25
+ # @return [String]
22
26
  def htmlify text
23
27
  Kramdown::Document.new(
24
28
  text.to_s.lines.map{|l| l.gsub(/^ /, "\t")}.join,
@@ -33,16 +37,23 @@ module Solargraph
33
37
  ).to_html
34
38
  end
35
39
 
40
+ # @param code [String]
41
+ # @return [String]
36
42
  def ruby_to_html code
37
43
  code
38
44
  end
39
45
  end
40
46
  private_constant :Binder
41
47
 
48
+ # @param directory [String]
42
49
  def initialize directory = VIEWS_PATH
43
50
  directory = VIEWS_PATH if directory.nil? or !File.directory?(directory)
44
51
  directories = [directory]
45
52
  directories.push VIEWS_PATH if directory != VIEWS_PATH
53
+ # @type [Proc]
54
+ # @param template [String]
55
+ # @param layout [Boolean]
56
+ # @param locals [Hash]
46
57
  @render_method = proc { |template, layout: false, locals: {}|
47
58
  binder = Binder.new(locals, @render_method)
48
59
  if layout
@@ -55,10 +66,17 @@ module Solargraph
55
66
  }
56
67
  end
57
68
 
69
+ # @param template [String]
70
+ # @param layout [Boolean]
71
+ # @param locals [Hash]
72
+ # @return [String]
58
73
  def render template, layout: true, locals: {}
59
74
  @render_method.call(template, layout: layout, locals: locals)
60
75
  end
61
76
 
77
+ # @param directories [Array<String>]
78
+ # @param name [String]
79
+ # @return [String]
62
80
  def self.select_template directories, name
63
81
  directories.each do |dir|
64
82
  path = File.join(dir, "#{name}.erb")
@@ -236,7 +236,8 @@ module Solargraph
236
236
 
237
237
  # @return [void]
238
238
  def parse_comments
239
- if comments.empty?
239
+ # HACK: Avoid a NoMethodError on nil with empty overload tags
240
+ if comments.empty? || comments.strip.end_with?('@overload')
240
241
  @docstring = nil
241
242
  @directives = []
242
243
  else
@@ -5,8 +5,10 @@ module Solargraph
5
5
  class BaseVariable < Base
6
6
  include Solargraph::Source::NodeMethods
7
7
 
8
+ # @return [Parser::AST::Node, nil]
8
9
  attr_reader :assignment
9
10
 
11
+ # @param assignment [Parser::AST::Node, nil]
10
12
  def initialize assignment: nil, **splat
11
13
  super(splat)
12
14
  @assignment = assignment
@@ -41,11 +43,9 @@ module Solargraph
41
43
  return ComplexType::UNDEFINED if @assignment.nil?
42
44
  types = []
43
45
  returns_from(@assignment).each do |node|
44
- chain = Source::NodeChainer.chain(node, filename)
45
- next if chain.links.first.word == name
46
- clip = api_map.clip_at(location.filename, location.range.start)
47
- locals = clip.locals - [self]
48
- result = chain.infer(api_map, closure, locals)
46
+ pos = Solargraph::Position.new(node.loc.expression.last_line, node.loc.expression.last_column)
47
+ clip = api_map.clip_at(location.filename, pos)
48
+ result = clip.infer
49
49
  types.push result unless result.undefined?
50
50
  end
51
51
  return ComplexType::UNDEFINED if types.empty?
@@ -66,6 +66,7 @@ module Solargraph
66
66
 
67
67
  private
68
68
 
69
+ # @return [ComplexType]
69
70
  def generate_complex_type
70
71
  tag = docstring.tag(:type)
71
72
  return ComplexType.try_parse(*tag.types) unless tag.nil? || tag.types.nil? || tag.types.empty?
@@ -26,13 +26,6 @@ module Solargraph
26
26
  closure.is_a?(Pin::Block) ? typify_block_param(api_map) : typify_method_param(api_map)
27
27
  end
28
28
 
29
- def try_merge! pin
30
- return false unless super && closure.nearly?(pin.closure)
31
- @return_type = pin.return_type
32
- reset_conversions
33
- true
34
- end
35
-
36
29
  def documentation
37
30
  tag = param_tag
38
31
  return '' if tag.nil? || tag.text.nil?
@@ -118,7 +111,7 @@ module Solargraph
118
111
  # @param heredoc [YARD::Docstring]
119
112
  # @param api_map [ApiMap]
120
113
  # @param skip [Array]
121
- # @return [ComplexType]
114
+ # @return [Array<YARD::Tags::Tag>]
122
115
  def see_reference heredoc, api_map, skip = []
123
116
  heredoc.ref_tags.each do |ref|
124
117
  next unless ref.tag_name == 'param' && ref.owner
@@ -131,7 +124,7 @@ module Solargraph
131
124
  # @param ref [String]
132
125
  # @param api_map [ApiMap]
133
126
  # @param skip [Array]
134
- # @return [ComplexType]
127
+ # @return [Array<YARD::Tags::Tag>, nil]
135
128
  def resolve_reference ref, api_map, skip
136
129
  return nil if skip.include?(ref)
137
130
  skip.push ref
@@ -140,7 +133,7 @@ module Solargraph
140
133
  path = "#{namespace}#{ref}"
141
134
  else
142
135
  fqns = api_map.qualify(parts.first, namespace)
143
- return ComplexType::UNDEFINED if fqns.nil?
136
+ return nil if fqns.nil?
144
137
  path = fqns + ref[parts.first.length] + parts.last
145
138
  end
146
139
  pins = api_map.get_path_pins(path)
@@ -19,6 +19,7 @@ module Solargraph
19
19
  autoload :Literal, 'solargraph/source/chain/literal'
20
20
  autoload :Head, 'solargraph/source/chain/head'
21
21
  autoload :Or, 'solargraph/source/chain/or'
22
+ autoload :BlockVariable, 'solargraph/source/chain/block_variable'
22
23
 
23
24
  @@inference_stack = []
24
25
  @@inference_depth = 0
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ class Chain
6
+ class BlockVariable < Link
7
+ def resolve api_map, name_pin, locals
8
+ Pin::ProxyType.anonymous('Proc')
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -48,7 +48,9 @@ module Solargraph
48
48
  return generate_links(n.children[0]) if n.type == :begin
49
49
  result = []
50
50
  if n.type == :block
51
+ @in_block = true
51
52
  result.concat generate_links(n.children[0])
53
+ @in_block = false
52
54
  elsif n.type == :send
53
55
  if n.children[0].is_a?(Parser::AST::Node)
54
56
  result.concat generate_links(n.children[0])
@@ -56,13 +58,13 @@ module Solargraph
56
58
  n.children[2..-1].each do |c|
57
59
  args.push NodeChainer.chain(c)
58
60
  end
59
- result.push Chain::Call.new(n.children[1].to_s, args, @in_block)
61
+ result.push Chain::Call.new(n.children[1].to_s, args, @in_block || block_passed?(n))
60
62
  elsif n.children[0].nil?
61
63
  args = []
62
64
  n.children[2..-1].each do |c|
63
65
  args.push NodeChainer.chain(c)
64
66
  end
65
- result.push Chain::Call.new(n.children[1].to_s, args, @in_block)
67
+ result.push Chain::Call.new(n.children[1].to_s, args, @in_block || block_passed?(n))
66
68
  else
67
69
  raise "No idea what to do with #{n}"
68
70
  end
@@ -92,12 +94,18 @@ module Solargraph
92
94
  result.push Chain::Or.new([NodeChainer.chain(n.children[0], @filename), NodeChainer.chain(n.children[1], @filename)])
93
95
  elsif [:begin, :kwbegin].include?(n.type)
94
96
  result.concat generate_links(n.children[0])
97
+ elsif n.type == :block_pass
98
+ result.push Chain::BlockVariable.new("&#{n.children[0].children[0].to_s}")
95
99
  else
96
100
  lit = infer_literal_node_type(n)
97
101
  result.push (lit ? Chain::Literal.new(lit) : Chain::Link.new)
98
102
  end
99
103
  result
100
104
  end
105
+
106
+ def block_passed? node
107
+ node.children.last.is_a?(Parser::AST::Node) && node.children.last.type == :block_pass
108
+ end
101
109
  end
102
110
  end
103
111
  end
@@ -122,6 +122,8 @@ module Solargraph
122
122
  signature
123
123
  end
124
124
 
125
+ NIL_NODE = Parser::AST::Node.new(:nil)
126
+
125
127
  # Find all the nodes within the provided node that potentially return a
126
128
  # value.
127
129
  #
@@ -129,24 +131,20 @@ module Solargraph
129
131
  # second child (after the :args node) of a :def node. A simple one-line
130
132
  # method would typically return itself, while a node with conditions
131
133
  # would return the resulting node from each conditional branch. Nodes
132
- # that follow a :return node are assumed to be unreachable. Implicit nil
133
- # values are ignored.
134
- #
135
- # @todo Maybe this method should include implicit nil values in results.
136
- # For example, a bare `return` would return a :nil node instead of an
137
- # empty array.
134
+ # that follow a :return node are assumed to be unreachable. Nil values
135
+ # are converted to nil node types.
138
136
  #
139
- # @param node [AST::Node]
140
- # @return [Array<AST::Node>]
137
+ # @param node [Parser::AST::Node]
138
+ # @return [Array<Parser::AST::Node>]
141
139
  def returns_from node
142
- DeepInference.get_return_nodes(node)
140
+ DeepInference.get_return_nodes(node).map { |n| n || NIL_NODE }
143
141
  end
144
142
 
145
143
  module DeepInference
146
144
  class << self
147
145
  CONDITIONAL = [:if, :unless]
148
146
  REDUCEABLE = [:begin, :kwbegin]
149
- SKIPPABLE = [:def, :defs, :class, :sclass, :module, :block]
147
+ SKIPPABLE = [:def, :defs, :class, :sclass, :module]
150
148
 
151
149
  # @param node [Parser::AST::Node]
152
150
  # @return [Array<Parser::AST::Node>]
@@ -162,7 +160,8 @@ module Solargraph
162
160
  elsif node.type == :return
163
161
  result.concat reduce_to_value_nodes([node.children[0]])
164
162
  elsif node.type == :block
165
- result.concat reduce_to_value_nodes(node.children[0..-2])
163
+ result.concat reduce_to_value_nodes([node.children[0]])
164
+ result.concat get_return_nodes_only(node.children[2])
166
165
  else
167
166
  result.push node
168
167
  end
@@ -174,9 +173,12 @@ module Solargraph
174
173
  def get_return_nodes_from_children parent
175
174
  result = []
176
175
  nodes = parent.children.select{|n| n.is_a?(AST::Node)}
177
- nodes[0..-2].each do |node|
178
- next if SKIPPABLE.include?(node.type)
179
- if node.type == :return
176
+ nodes.each_with_index do |node, idx|
177
+ if node.type == :block
178
+ result.concat get_return_nodes_only(node.children[2])
179
+ elsif SKIPPABLE.include?(node.type)
180
+ next
181
+ elsif node.type == :return
180
182
  result.concat reduce_to_value_nodes([node.children[0]])
181
183
  # Return the result here because the rest of the code is
182
184
  # unreachable
@@ -184,8 +186,8 @@ module Solargraph
184
186
  else
185
187
  result.concat get_return_nodes_only(node)
186
188
  end
189
+ result.concat reduce_to_value_nodes([nodes.last]) if idx == nodes.length - 1
187
190
  end
188
- result.concat reduce_to_value_nodes([nodes.last]) unless nodes.last.nil?
189
191
  result
190
192
  end
191
193
 
@@ -41,6 +41,7 @@ module Solargraph
41
41
  node, parent = source.tree_at(position.line, position.column)[0..2]
42
42
  elsif source.parsed? && source.repaired? && end_of_phrase == '.'
43
43
  node, parent = source.tree_at(fixed_position.line, fixed_position.column)[0..2]
44
+ node = Source.parse(fixed_phrase) if node.nil?
44
45
  else
45
46
  node, parent = source.tree_at(fixed_position.line, fixed_position.column)[0..2] unless source.error_ranges.any?{|r| r.nil? || r.include?(fixed_position)}
46
47
  # Exception for positions that chain literal nodes in unsynchronized sources
@@ -53,9 +53,9 @@ module Solargraph
53
53
  type = par.typify(api_map)
54
54
  pdefs = ParamDef.from(par.closure)
55
55
  if type.undefined?
56
- if par.return_type.undefined? && !pdefs.any? { |pd| pd.name == par.name && [:restarg, :kwrestarg].include?(pd.type) }
56
+ if par.return_type.undefined? && !pdefs.any? { |pd| pd.name == par.name && [:restarg, :kwrestarg, :blockarg].include?(pd.type) }
57
57
  result.push Problem.new(par.location, "#{par.closure.name} has undefined @param type for #{par.name}")
58
- elsif !pdefs.any? { |pd| [:restarg, :kwrestarg].include?(pd.type) }
58
+ elsif !pdefs.any? { |pd| [:restarg, :kwrestarg, :blockarg].include?(pd.type) }
59
59
  result.push Problem.new(par.location, "#{par.closure.name} has unresolved @param type for #{par.name}")
60
60
  end
61
61
  end
@@ -40,6 +40,7 @@ module Solargraph
40
40
  return :optarg if string.include?('=')
41
41
  return :kwoptarg if string.end_with?(':')
42
42
  return :kwarg if string =~ /^[a-z0-9_]*?:/
43
+ return :blockarg if string.start_with?('&')
43
44
  :arg
44
45
  end
45
46
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.34.3'
4
+ VERSION = '0.35.0'
5
5
  end
@@ -10,7 +10,7 @@ module Solargraph
10
10
  # The maximum number of files that can be added to a workspace.
11
11
  # The workspace's .solargraph.yml can override this value.
12
12
  MAX_FILES = 5000
13
-
13
+
14
14
  # @return [String]
15
15
  attr_reader :directory
16
16
 
@@ -20,24 +20,7 @@ module Solargraph
20
20
  # @param directory [String]
21
21
  def initialize directory = ''
22
22
  @directory = directory
23
- include_globs = ['**/*.rb']
24
- exclude_globs = ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*']
25
- unless @directory.empty?
26
- sfile = File.join(@directory, '.solargraph.yml')
27
- if File.file?(sfile)
28
- @raw_data = YAML.safe_load(File.read(sfile))
29
- include_globs = @raw_data['include'] || include_globs
30
- exclude_globs = @raw_data['exclude'] || []
31
- end
32
- end
33
- @raw_data ||= {}
34
- @raw_data['include'] ||= include_globs
35
- @raw_data['exclude'] ||= exclude_globs
36
- @raw_data['require'] ||= []
37
- @raw_data['domains'] ||= []
38
- @raw_data['reporters'] ||= %w[rubocop require_not_found]
39
- @raw_data['require_paths'] ||= []
40
- @raw_data['max_files'] ||= MAX_FILES
23
+ @raw_data = config_data
41
24
  included
42
25
  excluded
43
26
  end
@@ -110,6 +93,54 @@ module Solargraph
110
93
  end
111
94
 
112
95
  private
96
+
97
+ # @return [String]
98
+ def global_config_path
99
+ ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
100
+ File.join(Dir.home, '.config', 'solargraph', 'config.yml')
101
+ end
102
+
103
+ # @return [String]
104
+ def workspace_config_path
105
+ return '' if @directory.empty?
106
+ File.join(@directory, '.solargraph.yml')
107
+ end
108
+
109
+ # @return [Hash]
110
+ def config_data
111
+ workspace_config = read_config(workspace_config_path)
112
+ global_config = read_config(global_config_path)
113
+
114
+ defaults = default_config
115
+ defaults.merge({'exclude' => []}) unless workspace_config.nil?
116
+
117
+ defaults
118
+ .merge(global_config || {})
119
+ .merge(workspace_config || {})
120
+ end
121
+
122
+ # Read a .solargraph yaml config
123
+ #
124
+ # @param directory [String]
125
+ # @return [Hash]
126
+ def read_config config_path = ''
127
+ return nil if config_path.empty?
128
+ return nil unless File.file?(config_path)
129
+ YAML.safe_load(File.read(config_path))
130
+ end
131
+
132
+ # @return [Hash]
133
+ def default_config
134
+ {
135
+ 'include' => ['**/*.rb'],
136
+ 'exclude' => ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*'],
137
+ 'require' => [],
138
+ 'domains' => [],
139
+ 'reporters' => %w[rubocop require_not_found],
140
+ 'require_paths' => [],
141
+ 'max_files' => MAX_FILES,
142
+ }
143
+ end
113
144
 
114
145
  # Get an array of files from the provided globs.
115
146
  #
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.34.3
4
+ version: 0.35.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: 2019-07-15 00:00:00.000000000 Z
11
+ date: 2019-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backport
@@ -381,6 +381,7 @@ files:
381
381
  - lib/solargraph/shell.rb
382
382
  - lib/solargraph/source.rb
383
383
  - lib/solargraph/source/chain.rb
384
+ - lib/solargraph/source/chain/block_variable.rb
384
385
  - lib/solargraph/source/chain/call.rb
385
386
  - lib/solargraph/source/chain/class_variable.rb
386
387
  - lib/solargraph/source/chain/constant.rb