sord 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|