sord 0.8.0 → 3.0.0.beta.1

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  3. data/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
  4. data/.gitignore +0 -0
  5. data/.parlour +11 -0
  6. data/.rspec +0 -0
  7. data/.travis.yml +6 -0
  8. data/CHANGELOG.md +99 -0
  9. data/CODE_OF_CONDUCT.md +0 -0
  10. data/Gemfile +0 -0
  11. data/LICENSE.txt +0 -0
  12. data/README.md +17 -11
  13. data/Rakefile +87 -12
  14. data/exe/sord +50 -33
  15. data/lib/sord.rb +2 -1
  16. data/lib/sord/generator.rb +592 -0
  17. data/lib/sord/logging.rb +21 -30
  18. data/lib/sord/parlour_plugin.rb +84 -0
  19. data/lib/sord/resolver.rb +9 -2
  20. data/lib/sord/type_converter.rb +88 -42
  21. data/lib/sord/version.rb +1 -1
  22. data/rbi/sord.rbi +279 -68
  23. data/sord.gemspec +3 -3
  24. metadata +23 -38
  25. data/lib/sord/rbi_generator.rb +0 -334
  26. data/sorbet/config +0 -0
  27. data/sorbet/rbi/gems/colorize.rbi +0 -81
  28. data/sorbet/rbi/gems/docile.rbi +0 -31
  29. data/sorbet/rbi/gems/rake.rbi +0 -643
  30. data/sorbet/rbi/gems/rspec-core.rbi +0 -1658
  31. data/sorbet/rbi/gems/rspec-expectations.rbi +0 -389
  32. data/sorbet/rbi/gems/rspec-mocks.rbi +0 -823
  33. data/sorbet/rbi/gems/rspec-support.rbi +0 -268
  34. data/sorbet/rbi/gems/rspec.rbi +0 -14
  35. data/sorbet/rbi/gems/simplecov-html.rbi +0 -30
  36. data/sorbet/rbi/gems/simplecov.rbi +0 -223
  37. data/sorbet/rbi/gems/sorbet-runtime.rbi +0 -647
  38. data/sorbet/rbi/gems/yard.rbi +0 -310
  39. data/sorbet/rbi/hidden-definitions/errors.txt +0 -9353
  40. data/sorbet/rbi/hidden-definitions/hidden.rbi +0 -16640
  41. data/sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi +0 -8547
  42. data/sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi +0 -111
  43. data/sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi +0 -543
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sord
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 3.0.0.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Christiansen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-07 00:00:00.000000000 Z
11
+ date: 2020-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: yard
@@ -39,33 +39,33 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: colorize
42
+ name: commander
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '4.5'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '4.5'
55
55
  - !ruby/object:Gem::Dependency
56
- name: commander
56
+ name: parlour
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: '4.4'
61
+ version: 5.0.0.beta.3
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: '4.4'
68
+ version: 5.0.0.beta.3
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: bundler
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -136,7 +136,7 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
- description:
139
+ description:
140
140
  email:
141
141
  - aaronc20000@gmail.com
142
142
  executables:
@@ -147,7 +147,9 @@ files:
147
147
  - ".github/ISSUE_TEMPLATE/bug_report.md"
148
148
  - ".github/ISSUE_TEMPLATE/feature-request.md"
149
149
  - ".gitignore"
150
+ - ".parlour"
150
151
  - ".rspec"
152
+ - ".travis.yml"
151
153
  - CHANGELOG.md
152
154
  - CODE_OF_CONDUCT.md
153
155
  - Gemfile
@@ -156,36 +158,19 @@ files:
156
158
  - Rakefile
157
159
  - exe/sord
158
160
  - lib/sord.rb
161
+ - lib/sord/generator.rb
159
162
  - lib/sord/logging.rb
160
- - lib/sord/rbi_generator.rb
163
+ - lib/sord/parlour_plugin.rb
161
164
  - lib/sord/resolver.rb
162
165
  - lib/sord/type_converter.rb
163
166
  - lib/sord/version.rb
