solargraph 0.32.1 → 0.32.2

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.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +6 -0
  5. data/.travis.yml +25 -0
  6. data/EXAMPLES.md +76 -0
  7. data/Gemfile +3 -0
  8. data/LANGUAGE_SERVER.md +51 -0
  9. data/LICENSE +21 -0
  10. data/OVERVIEW.md +37 -0
  11. data/README.md +106 -0
  12. data/Rakefile +14 -0
  13. data/SERVER.md +95 -0
  14. data/bin/solargraph +0 -0
  15. data/bin/solargraph-runtime +5 -5
  16. data/lib/solargraph.rb +54 -54
  17. data/lib/solargraph/api_map.rb +659 -659
  18. data/lib/solargraph/api_map/cache.rb +49 -49
  19. data/lib/solargraph/api_map/source_to_yard.rb +67 -67
  20. data/lib/solargraph/api_map/store.rb +201 -201
  21. data/lib/solargraph/bundle.rb +24 -24
  22. data/lib/solargraph/complex_type.rb +150 -150
  23. data/lib/solargraph/complex_type/type_methods.rb +124 -124
  24. data/lib/solargraph/complex_type/unique_type.rb +44 -44
  25. data/lib/solargraph/core_fills.rb +37 -37
  26. data/lib/solargraph/diagnostics.rb +52 -52
  27. data/lib/solargraph/diagnostics/base.rb +20 -20
  28. data/lib/solargraph/diagnostics/require_not_found.rb +28 -28
  29. data/lib/solargraph/diagnostics/rubocop.rb +98 -98
  30. data/lib/solargraph/diagnostics/rubocop_helpers.rb +46 -46
  31. data/lib/solargraph/diagnostics/type_not_defined.rb +108 -108
  32. data/lib/solargraph/diagnostics/update_errors.rb +38 -38
  33. data/lib/solargraph/language_server/completion_item_kinds.rb +33 -33
  34. data/lib/solargraph/language_server/error_codes.rb +18 -18
  35. data/lib/solargraph/language_server/host.rb +684 -681
  36. data/lib/solargraph/language_server/host/cataloger.rb +54 -79
  37. data/lib/solargraph/language_server/host/diagnoser.rb +80 -80
  38. data/lib/solargraph/language_server/host/dispatch.rb +112 -113
  39. data/lib/solargraph/language_server/host/sources.rb +138 -138
  40. data/lib/solargraph/language_server/message.rb +90 -90
  41. data/lib/solargraph/language_server/message/base.rb +83 -83
  42. data/lib/solargraph/language_server/message/completion_item/resolve.rb +40 -40
  43. data/lib/solargraph/language_server/message/exit_notification.rb +11 -11
  44. data/lib/solargraph/language_server/message/extended.rb +19 -19
  45. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +86 -86
  46. data/lib/solargraph/language_server/message/extended/document.rb +18 -18
  47. data/lib/solargraph/language_server/message/extended/document_gems.rb +30 -30
  48. data/lib/solargraph/language_server/message/extended/environment.rb +20 -20
  49. data/lib/solargraph/language_server/message/extended/search.rb +18 -18
  50. data/lib/solargraph/language_server/message/initialize.rb +141 -141
  51. data/lib/solargraph/language_server/message/initialized.rb +23 -23
  52. data/lib/solargraph/language_server/message/shutdown.rb +11 -11
  53. data/lib/solargraph/language_server/message/text_document.rb +25 -25
  54. data/lib/solargraph/language_server/message/text_document/completion.rb +51 -51
  55. data/lib/solargraph/language_server/message/text_document/definition.rb +18 -18
  56. data/lib/solargraph/language_server/message/text_document/did_change.rb +13 -13
  57. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +21 -21
  58. data/lib/solargraph/language_server/message/text_document/folding_range.rb +24 -24
  59. data/lib/solargraph/language_server/message/text_document/formatting.rb +50 -50
  60. data/lib/solargraph/language_server/message/text_document/hover.rb +31 -31
  61. data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +32 -32
  62. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +9 -9
  63. data/lib/solargraph/language_server/message/text_document/references.rb +14 -14
  64. data/lib/solargraph/language_server/message/text_document/rename.rb +17 -17
  65. data/lib/solargraph/language_server/message/text_document/signature_help.rb +19 -19
  66. data/lib/solargraph/language_server/message/workspace.rb +12 -12
  67. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +29 -29
  68. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +29 -27
  69. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +24 -24
  70. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +21 -21
  71. data/lib/solargraph/language_server/request.rb +22 -22
  72. data/lib/solargraph/language_server/symbol_kinds.rb +34 -34
  73. data/lib/solargraph/language_server/transport.rb +11 -11
  74. data/lib/solargraph/language_server/transport/adapter.rb +60 -60
  75. data/lib/solargraph/language_server/transport/data_reader.rb +66 -66
  76. data/lib/solargraph/language_server/uri_helpers.rb +25 -25
  77. data/lib/solargraph/library.rb +421 -419
  78. data/lib/solargraph/live_map.rb +126 -126
  79. data/lib/solargraph/live_map/cache.rb +38 -38
  80. data/lib/solargraph/location.rb +31 -31
  81. data/lib/solargraph/logging.rb +25 -25
  82. data/lib/solargraph/page.rb +68 -68
  83. data/lib/solargraph/pin.rb +50 -50
  84. data/lib/solargraph/pin/attribute.rb +41 -41
  85. data/lib/solargraph/pin/base.rb +280 -280
  86. data/lib/solargraph/pin/base_method.rb +76 -76
  87. data/lib/solargraph/pin/base_variable.rb +72 -72
  88. data/lib/solargraph/pin/block.rb +32 -32
  89. data/lib/solargraph/pin/block_parameter.rb +103 -103
  90. data/lib/solargraph/pin/class_variable.rb +9 -9
  91. data/lib/solargraph/pin/constant.rb +30 -30
  92. data/lib/solargraph/pin/conversions.rb +79 -79
  93. data/lib/solargraph/pin/documenting.rb +41 -41
  94. data/lib/solargraph/pin/duck_method.rb +14 -14
  95. data/lib/solargraph/pin/global_variable.rb +9 -9
  96. data/lib/solargraph/pin/instance_variable.rb +9 -9
  97. data/lib/solargraph/pin/keyword.rb +17 -17
  98. data/lib/solargraph/pin/local_variable.rb +23 -23
  99. data/lib/solargraph/pin/localized.rb +22 -22
  100. data/lib/solargraph/pin/method.rb +126 -126
  101. data/lib/solargraph/pin/method_alias.rb +30 -30
  102. data/lib/solargraph/pin/method_parameter.rb +40 -40
  103. data/lib/solargraph/pin/namespace.rb +54 -54
  104. data/lib/solargraph/pin/plugin/method.rb +25 -25
  105. data/lib/solargraph/pin/proxy_type.rb +35 -35
  106. data/lib/solargraph/pin/reference.rb +22 -22
  107. data/lib/solargraph/pin/reference/extend.rb +11 -11
  108. data/lib/solargraph/pin/reference/include.rb +11 -11
  109. data/lib/solargraph/pin/reference/require.rb +15 -15
  110. data/lib/solargraph/pin/reference/superclass.rb +11 -11
  111. data/lib/solargraph/pin/symbol.rb +44 -44
  112. data/lib/solargraph/pin/yard_pin.rb +10 -10
  113. data/lib/solargraph/pin/yard_pin/constant.rb +14 -14
  114. data/lib/solargraph/pin/yard_pin/method.rb +35 -35
  115. data/lib/solargraph/pin/yard_pin/namespace.rb +19 -19
  116. data/lib/solargraph/pin/yard_pin/yard_mixin.rb +14 -14
  117. data/lib/solargraph/plugin.rb +8 -8
  118. data/lib/solargraph/plugin/base.rb +41 -41
  119. data/lib/solargraph/plugin/canceler.rb +11 -11
  120. data/lib/solargraph/plugin/process.rb +172 -172
  121. data/lib/solargraph/plugin/runtime.rb +134 -134
  122. data/lib/solargraph/position.rb +110 -110
  123. data/lib/solargraph/range.rb +83 -83
  124. data/lib/solargraph/server_methods.rb +14 -14
  125. data/lib/solargraph/shell.rb +102 -102
  126. data/lib/solargraph/source.rb +521 -521
  127. data/lib/solargraph/source/chain.rb +120 -120
  128. data/lib/solargraph/source/chain/call.rb +107 -107
  129. data/lib/solargraph/source/chain/class_variable.rb +11 -11
  130. data/lib/solargraph/source/chain/constant.rb +30 -30
  131. data/lib/solargraph/source/chain/global_variable.rb +11 -11
  132. data/lib/solargraph/source/chain/head.rb +33 -33
  133. data/lib/solargraph/source/chain/instance_variable.rb +11 -11
  134. data/lib/solargraph/source/chain/link.rb +33 -33
  135. data/lib/solargraph/source/chain/literal.rb +21 -21
  136. data/lib/solargraph/source/chain/variable.rb +11 -11
  137. data/lib/solargraph/source/change.rb +77 -77
  138. data/lib/solargraph/source/cursor.rb +157 -157
  139. data/lib/solargraph/source/node_chainer.rb +96 -96
  140. data/lib/solargraph/source/node_methods.rb +225 -225
  141. data/lib/solargraph/source/source_chainer.rb +183 -183
  142. data/lib/solargraph/source_map.rb +169 -169
  143. data/lib/solargraph/source_map/clip.rb +145 -145
  144. data/lib/solargraph/source_map/completion.rb +21 -21
  145. data/lib/solargraph/source_map/mapper.rb +149 -149
  146. data/lib/solargraph/source_map/node_processor.rb +78 -78
  147. data/lib/solargraph/source_map/node_processor/alias_node.rb +19 -19
  148. data/lib/solargraph/source_map/node_processor/args_node.rb +28 -28
  149. data/lib/solargraph/source_map/node_processor/base.rb +68 -68
  150. data/lib/solargraph/source_map/node_processor/begin_node.rb +11 -11
  151. data/lib/solargraph/source_map/node_processor/block_node.rb +14 -14
  152. data/lib/solargraph/source_map/node_processor/casgn_node.rb +14 -14
  153. data/lib/solargraph/source_map/node_processor/cvasgn_node.rb +14 -14
  154. data/lib/solargraph/source_map/node_processor/def_node.rb +54 -54
  155. data/lib/solargraph/source_map/node_processor/defs_node.rb +21 -21
  156. data/lib/solargraph/source_map/node_processor/gvasgn_node.rb +12 -12
  157. data/lib/solargraph/source_map/node_processor/ivasgn_node.rb +18 -18
  158. data/lib/solargraph/source_map/node_processor/lvasgn_node.rb +16 -16
  159. data/lib/solargraph/source_map/node_processor/namespace_node.rb +26 -26
  160. data/lib/solargraph/source_map/node_processor/orasgn_node.rb +12 -12
  161. data/lib/solargraph/source_map/node_processor/sclass_node.rb +11 -11
  162. data/lib/solargraph/source_map/node_processor/send_node.rb +162 -162
  163. data/lib/solargraph/source_map/node_processor/sym_node.rb +11 -11
  164. data/lib/solargraph/source_map/region.rb +58 -58
  165. data/lib/solargraph/version.rb +3 -3
  166. data/lib/solargraph/views/environment.erb +53 -53
  167. data/lib/solargraph/workspace.rb +183 -183
  168. data/lib/solargraph/workspace/config.rb +170 -170
  169. data/lib/solargraph/yard_map.rb +298 -298
  170. data/lib/solargraph/yard_map/cache.rb +17 -17
  171. data/lib/solargraph/yard_map/core_docs.rb +163 -163
  172. data/lib/solargraph/yard_map/core_gen.rb +76 -76
  173. data/lib/yard-coregen.rb +16 -16
  174. data/lib/yard-solargraph.rb +18 -18
  175. data/solargraph.gemspec +37 -0
  176. data/travis-bundler.rb +10 -0
  177. metadata +19 -6
