solargraph 0.26.1 → 0.27.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 +4 -4
- data/lib/solargraph.rb +5 -2
- data/lib/solargraph/api_map.rb +236 -234
- data/lib/solargraph/api_map/store.rb +18 -53
- data/lib/solargraph/bundle.rb +22 -0
- data/lib/solargraph/complex_type.rb +9 -5
- data/lib/solargraph/complex_type/type_methods.rb +113 -0
- data/lib/solargraph/complex_type/unique_type.rb +35 -0
- data/lib/solargraph/core_fills.rb +1 -0
- data/lib/solargraph/diagnostics.rb +6 -4
- data/lib/solargraph/diagnostics/base.rb +3 -0
- data/lib/solargraph/diagnostics/require_not_found.rb +2 -1
- data/lib/solargraph/diagnostics/rubocop.rb +21 -6
- data/lib/solargraph/diagnostics/type_not_defined.rb +4 -3
- data/lib/solargraph/diagnostics/update_errors.rb +18 -0
- data/lib/solargraph/language_server/host.rb +90 -222
- data/lib/solargraph/language_server/host/cataloger.rb +68 -0
- data/lib/solargraph/language_server/host/diagnoser.rb +85 -0
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +35 -24
- data/lib/solargraph/language_server/message/text_document/completion.rb +6 -8
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +1 -1
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +0 -1
- data/lib/solargraph/language_server/transport/socket.rb +4 -6
- data/lib/solargraph/language_server/transport/stdio.rb +4 -6
- data/lib/solargraph/library.rb +152 -99
- data/lib/solargraph/live_map.rb +1 -1
- data/lib/solargraph/location.rb +28 -0
- data/lib/solargraph/pin.rb +2 -0
- data/lib/solargraph/pin/attribute.rb +26 -12
- data/lib/solargraph/pin/base.rb +15 -35
- data/lib/solargraph/pin/base_variable.rb +7 -15
- data/lib/solargraph/pin/block.rb +5 -9
- data/lib/solargraph/pin/block_parameter.rb +9 -7
- data/lib/solargraph/pin/conversions.rb +5 -5
- data/lib/solargraph/pin/duck_method.rb +1 -1
- data/lib/solargraph/pin/instance_variable.rb +0 -4
- data/lib/solargraph/pin/keyword.rb +4 -0
- data/lib/solargraph/pin/localized.rb +5 -3
- data/lib/solargraph/pin/method.rb +11 -0
- data/lib/solargraph/pin/namespace.rb +7 -3
- data/lib/solargraph/pin/proxy_type.rb +3 -7
- data/lib/solargraph/pin/reference.rb +2 -2
- data/lib/solargraph/pin/symbol.rb +1 -1
- data/lib/solargraph/pin/yard_pin/method.rb +2 -2
- data/lib/solargraph/pin/yard_pin/namespace.rb +16 -7
- data/lib/solargraph/position.rb +103 -0
- data/lib/solargraph/range.rb +70 -0
- data/lib/solargraph/source.rb +159 -328
- data/lib/solargraph/source/chain.rb +38 -55
- data/lib/solargraph/source/chain/call.rb +47 -29
- data/lib/solargraph/source/chain/class_variable.rb +2 -2
- data/lib/solargraph/source/chain/constant.rb +3 -3
- data/lib/solargraph/source/chain/definition.rb +7 -3
- data/lib/solargraph/source/chain/global_variable.rb +1 -1
- data/lib/solargraph/source/chain/head.rb +22 -9
- data/lib/solargraph/source/chain/instance_variable.rb +2 -2
- data/lib/solargraph/source/chain/link.rb +4 -4
- data/lib/solargraph/source/chain/literal.rb +1 -1
- data/lib/solargraph/source/chain/variable.rb +2 -2
- data/lib/solargraph/source/change.rb +0 -6
- data/lib/solargraph/source/cursor.rb +161 -0
- data/lib/solargraph/source/encoding_fixes.rb +1 -1
- data/lib/solargraph/source/node_chainer.rb +28 -21
- data/lib/solargraph/source/node_methods.rb +1 -1
- data/lib/solargraph/source/source_chainer.rb +217 -0
- data/lib/solargraph/source_map.rb +138 -0
- data/lib/solargraph/source_map/clip.rb +123 -0
- data/lib/solargraph/{source → source_map}/completion.rb +3 -3
- data/lib/solargraph/{source → source_map}/mapper.rb +143 -41
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +13 -20
- data/lib/solargraph/yard_map.rb +77 -48
- metadata +17 -11
- data/lib/solargraph/basic_type.rb +0 -33
- data/lib/solargraph/basic_type_methods.rb +0 -111
- data/lib/solargraph/source/call_chainer.rb +0 -273
- data/lib/solargraph/source/fragment.rb +0 -342
- data/lib/solargraph/source/location.rb +0 -23
- data/lib/solargraph/source/position.rb +0 -95
- data/lib/solargraph/source/range.rb +0 -64
@@ -3,41 +3,12 @@ require 'set'
|
|
3
3
|
module Solargraph
|
4
4
|
class ApiMap
|
5
5
|
class Store
|
6
|
-
# @param sources [Array<Solargraph::Source>]
|
7
|
-
# @param yard_pins [Array<Solargraph::Pin::Base>]
|
8
|
-
def initialize sources, yard_pins
|
9
|
-
inner_update sources
|
10
|
-
pins.concat yard_pins
|
11
|
-
index
|
12
|
-
end
|
13
|
-
|
14
6
|
# @return [Array<Solargraph::Pin::Base>]
|
15
|
-
|
16
|
-
@pins ||= []
|
17
|
-
end
|
7
|
+
attr_reader :pins
|
18
8
|
|
19
|
-
# @param
|
20
|
-
|
21
|
-
|
22
|
-
sources.each do |source|
|
23
|
-
pins.delete_if { |pin| !pin.yard_pin? and pin.filename == source.filename }
|
24
|
-
symbols.delete_if { |pin| pin.filename == source.filename }
|
25
|
-
end
|
26
|
-
index
|
27
|
-
end
|
28
|
-
|
29
|
-
# @param *sources [Array<Solargraph::Source>]
|
30
|
-
# @return [void]
|
31
|
-
def update *sources
|
32
|
-
inner_update sources
|
33
|
-
index
|
34
|
-
end
|
35
|
-
|
36
|
-
# @param yard_pins [Array<Solargraph::Pin::Base>]
|
37
|
-
# @return [void]
|
38
|
-
def update_yard yard_pins
|
39
|
-
pins.delete_if(&:yard_pin?)
|
40
|
-
pins.concat yard_pins
|
9
|
+
# @param pins [Array<Solargraph::Source>]
|
10
|
+
def initialize pins = []
|
11
|
+
@pins = pins
|
41
12
|
index
|
42
13
|
end
|
43
14
|
|
@@ -56,17 +27,10 @@ module Solargraph
|
|
56
27
|
# @return [Array<Solargraph::Pin::Base>]
|
57
28
|
def get_methods fqns, scope: :instance, visibility: [:public]
|
58
29
|
namespace_children(fqns).select{ |pin|
|
59
|
-
pin.kind
|
30
|
+
[Pin::METHOD, Pin::ATTRIBUTE].include?(pin.kind) and (pin.scope == scope or fqns == '') and visibility.include?(pin.visibility)
|
60
31
|
}
|
61
32
|
end
|
62
33
|
|
63
|
-
# @param fqns [String]
|
64
|
-
# @param scope [Symbol]
|
65
|
-
# @return [Array<Solargraph::Pin::Base>]
|
66
|
-
def get_attrs fqns, scope
|
67
|
-
namespace_children(fqns).select{ |pin| pin.kind == Pin::ATTRIBUTE and pin.scope == scope }
|
68
|
-
end
|
69
|
-
|
70
34
|
# @param fqns [String]
|
71
35
|
# @return [String]
|
72
36
|
def get_superclass fqns
|
@@ -110,7 +74,7 @@ module Solargraph
|
|
110
74
|
# @param scope [Symbol] :class or :instance
|
111
75
|
# @return [Array<Solargraph::Pin::Base>]
|
112
76
|
def get_instance_variables(fqns, scope = :instance)
|
113
|
-
namespace_children(fqns).select{|pin| pin.kind == Pin::INSTANCE_VARIABLE and pin.scope == scope}
|
77
|
+
namespace_children(fqns).select{|pin| pin.kind == Pin::INSTANCE_VARIABLE and pin.context.scope == scope}
|
114
78
|
end
|
115
79
|
|
116
80
|
# @param fqns [String]
|
@@ -145,6 +109,16 @@ module Solargraph
|
|
145
109
|
@method_pins ||= pins.select{|p| p.kind == Pin::METHOD or p.kind == Pin::ATTRIBUTE}
|
146
110
|
end
|
147
111
|
|
112
|
+
# @param fqns [String]
|
113
|
+
# @return [Array<String>]
|
114
|
+
def domains(fqns)
|
115
|
+
result = []
|
116
|
+
fqns_pins(fqns).each do |nspin|
|
117
|
+
result.concat nspin.domains
|
118
|
+
end
|
119
|
+
result
|
120
|
+
end
|
121
|
+
|
148
122
|
private
|
149
123
|
|
150
124
|
# @param fqns [String]
|
@@ -182,26 +156,17 @@ module Solargraph
|
|
182
156
|
def index
|
183
157
|
namespace_map.clear
|
184
158
|
namespaces.clear
|
159
|
+
symbols.clear
|
185
160
|
namespace_map[''] = []
|
186
161
|
pins.each do |pin|
|
187
162
|
namespace_map[pin.namespace] ||= []
|
188
163
|
namespace_map[pin.namespace].push pin
|
189
164
|
namespaces.add pin.path if pin.kind == Pin::NAMESPACE and !pin.path.empty?
|
165
|
+
symbols.push pin if pin.kind == Pin::SYMBOL
|
190
166
|
end
|
191
167
|
@namespace_pins = nil
|
192
168
|
@method_pins = nil
|
193
169
|
end
|
194
|
-
|
195
|
-
# @param sources [Array<Solargraph::Source>]
|
196
|
-
# @return [void]
|
197
|
-
def inner_update sources
|
198
|
-
sources.each do |source|
|
199
|
-
pins.delete_if { |pin| !pin.yard_pin? and pin.filename == source.filename }
|
200
|
-
symbols.delete_if { |pin| pin.filename == source.filename }
|
201
|
-
pins.concat source.pins
|
202
|
-
symbols.concat source.symbols
|
203
|
-
end
|
204
|
-
end
|
205
170
|
end
|
206
171
|
end
|
207
172
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Solargraph
|
2
|
+
class Bundle
|
3
|
+
# @return [Array<Source>]
|
4
|
+
attr_reader :sources
|
5
|
+
|
6
|
+
# @return [Array<String>]
|
7
|
+
attr_reader :required
|
8
|
+
|
9
|
+
# @return [Array<String>]
|
10
|
+
attr_reader :load_paths
|
11
|
+
|
12
|
+
# @return [YardMap]
|
13
|
+
attr_reader :yard_map
|
14
|
+
|
15
|
+
def initialize sources: [], required: [], load_paths: [], yard_map: YardMap.new
|
16
|
+
@sources = sources
|
17
|
+
@required = required
|
18
|
+
@load_paths = load_paths
|
19
|
+
@yard_map = yard_map
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -4,8 +4,11 @@ module Solargraph
|
|
4
4
|
# including the module. One possibility:
|
5
5
|
#
|
6
6
|
# @!parse
|
7
|
-
# include
|
7
|
+
# include TypeMethods
|
8
8
|
|
9
|
+
autoload :TypeMethods, 'solargraph/complex_type/type_methods'
|
10
|
+
autoload :UniqueType, 'solargraph/complex_type/unique_type'
|
11
|
+
|
9
12
|
def initialize types = [ComplexType::UNDEFINED]
|
10
13
|
super()
|
11
14
|
concat types
|
@@ -24,7 +27,7 @@ module Solargraph
|
|
24
27
|
end
|
25
28
|
|
26
29
|
def respond_to_missing?(name, include_private = false)
|
27
|
-
|
30
|
+
TypeMethods.public_instance_methods.include?(name) || super
|
28
31
|
end
|
29
32
|
|
30
33
|
def to_s
|
@@ -71,7 +74,7 @@ module Solargraph
|
|
71
74
|
subtype_string += char
|
72
75
|
elsif base.end_with?('=')
|
73
76
|
raise ComplexTypeError, "Invalid hash thing" unless key_types.nil?
|
74
|
-
types.push ComplexType.new([
|
77
|
+
types.push ComplexType.new([UniqueType.new(base[0..-2].strip)])
|
75
78
|
key_types = types
|
76
79
|
types = []
|
77
80
|
base = ''
|
@@ -99,7 +102,7 @@ module Solargraph
|
|
99
102
|
raise ComplexTypeError, "Invalid close in type #{type_string}" if paren_stack < 0
|
100
103
|
next
|
101
104
|
elsif char == ',' and point_stack == 0 and curly_stack == 0 and paren_stack == 0
|
102
|
-
types.push ComplexType.new([
|
105
|
+
types.push ComplexType.new([UniqueType.new(base.strip, subtype_string.strip)])
|
103
106
|
base = ''
|
104
107
|
subtype_string = ''
|
105
108
|
next
|
@@ -113,7 +116,7 @@ module Solargraph
|
|
113
116
|
base.strip!
|
114
117
|
subtype_string.strip!
|
115
118
|
raise ComplexTypeError, "Unclosed subtype in #{type_string}" if point_stack != 0 or curly_stack != 0 or paren_stack != 0
|
116
|
-
types.push ComplexType.new([
|
119
|
+
types.push ComplexType.new([UniqueType.new(base, subtype_string)])
|
117
120
|
end
|
118
121
|
unless key_types.nil?
|
119
122
|
raise ComplexTypeError, "Invalid use of key/value parameters" unless partial
|
@@ -129,5 +132,6 @@ module Solargraph
|
|
129
132
|
VOID = ComplexType.parse('void')
|
130
133
|
UNDEFINED = ComplexType.parse('undefined')
|
131
134
|
SYMBOL = ComplexType.parse('Symbol')
|
135
|
+
ROOT = ComplexType.parse('Class<>')
|
132
136
|
end
|
133
137
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Solargraph
|
2
|
+
class ComplexType
|
3
|
+
module TypeMethods
|
4
|
+
# @return [String]
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
# @return [String]
|
8
|
+
attr_reader :substring
|
9
|
+
|
10
|
+
# @return [String]
|
11
|
+
attr_reader :tag
|
12
|
+
|
13
|
+
# @return [Array<ComplexType>]
|
14
|
+
attr_reader :subtypes
|
15
|
+
|
16
|
+
# @return [Boolean]
|
17
|
+
def duck_type?
|
18
|
+
@duck_type ||= name.start_with?('#')
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Boolean]
|
22
|
+
def nil_type?
|
23
|
+
@nil_type ||= (name.downcase == 'nil')
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Boolean]
|
27
|
+
def parameters?
|
28
|
+
!substring.empty?
|
29
|
+
end
|
30
|
+
|
31
|
+
def void?
|
32
|
+
name == 'void'
|
33
|
+
end
|
34
|
+
|
35
|
+
def defined?
|
36
|
+
!undefined?
|
37
|
+
end
|
38
|
+
|
39
|
+
def undefined?
|
40
|
+
name == 'undefined'
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [Boolean]
|
44
|
+
def list_parameters?
|
45
|
+
substring.start_with?('<')
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [Boolean]
|
49
|
+
def fixed_parameters?
|
50
|
+
substring.start_with?('(')
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [Boolean]
|
54
|
+
def hash_parameters?
|
55
|
+
substring.start_with?('{')
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [Array<ComplexType>]
|
59
|
+
def value_types
|
60
|
+
@subtypes
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [Array<ComplexType>]
|
64
|
+
def key_types
|
65
|
+
@key_types
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [String]
|
69
|
+
def namespace
|
70
|
+
@namespace ||= 'Object' if duck_type?
|
71
|
+
@namespace ||= 'NilClass' if nil_type?
|
72
|
+
@namespace ||= ((name == 'Class' or name == 'Module') and !subtypes.empty?) ? subtypes.first.name : name
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [Symbol] :class or :instance
|
76
|
+
def scope
|
77
|
+
@scope ||= :instance if duck_type? or nil_type?
|
78
|
+
@scope ||= ((name == 'Class' or name == 'Module') and !subtypes.empty?) ? :class : :instance
|
79
|
+
end
|
80
|
+
|
81
|
+
def == other
|
82
|
+
return false unless self.class == other.class
|
83
|
+
tag == other.tag
|
84
|
+
end
|
85
|
+
|
86
|
+
# Generate a ComplexType that fully qualifies this type's namespaces.
|
87
|
+
#
|
88
|
+
# @param api_map [ApiMap] The ApiMap that performs qualification
|
89
|
+
# @param context [String] The namespace from which to resolve names
|
90
|
+
# @return [ComplexType] The generated ComplexType
|
91
|
+
def qualify api_map, context = ''
|
92
|
+
return ComplexType.parse(tag) if duck_type? or void? or undefined?
|
93
|
+
fqns = api_map.qualify(name, context)
|
94
|
+
return ComplexType::UNDEFINED if fqns.nil?
|
95
|
+
ltypes = key_types.map do |t|
|
96
|
+
t.qualify api_map, context
|
97
|
+
end
|
98
|
+
rtypes = value_types.map do |t|
|
99
|
+
t.qualify api_map, context
|
100
|
+
end
|
101
|
+
if list_parameters?
|
102
|
+
Solargraph::ComplexType.parse("#{fqns}<#{rtypes.map(&:tag).join(', ')}>").first
|
103
|
+
elsif fixed_parameters?
|
104
|
+
Solargraph::ComplexType.parse("#{fqns}(#{rtypes.map(&:tag).join(', ')})").first
|
105
|
+
elsif hash_parameters?
|
106
|
+
Solargraph::ComplexType.parse("#{fqns}{#{ltypes.map(&:tag).join(', ')} => #{rtypes.map(&:tag).join(', ')}}").first
|
107
|
+
else
|
108
|
+
Solargraph::ComplexType.parse(fqns).first
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Solargraph
|
2
|
+
class ComplexType
|
3
|
+
class UniqueType
|
4
|
+
include TypeMethods
|
5
|
+
|
6
|
+
# Create a BasicType with the specified name and an optional substring.
|
7
|
+
# The substring is the parameter section of a parametrized type, e.g., for
|
8
|
+
# the type `Array<String>`, the name is `Array` and the substring is
|
9
|
+
# `<String>`.
|
10
|
+
#
|
11
|
+
# @param name [String] The name of the type
|
12
|
+
# @param substring [String] The substring of the type
|
13
|
+
def initialize name, substring = ''
|
14
|
+
@name = name
|
15
|
+
@substring = substring
|
16
|
+
@tag = name + substring
|
17
|
+
@key_types = []
|
18
|
+
@subtypes = []
|
19
|
+
return unless parameters?
|
20
|
+
subs = ComplexType.parse(substring[1..-2], partial: true)
|
21
|
+
if hash_parameters?
|
22
|
+
raise ComplexTypeError, "Bad hash type" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(ComplexType) and !subs[1].is_a?(ComplexType)
|
23
|
+
@key_types.concat subs[0]
|
24
|
+
@subtypes.concat subs[1]
|
25
|
+
else
|
26
|
+
@subtypes.concat subs
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
tag
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -3,11 +3,12 @@ module Solargraph
|
|
3
3
|
# and providing the results to language server clients.
|
4
4
|
#
|
5
5
|
module Diagnostics
|
6
|
-
autoload :Base,
|
7
|
-
autoload :Severities,
|
8
|
-
autoload :Rubocop,
|
6
|
+
autoload :Base, 'solargraph/diagnostics/base'
|
7
|
+
autoload :Severities, 'solargraph/diagnostics/severities'
|
8
|
+
autoload :Rubocop, 'solargraph/diagnostics/rubocop'
|
9
9
|
autoload :RequireNotFound, 'solargraph/diagnostics/require_not_found'
|
10
|
-
autoload :TypeNotDefined,
|
10
|
+
autoload :TypeNotDefined, 'solargraph/diagnostics/type_not_defined'
|
11
|
+
autoload :UpdateErrors, 'solargraph/diagnostics/update_errors'
|
11
12
|
|
12
13
|
class << self
|
13
14
|
# Add a reporter with a name to identify it in .solargraph.yml files.
|
@@ -44,5 +45,6 @@ module Solargraph
|
|
44
45
|
register 'rubocop', Rubocop
|
45
46
|
register 'require_not_found', RequireNotFound
|
46
47
|
register 'type_not_defined', TypeNotDefined
|
48
|
+
register 'update_errors', UpdateErrors
|
47
49
|
end
|
48
50
|
end
|
@@ -5,10 +5,13 @@ module Solargraph
|
|
5
5
|
# The result is an array of hash objects that conform to the LSP's
|
6
6
|
# Diagnostic specification.
|
7
7
|
#
|
8
|
+
# Subclasses should override this method.
|
9
|
+
#
|
8
10
|
# @param source [Solargraph::Source]
|
9
11
|
# @param api_map [Solargraph::ApiMap]
|
10
12
|
# @return [Array<Hash>]
|
11
13
|
def diagnose source, api_map
|
14
|
+
[]
|
12
15
|
end
|
13
16
|
end
|
14
17
|
end
|
@@ -20,7 +20,7 @@ module Solargraph
|
|
20
20
|
# @return [Array<Hash>]
|
21
21
|
def diagnose source, api_map
|
22
22
|
begin
|
23
|
-
options, paths = generate_options(
|
23
|
+
options, paths = generate_options(source.filename, source.code)
|
24
24
|
runner = RuboCop::Runner.new(options, RuboCop::ConfigStore.new)
|
25
25
|
result = redirect_stdout{ runner.run(paths) }
|
26
26
|
make_array JSON.parse(result)
|
@@ -35,18 +35,33 @@ module Solargraph
|
|
35
35
|
# @param filename [String]
|
36
36
|
# @param code [String]
|
37
37
|
# @return [Array]
|
38
|
-
def generate_options workspace, filename, code
|
38
|
+
# def generate_options workspace, filename, code
|
39
|
+
def generate_options filename, code
|
39
40
|
args = ['-f', 'j']
|
40
|
-
|
41
|
-
|
42
|
-
args.push('-c', fix_drive_letter(rc)) if File.file?(rc)
|
43
|
-
end
|
41
|
+
rubocop_file = find_rubocop_file(filename)
|
42
|
+
args.push('-c', fix_drive_letter(rubocop_file)) unless rubocop_file.nil?
|
44
43
|
args.push filename
|
45
44
|
options, paths = RuboCop::Options.new.parse(args)
|
46
45
|
options[:stdin] = code
|
47
46
|
[options, paths]
|
48
47
|
end
|
49
48
|
|
49
|
+
def find_rubocop_file filename
|
50
|
+
rcfile = nil
|
51
|
+
dir = File.dirname(filename)
|
52
|
+
while rcfile.nil?
|
53
|
+
here = File.join(dir, '.rubocop.yml')
|
54
|
+
if File.exist?(here)
|
55
|
+
rcfile = here
|
56
|
+
break
|
57
|
+
else
|
58
|
+
break if File.dirname(dir) == dir
|
59
|
+
dir = File.dirname(dir)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
rcfile
|
63
|
+
end
|
64
|
+
|
50
65
|
# @todo This is a smelly way to redirect output, but the RuboCop specs do the
|
51
66
|
# same thing.
|
52
67
|
# @return [String]
|