164
167
  - rbi/sord.rbi
165
- - sorbet/config
166
- - sorbet/rbi/gems/colorize.rbi
167
- - sorbet/rbi/gems/docile.rbi
168
- - sorbet/rbi/gems/rake.rbi
169
- - sorbet/rbi/gems/rspec-core.rbi
170
- - sorbet/rbi/gems/rspec-expectations.rbi
171
- - sorbet/rbi/gems/rspec-mocks.rbi
172
- - sorbet/rbi/gems/rspec-support.rbi
173
- - sorbet/rbi/gems/rspec.rbi
174
- - sorbet/rbi/gems/simplecov-html.rbi
175
- - sorbet/rbi/gems/simplecov.rbi
176
- - sorbet/rbi/gems/sorbet-runtime.rbi
177
- - sorbet/rbi/gems/yard.rbi
178
- - sorbet/rbi/hidden-definitions/errors.txt
179
- - sorbet/rbi/hidden-definitions/hidden.rbi
180
- - sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi
181
- - sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi
182
- - sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi
183
168
  - sord.gemspec
184
169
  homepage: https://github.com/AaronC81/sord
185
170
  licenses:
186
171
  - MIT
187
172
  metadata: {}
188
- post_install_message:
173
+ post_install_message:
189
174
  rdoc_options: []
190
175
  require_paths:
191
176
  - lib
@@ -196,12 +181,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
196
181
  version: '0'
197
182
  required_rubygems_version: !ruby/object:Gem::Requirement
198
183
  requirements:
199
- - - ">="
184
+ - - ">"
200
185
  - !ruby/object:Gem::Version
201
- version: '0'
186
+ version: 1.3.1
202
187
  requirements: []
203
- rubygems_version: 3.0.2
204
- signing_key:
188
+ rubygems_version: 3.0.3
189
+ signing_key:
205
190
  specification_version: 4
206
191
  summary: Generate Sorbet RBI files from YARD documentation
207
192
  test_files: []
