sord 7.0.0 → 7.1.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/.github/workflows/examples.yml +22 -0
- data/.github/workflows/ruby.yml +1 -1
- data/CHANGELOG.md +16 -0
- data/Rakefile +109 -56
- data/lib/sord/generator.rb +24 -19
- data/lib/sord/resolver.rb +13 -6
- data/lib/sord/type_converter.rb +8 -3
- data/lib/sord/version.rb +1 -1
- data/rbi/sord.rbi +1 -1
- data/sord.gemspec +1 -1
- metadata +12 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f9681f7b1837fb0fb51588fb60d8bb94406b9bb9a488670244542971b0b66c7
|
4
|
+
data.tar.gz: 7db1dc6e7a1e3cf43d08ef6850da15eaebf18463fb5a329cdf42acb7da12c0a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84ae70452bf558690f4da7c7fb6c2b1ba65b4cf906a813b04c27766b7ad7ddb549013b49f149593c0a4366016689c0f21f904c09cd3533a19f42ea814655fea7
|
7
|
+
data.tar.gz: 349e397a495df5dd01d7a13eac6541f9d2b0446dbc150e74be756dbc02ead11e7c558ec27f111d852f6c39f4719deb6ba6c56bffed99a44af5a11570f20ea3fc
|
@@ -0,0 +1,22 @@
|
|
1
|
+
name: Run Sord on examples
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
continue-on-error: false
|
9
|
+
steps:
|
10
|
+
- uses: actions/checkout@v2
|
11
|
+
- name: Set up Ruby
|
12
|
+
uses: ruby/setup-ruby@v1
|
13
|
+
with:
|
14
|
+
ruby-version: 3.4 # Use latest for best chance of dependencies resolving
|
15
|
+
- name: Install dependencies
|
16
|
+
run: bundle install
|
17
|
+
- name: Install example dependencies
|
18
|
+
run: sudo apt-get install libldap2-dev libidn11-dev # Dependencies for `addressable`
|
19
|
+
- name: Run examples (RBI)
|
20
|
+
run: bundle exec rake examples:seed[rbi]
|
21
|
+
- name: Run examples (RBS)
|
22
|
+
run: bundle exec rake examples:reseed[rbs]
|
data/.github/workflows/ruby.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file.
|
|
3
3
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
5
5
|
|
6
|
+
## [7.1.0] - 2025-07-07
|
7
|
+
### Added
|
8
|
+
- `nil` can be used as an alias for `NilClass` in more places in YARD types. (Thanks @apiology)
|
9
|
+
- The Solargraph convention `undefined` can now be used as an "untyped" type. (Thanks @apiology)
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
- If a constant's value does not parse successfully, type information can still be generated for
|
13
|
+
that constant, and Sord emits a warning. Previously, this would cause a fatal exception.
|
14
|
+
- The version restriction on the RBS gem has been relaxed, to permit usage of 4.x versions.
|
15
|
+
RBS 3.x can still be used as before.
|
16
|
+
(Thanks @apiology)
|
17
|
+
|
18
|
+
### Fixed
|
19
|
+
- Sord now correctly resolves namespaces when classes have a namespace, e.g. `class X::Y`.
|
20
|
+
(Thanks @dorner)
|
21
|
+
|
6
22
|
## [7.0.0] - 2025-03-03
|
7
23
|
### Added
|
8
24
|
- Messages now show the file and line number that the message originated from. (Thanks @apiology)
|
data/Rakefile
CHANGED
@@ -19,85 +19,138 @@ REPOS = {
|
|
19
19
|
zeitwerk: 'https://github.com/fxn/zeitwerk'
|
20
20
|
}
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
# Thrown by tasks to present a "friendly" error message and abort the task.
|
23
|
+
class TaskError < StandardError
|
24
|
+
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
# Handles Sord examples, including checkout and running Sord to generate types.
|
27
|
+
class ExampleRunner
|
28
|
+
attr_reader :mode, :mode_arg, :clean
|
29
|
+
alias clean? clean
|
30
|
+
|
31
|
+
# @return [<Symbol>] Names of gems where Sord failed.
|
32
|
+
attr_accessor :failed_examples
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
# @param [String] mode "rbi" or "rbs".
|
35
|
+
# @param [Boolean] clean Run Sord with additional options to generate minimal type output.
|
36
|
+
def initialize(mode:, clean: false)
|
37
|
+
@mode = mode
|
38
|
+
@clean = clean
|
39
|
+
|
40
|
+
if mode == 'rbi'
|
41
|
+
@mode_arg = '--rbi'
|
42
|
+
elsif mode == 'rbs'
|
43
|
+
@mode_arg = '--rbs'
|
37
44
|
else
|
38
|
-
|
39
|
-
|
45
|
+
raise TaskError, 'please specify \'rbi\' or \'rbs\'!'
|
46
|
+
end
|
47
|
+
|
48
|
+
@failed_examples = []
|
49
|
+
end
|
50
|
+
|
51
|
+
# Create the `sord_examples` directory, ready for checkouts.
|
52
|
+
# @raise [TaskError] If it already exists.
|
53
|
+
def create_examples_dir
|
54
|
+
if File.directory?(File.join(__dir__, 'sord_examples'))
|
55
|
+
raise TaskError, 'sord_examples directory already exists, please delete the directory or run a reseed!'
|
40
56
|
end
|
41
57
|
|
42
58
|
FileUtils.mkdir 'sord_examples'
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
59
|
+
end
|
60
|
+
|
61
|
+
# Check that the `sord_examples` directory exists.
|
62
|
+
# @raise [TaskError] If it doesn't.
|
63
|
+
def validate_examples_dir
|
64
|
+
unless File.directory?(File.join(__dir__, 'sord_examples'))
|
65
|
+
raise TaskError, 'The sord_examples directory does not exist. Have you run the seed task?'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Check out a repository, add Sord to its Gemfile, and install its dependencies.
|
70
|
+
# @param [Symbol] name Name of the checkout.
|
71
|
+
# @param [String] url Git URL.
|
72
|
+
def prepare_checkout(name, url)
|
73
|
+
Dir.chdir(File.join(__dir__, 'sord_examples')) do
|
74
|
+
puts "Cloning #{name}..."
|
75
|
+
system("git clone #{url} --depth=1")
|
76
|
+
|
77
|
+
Dir.chdir(name.to_s) do
|
51
78
|
# Add sord to gemfile.
|
52
79
|
`echo "gem 'sord', path: '../../'" >> Gemfile`
|
80
|
+
|
53
81
|
# Run bundle install.
|
54
82
|
system('bundle install')
|
55
|
-
# Generate sri
|
56
|
-
puts "Generating rbi for #{name}..."
|
57
|
-
if args[:clean]
|
58
|
-
system("bundle exec sord ../#{name}.#{args[:mode]} #{mode_arg} --no-sord-comments --replace-errors-with-untyped --replace-unresolved-with-untyped")
|
59
|
-
else
|
60
|
-
system("bundle exec sord ../#{name}.#{args[:mode]} #{mode_arg}")
|
61
|
-
end
|
62
|
-
puts "#{name}.#{args[:mode]} generated!"
|
63
|
-
FileUtils.cd '..'
|
64
83
|
end
|
65
84
|
end
|
85
|
+
end
|
66
86
|
|
67
|
-
|
87
|
+
# Run Sord on a checked-out repository.
|
88
|
+
# @param [Symbol] name Name of the checkout.
|
89
|
+
def generate_types(name)
|
90
|
+
puts "Generating rbi for #{name}..."
|
91
|
+
|
92
|
+
Dir.chdir(File.join(__dir__, 'sord_examples', name.to_s)) do
|
93
|
+
if clean?
|
94
|
+
system("bundle exec sord ../#{name}.#{mode} #{mode_arg} --no-sord-comments --replace-errors-with-untyped --replace-unresolved-with-untyped")
|
95
|
+
else
|
96
|
+
system("bundle exec sord ../#{name}.#{mode} #{mode_arg}")
|
97
|
+
end
|
98
|
+
|
99
|
+
if $?.success?
|
100
|
+
puts "#{name}.#{mode} generated!"
|
101
|
+
else
|
102
|
+
puts "Sord exited with error"
|
103
|
+
failed_examples << name
|
104
|
+
end
|
105
|
+
end
|
68
106
|
end
|
69
107
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
raise Rainbow("The sord_examples directory does not exist. Have you run the seed task?").red.bold
|
108
|
+
# Check that all Sord executions were successful.
|
109
|
+
# @raise [TaskError] If any failed.
|
110
|
+
def validate_sord_success
|
111
|
+
if failed_examples.any?
|
112
|
+
raise TaskError, "Not all Sord runs were successful: #{failed_examples.map(&:to_s).join(', ')}"
|
76
113
|
end
|
114
|
+
end
|
115
|
+
end
|
77
116
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
117
|
+
namespace :examples do
|
118
|
+
require 'fileutils'
|
119
|
+
require 'rainbow'
|
120
|
+
|
121
|
+
desc "Clone git repositories and run Sord on them as examples"
|
122
|
+
task :seed, [:mode, :clean] do |t, args|
|
123
|
+
examples = ExampleRunner.new(**args)
|
124
|
+
examples.create_examples_dir
|
125
|
+
|
126
|
+
Bundler.with_clean_env do
|
127
|
+
REPOS.each do |name, url|
|
128
|
+
examples.prepare_checkout(name, url)
|
129
|
+
examples.generate_types(name)
|
130
|
+
end
|
85
131
|
end
|
132
|
+
examples.validate_sord_success
|
133
|
+
|
134
|
+
puts Rainbow("Seeding complete!").green
|
135
|
+
|
136
|
+
rescue TaskError => e
|
137
|
+
abort Rainbow(e.to_s).red
|
138
|
+
end
|
139
|
+
|
140
|
+
desc 'Regenerate the rbi files in sord_examples.'
|
141
|
+
task :reseed, [:mode, :clean] do |t, args|
|
142
|
+
examples = ExampleRunner.new(**args)
|
143
|
+
examples.validate_examples_dir
|
86
144
|
|
87
145
|
REPOS.keys.each do |name|
|
88
|
-
|
89
|
-
puts "Regenerating rbi file for #{name}..."
|
90
|
-
Bundler.with_clean_env do
|
91
|
-
if args[:clean]
|
92
|
-
system("bundle exec sord ../#{name}.#{args[:mode]} #{mode_arg} --no-regenerate --no-sord-comments --replace-errors-with-untyped --replace-unresolved-with-untyped")
|
93
|
-
else
|
94
|
-
system("bundle exec sord ../#{name}.#{args[:mode]} #{mode_arg} --no-regenerate")
|
95
|
-
end
|
96
|
-
end
|
97
|
-
FileUtils.cd '..'
|
146
|
+
examples.generate_types(name)
|
98
147
|
end
|
148
|
+
examples.validate_sord_success
|
99
149
|
|
100
150
|
puts Rainbow("Re-seeding complete!").green
|
151
|
+
|
152
|
+
rescue TaskError => e
|
153
|
+
abort Rainbow(e.to_s).red
|
101
154
|
end
|
102
155
|
|
103
156
|
desc 'Delete the sord_examples directory to allow the seeder to run again.'
|
data/lib/sord/generator.rb
CHANGED
@@ -143,22 +143,29 @@ module Sord
|
|
143
143
|
when :rbi
|
144
144
|
# Parse so we can set up constant with correct heredoc syntax
|
145
145
|
kwargs = {}
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
146
|
+
|
147
|
+
value = constant.value
|
148
|
+
begin
|
149
|
+
value_node = Parser::CurrentRuby.parse(constant.value)
|
150
|
+
loc = value_node.loc
|
151
|
+
if loc.instance_of? Parser::Source::Map::Heredoc
|
152
|
+
#
|
153
|
+
# heredocs in Ruby come after the full expression is complete. e.g.,
|
154
|
+
# puts(>>FOO)
|
155
|
+
# bar
|
156
|
+
# FOO
|
157
|
+
#
|
158
|
+
# so if we want to wrap them in a T.let, we need to parse out the expression vs the rest
|
159
|
+
kwargs[:heredocs] = constant.value[loc.heredoc_body.begin_pos...loc.heredoc_end.end_pos]
|
160
|
+
expression = loc.expression
|
161
|
+
value = constant.value[expression.begin_pos...expression.end_pos]
|
162
|
+
end
|
163
|
+
|
164
|
+
rescue Parser::SyntaxError => e
|
165
|
+
# Emit a warning, since this may cause a syntax error when parsing the RBI
|
166
|
+
Logging.warn("syntax error on constant value: #{e}", constant)
|
161
167
|
end
|
168
|
+
|
162
169
|
@current_object.create_constant(constant_name, value: "T.let(#{value}, T.untyped)", **kwargs) do |c|
|
163
170
|
c.add_comments(constant.docstring.all.split("\n"))
|
164
171
|
end
|
@@ -681,10 +688,8 @@ module Sord
|
|
681
688
|
end
|
682
689
|
end
|
683
690
|
rescue
|
684
|
-
Logging.error($!)
|
685
|
-
|
686
|
-
puts " #{line}"
|
687
|
-
end
|
691
|
+
Logging.error("An internal error occurred while running Sord: #{$!}")
|
692
|
+
raise
|
688
693
|
end
|
689
694
|
|
690
695
|
# Given two pairs of arrays representing method parameters, in the form
|
data/lib/sord/resolver.rb
CHANGED
@@ -70,14 +70,21 @@ module Sord
|
|
70
70
|
klasses = [
|
71
71
|
Parlour::RbiGenerator::Constant,
|
72
72
|
Parlour::RbiGenerator::ModuleNamespace,
|
73
|
-
Parlour::RbiGenerator::ClassNamespace
|
73
|
+
Parlour::RbiGenerator::ClassNamespace,
|
74
|
+
Parlour::RbiGenerator::Namespace
|
75
|
+
]
|
76
|
+
child_only_classes = [
|
77
|
+
Parlour::RbiGenerator::Namespace
|
74
78
|
]
|
75
79
|
nodes.each do |node|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
80
|
+
if klasses.include?(node.class)
|
81
|
+
new_path = path + [node.name]
|
82
|
+
unless child_only_classes.include?(node.class)
|
83
|
+
names_to_paths[node.name] ||= Set.new
|
84
|
+
names_to_paths[node.name] << new_path.join('::')
|
85
|
+
end
|
86
|
+
add_rbi_objects_to_paths(node.children, names_to_paths, new_path) if node.respond_to?(:children)
|
87
|
+
end
|
81
88
|
end
|
82
89
|
end
|
83
90
|
|
data/lib/sord/type_converter.rb
CHANGED
@@ -129,8 +129,12 @@ module Sord
|
|
129
129
|
case yard
|
130
130
|
when nil # Type not specified
|
131
131
|
Parlour::Types::Untyped.new
|
132
|
+
when "nil"
|
133
|
+
Parlour::Types::Raw.new('NilClass')
|
132
134
|
when "bool", "Bool", "boolean", "Boolean", "true", "false"
|
133
135
|
Parlour::Types::Boolean.new
|
136
|
+
when "undefined" # solargraph convention
|
137
|
+
Parlour::Types::Untyped.new
|
134
138
|
when 'self'
|
135
139
|
Parlour::Types::Self.new
|
136
140
|
when Array
|
@@ -195,10 +199,11 @@ module Sord
|
|
195
199
|
relative_generic_type = generic_type.start_with?('::') \
|
196
200
|
? generic_type[2..-1] : generic_type
|
197
201
|
|
198
|
-
|
202
|
+
yard_parameters = split_type_parameters(type_parameters)
|
203
|
+
parameters = yard_parameters
|
199
204
|
.map { |x| yard_to_parlour(x, item, config) }
|
200
|
-
if SINGLE_ARG_GENERIC_TYPES.include?(relative_generic_type) &&
|
201
|
-
Parlour::Types.const_get(relative_generic_type).new(
|
205
|
+
if SINGLE_ARG_GENERIC_TYPES.include?(relative_generic_type) && yard_parameters.length > 1
|
206
|
+
Parlour::Types.const_get(relative_generic_type).new(yard_to_parlour(yard_parameters, item, config))
|
202
207
|
elsif relative_generic_type == 'Class'
|
203
208
|
if parameters.length == 1
|
204
209
|
Parlour::Types::Class.new(parameters.first)
|
data/lib/sord/version.rb
CHANGED
data/rbi/sord.rbi
CHANGED
data/sord.gemspec
CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_dependency 'commander', '~> 5.0'
|
28
28
|
spec.add_dependency "parser"
|
29
29
|
spec.add_dependency 'parlour', '~> 9.1'
|
30
|
-
spec.add_dependency 'rbs', '
|
30
|
+
spec.add_dependency 'rbs', '>=3.0', '<5'
|
31
31
|
|
32
32
|
spec.add_development_dependency "bundler", "~> 2.0"
|
33
33
|
spec.add_development_dependency "rake", "~> 13.0"
|
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: 7.
|
4
|
+
version: 7.1.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: 2025-
|
11
|
+
date: 2025-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: yard
|
@@ -84,16 +84,22 @@ dependencies:
|
|
84
84
|
name: rbs
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '3.0'
|
90
|
+
- - "<"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '5'
|
90
93
|
type: :runtime
|
91
94
|
prerelease: false
|
92
95
|
version_requirements: !ruby/object:Gem::Requirement
|
93
96
|
requirements:
|
94
|
-
- - "
|
97
|
+
- - ">="
|
95
98
|
- !ruby/object:Gem::Version
|
96
99
|
version: '3.0'
|
100
|
+
- - "<"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '5'
|
97
103
|
- !ruby/object:Gem::Dependency
|
98
104
|
name: bundler
|
99
105
|
requirement: !ruby/object:Gem::Requirement
|
@@ -174,6 +180,7 @@ extra_rdoc_files: []
|
|
174
180
|
files:
|
175
181
|
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
176
182
|
- ".github/ISSUE_TEMPLATE/feature-request.md"
|
183
|
+
- ".github/workflows/examples.yml"
|
177
184
|
- ".github/workflows/ruby.yml"
|
178
185
|
- ".gitignore"
|
179
186
|
- ".parlour"
|
@@ -214,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
214
221
|
- !ruby/object:Gem::Version
|
215
222
|
version: '0'
|
216
223
|
requirements: []
|
217
|
-
rubygems_version: 3.
|
224
|
+
rubygems_version: 3.4.1
|
218
225
|
signing_key:
|
219
226
|
specification_version: 4
|
220
227
|
summary: Generate Sorbet RBI files from YARD documentation
|