curdle 1.0.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 +7 -0
- data/Gemfile +15 -0
- data/LICENSE +21 -0
- data/Rakefile +14 -0
- data/bin/curdle +8 -0
- data/curdle.gemspec +23 -0
- data/lib/curdle/remove_sorbet.rb +209 -0
- data/lib/curdle/tasks.rb +46 -0
- data/lib/curdle/version.rb +3 -0
- data/lib/curdle.rb +18 -0
- data/spec/curdle_spec.rb +155 -0
- data/spec/spec_helper.rb +8 -0
- metadata +82 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '03619ba9f0f656e0ecb014f9e363d30489dcdf5e0ba644ca6cfcd97d07ce117f'
|
4
|
+
data.tar.gz: f77085d060179a1d04ab0c1c7c7d33452d999dc076eba557a782ab16955ba339
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 822585de86c1001268f0124c8b9fb88f8b6fc7b1fcbc73ed36196fef1bdc3fe7caa1cd1ce2c5d6bc4767d3e1f47a030c55bd9e153e593891b735ce08c101252a
|
7
|
+
data.tar.gz: e5f2be2f8e08e34a495965df1359f6fa25a5b9bd5c5c53866192fc6a65218bcc7a11fc1c9846cdce876c3b035f1ce6c3db6ec2485b2f6426aeca5b5186b80a19
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2022 Cameron Dutro
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'rubygems/package_task'
|
4
|
+
|
5
|
+
require 'curdle'
|
6
|
+
|
7
|
+
Bundler::GemHelper.install_tasks
|
8
|
+
|
9
|
+
task default: :spec
|
10
|
+
|
11
|
+
desc 'Run specs'
|
12
|
+
RSpec::Core::RakeTask.new do |t|
|
13
|
+
t.pattern = './spec/**/*_spec.rb'
|
14
|
+
end
|
data/bin/curdle
ADDED
data/curdle.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.unshift File.expand_path('lib', __dir__)
|
2
|
+
require 'curdle/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'curdle'
|
6
|
+
s.version = ::Curdle::VERSION
|
7
|
+
s.authors = ['Cameron Dutro']
|
8
|
+
s.email = ['camertron@gmail.com']
|
9
|
+
s.homepage = 'http://github.com/camertron/curdle'
|
10
|
+
|
11
|
+
s.description = s.summary = 'Programmatically remove Sorbet type annotations from Ruby code.'
|
12
|
+
|
13
|
+
s.platform = Gem::Platform::RUBY
|
14
|
+
|
15
|
+
s.add_dependency 'parser', '~> 3.1'
|
16
|
+
|
17
|
+
s.add_development_dependency 'rspec'
|
18
|
+
|
19
|
+
s.require_path = 'lib'
|
20
|
+
s.executables << 'curdle'
|
21
|
+
|
22
|
+
s.files = Dir['{lib,spec}/**/*', 'Gemfile', 'LICENSE', 'CHANGELOG.md', 'README.md', 'Rakefile', 'curdle.gemspec']
|
23
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
require 'parser/current'
|
2
|
+
|
3
|
+
module Curdle
|
4
|
+
class RemoveSorbet < ::Parser::TreeRewriter
|
5
|
+
def on_send(node)
|
6
|
+
remove_extend(node, 'T::Sig') ||
|
7
|
+
remove_extend(node, 'T::Generic') ||
|
8
|
+
remove_extend(node, 'T::Helpers') ||
|
9
|
+
remove_t_send(node) ||
|
10
|
+
remove_abstract_bang(node)
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_block(node)
|
16
|
+
remove_sig(node)
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_ivasgn(node)
|
21
|
+
remove_let(node)
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_casgn(node)
|
26
|
+
remove_let(node) ||
|
27
|
+
remove_type_member(node) ||
|
28
|
+
remove_type_alias(node)
|
29
|
+
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def remove_extend(send_node, const_str)
|
36
|
+
receiver, name, *args = *send_node
|
37
|
+
return false unless receiver.nil? && name == :extend
|
38
|
+
return false unless args.size == 1
|
39
|
+
return false unless args.first.location.expression.is?(const_str)
|
40
|
+
|
41
|
+
replace(
|
42
|
+
send_node.location.expression,
|
43
|
+
"# #{send_node.location.expression.source}"
|
44
|
+
)
|
45
|
+
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
def remove_sig(block_node)
|
50
|
+
send_node, = *block_node
|
51
|
+
receiver, name, *args = *send_node
|
52
|
+
return false unless receiver.nil? && name == :sig && args.empty?
|
53
|
+
|
54
|
+
comment_out_node(block_node)
|
55
|
+
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
def remove_t_send(send_node)
|
60
|
+
receiver, name = *send_node
|
61
|
+
return false unless receiver && receiver.location.expression.is?('T')
|
62
|
+
|
63
|
+
remove_cast(send_node) ||
|
64
|
+
remove_must(send_node) ||
|
65
|
+
remove_unsafe(send_node)
|
66
|
+
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
def remove_abstract_bang(send_node)
|
71
|
+
receiver, name = *send_node
|
72
|
+
return false unless receiver.nil? && name == :abstract!
|
73
|
+
|
74
|
+
comment_out_node(send_node)
|
75
|
+
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
def remove_cast(send_node)
|
80
|
+
_, name, *args = *send_node
|
81
|
+
return false unless name == :cast
|
82
|
+
|
83
|
+
remove_method_call(send_node)
|
84
|
+
remove_all_but_first_arg(send_node)
|
85
|
+
|
86
|
+
true
|
87
|
+
end
|
88
|
+
|
89
|
+
def remove_must(send_node)
|
90
|
+
_, name, *args = *send_node
|
91
|
+
return false unless name == :must
|
92
|
+
|
93
|
+
remove_method_call(send_node)
|
94
|
+
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
def remove_unsafe(send_node)
|
99
|
+
_, name, *args = *send_node
|
100
|
+
return false unless name == :unsafe
|
101
|
+
|
102
|
+
remove_method_call(send_node)
|
103
|
+
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
def remove_let(asgn_node)
|
108
|
+
case asgn_node.type
|
109
|
+
when :ivasgn
|
110
|
+
lhs_var, rhs = *asgn_node
|
111
|
+
when :casgn
|
112
|
+
_, lhs_var, rhs = *asgn_node
|
113
|
+
else
|
114
|
+
raise "Unexpected node type '#{asgn_node.type}'"
|
115
|
+
end
|
116
|
+
|
117
|
+
return false unless rhs
|
118
|
+
return false unless rhs.type == :send
|
119
|
+
|
120
|
+
receiver, name, *args = *rhs
|
121
|
+
return false unless name == :let && receiver.location.expression.is?('T')
|
122
|
+
|
123
|
+
if args.first.type == :ivar || args.first.type == :cvar
|
124
|
+
rhs_var, = *args.first
|
125
|
+
|
126
|
+
# Indicates the @ivar = T.let(@ivar, ...) pattern. The entire ivar
|
127
|
+
# assignment statement can be removed
|
128
|
+
if lhs_var == rhs_var
|
129
|
+
comment_out_node(asgn_node)
|
130
|
+
end
|
131
|
+
else
|
132
|
+
# indicates assigning the ivar to an actual value, in which case we
|
133
|
+
# can just remove the let and all args except the first
|
134
|
+
remove_method_call(rhs)
|
135
|
+
remove_all_but_first_arg(rhs)
|
136
|
+
end
|
137
|
+
|
138
|
+
true
|
139
|
+
end
|
140
|
+
|
141
|
+
def remove_type_member(casgn_node)
|
142
|
+
_, _const_name, value_node = *casgn_node
|
143
|
+
return false unless value_node.type == :send
|
144
|
+
|
145
|
+
receiver, name = *value_node
|
146
|
+
return false unless receiver.nil? && name == :type_member
|
147
|
+
|
148
|
+
comment_out_node(casgn_node)
|
149
|
+
|
150
|
+
true
|
151
|
+
end
|
152
|
+
|
153
|
+
def remove_type_alias(casgn_node)
|
154
|
+
_, _const_name, value_node = *casgn_node
|
155
|
+
return false unless value_node.type == :block
|
156
|
+
|
157
|
+
send_node, = *value_node
|
158
|
+
receiver, name = *send_node
|
159
|
+
return false unless receiver && receiver.location.expression.is?('T') && name == :type_alias
|
160
|
+
|
161
|
+
comment_out_node(casgn_node)
|
162
|
+
|
163
|
+
true
|
164
|
+
end
|
165
|
+
|
166
|
+
def remove_method_call(send_node)
|
167
|
+
receiver, name = *send_node
|
168
|
+
|
169
|
+
# remove receiver, dot, and method name
|
170
|
+
remove(receiver.location.expression) if receiver
|
171
|
+
remove(send_node.location.dot) if send_node.location.dot
|
172
|
+
remove(send_node.location.selector)
|
173
|
+
|
174
|
+
# remove enclosing parens
|
175
|
+
remove(send_node.location.begin) if send_node.location.begin
|
176
|
+
remove(send_node.location.end) if send_node.location.end
|
177
|
+
end
|
178
|
+
|
179
|
+
def remove_all_but_first_arg(send_node)
|
180
|
+
_, _, *args = *send_node
|
181
|
+
first_arg_loc = args[0].location.expression
|
182
|
+
remove(args[1].location.expression.with(begin_pos: first_arg_loc.end_pos))
|
183
|
+
end
|
184
|
+
|
185
|
+
def comment_out_node(node)
|
186
|
+
location = include_leading_whitespace(node.location.expression)
|
187
|
+
lines = location.source.split(/\r?\n/)
|
188
|
+
indent = lines.map { |line| line.index(/[\S]/) }.min
|
189
|
+
new_str = lines.map { |line| line.insert(indent, '# ') }.join("\n")
|
190
|
+
replace(location, new_str)
|
191
|
+
end
|
192
|
+
|
193
|
+
def include_leading_whitespace(location)
|
194
|
+
source = location.source_buffer.source
|
195
|
+
start = source.rindex(/[^ \t]/, location.begin_pos - 1) + 1
|
196
|
+
location.with(begin_pos: start)
|
197
|
+
end
|
198
|
+
|
199
|
+
# this isn't used anywhere but it was so hard to write I'm keeping it in case
|
200
|
+
# I ever need to use it again
|
201
|
+
def include_trailing_whitespace(location)
|
202
|
+
if m = source.match(/[ \t]*(?:\r?\n)*/, location.end_pos)
|
203
|
+
location = location.with(end_pos: location.end_pos + m[0].size)
|
204
|
+
end
|
205
|
+
|
206
|
+
location
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
data/lib/curdle/tasks.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Curdle
|
2
|
+
module Tasks
|
3
|
+
class << self
|
4
|
+
include Rake::DSL
|
5
|
+
|
6
|
+
def install(gemspec_file = find_gemspec)
|
7
|
+
task :build do
|
8
|
+
require 'tmpdir'
|
9
|
+
require 'fileutils'
|
10
|
+
|
11
|
+
Dir.mktmpdir do |build_dir|
|
12
|
+
spec = Bundler.load_gemspec(gemspec_file)
|
13
|
+
|
14
|
+
spec.files.each do |source_path|
|
15
|
+
next if File.directory?(source_path)
|
16
|
+
|
17
|
+
dest_path = File.join(build_dir, source_path)
|
18
|
+
FileUtils.mkdir_p(File.dirname(dest_path))
|
19
|
+
|
20
|
+
if File.extname(source_path) == '.rb'
|
21
|
+
File.write(dest_path, Curdle.process(File.read(source_path)))
|
22
|
+
else
|
23
|
+
FileUtils.cp(source_path, dest_path)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
system("gem build --silent -C #{build_dir}")
|
28
|
+
artifact = Dir.glob(File.join(build_dir, "#{spec.name}*.gem")).first
|
29
|
+
|
30
|
+
FileUtils.mkdir_p('pkg')
|
31
|
+
artifact_dest = File.join('pkg', File.basename(artifact))
|
32
|
+
FileUtils.cp(artifact, artifact_dest)
|
33
|
+
|
34
|
+
puts "#{spec.name} #{spec.version} built to #{artifact_dest}."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def find_gemspec
|
42
|
+
Dir.glob(File.join(Dir.getwd, '*.gemspec')).first
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/curdle.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'parser/current'
|
2
|
+
|
3
|
+
module Curdle
|
4
|
+
autoload :RemoveSorbet, 'curdle/remove_sorbet'
|
5
|
+
autoload :Tasks, 'curdle/tasks'
|
6
|
+
|
7
|
+
def self.process_file(file)
|
8
|
+
code = File.read(file)
|
9
|
+
File.write(file, process(code, file))
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.process(code, filename = '(curdle)')
|
13
|
+
ast = Parser::CurrentRuby.parse(code)
|
14
|
+
buffer = Parser::Source::Buffer.new(filename, source: code)
|
15
|
+
rewriter = Curdle::RemoveSorbet.new
|
16
|
+
rewriter.rewrite(buffer, ast)
|
17
|
+
end
|
18
|
+
end
|
data/spec/curdle_spec.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Curdle do
|
4
|
+
def verify(input, expected)
|
5
|
+
expect(described_class.process(input)).to eq(expected)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'removes extend T::Sig' do
|
9
|
+
verify('extend T::Sig', '# extend T::Sig')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'removes extend T::Generic' do
|
13
|
+
verify('extend T::Generic', '# extend T::Generic')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'removes extend T::Helpers' do
|
17
|
+
verify('extend T::Helpers', '# extend T::Helpers')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'removes casts' do
|
21
|
+
verify('foo = T.cast(bar, String)', 'foo = bar')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'removes musts' do
|
25
|
+
verify('foo = T.must(bar)', 'foo = bar')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'removes unsafes' do
|
29
|
+
verify('foo = T.unsafe(bar)', 'foo = bar')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'removes abstract! calls' do
|
33
|
+
verify(<<~END1, <<~END2)
|
34
|
+
class Foo
|
35
|
+
abstract!
|
36
|
+
end
|
37
|
+
END1
|
38
|
+
class Foo
|
39
|
+
# abstract!
|
40
|
+
end
|
41
|
+
END2
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'removes single-line sigs' do
|
45
|
+
verify(<<~END1, <<~END2)
|
46
|
+
class Foo
|
47
|
+
sig { returns(String) }
|
48
|
+
def foo
|
49
|
+
end
|
50
|
+
end
|
51
|
+
END1
|
52
|
+
class Foo
|
53
|
+
# sig { returns(String) }
|
54
|
+
def foo
|
55
|
+
end
|
56
|
+
end
|
57
|
+
END2
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'removes multi-line sigs' do
|
61
|
+
verify(<<~END1, <<~END2)
|
62
|
+
class Foo
|
63
|
+
sig {
|
64
|
+
params(bar: String, baz: Integer).returns(String)
|
65
|
+
}
|
66
|
+
def foo(bar, baz)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
END1
|
70
|
+
class Foo
|
71
|
+
# sig {
|
72
|
+
# params(bar: String, baz: Integer).returns(String)
|
73
|
+
# }
|
74
|
+
def foo(bar, baz)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
END2
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'removes T.let assigned to an instance variable' do
|
81
|
+
verify(<<~END1, <<~END2)
|
82
|
+
class Foo
|
83
|
+
def initialize
|
84
|
+
@version = T.let(@version, T.nilable(String))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
END1
|
88
|
+
class Foo
|
89
|
+
def initialize
|
90
|
+
# @version = T.let(@version, T.nilable(String))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
END2
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'removes T.let ivar with an actual value' do
|
97
|
+
verify(<<~END1, <<~END2)
|
98
|
+
class Foo
|
99
|
+
def initialize
|
100
|
+
@version = T.let(version, T.nilable(String))
|
101
|
+
end
|
102
|
+
end
|
103
|
+
END1
|
104
|
+
class Foo
|
105
|
+
def initialize
|
106
|
+
@version = version
|
107
|
+
end
|
108
|
+
end
|
109
|
+
END2
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'removes T.let assigned to a constant' do
|
113
|
+
verify(<<~END1, <<~END2)
|
114
|
+
class Foo
|
115
|
+
FOO = T.let('foo'.freeze, String)
|
116
|
+
end
|
117
|
+
END1
|
118
|
+
class Foo
|
119
|
+
FOO = 'foo'.freeze
|
120
|
+
end
|
121
|
+
END2
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'removes type_members' do
|
125
|
+
verify(<<~END1, <<~END2)
|
126
|
+
class Foo
|
127
|
+
extend T::Generic
|
128
|
+
|
129
|
+
Elem = type_member
|
130
|
+
end
|
131
|
+
END1
|
132
|
+
class Foo
|
133
|
+
# extend T::Generic
|
134
|
+
|
135
|
+
# Elem = type_member
|
136
|
+
end
|
137
|
+
END2
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'removes type_aliases' do
|
141
|
+
verify(<<~END1, <<~END2)
|
142
|
+
class Foo
|
143
|
+
AfterCallback = T.type_alias do
|
144
|
+
T.proc.params(cmd: T::Array[String], last_status: T.nilable(Process::Status)).void
|
145
|
+
end
|
146
|
+
end
|
147
|
+
END1
|
148
|
+
class Foo
|
149
|
+
# AfterCallback = T.type_alias do
|
150
|
+
# T.proc.params(cmd: T::Array[String], last_status: T.nilable(Process::Status)).void
|
151
|
+
# end
|
152
|
+
end
|
153
|
+
END2
|
154
|
+
end
|
155
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: curdle
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cameron Dutro
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-04-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: parser
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Programmatically remove Sorbet type annotations from Ruby code.
|
42
|
+
email:
|
43
|
+
- camertron@gmail.com
|
44
|
+
executables:
|
45
|
+
- curdle
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- Gemfile
|
50
|
+
- LICENSE
|
51
|
+
- Rakefile
|
52
|
+
- bin/curdle
|
53
|
+
- curdle.gemspec
|
54
|
+
- lib/curdle.rb
|
55
|
+
- lib/curdle/remove_sorbet.rb
|
56
|
+
- lib/curdle/tasks.rb
|
57
|
+
- lib/curdle/version.rb
|
58
|
+
- spec/curdle_spec.rb
|
59
|
+
- spec/spec_helper.rb
|
60
|
+
homepage: http://github.com/camertron/curdle
|
61
|
+
licenses: []
|
62
|
+
metadata: {}
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubygems_version: 3.2.32
|
79
|
+
signing_key:
|
80
|
+
specification_version: 4
|
81
|
+
summary: Programmatically remove Sorbet type annotations from Ruby code.
|
82
|
+
test_files: []
|