@@ -1,334 +0,0 @@
1
- # typed: true
2
- require 'yard'
3
- require 'sord/type_converter'
4
- require 'colorize'
5
- require 'sord/logging'
6
-
7
- module Sord
8
- # Converts the current working directory's YARD registry into an RBI file.
9
- class RbiGenerator
10
- # @return [Array<String>] The lines of the generated RBI file so far.
11
- attr_reader :rbi_contents
12
-
13
- # @return [Integer] The number of objects this generator has processed so
14
- # far.
15
- def object_count
16
- @namespace_count + @method_count
17
- end
18
-
19
- # @return [Array<Array(String, YARD::CodeObjects::Base, Integer)>] The
20
- # errors encountered by by the generator. Each element is of the form
21
- # [message, item, line].
22
- attr_reader :warnings
23
-
24
- # @return [Boolean] A boolean indicating whether the next item is the first
25
- # in its namespace. This is used to determine whether to insert a blank
26
- # line before it or not.
27
- attr_accessor :next_item_is_first_in_namespace
28
-
29
- # Create a new RBI generator.
30
- # @param [Hash] options
31
- # @option options [Integer] break_params
32
- # @option options [Boolean] replace_errors_with_untyped
33
- # @option options [Boolean] comments
34
- # @return [void]
35
- def initialize(options)
36
- @rbi_contents = ['# typed: strong']
37
- @namespace_count = 0
38
- @method_count = 0
39
- @break_params = options[:break_params]
40
- @replace_errors_with_untyped = options[:replace_errors_with_untyped]
41
- @warnings = []
42
- @next_item_is_first_in_namespace = true
43
-
44
- # Hook the logger so that messages are added as comments to the RBI file
45
- Logging.add_hook do |type, msg, item, indent_level = 0|
46
- rbi_contents << "#{' ' * (indent_level + 1)}# sord #{type} - #{msg}"
47
- end if options[:comments]
48
-
49
- # Hook the logger so that warnings are collected
50
- Logging.add_hook do |type, msg, item, indent_level = 0|
51
- warnings << [msg, item, rbi_contents.length] \
52
- if type == :warn
53
- end
54
- end
55
-
56
- # Increment the namespace counter.
57
- # @return [void]
58
- def count_namespace
59
- @namespace_count += 1
60
- end
61
-
62
- # Increment the method counter.
63
- # @return [void]
64
- def count_method
65
- @method_count += 1
66
- end
67
-
68
- # Adds a single blank line to the RBI file, unless this item is the first
69
- # in its namespace.
70
- # @return [void]
71
- def add_blank
72
- rbi_contents << '' unless next_item_is_first_in_namespace
73
- self.next_item_is_first_in_namespace = false
74
- end
75
-
76
- # Given a YARD CodeObject, add lines defining its mixins (that is, extends
77
- # and includes) to the current RBI file. Returns the number of mixins.
78
- # @param [YARD::CodeObjects::Base] item
79
- # @param [Integer] indent_level
80
- # @return [Integer]
81
- def add_mixins(item, indent_level)
82
- includes = item.instance_mixins
83
- extends = item.class_mixins
84
-
85
- extends.reverse_each do |this_extend|
86
- rbi_contents << "#{' ' * (indent_level + 1)}extend #{this_extend.path}"
87
- end
88
- includes.reverse_each do |this_include|
89
- rbi_contents << "#{' ' * (indent_level + 1)}include #{this_include.path}"
90
- end
91
-
92
- extends.length + includes.length
93
- end
94
-
95
- # Given an array of parameters and a return type, inserts the signature for
96
- # a method with those properties into the current RBI file.
97
- # @param [Array<String>] params
98
- # @param [String] returns
99
- # @param [Integer] indent_level
100
- # @return [void]
101
- def add_signature(params, returns, indent_level)
102
- if params.empty?
103
- rbi_contents << "#{' ' * (indent_level + 1)}sig { #{returns} }"
104
- return
105
- end
106
-
107
- if params.length >= @break_params
108
- rbi_contents << "#{' ' * (indent_level + 1)}sig do"
109
- rbi_contents << "#{' ' * (indent_level + 2)}params("
110
- params.each.with_index do |param, i|
111
- terminator = params.length - 1 == i ? '' : ','
112
- rbi_contents << "#{' ' * (indent_level + 3)}#{param}#{terminator}"
113
- end
114
- rbi_contents << "#{' ' * (indent_level + 2)}).#{returns}"
115
- rbi_contents << "#{' ' * (indent_level + 1)}end"
116
- else
117
- rbi_contents << "#{' ' * (indent_level + 1)}sig { params(#{params.join(', ')}).#{returns} }"
118
- end
119
- end
120
-
121
- # Given a YARD NamespaceObject, add lines defining its methods and their
122
- # signatures to the current RBI file.
123
- # @param [YARD::CodeObjects::NamespaceObject] item
124
- # @param [Integer] indent_level
125
- # @return [void]
126
- def add_methods(item, indent_level)
127
- item.meths.each do |meth|
128
- count_method
129
-
130
- # If the method is an alias, skip it so we don't define it as a
131
- # separate method. Sorbet will handle it automatically.
132
- if meth.is_alias?
133
- next
134
- end
135
-
136
- add_blank
137
-
138
- parameter_list = meth.parameters.map do |name, default|
139
- # Handle these three main cases:
140
- # - def method(param) or def method(param:)
141
- # - def method(param: 'default')
142
- # - def method(param = 'default')
143
- if default.nil?
144
- "#{name}"
145
- elsif !default.nil? && name.end_with?(':')
146
- "#{name} #{default}"
147
- else
148
- "#{name} = #{default}"
149
- end
150
- end.join(", ")
151
-
152
- # This is better than iterating over YARD's "@param" tags directly
153
- # because it includes parameters without documentation
154
- # (The gsubs allow for better splat-argument compatibility)
155
- parameter_names_to_tags = meth.parameters.map do |name, _|
156
- [name, meth.tags('param')
157
- .find { |p| p.name&.gsub('*', '') == name.gsub('*', '') }]
158
- end.to_h
159
-
160
- sig_params_list = parameter_names_to_tags.map do |name, tag|
161
- name = name.gsub('*', '')
162
-
163
- if tag
164
- "#{name}: #{TypeConverter.yard_to_sorbet(tag.types, meth, indent_level, @replace_errors_with_untyped)}"
165
- elsif name.start_with? '&'
166
- # Cut the ampersand from the block parameter name
167
- name = name.gsub('&', '')
168
-
169
- # Find yieldparams and yieldreturn
170
- yieldparams = meth.tags('yieldparam')
171
- yieldreturn = meth.tag('yieldreturn')&.types
172
- yieldreturn = nil if yieldreturn&.length == 1 &&
173
- yieldreturn&.first&.downcase == 'void'
174
-
175
- # Create strings
176
- params_string = yieldparams.map do |param|
177
- "#{param.name.gsub('*', '')}: #{TypeConverter.yard_to_sorbet(param.types, meth, indent_level, @replace_errors_with_untyped)}" unless param.name.nil?
178
- end.join(', ')
179
- return_string = TypeConverter.yard_to_sorbet(yieldreturn, meth, indent_level, @replace_errors_with_untyped)
180
-
181
- # Create proc types, if possible
182
- if yieldparams.empty? && yieldreturn.nil?
183
- "#{name}: T.untyped"
184
- elsif yieldreturn.nil?
185
- "#{name}: T.proc#{params_string.empty? ? '' : ".params(#{params_string})"}.void"
186
- else
187
- "#{name}: T.proc#{params_string.empty? ? '' : ".params(#{params_string})"}.returns(#{return_string})"
188
- end
189
- elsif meth.path.end_with? '='
190
- # Look for the matching getter method
191
- getter_path = meth.path[0...-1]
192
- getter = item.meths.find { |m| m.path == getter_path }
193
-
194
- unless getter
195
- if parameter_names_to_tags.length == 1 \
196
- && meth.tags('param').length == 1 \
197
- && meth.tag('param').types
198
-
199
- Logging.infer("argument name in single @param inferred as #{parameter_names_to_tags.first.first.inspect}", meth, indent_level)
200
- next "#{name}: #{TypeConverter.yard_to_sorbet(meth.tag('param').types, meth, indent_level, @replace_errors_with_untyped)}"
201
- else
202
- Logging.omit("no YARD type given for #{name.inspect}, using T.untyped", meth, indent_level)
203
- next "#{name}: T.untyped"
204
- end
205
- end
206
-
207
- inferred_type = TypeConverter.yard_to_sorbet(
208
- getter.tags('return').flat_map(&:types), meth, indent_level, @replace_errors_with_untyped)
209
-
210
- Logging.infer("inferred type of parameter #{name.inspect} as #{inferred_type} using getter's return type", meth, indent_level)
211
- # Get rid of : on keyword arguments.
212
- name = name.chop if name.end_with?(':')
213
- "#{name}: #{inferred_type}"
214
- else
215
- # Is this the only argument, and was a @param specified without an
216
- # argument name? If so, infer it
217
- if parameter_names_to_tags.length == 1 \
218
- && meth.tags('param').length == 1 \
219
- && meth.tag('param').types
220
-
221
- Logging.infer("argument name in single @param inferred as #{parameter_names_to_tags.first.first.inspect}", meth, indent_level)
222
- "#{name}: #{TypeConverter.yard_to_sorbet(meth.tag('param').types, meth, indent_level, @replace_errors_with_untyped)}"
223
- else
224
- Logging.omit("no YARD type given for #{name.inspect}, using T.untyped", meth, indent_level)
225
- # Get rid of : on keyword arguments.
226
- name = name.chop if name.end_with?(':')
227
- "#{name}: T.untyped"
228
- end
229
- end
230
- end
231
-
232
- return_tags = meth.tags('return')
233
- returns = if return_tags.length == 0
234
- Logging.omit("no YARD return type given, using T.untyped", meth, indent_level)
235
- "returns(T.untyped)"
236
- elsif return_tags.length == 1 && return_tags&.first&.types&.first&.downcase == "void"
237
- "void"
238
- else
239
- "returns(#{TypeConverter.yard_to_sorbet(meth.tag('return').types, meth, indent_level, @replace_errors_with_untyped)})"
240
- end
241
-
242
- prefix = meth.scope == :class ? 'self.' : ''
243
-
244
- add_signature(sig_params_list, returns, indent_level)
245
-
246
- rbi_contents << "#{' ' * (indent_level + 1)}def #{prefix}#{meth.name}(#{parameter_list}); end"
247
- end
248
- end
249
-
250
- # Given a YARD NamespaceObject, add lines defining its mixins, methods
251
- # and children to the RBI file.
252
- # @param [YARD::CodeObjects::NamespaceObject] item
253
- # @param [Integer] indent_level
254
- # @return [void]
255
- def add_namespace(item, indent_level = 0)
256
- count_namespace
257
- add_blank
258
-
259
- if item.type == :class && item.superclass.to_s != "Object"
260
- rbi_contents << "#{' ' * indent_level}class #{item.name} < #{item.superclass.path}"
261
- else
262
- rbi_contents << "#{' ' * indent_level}#{item.type} #{item.name}"
263
- end
264
-
265
- self.next_item_is_first_in_namespace = true
266
- if add_mixins(item, indent_level) > 0
267
- self.next_item_is_first_in_namespace = false
268
- end
269
- add_methods(item, indent_level)
270
-
271
- item.children.select { |x| [:class, :module].include?(x.type) }
272
- .each { |child| add_namespace(child, indent_level + 1) }
273
-
274
- self.next_item_is_first_in_namespace = false
275
-
276
- rbi_contents << "#{' ' * indent_level}end"
277
- end
278
-
279
- # Generates the RBI file from the loading registry and returns its contents.
280
- # You must load a registry first!
281
- # @return [String]
282
- def generate
283
- # Generate top-level modules, which recurses to all modules
284
- YARD::Registry.root.children
285
- .select { |x| [:class, :module].include?(x.type) }
286
- .each { |child| add_namespace(child) }
287
-
288
- rbi_contents.join("\n")
289
- end
290
-
291
- # Generates the RBI file and writes it to the given file path, printing a
292
- # summary and any warnings at the end. The registry is also loaded.
293
- # @param [String, nil] filename
294
- # @return [void]
295
- def run(filename)
296
- raise 'No filename specified' unless filename
297
-
298
- # Get YARD ready
299
- YARD::Registry.load!
300
-
301
- # Write the file
302
- File.write(filename, generate)
303
-
304
- if object_count.zero?
305
- Logging.warn("No objects processed.")
306
- Logging.warn("Have you definitely generated the YARD documentation for this project?")
307
- Logging.warn("Run `yard` to generate docs.")
308
- end
309
-
310
- Logging.done("Processed #{object_count} objects (#{@namespace_count} namespaces and #{@method_count} methods)")
311
-
312
- Logging.hooks.clear
313
-
314
- unless warnings.empty?
315
- Logging.warn("There were #{warnings.length} important warnings in the RBI file, listed below.")
316
- if @replace_errors_with_untyped
317
- Logging.warn("The types which caused them have been replaced with T.untyped.")
318
- else
319
- Logging.warn("The types which caused them have been replaced with SORD_ERROR_ constants.")
320
- end
321
- Logging.warn("Please edit the file near the line numbers given to fix these errors.")
322
- Logging.warn("Alternatively, edit your YARD documentation so that your types are valid and re-run Sord.")
323
- warnings.each do |(msg, item, line)|
324
- puts " #{"Line #{line} |".light_black} (#{item&.path&.bold}) #{msg}"
325
- end
326
- end
327
- rescue
328
- Logging.error($!)
329
- $@.each do |line|
330
- puts " #{line}"
331
- end
332
- end
333
- end
334
- end