sord 0.6.0 → 0.7.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/.gitignore +1 -0
- data/CHANGELOG.md +92 -0
- data/README.md +23 -14
- data/exe/sord +13 -2
- data/lib/sord/logging.rb +41 -16
- data/lib/sord/rbi_generator.rb +76 -28
- data/lib/sord/type_converter.rb +30 -7
- data/lib/sord/version.rb +1 -1
- metadata +3 -3
- data/Gemfile.lock +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ea0cd169aa8fb78913ee6547177fcf31665bd776846f29652f3a1c156caf856
|
4
|
+
data.tar.gz: 9ac77d33766f851ffdaac0c3fe34e238a432e57ea8d4518ff1e095382ac9dc4a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ae4e4cfba74c8bfcdb7f91296d18f1aa4ccfd6545d407b8997df4516a181e5b4aa85277bbdef623aed16de060a3479a9c5b7c6b4b34658ae328dd62f9cba929
|
7
|
+
data.tar.gz: cba4988403819d61a068adb45105941951a172d96997258f92848b014e51f657d65dacd7963d27dd1b3803baf3c78cf5a3764593201954c47e4abc4ebe4b9c8c
|
data/.gitignore
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
5
|
+
|
6
|
+
## [0.7.0]
|
7
|
+
### Added
|
8
|
+
- A warning message is now shown if the YARD registry has no objects. (#31)
|
9
|
+
- Integer, Float and Symbol literals are now supported as types. (#26)
|
10
|
+
- Add support for multi-method YARD duck types. (#38)
|
11
|
+
- Namespaces are now indented properly. (#41)
|
12
|
+
- Individual method and namespace counts are now shown, rather than just an overall object count. (#36)
|
13
|
+
|
14
|
+
### Changed
|
15
|
+
- Paths to log message items are now bold rather than white, so that they can be seen on white terminals. (#28)
|
16
|
+
- Alias methods are now ignored. (#34)
|
17
|
+
- Remove Gemfile.lock. (#33)
|
18
|
+
- YARD is executed when Sord is executed. To disable this behaviour, use `--no-regenerate`. (#31)
|
19
|
+
|
20
|
+
### Fixed
|
21
|
+
- Resolved crash when a @return tag gave no type. (#35)
|
22
|
+
|
23
|
+
## [0.6.0] - 2019-06-23
|
24
|
+
### Added
|
25
|
+
- Namespaces are now nested inside each other in the RBI file, fixing many constant scoping issues. (#25)
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
- Move unfinished tasks from README to GitHub issues.
|
29
|
+
|
30
|
+
### Fixed
|
31
|
+
- Fix typo of 'duck' as 'ducl' (#24)
|
32
|
+
|
33
|
+
## [0.5.0] - 2019-06-23
|
34
|
+
### Added
|
35
|
+
- Hash rocket syntax for hash types is now supported. (#18)
|
36
|
+
- Arrays with multiple element types are handled correctly. (#21)
|
37
|
+
|
38
|
+
### Fixed
|
39
|
+
- Move a dependency from Gemfile to Gemspec for consistency. (#19)
|
40
|
+
- Fix bug where splat-args (`*a`) were always called `args` in signatures. (#20)
|
41
|
+
|
42
|
+
## [0.4.1] - 2019-06-22
|
43
|
+
### Fixed
|
44
|
+
- The changelog for this version is the same as 0.4.0, but resolving an issue where some changes were not published correctly to RubyGems.
|
45
|
+
|
46
|
+
## [0.4.0] - 2019-06-22 [YANKED]
|
47
|
+
### Added
|
48
|
+
- Commander is now used for the CLI, which enables a `--help` switch.
|
49
|
+
- Add a `--no-comments` switch for disabling comments in the RBI file.
|
50
|
+
|
51
|
+
### Changed
|
52
|
+
- Sord now exits as early as possible if no filename is specified. (#17)
|
53
|
+
|
54
|
+
### Fixed
|
55
|
+
- Remove & in block parameter names in signatures, fixing a syntax error in RBIs. (#16)
|
56
|
+
|
57
|
+
## [0.3.0] - 2019-06-22
|
58
|
+
### Added
|
59
|
+
- `self` now resolves to a type in signatures.
|
60
|
+
- `true` and `false` are now converted to `T::Boolean` in signatures.
|
61
|
+
- If a `T.any` contains `nil`, it now instead wraps that part of the signature in a `T.nilable` instead.
|
62
|
+
- Add GitHub issue templates.
|
63
|
+
|
64
|
+
### Changed
|
65
|
+
- `.vscode` is now git-ignored.
|
66
|
+
- Method definitions now have a semicolon before the end for consistency with Sorbet's RBIs. (#6)
|
67
|
+
- `params` is now omitted from signatures if a method has no parameters. (#4)
|
68
|
+
|
69
|
+
### Fixed
|
70
|
+
- Fix kwargs in signatures by removing the duplicate colon from their identifier. (#12)
|
71
|
+
- Fix kwargs in definitions by not inserting an equal-to symbol for their defaults. (#11)
|
72
|
+
|
73
|
+
## [0.2.1] - 2019-06-22
|
74
|
+
### Fixed
|
75
|
+
- Fix exception on launch due to forgetting to initialise a class variable. (#1)
|
76
|
+
|
77
|
+
## [0.2.0] - 2019-06-22
|
78
|
+
### Added
|
79
|
+
- Add RSpec tests.
|
80
|
+
- Add the Logging class with prettier output.
|
81
|
+
- Generic types can now take more than one type parameter.
|
82
|
+
- Add documentation for all classes.
|
83
|
+
- Add a README.
|
84
|
+
- Add Sorbet directory and typing mode comments (`srb init`).
|
85
|
+
|
86
|
+
### Changed
|
87
|
+
- Sord now requires a command-line argument to save the RBI to.
|
88
|
+
|
89
|
+
## [0.1.0] 2019-06-21
|
90
|
+
### Added
|
91
|
+
- First release.
|
92
|
+
|
data/README.md
CHANGED
@@ -21,10 +21,12 @@ Sord has the following features:
|
|
21
21
|
|
22
22
|
Install Sord with `gem install sord`.
|
23
23
|
|
24
|
+
**NOTE**: You need to run `yard` before you generate the `.rbi` file or
|
25
|
+
Sord won't have any information to work with.
|
26
|
+
|
24
27
|
Sord is a command line tool. To use it, open a terminal in the root directory
|
25
|
-
of your project
|
26
|
-
|
27
|
-
RBI to (this file will be overwritten):
|
28
|
+
of your project and invoke `sord`, passing a path where you'd like to save your
|
29
|
+
`.rbi` (this file will be overwritten):
|
28
30
|
|
29
31
|
```
|
30
32
|
sord defs.rbi
|
@@ -34,6 +36,13 @@ Sord will print information about what it's inferred as it runs. It is best to
|
|
34
36
|
fix any issues in the YARD documentation, as any edits made to the resulting
|
35
37
|
RBI file will be replaced if you re-run Sord.
|
36
38
|
|
39
|
+
### Flags
|
40
|
+
|
41
|
+
Sord also takes some flags to alter the generated `.rbi` file:
|
42
|
+
|
43
|
+
- `--no-comments`: Generates the `.rbi` file without any comments about
|
44
|
+
warnings/inferences/errors.
|
45
|
+
|
37
46
|
## Example
|
38
47
|
|
39
48
|
Say we have this file, called `test.rb`:
|
@@ -78,24 +87,24 @@ files! Note the `.rbi` file extension.) In doing this, Sord prints:
|
|
78
87
|
The `test.rbi` file then contains a complete RBI file for `test.rb`:
|
79
88
|
|
80
89
|
```ruby
|
81
|
-
# typed:
|
90
|
+
# typed: strong
|
82
91
|
module Example
|
83
|
-
|
84
|
-
class Example::Person
|
92
|
+
class Person
|
85
93
|
sig { params(name: String, age: Integer).returns(Example::Person) }
|
86
|
-
def initialize(name, age) end
|
87
|
-
sig {
|
88
|
-
def name() end
|
94
|
+
def initialize(name, age); end
|
95
|
+
sig { returns(String) }
|
96
|
+
def name(); end
|
89
97
|
# sord infer - inferred type of parameter "value" as String using getter's return type
|
90
98
|
sig { params(value: String).returns(String) }
|
91
|
-
def name=(value) end
|
92
|
-
sig {
|
93
|
-
def age() end
|
99
|
+
def name=(value); end
|
100
|
+
sig { returns(Integer) }
|
101
|
+
def age(); end
|
94
102
|
# sord infer - inferred type of parameter "value" as Integer using getter's return type
|
95
103
|
sig { params(value: Integer).returns(Integer) }
|
96
|
-
def age=(value) end
|
104
|
+
def age=(value); end
|
97
105
|
sig { params(possible_names: T::Array[String], possible_ages: T::Array[Integer]).returns(Example::Person) }
|
98
|
-
def self.construct_randomly(possible_names, possible_ages) end
|
106
|
+
def self.construct_randomly(possible_names, possible_ages); end
|
107
|
+
end
|
99
108
|
end
|
100
109
|
```
|
101
110
|
|
data/exe/sord
CHANGED
@@ -10,16 +10,27 @@ default_command :gen
|
|
10
10
|
command :gen do |c|
|
11
11
|
c.syntax = 'sord gen <output-file> [options]'
|
12
12
|
c.description = 'Generates an RBI file from this directory\'s YARD docs'
|
13
|
-
c.option '--[no-]comments', '
|
13
|
+
c.option '--[no-]comments', 'Controls informational/warning comments in the RBI file'
|
14
|
+
c.option '--[no-]regenerate', 'Controls whether YARD is executed before Sord runs'
|
14
15
|
|
15
16
|
c.action do |args, options|
|
16
|
-
options.default comments: true
|
17
|
+
options.default comments: true, regenerate: true
|
17
18
|
|
18
19
|
if args.length != 1
|
19
20
|
Sord::Logging.error('Must specify filename')
|
20
21
|
exit 1
|
21
22
|
end
|
22
23
|
|
24
|
+
begin
|
25
|
+
Sord::Logging.info('Running YARD...')
|
26
|
+
`yard`
|
27
|
+
rescue Errno::ENOENT
|
28
|
+
Sord::Logging.error('The YARD tool could not be found on your PATH.')
|
29
|
+
Sord::Logging.error('You may need to run \'gem install yard\'.')
|
30
|
+
Sord::Logging.error('If documentation has already been generated, pass --no-regenerate to Sord.')
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
23
34
|
Sord::RbiGenerator.new(options).run(args.first)
|
24
35
|
end
|
25
36
|
end
|
data/lib/sord/logging.rb
CHANGED
@@ -7,6 +7,11 @@ module Sord
|
|
7
7
|
# The callables should take three parameters: (kind, msg, item).
|
8
8
|
@@hooks = []
|
9
9
|
|
10
|
+
# @return [Array<Proc>] The hooks registered on the logger.
|
11
|
+
def self.hooks
|
12
|
+
@@hooks
|
13
|
+
end
|
14
|
+
|
10
15
|
# Whether log messages should be printed or not.
|
11
16
|
@@silent = false
|
12
17
|
|
@@ -33,14 +38,15 @@ module Sord
|
|
33
38
|
# @param [YARD::CodeObjects::Base] item The CodeObject which this log
|
34
39
|
# is associated with, if any. This is shown before the log message if it is
|
35
40
|
# specified.
|
36
|
-
|
41
|
+
# @param [Integer] indent_level The level at which to indent the code.
|
42
|
+
def self.generic(kind, header, msg, item, indent_level = 0)
|
37
43
|
if item
|
38
|
-
puts "#{header} (#{item.path.
|
44
|
+
puts "#{header} (#{item.path.bold}) #{msg}" unless silent?
|
39
45
|
else
|
40
46
|
puts "#{header} #{msg}" unless silent?
|
41
47
|
end
|
42
48
|
|
43
|
-
invoke_hooks(kind, msg, item)
|
49
|
+
invoke_hooks(kind, msg, item, indent_level)
|
44
50
|
end
|
45
51
|
|
46
52
|
# Print a warning message. This should be used for things which require the
|
@@ -49,8 +55,20 @@ module Sord
|
|
49
55
|
# @param [YARD::CodeObjects::Base] item The CodeObject which this log
|
50
56
|
# is associated with, if any. This is shown before the log message if it is
|
51
57
|
# specified.
|
52
|
-
|
53
|
-
|
58
|
+
# @param [Integer] indent_level The level at which to indent the code.
|
59
|
+
def self.warn(msg, item = nil, indent_level = 0)
|
60
|
+
generic(:warn, '[WARN ]'.yellow, msg, item, indent_level)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Print an info message. This should be used for generic informational
|
64
|
+
# messages which the user doesn't need to act on.
|
65
|
+
# @param [String] msg The log message to write.
|
66
|
+
# @param [YARD::CodeObjects::Base] item The CodeObject which this log
|
67
|
+
# is associated with, if any. This is shown before the log message if it is
|
68
|
+
# specified.
|
69
|
+
# @param [Integer] indent_level The level at which to indent the code.
|
70
|
+
def self.info(msg, item = nil, indent_level = 0)
|
71
|
+
generic(:info, '[INFO ]', msg, item, indent_level)
|
54
72
|
end
|
55
73
|
|
56
74
|
# Print a duck-typing message. This should be used when the YARD
|
@@ -60,8 +78,9 @@ module Sord
|
|
60
78
|
# @param [YARD::CodeObjects::Base] item The CodeObject which this log
|
61
79
|
# is associated with, if any. This is shown before the log message if it is
|
62
80
|
# specified.
|
63
|
-
|
64
|
-
|
81
|
+
# @param [Integer] indent_level The level at which to indent the code.
|
82
|
+
def self.duck(msg, item = nil, indent_level = 0)
|
83
|
+
generic(:duck, '[DUCK ]'.cyan, msg, item, indent_level)
|
65
84
|
end
|
66
85
|
|
67
86
|
# Print an error message. This should be used for things which require the
|
@@ -70,8 +89,9 @@ module Sord
|
|
70
89
|
# @param [YARD::CodeObjects::Base] item The CodeObject which this log
|
71
90
|
# is associated with, if any. This is shown before the log message if it is
|
72
91
|
# specified.
|
73
|
-
|
74
|
-
|
92
|
+
# @param [Integer] indent_level The level at which to indent the code.
|
93
|
+
def self.error(msg, item = nil, indent_level = 0)
|
94
|
+
generic(:error, '[ERROR]'.red, msg, item, indent_level)
|
75
95
|
end
|
76
96
|
|
77
97
|
# Print an infer message. This should be used when the user should be told
|
@@ -81,8 +101,9 @@ module Sord
|
|
81
101
|
# @param [YARD::CodeObjects::Base] item The CodeObject which this log
|
82
102
|
# is associated with, if any. This is shown before the log message if it is
|
83
103
|
# specified.
|
84
|
-
|
85
|
-
|
104
|
+
# @param [Integer] indent_level The level at which to indent the code.
|
105
|
+
def self.infer(msg, item = nil, indent_level = 0)
|
106
|
+
generic(:infer, '[INFER]'.light_blue, msg, item, indent_level)
|
86
107
|
end
|
87
108
|
|
88
109
|
# Print an omit message. This should be used as a special type of warning
|
@@ -92,8 +113,9 @@ module Sord
|
|
92
113
|
# @param [YARD::CodeObjects::Base] item The CodeObject which this log
|
93
114
|
# is associated with, if any. This is shown before the log message if it is
|
94
115
|
# specified.
|
95
|
-
|
96
|
-
|
116
|
+
# @param [Integer] indent_level The level at which to indent the code.
|
117
|
+
def self.omit(msg, item = nil, indent_level = 0)
|
118
|
+
generic(:omit, '[OMIT ]'.magenta, msg, item, indent_level)
|
97
119
|
end
|
98
120
|
|
99
121
|
# Print a done message. This should be used when a process completes
|
@@ -101,7 +123,8 @@ module Sord
|
|
101
123
|
# @param [YARD::CodeObjects::Base] item The CodeObject which this log
|
102
124
|
# is associated with, if any. This is shown before the log message if it is
|
103
125
|
# specified.
|
104
|
-
|
126
|
+
# @param [Integer] indent_level The level at which to indent the code.
|
127
|
+
def self.done(msg, item = nil, indent_level = 0)
|
105
128
|
generic(:done, '[DONE ]'.green, msg, item)
|
106
129
|
end
|
107
130
|
|
@@ -111,9 +134,10 @@ module Sord
|
|
111
134
|
# @param [YARD::CodeObjects::Base] item The CodeObject which this log
|
112
135
|
# is associated with, if any. This is shown before the log message if it is
|
113
136
|
# specified.
|
114
|
-
|
137
|
+
# @param [Integer] indent_level The level at which to indent the code.
|
138
|
+
def self.invoke_hooks(kind, msg, item, indent_level = 0)
|
115
139
|
@@hooks.each do |hook|
|
116
|
-
hook.(kind, msg, item) rescue nil
|
140
|
+
hook.(kind, msg, item, indent_level) rescue nil
|
117
141
|
end
|
118
142
|
end
|
119
143
|
|
@@ -123,6 +147,7 @@ module Sord
|
|
123
147
|
# @yieldparam [YARD::CodeObjects::Base] item The CodeObject which this log
|
124
148
|
# is associated with, if any. This is shown before the log message if it is
|
125
149
|
# specified.
|
150
|
+
# @yieldparam [Integer] indent_level The level at which to indent the code.
|
126
151
|
# @yieldreturn [void]
|
127
152
|
def self.add_hook(&blk)
|
128
153
|
@@hooks << blk
|
data/lib/sord/rbi_generator.rb
CHANGED
@@ -12,52 +12,81 @@ module Sord
|
|
12
12
|
|
13
13
|
# @return [Integer] The number of objects this generator has processed so
|
14
14
|
# far.
|
15
|
-
|
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
|
16
23
|
|
17
24
|
# Create a new RBI generator.
|
18
25
|
# @param [Hash] options
|
19
26
|
# @return [RbiGenerator]
|
20
27
|
def initialize(options)
|
21
28
|
@rbi_contents = ['# typed: strong']
|
22
|
-
@
|
29
|
+
@namespace_count = 0
|
30
|
+
@method_count = 0
|
31
|
+
@warnings = []
|
23
32
|
|
24
33
|
# Hook the logger so that messages are added as comments to the RBI file
|
25
|
-
Logging.add_hook do |type, msg, item|
|
26
|
-
rbi_contents << " # sord #{type} - #{msg}"
|
34
|
+
Logging.add_hook do |type, msg, item, indent_level = 0|
|
35
|
+
rbi_contents << "#{' ' * (indent_level + 1)}# sord #{type} - #{msg}"
|
27
36
|
end if options.comments
|
37
|
+
|
38
|
+
# Hook the logger so that warnings are collected
|
39
|
+
Logging.add_hook do |type, msg, item, indent_level = 0|
|
40
|
+
warnings << [msg, item, rbi_contents.length] \
|
41
|
+
if type == :warn
|
42
|
+
end
|
28
43
|
end
|
29
44
|
|
30
|
-
# Increment the
|
45
|
+
# Increment the namespace counter.
|
31
46
|
# @return [void]
|
32
|
-
def
|
33
|
-
@
|
47
|
+
def count_namespace
|
48
|
+
@namespace_count += 1
|
49
|
+
end
|
50
|
+
|
51
|
+
# Increment the method counter.
|
52
|
+
# @return [void]
|
53
|
+
def count_method
|
54
|
+
@method_count += 1
|
34
55
|
end
|
35
56
|
|
36
57
|
# Given a YARD CodeObject, add lines defining its mixins (that is, extends
|
37
58
|
# and includes) to the current RBI file.
|
38
59
|
# @param [YARD::CodeObjects::Base] item
|
60
|
+
# @param [Integer] indent_level
|
39
61
|
# @return [void]
|
40
|
-
def add_mixins(item)
|
62
|
+
def add_mixins(item, indent_level)
|
41
63
|
extends = item.instance_mixins
|
42
64
|
includes = item.class_mixins
|
43
65
|
|
44
66
|
extends.each do |this_extend|
|
45
|
-
rbi_contents << " extend #{this_extend.path}"
|
67
|
+
rbi_contents << "#{' ' * (indent_level + 1)}extend #{this_extend.path}"
|
46
68
|
end
|
47
69
|
includes.each do |this_include|
|
48
|
-
rbi_contents << " include #{this_include.path}"
|
70
|
+
rbi_contents << "#{' ' * (indent_level + 1)}include #{this_include.path}"
|
49
71
|
end
|
50
72
|
end
|
51
73
|
|
52
74
|
# Given a YARD NamespaceObject, add lines defining its methods and their
|
53
75
|
# signatures to the current RBI file.
|
54
76
|
# @param [YARD::CodeObjects::NamespaceObject] item
|
77
|
+
# @param [Integer] indent_level
|
55
78
|
# @return [void]
|
56
|
-
def add_methods(item)
|
79
|
+
def add_methods(item, indent_level)
|
57
80
|
# TODO: block documentation
|
58
81
|
|
59
82
|
item.meths.each do |meth|
|
60
|
-
|
83
|
+
count_method
|
84
|
+
|
85
|
+
# If the method is an alias, skip it so we don't define it as a
|
86
|
+
# separate method. Sorbet will handle it automatically.
|
87
|
+
if meth.is_alias?
|
88
|
+
next
|
89
|
+
end
|
61
90
|
|
62
91
|
parameter_list = meth.parameters.map do |name, default|
|
63
92
|
# Handle these three main cases:
|
@@ -95,19 +124,19 @@ module Sord
|
|
95
124
|
getter = item.meths.find { |m| m.path == getter_path }
|
96
125
|
|
97
126
|
unless getter
|
98
|
-
Logging.omit("no YARD type given for #{name.inspect}, using T.untyped", meth)
|
127
|
+
Logging.omit("no YARD type given for #{name.inspect}, using T.untyped", meth, indent_level)
|
99
128
|
next "#{name}: T.untyped"
|
100
129
|
end
|
101
130
|
|
102
131
|
inferred_type = TypeConverter.yard_to_sorbet(
|
103
132
|
getter.tags('return').flat_map(&:types), meth)
|
104
133
|
|
105
|
-
Logging.infer("inferred type of parameter #{name.inspect} as #{inferred_type} using getter's return type", meth)
|
134
|
+
Logging.infer("inferred type of parameter #{name.inspect} as #{inferred_type} using getter's return type", meth, indent_level)
|
106
135
|
# Get rid of : on keyword arguments.
|
107
136
|
name = name.chop if name.end_with?(':')
|
108
137
|
"#{name}: #{inferred_type}"
|
109
138
|
else
|
110
|
-
Logging.omit("no YARD type given for #{name.inspect}, using T.untyped", meth)
|
139
|
+
Logging.omit("no YARD type given for #{name.inspect}, using T.untyped", meth, indent_level)
|
111
140
|
# Get rid of : on keyword arguments.
|
112
141
|
name = name.chop if name.end_with?(':')
|
113
142
|
"#{name}: T.untyped"
|
@@ -117,7 +146,7 @@ module Sord
|
|
117
146
|
return_tags = meth.tags('return')
|
118
147
|
returns = if return_tags.length == 0
|
119
148
|
"void"
|
120
|
-
elsif return_tags.length == 1 && return_tags
|
149
|
+
elsif return_tags.length == 1 && return_tags&.first&.types&.first&.downcase == "void"
|
121
150
|
"void"
|
122
151
|
else
|
123
152
|
"returns(#{TypeConverter.yard_to_sorbet(meth.tag('return').types, meth)})"
|
@@ -125,31 +154,32 @@ module Sord
|
|
125
154
|
|
126
155
|
prefix = meth.scope == :class ? 'self.' : ''
|
127
156
|
|
128
|
-
sig = sig_params_list.empty? ? " sig { #{returns} }" : " sig { params(#{sig_params_list}).#{returns} }"
|
157
|
+
sig = sig_params_list.empty? ? "#{' ' * (indent_level + 1)}sig { #{returns} }" : "#{' ' * (indent_level + 1)}sig { params(#{sig_params_list}).#{returns} }"
|
129
158
|
rbi_contents << sig
|
130
159
|
|
131
|
-
rbi_contents << " def #{prefix}#{meth.name}(#{parameter_list}); end"
|
160
|
+
rbi_contents << "#{' ' * (indent_level + 1)}def #{prefix}#{meth.name}(#{parameter_list}); end"
|
132
161
|
end
|
133
162
|
end
|
134
163
|
|
135
164
|
# Given a YARD NamespaceObject, add lines defining its mixins, methods
|
136
165
|
# and children to the RBI file.
|
137
166
|
# @param [YARD::CodeObjects::NamespaceObject] item
|
138
|
-
|
139
|
-
|
167
|
+
# @param [Integer] indent_level
|
168
|
+
def add_namespace(item, indent_level = 0)
|
169
|
+
count_namespace
|
140
170
|
|
141
171
|
if item.type == :class && item.superclass.to_s != "Object"
|
142
|
-
rbi_contents << "class #{item.name} < #{item.superclass.path}"
|
172
|
+
rbi_contents << "#{' ' * indent_level}class #{item.name} < #{item.superclass.path}"
|
143
173
|
else
|
144
|
-
rbi_contents << "#{item.type} #{item.name}"
|
174
|
+
rbi_contents << "#{' ' * indent_level}#{item.type} #{item.name}"
|
145
175
|
end
|
146
|
-
add_mixins(item)
|
147
|
-
add_methods(item)
|
176
|
+
add_mixins(item, indent_level)
|
177
|
+
add_methods(item, indent_level)
|
148
178
|
|
149
179
|
item.children.select { |x| [:class, :module].include?(x.type) }
|
150
|
-
.each { |child| add_namespace(child) }
|
180
|
+
.each { |child| add_namespace(child, indent_level + 1) }
|
151
181
|
|
152
|
-
rbi_contents << "end"
|
182
|
+
rbi_contents << "#{' ' * indent_level}end"
|
153
183
|
end
|
154
184
|
|
155
185
|
# Generates the RBI file and writes it to the given file path.
|
@@ -171,11 +201,29 @@ module Sord
|
|
171
201
|
# Write the file
|
172
202
|
File.write(filename, rbi_contents.join(?\n))
|
173
203
|
|
174
|
-
|
204
|
+
if object_count.zero?
|
205
|
+
Logging.warn("No objects processed.")
|
206
|
+
Logging.warn("Have you definitely generated the YARD documentation for this project?")
|
207
|
+
Logging.warn("Run `yard` to generate docs.")
|
208
|
+
end
|
209
|
+
|
210
|
+
Logging.done("Processed #{object_count} objects (#{@namespace_count} namespaces and #{@method_count} methods)")
|
211
|
+
|
212
|
+
Logging.hooks.clear
|
213
|
+
|
214
|
+
unless warnings.empty?
|
215
|
+
Logging.warn("There were #{warnings.length} important warnings in the RBI file, listed below.")
|
216
|
+
Logging.warn("The types which caused them have been replaced with SORD_ERROR_ constants.")
|
217
|
+
Logging.warn("Please edit the file near the line numbers given to fix these errors.")
|
218
|
+
Logging.warn("Alternatively, edit your YARD documentation so that your types are valid and re-run Sord.")
|
219
|
+
warnings.each do |(msg, item, line)|
|
220
|
+
puts " #{"Line #{line} |".light_black} (#{item.path.bold}) #{msg}"
|
221
|
+
end
|
222
|
+
end
|
175
223
|
rescue
|
176
224
|
Logging.error($!)
|
177
225
|
$@.each do |line|
|
178
|
-
puts " #{line}"
|
226
|
+
puts " #{line}"
|
179
227
|
end
|
180
228
|
end
|
181
229
|
end
|
data/lib/sord/type_converter.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'yaml'
|
1
2
|
require 'sord/logging'
|
2
3
|
|
3
4
|
module Sord
|
@@ -7,14 +8,24 @@ module Sord
|
|
7
8
|
# "Foo", "Foo::Bar", and "::Foo::Bar" are all matches, whereas "Foo.Bar"
|
8
9
|
# or "Foo#bar" are not.
|
9
10
|
SIMPLE_TYPE_REGEX =
|
10
|
-
/(?:\:\:)?[a-zA-Z_][
|
11
|
+
/(?:\:\:)?[a-zA-Z_][\w]*(?:\:\:[a-zA-Z_][\w]*)*/
|
11
12
|
|
12
13
|
# A regular expression which matches a Ruby namespace immediately followed
|
13
|
-
# by another Ruby namespace in angle brackets
|
14
|
-
# used in YARD to model generic
|
15
|
-
# "
|
14
|
+
# by another Ruby namespace in angle brackets or curly braces.
|
15
|
+
# This is the format usually used in YARD to model generic
|
16
|
+
# types, such as "Array<String>", "Hash<String, Symbol>",
|
17
|
+
# "Hash{String => Symbol}", etc.
|
16
18
|
GENERIC_TYPE_REGEX =
|
17
19
|
/(#{SIMPLE_TYPE_REGEX})\s*[<{]\s*(.*)\s*[>}]/
|
20
|
+
|
21
|
+
# Match duck types which require the object implement one or more methods,
|
22
|
+
# like '#foo', '#foo & #bar', '#foo&#bar&#baz', and '#foo&#bar&#baz&#foo_bar'.
|
23
|
+
DUCK_TYPE_REGEX =
|
24
|
+
/^\##{SIMPLE_TYPE_REGEX}(?:( ?\& ?\#)*[a-zA-Z_][a-zA-Z_0-9]*)*$/
|
25
|
+
|
26
|
+
# A regular expression which matches ordered lists in the format of
|
27
|
+
# either "Array(String, Symbol)" or "(String, Symbol)".
|
28
|
+
ORDERED_LIST_REGEX = /^(?:Array|)\((.*)\s*\)$/
|
18
29
|
|
19
30
|
# An array of built-in generic types supported by Sorbet.
|
20
31
|
SORBET_SUPPORTED_GENERIC_TYPES = %w{Array Set Enumerable Enumerator Range Hash}
|
@@ -33,11 +44,11 @@ module Sord
|
|
33
44
|
while character_pointer < params.length
|
34
45
|
should_buffer = true
|
35
46
|
|
36
|
-
current_bracketing_level += 1 if ['<', '{'].include?(params[character_pointer])
|
47
|
+
current_bracketing_level += 1 if ['<', '{', '('].include?(params[character_pointer])
|
37
48
|
# Decrease bracketing level by 1 when encountering `>` or `}`, unless
|
38
49
|
# the previous character is `=` (to prevent hash rockets from causing
|
39
50
|
# nesting problems).
|
40
|
-
current_bracketing_level -= 1 if ['>', '}'].include?(params[character_pointer]) && params[character_pointer - 1] != '='
|
51
|
+
current_bracketing_level -= 1 if ['>', '}', ')'].include?(params[character_pointer]) && params[character_pointer - 1] != '='
|
41
52
|
|
42
53
|
# Handle commas as separators.
|
43
54
|
# e.g. Hash<Symbol, String>
|
@@ -98,7 +109,7 @@ module Sord
|
|
98
109
|
Logging.warn("#{yard} is probably not a type, but using anyway", item)
|
99
110
|
end
|
100
111
|
yard
|
101
|
-
when
|
112
|
+
when DUCK_TYPE_REGEX
|
102
113
|
Logging.duck("#{yard} looks like a duck type, replacing with T.untyped", item)
|
103
114
|
'T.untyped'
|
104
115
|
when /^#{GENERIC_TYPE_REGEX}$/
|
@@ -117,7 +128,19 @@ module Sord
|
|
117
128
|
Logging.warn("unsupported generic type #{generic_type.inspect} in #{yard.inspect}", item)
|
118
129
|
"SORD_ERROR_#{generic_type.gsub(/[^0-9A-Za-z_]/i, '')}"
|
119
130
|
end
|
131
|
+
# Converts ordered lists like Array(Symbol, String) or (Symbol, String)
|
132
|
+
# into Sorbet Tuples like [Symbol, String].
|
133
|
+
when ORDERED_LIST_REGEX
|
134
|
+
type_parameters = $1
|
135
|
+
parameters = split_type_parameters(type_parameters)
|
136
|
+
.map { |x| yard_to_sorbet(x, item) }
|
137
|
+
"[#{parameters.join(', ')}]"
|
120
138
|
else
|
139
|
+
# Check for literals
|
140
|
+
from_yaml = YAML.load(yard) rescue nil
|
141
|
+
return from_yaml.class.to_s \
|
142
|
+
if [Symbol, Float, Integer].include?(from_yaml.class)
|
143
|
+
|
121
144
|
Logging.warn("#{yard.inspect} does not appear to be a type", item)
|
122
145
|
"SORD_ERROR_#{yard.gsub(/[^0-9A-Za-z_]/i, '')}"
|
123
146
|
end
|
data/lib/sord/version.rb
CHANGED
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.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Christiansen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: yard
|
@@ -148,9 +148,9 @@ files:
|
|
148
148
|
- ".github/ISSUE_TEMPLATE/feature-request.md"
|
149
149
|
- ".gitignore"
|
150
150
|
- ".rspec"
|
151
|
+
- CHANGELOG.md
|
151
152
|
- CODE_OF_CONDUCT.md
|
152
153
|
- Gemfile
|
153
|
-
- Gemfile.lock
|
154
154
|
- LICENSE.txt
|
155
155
|
- README.md
|
156
156
|
- Rakefile
|
data/Gemfile.lock
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
sord (0.4.1)
|
5
|
-
colorize
|
6
|
-
commander (~> 4.4)
|
7
|
-
sorbet-runtime
|
8
|
-
yard
|
9
|
-
|
10
|
-
GEM
|
11
|
-
remote: https://rubygems.org/
|
12
|
-
specs:
|
13
|
-
colorize (0.8.1)
|
14
|
-
commander (4.4.7)
|
15
|
-
highline (~> 2.0.0)
|
16
|
-
diff-lcs (1.3)
|
17
|
-
docile (1.3.2)
|
18
|
-
highline (2.0.2)
|
19
|
-
json (2.2.0)
|
20
|
-
rake (10.5.0)
|
21
|
-
rspec (3.8.0)
|
22
|
-
rspec-core (~> 3.8.0)
|
23
|
-
rspec-expectations (~> 3.8.0)
|
24
|
-
rspec-mocks (~> 3.8.0)
|
25
|
-
rspec-core (3.8.1)
|
26
|
-
rspec-support (~> 3.8.0)
|
27
|
-
rspec-expectations (3.8.4)
|
28
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
29
|
-
rspec-support (~> 3.8.0)
|
30
|
-
rspec-mocks (3.8.1)
|
31
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
32
|
-
rspec-support (~> 3.8.0)
|
33
|
-
rspec-support (3.8.2)
|
34
|
-
simplecov (0.16.1)
|
35
|
-
docile (~> 1.1)
|
36
|
-
json (>= 1.8, < 3)
|
37
|
-
simplecov-html (~> 0.10.0)
|
38
|
-
simplecov-html (0.10.2)
|
39
|
-
sorbet (0.4.4254)
|
40
|
-
sorbet-static (= 0.4.4254)
|
41
|
-
sorbet-runtime (0.4.4294)
|
42
|
-
sorbet-static (0.4.4254-x86_64-linux)
|
43
|
-
yard (0.9.19)
|
44
|
-
|
45
|
-
PLATFORMS
|
46
|
-
ruby
|
47
|
-
|
48
|
-
DEPENDENCIES
|
49
|
-
bundler (~> 2.0)
|
50
|
-
rake (~> 10.0)
|
51
|
-
rspec (~> 3.0)
|
52
|
-
simplecov
|
53
|
-
sorbet
|
54
|
-
sord!
|
55
|
-
|
56
|
-
BUNDLED WITH
|
57
|
-
2.0.1
|