@@ -1,170 +1,170 @@
1
- require 'yaml'
2
-
3
- module Solargraph
4
- class Workspace
5
- # Configuration data for a workspace.
6
- #
7
- class Config
8
- # The maximum number of files that can be added to a workspace.
9
- # The workspace's .solargraph.yml can override this value.
10
- MAX_FILES = 5000
11
-
12
- # @return [String]
13
- attr_reader :directory
14
-
15
- # @return [Hash]
16
- attr_reader :raw_data
17
-
18
- # @param directory [String]
19
- def initialize directory = ''
20
- @directory = directory
21
- include_globs = ['**/*.rb']
22
- exclude_globs = ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*']
23
- unless @directory.empty?
24
- sfile = File.join(@directory, '.solargraph.yml')
25
- if File.file?(sfile)
26
- @raw_data = YAML.safe_load(File.read(sfile))
27
- include_globs = @raw_data['include'] || include_globs
28
- exclude_globs = @raw_data['exclude'] || []
29
- end
30
- end
31
- @raw_data ||= {}
32
- @raw_data['include'] ||= include_globs
33
- @raw_data['exclude'] ||= exclude_globs
34
- @raw_data['require'] ||= []
35
- @raw_data['domains'] ||= []
36
- @raw_data['reporters'] ||= %w[rubocop require_not_found]
37
- @raw_data['plugins'] ||= []
38
- @raw_data['require_paths'] ||= []
39
- @raw_data['max_files'] ||= MAX_FILES
40
- included
41
- excluded
42
- end
43
-
44
- # An array of files included in the workspace (before calculating excluded files).
45
- #
46
- # @return [Array<String>]
47
- def included
48
- return [] if directory.empty? || directory == '*'
49
- @included ||= process_globs(@raw_data['include'])
50
- end
51
-
52
- # An array of files excluded from the workspace.
53
- #
54
- # @return [Array<String>]
55
- def excluded
56
- return [] if directory.empty? || directory == '*'
57
- @excluded ||= process_exclusions(@raw_data['exclude'])
58
- end
59
-
60
- # The calculated array of (included - excluded) files in the workspace.
61
- #
62
- # @return [Array<String>]
63
- def calculated
64
- Solargraph.logger.info "Indexing workspace files in #{directory}" unless @calculated || directory.empty? || directory == '*'
65
- @calculated ||= included - excluded
66
- end
67
-
68
- # An array of domains configured for the workspace.
69
- # A domain is a namespace that the ApiMap should include in the global
70
- # namespace. It's typically used to identify available DSLs.
71
- #
72
- # @return [Array<String>]
73
- def domains
74
- raw_data['domains']
75
- end
76
-
77
- # An array of required paths to add to the workspace.
78
- #
79
- # @return [Array<String>]
80
- def required
81
- raw_data['require']
82
- end
83
-
84
- # An array of load paths for required paths.
85
- #
86
- # @return [Array<String>]
87
- def require_paths
88
- raw_data['require_paths'] || []
89
- end
90
-
91
- # An array of Solargraph plugins to install.
92
- #
93
- # @return [Array<String>]
94
- def plugins
95
- raw_data['plugins']
96
- end
97
-
98
- # An array of reporters to use for diagnostics.
99
- #
100
- # @return [Array<String>]
101
- def reporters
102
- raw_data['reporters']
103
- end
104
-
105
- # The maximum number of files to parse from the workspace.
106
- #
107
- # @return [Integer]
108
- def max_files
109
- raw_data['max_files']
110
- end
111
-
112
- private
113
-
114
- # Get an array of files from the provided globs.
115
- #
116
- # @param globs [Array<String>]
117
- # @return [Array<String>]
118
- def process_globs globs
119
- result = []
120
- globs.each do |glob|
121
- result.concat Dir[File.join directory, glob].map{ |f| f.gsub(/\\/, '/') }
122
- end
123
- result
124
- end
125
-
126
- # Modify the included files based on excluded directories and get an
127
- # array of additional files to exclude.
128
- #
129
- # @param globs [Array<String>]
130
- # @return [Array<String>]
131
- def process_exclusions globs
132
- remainder = globs.select do |glob|
133
- if glob_is_directory?(glob)
134
- exdir = File.join(directory, glob_to_directory(glob))
135
- included.delete_if { |file| file.start_with?(exdir) }
136
- false
137
- else
138
- true
139
- end
140
- end
141
- process_globs remainder
142
- end
143
-
144
- # True if the glob translates to a whole directory.
145
- #
146
- # @example
147
- # glob_is_directory?('path/to/dir') # => true
148
- # glob_is_directory?('path/to/dir/**/*) # => true
149
- # glob_is_directory?('path/to/file.txt') # => false
150
- # glob_is_directory?('path/to/*.txt') # => false
151
- #
152
- # @param glob [String]
153
- # @return [Boolean]
154
- def glob_is_directory? glob
155
- File.directory?(glob) || File.directory?(glob_to_directory(glob))
156
- end
157
-
158
- # Translate a glob to a base directory if applicable
159
- #
160
- # @example
161
- # glob_to_directory('path/to/dir/**/*') # => 'path/to/dir'
162
- #
163
- # @param glob [String]
164
- # @return [String]
165
- def glob_to_directory glob
166
- glob.gsub(/(\/\*|\/\*\*\/\*\*?)$/, '')
167
- end
168
- end
169
- end
170
- end
1
+ require 'yaml'
2
+
3
+ module Solargraph
4
+ class Workspace
5
+ # Configuration data for a workspace.
6
+ #
7
+ class Config
8
+ # The maximum number of files that can be added to a workspace.
9
+ # The workspace's .solargraph.yml can override this value.
10
+ MAX_FILES = 5000
11
+
12
+ # @return [String]
13
+ attr_reader :directory
14
+
15
+ # @return [Hash]
16
+ attr_reader :raw_data
17
+
18
+ # @param directory [String]
19
+ def initialize directory = ''
20
+ @directory = directory
21
+ include_globs = ['**/*.rb']
22
+ exclude_globs = ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*']
23
+ unless @directory.empty?
24
+ sfile = File.join(@directory, '.solargraph.yml')
25
+ if File.file?(sfile)
26
+ @raw_data = YAML.safe_load(File.read(sfile))
27
+ include_globs = @raw_data['include'] || include_globs
28
+ exclude_globs = @raw_data['exclude'] || []
29
+ end
30
+ end
31
+ @raw_data ||= {}
32
+ @raw_data['include'] ||= include_globs
33
+ @raw_data['exclude'] ||= exclude_globs
34
+ @raw_data['require'] ||= []
35
+ @raw_data['domains'] ||= []
36
+ @raw_data['reporters'] ||= %w[rubocop require_not_found]
37
+ @raw_data['plugins'] ||= []
38
+ @raw_data['require_paths'] ||= []
39
+ @raw_data['max_files'] ||= MAX_FILES
40
+ included
41
+ excluded
42
+ end
43
+
44
+ # An array of files included in the workspace (before calculating excluded files).
45
+ #
46
+ # @return [Array<String>]
47
+ def included
48
+ return [] if directory.empty? || directory == '*'
49
+ @included ||= process_globs(@raw_data['include'])
50
+ end
51
+
52
+ # An array of files excluded from the workspace.
53
+ #
54
+ # @return [Array<String>]
55
+ def excluded
56
+ return [] if directory.empty? || directory == '*'
57
+ @excluded ||= process_exclusions(@raw_data['exclude'])
58
+ end
59
+
60
+ # The calculated array of (included - excluded) files in the workspace.
61
+ #
62
+ # @return [Array<String>]
63
+ def calculated
64
+ Solargraph.logger.info "Indexing workspace files in #{directory}" unless @calculated || directory.empty? || directory == '*'
65
+ @calculated ||= included - excluded
66
+ end
67
+
68
+ # An array of domains configured for the workspace.
69
+ # A domain is a namespace that the ApiMap should include in the global
70
+ # namespace. It's typically used to identify available DSLs.
71
+ #
72
+ # @return [Array<String>]
73
+ def domains
74
+ raw_data['domains']
75
+ end
76
+
77
+ # An array of required paths to add to the workspace.
78
+ #
79
+ # @return [Array<String>]
80
+ def required
81
+ raw_data['require']
82
+ end
83
+
84
+ # An array of load paths for required paths.
85
+ #
86
+ # @return [Array<String>]
87
+ def require_paths
88
+ raw_data['require_paths'] || []
89
+ end
90
+
91
+ # An array of Solargraph plugins to install.
92
+ #
93
+ # @return [Array<String>]
94
+ def plugins
95
+ raw_data['plugins']
96
+ end
97
+
98
+ # An array of reporters to use for diagnostics.
99
+ #
100
+ # @return [Array<String>]
101
+ def reporters
102
+ raw_data['reporters']
103
+ end
104
+
105
+ # The maximum number of files to parse from the workspace.
106
+ #
107
+ # @return [Integer]
108
+ def max_files
109
+ raw_data['max_files']
110
+ end
111
+
112
+ private
113
+
114
+ # Get an array of files from the provided globs.
115
+ #
116
+ # @param globs [Array<String>]
117
+ # @return [Array<String>]
118
+ def process_globs globs
119
+ result = []
120
+ globs.each do |glob|
121
+ result.concat Dir[File.join directory, glob].map{ |f| f.gsub(/\\/, '/') }
122
+ end
123
+ result
124
+ end
125
+
126
+ # Modify the included files based on excluded directories and get an
127
+ # array of additional files to exclude.
128
+ #
129
+ # @param globs [Array<String>]
130
+ # @return [Array<String>]
131
+ def process_exclusions globs
132
+ remainder = globs.select do |glob|
133
+ if glob_is_directory?(glob)
134
+ exdir = File.join(directory, glob_to_directory(glob))
135
+ included.delete_if { |file| file.start_with?(exdir) }
136
+ false
137
+ else
138
+ true
139
+ end
140
+ end
141
+ process_globs remainder
142
+ end
143
+
144
+ # True if the glob translates to a whole directory.
145
+ #
146
+ # @example
147
+ # glob_is_directory?('path/to/dir') # => true
148
+ # glob_is_directory?('path/to/dir/**/*) # => true
149
+ # glob_is_directory?('path/to/file.txt') # => false
150
+ # glob_is_directory?('path/to/*.txt') # => false
151
+ #
152
+ # @param glob [String]
153
+ # @return [Boolean]
154
+ def glob_is_directory? glob
155
+ File.directory?(glob) || File.directory?(glob_to_directory(glob))
156
+ end
157
+
158
+ # Translate a glob to a base directory if applicable
159
+ #
160
+ # @example
161
+ # glob_to_directory('path/to/dir/**/*') # => 'path/to/dir'
162
+ #
163
+ # @param glob [String]
164
+ # @return [String]
165
+ def glob_to_directory glob
166
+ glob.gsub(/(\/\*|\/\*\*\/\*\*?)$/, '')
167
+ end
168
+ end
169
+ end
170
+ end
@@ -1,298 +1,298 @@
1
- require 'yard'
2
-
3
- module Solargraph
4
- # The YardMap provides access to YARD documentation for the Ruby core, the
5
- # stdlib, and gems.
6
- #
7
- class YardMap
8
- autoload :Cache, 'solargraph/yard_map/cache'
9
- autoload :CoreDocs, 'solargraph/yard_map/core_docs'
10
- autoload :CoreGen, 'solargraph/yard_map/core_gen'
11
-
12
- CoreDocs.require_minimum
13
- @@stdlib_yardoc = CoreDocs.yardoc_stdlib_file
14
- @@stdlib_paths = {}
15
- YARD::Registry.load! @@stdlib_yardoc
16
- YARD::Registry.all(:class, :module).each do |ns|
17
- next if ns.file.nil?
18
- path = ns.file.sub(/^(ext|lib)\//, '').sub(/\.(rb|c)$/, '')
19
- next if path.start_with?('-')
20
- @@stdlib_paths[path] ||= []
21
- @@stdlib_paths[path].push ns
22
- end
23
-
24
- # @return [Array<String>]
25
- attr_reader :required
26
-
27
- attr_writer :with_dependencies
28
-
29
- # @param required [Array<String>]
30
- # @param with_dependencies [Boolean]
31
- def initialize(required: [], with_dependencies: true)
32
- # HACK: YardMap needs its own copy of this array
33
- @required = required.clone
34
- @with_dependencies = with_dependencies
35
- @gem_paths = {}
36
- @stdlib_namespaces = []
37
- process_requires
38
- yardocs.uniq!
39
- end
40
-
41
- # @return [Array<Solargraph::Pin::Base>]
42
- def pins
43
- @pins ||= []
44
- end
45
-
46
- def with_dependencies?
47
- @with_dependencies ||= true unless @with_dependencies == false
48
- @with_dependencies
49
- end
50
-
51
- # @param new_requires [Array<String>]
52
- # @return [Boolean]
53
- def change new_requires
54
- if new_requires.uniq.sort == required.uniq.sort
55
- false
56
- else
57
- required.clear
58
- required.concat new_requires
59
- process_requires
60
- true
61
- end
62
- end
63
-
64
- # @return [Array<String>]
65
- def yardocs
66
- @yardocs ||= []
67
- end
68
-
69
- # @return [Array<String>]
70
- def unresolved_requires
71
- @unresolved_requires ||= []
72
- end
73
-
74
- # @param y [String]
75
- # @return [YARD::Registry]
76
- def load_yardoc y
77
- if y.kind_of?(Array)
78
- YARD::Registry.load y, true
79
- else
80
- YARD::Registry.load! y
81
- end
82
- rescue Exception => e
83
- Solargraph::Logging.logger.warn "Error loading yardoc '#{y}' #{e.class} #{e.message}"
84
- yardocs.delete y
85
- nil
86
- end
87
-
88
- # @return [Array<Solargraph::Pin::Base>]
89
- def core_pins
90
- @@core_pins ||= begin
91
- result = []
92
- load_yardoc CoreDocs.yardoc_file
93
- YARD::Registry.each do |o|
94
- result.concat generate_pins(o)
95
- end
96
- result
97
- end
98
- end
99
-
100
- # @param path [String]
101
- # @return [Pin::Base]
102
- def path_pin path
103
- pins.select{ |p| p.path == path }.first
104
- end
105
-
106
- private
107
-
108
- # @return [YardMap::Cache]
109
- def cache
110
- @cache ||= YardMap::Cache.new
111
- end
112
-
113
- # @param ns [YARD::CodeObjects::Namespace]
114
- # @return [Array<Solargraph::Pin::Base>]
115
- def recurse_namespace_object ns
116
- result = []
117
- ns.children.each do |c|
118
- result.concat generate_pins(c)
119
- result.concat recurse_namespace_object(c) if c.respond_to?(:children)
120
- end
121
- result
122
- end
123
-
124
- # @param code_object [YARD::CodeObjects::Base]
125
- # @return [Solargraph::Pin::Base]
126
- def generate_pins code_object, spec = nil
127
- result = []
128
- location = object_location(code_object, spec)
129
- if code_object.is_a?(YARD::CodeObjects::NamespaceObject)
130
- result.push Solargraph::Pin::YardPin::Namespace.new(code_object, location)
131
- if code_object.is_a?(YARD::CodeObjects::ClassObject) and !code_object.superclass.nil?
132
- # @todo This method of superclass detection is a bit of a hack. If
133
- # the superclass is a Proxy, it is assumed to be undefined in its
134
- # yardoc and converted to a fully qualified namespace.
135
- if code_object.superclass.is_a?(YARD::CodeObjects::Proxy)
136
- superclass = "::#{code_object.superclass}"
137
- else
138
- superclass = code_object.superclass.to_s
139
- end
140
- result.push Solargraph::Pin::Reference::Superclass.new(location, code_object.path, superclass)
141
- end
142
- code_object.class_mixins.each do |m|
143
- result.push Solargraph::Pin::Reference::Extend.new(location, code_object.path, m.path)
144
- end
145
- code_object.instance_mixins.each do |m|
146
- result.push Solargraph::Pin::Reference::Include.new(location, code_object.path, m.path)
147
- end
148
- elsif code_object.is_a?(YARD::CodeObjects::MethodObject)
149
- if code_object.name == :initialize && code_object.scope == :instance
150
- # @todo Check the visibility of <Class>.new
151
- result.push Solargraph::Pin::YardPin::Method.new(code_object, location, 'new', :class, :public)
152
- result.push Solargraph::Pin::YardPin::Method.new(code_object, location, 'initialize', :instance, :private)
153
- else
154
- result.push Solargraph::Pin::YardPin::Method.new(code_object, location)
155
- end
156
- elsif code_object.is_a?(YARD::CodeObjects::ConstantObject)
157
- result.push Solargraph::Pin::YardPin::Constant.new(code_object, location)
158
- end
159
- result
160
- end
161
-
162
- # @return [void]
163
- def process_requires
164
- pins.clear
165
- unresolved_requires.clear
166
- stdnames = {}
167
- done = []
168
- required.each do |r|
169
- next if r.nil? || r.empty? || done.include?(r)
170
- done.push r
171
- cached = cache.get_path_pins(r)
172
- unless cached.nil?
173
- pins.concat cached
174
- next
175
- end
176
- result = []
177
- begin
178
- spec = Gem::Specification.find_by_path(r) || Gem::Specification.find_by_name(r.split('/').first)
179
- ver = spec.version.to_s
180
- ver = ">= 0" if ver.empty?
181
- yd = YARD::Registry.yardoc_file_for_gem(spec.name, ver)
182
- # YARD detects gems for certain libraries that do not have a yardoc
183
- # but exist in the stdlib. `fileutils` is an example. Treat those
184
- # cases as errors and check the stdlib yardoc.
185
- raise Gem::LoadError if yd.nil?
186
- @gem_paths[spec.name] = spec.full_gem_path
187
- unless yardocs.include?(yd)
188
- yardocs.unshift yd
189
- result.concat process_yardoc yd, spec
190
- result.concat add_gem_dependencies(spec) if with_dependencies?
191
- end
192
- rescue Gem::LoadError => e
193
- stdtmp = []
194
- @@stdlib_paths.each_pair do |path, objects|
195
- stdtmp.concat objects if path == r || path.start_with?("#{r}/")
196
- end
197
- if stdtmp.empty?
198
- unresolved_requires.push r
199
- else
200
- stdnames[r] = stdtmp
201
- end
202
- end
203
- result.delete_if(&:nil?)
204
- unless result.empty?
205
- cache.set_path_pins r, result
206
- pins.concat result
207
- end
208
- end
209
- pins.concat process_stdlib(stdnames)
210
- pins.concat core_pins
211
- end
212
-
213
- # @param required_namespaces [Array<YARD::CodeObjects::Namespace>]
214
- # @return [Array<Solargraph::Pin::Base>]
215
- def process_stdlib required_namespaces
216
- pins = []
217
- unless required_namespaces.empty?
218
- yard = load_yardoc @@stdlib_yardoc
219
- done = []
220
- required_namespaces.each_pair do |r, objects|
221
- result = []
222
- objects.each do |ns|
223
- next if done.include?(ns.path)
224
- done.push ns.path
225
- result.concat generate_pins(ns)
226
- result.concat recurse_namespace_object(ns)
227
- end
228
- result.delete_if(&:nil?)
229
- cache.set_path_pins(r, result) unless result.empty?
230
- pins.concat result
231
- end
232
- end
233
- pins
234
- end
235
-
236
- # @param spec [Gem::Specification]
237
- # @return [void]
238
- def add_gem_dependencies spec
239
- result = []
240
- (spec.dependencies - spec.development_dependencies).each do |dep|
241
- begin
242
- depspec = Gem::Specification.find_by_name(dep.name)
243
- next if depspec.nil? || @gem_paths.key?(depspec.name)
244
- @gem_paths[depspec.name] = depspec.full_gem_path
245
- gy = YARD::Registry.yardoc_file_for_gem(dep.name)
246
- if gy.nil?
247
- unresolved_requires.push dep.name
248
- else
249
- next if yardocs.include?(gy)
250
- yardocs.unshift gy
251
- result.concat process_yardoc gy, depspec
252
- result.concat add_gem_dependencies(depspec)
253
- end
254
- rescue Gem::LoadError
255
- # This error probably indicates a bug in an installed gem
256
- Solargraph::Logging.logger.warn "Failed to resolve #{dep.name} gem dependency for #{spec.name}"
257
- end
258
- end
259
- result
260
- end
261
-
262
- # @param y [String, nil]
263
- # @return [Array<Pin::Base>]
264
- def process_yardoc y, spec = nil
265
- return [] if y.nil?
266
- size = Dir.glob(File.join(y, '**', '*'))
267
- .map{ |f| File.size(f) }
268
- .inject(:+)
269
- if !size.nil? && size > 20_000_000
270
- Solargraph::Logging.logger.warn "Yardoc at #{y} is too large to process (#{size} bytes)"
271
- return []
272
- end
273
- result = []
274
- load_yardoc y
275
- YARD::Registry.each do |o|
276
- result.concat generate_pins(o, spec)
277
- end
278
- result
279
- end
280
-
281
- # @param obj [YARD::CodeObjects::Base]
282
- # @return [Solargraph::Location]
283
- def object_location obj, spec = nil
284
- @object_file_cache ||= {}
285
- return nil if spec.nil? || obj.file.nil? || obj.line.nil?
286
- file = nil
287
- if @object_file_cache.key?(obj.file)
288
- file = @object_file_cache[obj.file]
289
- else
290
- tmp = File.join(spec.full_gem_path, obj.file)
291
- file = tmp if File.exist?(tmp)
292
- @object_file_cache[obj.file] = file
293
- end
294
- return nil if file.nil?
295
- Solargraph::Location.new(file, Solargraph::Range.from_to(obj.line - 1, 0, obj.line - 1, 0))
296
- end
297
- end
298
- end
1
+ require 'yard'
2
+
3
+ module Solargraph
4
+ # The YardMap provides access to YARD documentation for the Ruby core, the
5
+ # stdlib, and gems.
6
+ #
7
+ class YardMap
8
+ autoload :Cache, 'solargraph/yard_map/cache'
9
+ autoload :CoreDocs, 'solargraph/yard_map/core_docs'
10
+ autoload :CoreGen, 'solargraph/yard_map/core_gen'
11
+
12
+ CoreDocs.require_minimum
13
+ @@stdlib_yardoc = CoreDocs.yardoc_stdlib_file
14
+ @@stdlib_paths = {}
15
+ YARD::Registry.load! @@stdlib_yardoc
16
+ YARD::Registry.all(:class, :module).each do |ns|
17
+ next if ns.file.nil?
18
+ path = ns.file.sub(/^(ext|lib)\//, '').sub(/\.(rb|c)$/, '')
19
+ next if path.start_with?('-')
20
+ @@stdlib_paths[path] ||= []
21
+ @@stdlib_paths[path].push ns
22
+ end
23
+
24
+ # @return [Array<String>]
25
+ attr_reader :required
26
+
27
+ attr_writer :with_dependencies
28
+
29
+ # @param required [Array<String>]
30
+ # @param with_dependencies [Boolean]
31
+ def initialize(required: [], with_dependencies: true)
32
+ # HACK: YardMap needs its own copy of this array
33
+ @required = required.clone
34
+ @with_dependencies = with_dependencies
35
+ @gem_paths = {}
36
+ @stdlib_namespaces = []
37
+ process_requires
38
+ yardocs.uniq!
39
+ end
40
+
41
+ # @return [Array<Solargraph::Pin::Base>]
42
+ def pins
43
+ @pins ||= []
44
+ end
45
+
46
+ def with_dependencies?
47
+ @with_dependencies ||= true unless @with_dependencies == false
48
+ @with_dependencies
49
+ end
50
+
51
+ # @param new_requires [Array<String>]
52
+ # @return [Boolean]
53
+ def change new_requires
54
+ if new_requires.uniq.sort == required.uniq.sort
55
+ false
56
+ else
57
+ required.clear
58
+ required.concat new_requires
59
+ process_requires
60
+ true
61
+ end
62
+ end
63
+
64
+ # @return [Array<String>]
65
+ def yardocs
66
+ @yardocs ||= []
67
+ end
68
+
69
+ # @return [Array<String>]
70
+ def unresolved_requires
71
+ @unresolved_requires ||= []
72
+ end
73
+
74
+ # @param y [String]
75
+ # @return [YARD::Registry]
76
+ def load_yardoc y
77
+ if y.kind_of?(Array)
78
+ YARD::Registry.load y, true
79
+ else
80
+ YARD::Registry.load! y
81
+ end
82
+ rescue Exception => e
83
+ Solargraph::Logging.logger.warn "Error loading yardoc '#{y}' #{e.class} #{e.message}"
84
+ yardocs.delete y
85
+ nil
86
+ end
87
+
88
+ # @return [Array<Solargraph::Pin::Base>]
89
+ def core_pins
90
+ @@core_pins ||= begin
91
+ result = []
92
+ load_yardoc CoreDocs.yardoc_file
93
+ YARD::Registry.each do |o|
94
+ result.concat generate_pins(o)
95
+ end
96
+ result
97
+ end
98
+ end
99
+
100
+ # @param path [String]
101
+ # @return [Pin::Base]
102
+ def path_pin path
103
+ pins.select{ |p| p.path == path }.first
104
+ end
105
+
106
+ private
107
+
108
+ # @return [YardMap::Cache]
109
+ def cache
110
+ @cache ||= YardMap::Cache.new
111
+ end
112
+
113
+ # @param ns [YARD::CodeObjects::Namespace]
114
+ # @return [Array<Solargraph::Pin::Base>]
115
+ def recurse_namespace_object ns
116
+ result = []
117
+ ns.children.each do |c|
118
+ result.concat generate_pins(c)
119
+ result.concat recurse_namespace_object(c) if c.respond_to?(:children)
120
+ end
121
+ result
122
+ end
123
+
124
+ # @param code_object [YARD::CodeObjects::Base]
125
+ # @return [Solargraph::Pin::Base]
126
+ def generate_pins code_object, spec = nil
127
+ result = []
128
+ location = object_location(code_object, spec)
129
+ if code_object.is_a?(YARD::CodeObjects::NamespaceObject)
130
+ result.push Solargraph::Pin::YardPin::Namespace.new(code_object, location)
131
+ if code_object.is_a?(YARD::CodeObjects::ClassObject) and !code_object.superclass.nil?
132
+ # @todo This method of superclass detection is a bit of a hack. If
133
+ # the superclass is a Proxy, it is assumed to be undefined in its
134
+ # yardoc and converted to a fully qualified namespace.
135
+ if code_object.superclass.is_a?(YARD::CodeObjects::Proxy)
136
+ superclass = "::#{code_object.superclass}"
137
+ else
138
+ superclass = code_object.superclass.to_s
139
+ end
140
+ result.push Solargraph::Pin::Reference::Superclass.new(location, code_object.path, superclass)
141
+ end
142
+ code_object.class_mixins.each do |m|
143
+ result.push Solargraph::Pin::Reference::Extend.new(location, code_object.path, m.path)
144
+ end
145
+ code_object.instance_mixins.each do |m|
146
+ result.push Solargraph::Pin::Reference::Include.new(location, code_object.path, m.path)
147
+ end
148
+ elsif code_object.is_a?(YARD::CodeObjects::MethodObject)
149
+ if code_object.name == :initialize && code_object.scope == :instance
150
+ # @todo Check the visibility of <Class>.new
151
+ result.push Solargraph::Pin::YardPin::Method.new(code_object, location, 'new', :class, :public)
152
+ result.push Solargraph::Pin::YardPin::Method.new(code_object, location, 'initialize', :instance, :private)
153
+ else
154
+ result.push Solargraph::Pin::YardPin::Method.new(code_object, location)
155
+ end
156
+ elsif code_object.is_a?(YARD::CodeObjects::ConstantObject)
157
+ result.push Solargraph::Pin::YardPin::Constant.new(code_object, location)
158
+ end
159
+ result
160
+ end
161
+
162
+ # @return [void]
163
+ def process_requires
164
+ pins.clear
165
+ unresolved_requires.clear
166
+ stdnames = {}
167
+ done = []
168
+ required.each do |r|
169
+ next if r.nil? || r.empty? || done.include?(r)
170
+ done.push r
171
+ cached = cache.get_path_pins(r)
172
+ unless cached.nil?
173
+ pins.concat cached
174
+ next
175
+ end
176
+ result = []
177
+ begin
178
+ spec = Gem::Specification.find_by_path(r) || Gem::Specification.find_by_name(r.split('/').first)
179
+ ver = spec.version.to_s
180
+ ver = ">= 0" if ver.empty?
181
+ yd = YARD::Registry.yardoc_file_for_gem(spec.name, ver)
182
+ # YARD detects gems for certain libraries that do not have a yardoc
183
+ # but exist in the stdlib. `fileutils` is an example. Treat those
184
+ # cases as errors and check the stdlib yardoc.
185
+ raise Gem::LoadError if yd.nil?
186
+ @gem_paths[spec.name] = spec.full_gem_path
187
+ unless yardocs.include?(yd)
188
+ yardocs.unshift yd
189
+ result.concat process_yardoc yd, spec
190
+ result.concat add_gem_dependencies(spec) if with_dependencies?
191
+ end
192
+ rescue Gem::LoadError => e
193
+ stdtmp = []
194
+ @@stdlib_paths.each_pair do |path, objects|
195
+ stdtmp.concat objects if path == r || path.start_with?("#{r}/")
196
+ end
197
+ if stdtmp.empty?
198
+ unresolved_requires.push r
199
+ else
200
+ stdnames[r] = stdtmp
201
+ end
202
+ end
203
+ result.delete_if(&:nil?)
204
+ unless result.empty?
205
+ cache.set_path_pins r, result
206
+ pins.concat result
207
+ end
208
+ end
209
+ pins.concat process_stdlib(stdnames)
210
+ pins.concat core_pins
211
+ end
212
+
213
+ # @param required_namespaces [Array<YARD::CodeObjects::Namespace>]
214
+ # @return [Array<Solargraph::Pin::Base>]
215
+ def process_stdlib required_namespaces
216
+ pins = []
217
+ unless required_namespaces.empty?
218
+ yard = load_yardoc @@stdlib_yardoc
219
+ done = []
220
+ required_namespaces.each_pair do |r, objects|
221
+ result = []
222
+ objects.each do |ns|
223
+ next if done.include?(ns.path)
224
+ done.push ns.path
225
+ result.concat generate_pins(ns)
226
+ result.concat recurse_namespace_object(ns)
227
+ end
228
+ result.delete_if(&:nil?)
229
+ cache.set_path_pins(r, result) unless result.empty?
230
+ pins.concat result
231
+ end
232
+ end
233
+ pins
234
+ end
235
+
236
+ # @param spec [Gem::Specification]
237
+ # @return [void]
238
+ def add_gem_dependencies spec
239
+ result = []
240
+ (spec.dependencies - spec.development_dependencies).each do |dep|
241
+ begin
242
+ depspec = Gem::Specification.find_by_name(dep.name)
243
+ next if depspec.nil? || @gem_paths.key?(depspec.name)
244
+ @gem_paths[depspec.name] = depspec.full_gem_path
245
+ gy = YARD::Registry.yardoc_file_for_gem(dep.name)
246
+ if gy.nil?
247
+ unresolved_requires.push dep.name
248
+ else
249
+ next if yardocs.include?(gy)
250
+ yardocs.unshift gy
251
+ result.concat process_yardoc gy, depspec
252
+ result.concat add_gem_dependencies(depspec)
253
+ end
254
+ rescue Gem::LoadError
255
+ # This error probably indicates a bug in an installed gem
256
+ Solargraph::Logging.logger.warn "Failed to resolve #{dep.name} gem dependency for #{spec.name}"
257
+ end
258
+ end
259
+ result
260
+ end
261
+
262
+ # @param y [String, nil]
263
+ # @return [Array<Pin::Base>]
264
+ def process_yardoc y, spec = nil
265
+ return [] if y.nil?
266
+ size = Dir.glob(File.join(y, '**', '*'))
267
+ .map{ |f| File.size(f) }
268
+ .inject(:+)
269
+ if !size.nil? && size > 20_000_000
270
+ Solargraph::Logging.logger.warn "Yardoc at #{y} is too large to process (#{size} bytes)"
271
+ return []
272
+ end
273
+ result = []
274
+ load_yardoc y
275
+ YARD::Registry.each do |o|
276
+ result.concat generate_pins(o, spec)
277
+ end
278
+ result
279
+ end
280
+
281
+ # @param obj [YARD::CodeObjects::Base]
282
+ # @return [Solargraph::Location]
283
+ def object_location obj, spec = nil
284
+ @object_file_cache ||= {}
285
+ return nil if spec.nil? || obj.file.nil? || obj.line.nil?
286
+ file = nil
287
+ if @object_file_cache.key?(obj.file)
288
+ file = @object_file_cache[obj.file]
289
+ else
290
+ tmp = File.join(spec.full_gem_path, obj.file)
291
+ file = tmp if File.exist?(tmp)
292
+ @object_file_cache[obj.file] = file
293
+ end
294
+ return nil if file.nil?
295
+ Solargraph::Location.new(file, Solargraph::Range.from_to(obj.line - 1, 0, obj.line - 1, 0))
296
+ end
297
+ end
298
+ end