semdiff 0.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 +7 -0
- data/.editorconfig +8 -0
- data/.rubocop.yml +28 -0
- data/.rubocop_todo.yml +41 -0
- data/.ruby-version +1 -0
- data/Gemfile +16 -0
- data/LICENSE +21 -0
- data/README.md +55 -0
- data/Rakefile +12 -0
- data/bin/semdiff +6 -0
- data/lib/semdiff/algebra_compiler.rb +180 -0
- data/lib/semdiff/aliasing_compiler.rb +65 -0
- data/lib/semdiff/cli/cli.rb +160 -0
- data/lib/semdiff/constants_compiler.rb +91 -0
- data/lib/semdiff/identity_compiler.rb +136 -0
- data/lib/semdiff/structures_compiler.rb +194 -0
- data/lib/semdiff/type_visitor.rb +207 -0
- data/lib/semdiff/utils/compiler_utils.rb +22 -0
- data/lib/semdiff/utils/io_utils.rb +238 -0
- data/lib/semdiff/version.rb +5 -0
- data/lib/semdiff.rb +31 -0
- data/sig/semdiff.rbs +4 -0
- metadata +152 -0
@@ -0,0 +1,238 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
module Semdiff
|
6
|
+
module IOUtils
|
7
|
+
include ::Typeguard::TypeModel::Builder
|
8
|
+
|
9
|
+
FILE_PREFIX = 'source'
|
10
|
+
FILE_SUFFIX = '.rb'
|
11
|
+
DIR_PREFIX = 'yard_'
|
12
|
+
DIR_SUFFIX = '_db'
|
13
|
+
RUBY_VERSION_F = RUBY_VERSION.to_f
|
14
|
+
|
15
|
+
def with_types_desugared(*content)
|
16
|
+
with_temp_files(*content) do |files|
|
17
|
+
with_temp_dir do |dir|
|
18
|
+
system(*yardoc_cmd(files, dir))
|
19
|
+
program_node = Prism.parse_file(files.first.path).value
|
20
|
+
types = YardBuilder.new(dir, false).build
|
21
|
+
node_types = TypeVisitor.new(types).visit(program_node)
|
22
|
+
yield program_node, node_types
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def with_prism_and_yard_types(*contents)
|
28
|
+
with_temp_files(*contents) do |files|
|
29
|
+
with_temp_dir do |dir|
|
30
|
+
system(*yardoc_cmd(files, dir))
|
31
|
+
parse_lex_results = files.map do |f|
|
32
|
+
Prism.parse_lex_file(f.path)
|
33
|
+
end
|
34
|
+
types = YardBuilder.new(dir, false).build
|
35
|
+
yield files, dir, parse_lex_results, types
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def with_full_prism_desugared(*contents)
|
41
|
+
with_temp_files(*contents) do |files|
|
42
|
+
with_temp_dir do |dir|
|
43
|
+
system(*yardoc_cmd(files, dir))
|
44
|
+
program_nodes = files.map do |f|
|
45
|
+
Prism.parse_file(f.path).value.accept(Prism::DesugarCompiler.new)
|
46
|
+
end
|
47
|
+
types = YardBuilder.new(dir, false).build
|
48
|
+
yield files, dir, program_nodes, types
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def with_prism_desugared(*contents)
|
54
|
+
with_temp_files(*contents) do |files|
|
55
|
+
program_node = files.map do |f|
|
56
|
+
Prism.parse_file(f.path).value.accept(Prism::DesugarCompiler.new)
|
57
|
+
end
|
58
|
+
yield files, program_node
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def with_full_prism(*contents)
|
63
|
+
with_temp_files(*contents) do |files|
|
64
|
+
with_temp_dir do |dir|
|
65
|
+
system(*yardoc_cmd(files, dir))
|
66
|
+
program_node = Prism.parse_file(files.first.path).value
|
67
|
+
types = YardBuilder.new(dir, false).build
|
68
|
+
yield files, dir, program_node, types
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def with_prism(*contents)
|
74
|
+
with_temp_files(*contents) do |files|
|
75
|
+
program_node = files.map do |f|
|
76
|
+
Prism.parse_file(f.path).value
|
77
|
+
end
|
78
|
+
yield files, program_node
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def with_yard_types(*contents)
|
83
|
+
with_temp_files(*contents) do |files|
|
84
|
+
with_temp_dir do |dir|
|
85
|
+
system(*yardoc_cmd(files, dir))
|
86
|
+
types = YardBuilder.new(dir, false).build
|
87
|
+
yield files, dir, types
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def with_yardoc_and_prism(*contents)
|
93
|
+
with_temp_files(*contents) do |files|
|
94
|
+
with_temp_dir do |dir|
|
95
|
+
system(*yardoc_cmd(files, dir))
|
96
|
+
parse_lex_results = files.map do |f|
|
97
|
+
Prism.parse_lex_file(f.path)
|
98
|
+
end
|
99
|
+
yield files, dir, parse_lex_results
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def with_prism_parse_lex(*contents)
|
105
|
+
with_temp_files(*contents) do |files|
|
106
|
+
parse_lex_results = files.map do |f|
|
107
|
+
Prism.parse_lex_file(f.path)
|
108
|
+
end
|
109
|
+
yield files, parse_lex_results
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def with_yardoc(*contents)
|
114
|
+
with_temp_dir do |dir|
|
115
|
+
with_temp_files(*contents) do |files|
|
116
|
+
system(*yardoc_cmd(files, dir))
|
117
|
+
yield files, dir
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def with_rubocop_ast_and_yard_types(*contents)
|
123
|
+
with_temp_files(*contents) do |files|
|
124
|
+
with_temp_dir do |dir|
|
125
|
+
system(*yardoc_cmd(files, dir))
|
126
|
+
ast_results = files.map do |f|
|
127
|
+
RuboCop::AST::ProcessedSource.from_file(
|
128
|
+
f.path,
|
129
|
+
RUBY_VERSION_F,
|
130
|
+
parser_engine: :parser_prism
|
131
|
+
)
|
132
|
+
end
|
133
|
+
types = YardBuilder.new(dir, false).build
|
134
|
+
yield files, dir, ast_results, types
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def with_rubocop_ast_bypass(*file_prism_pairs)
|
140
|
+
ast_results = file_prism_pairs.map do |f, prism_result|
|
141
|
+
source = File.read(f.path)
|
142
|
+
RuboCop::AST::ProcessedSource.new(
|
143
|
+
source,
|
144
|
+
RUBY_VERSION_F,
|
145
|
+
f.path,
|
146
|
+
parser_engine: :parser_prism,
|
147
|
+
prism_result: prism_result
|
148
|
+
)
|
149
|
+
end
|
150
|
+
yield ast_results
|
151
|
+
end
|
152
|
+
|
153
|
+
def with_rubocop_ast(*contents)
|
154
|
+
with_temp_files(*contents) do |files|
|
155
|
+
ast_results = files.map do |f|
|
156
|
+
RuboCop::AST::ProcessedSource.from_file(
|
157
|
+
f.path,
|
158
|
+
RUBY_VERSION_F,
|
159
|
+
parser_engine: :parser_prism
|
160
|
+
)
|
161
|
+
end
|
162
|
+
yield files, ast_results
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def with_diff_files(contents, names, output_directory: nil)
|
167
|
+
prefix = 'unparsed_'
|
168
|
+
if output_directory
|
169
|
+
FileUtils.mkdir_p(output_directory)
|
170
|
+
b, a = contents.zip(names).map do |c, n|
|
171
|
+
path = File.join(output_directory, "#{prefix}#{n}")
|
172
|
+
File.write(path, c)
|
173
|
+
File.open(path, 'r')
|
174
|
+
end
|
175
|
+
begin
|
176
|
+
yield b, a
|
177
|
+
ensure
|
178
|
+
b.close
|
179
|
+
a.close
|
180
|
+
end
|
181
|
+
else
|
182
|
+
b_temp, a_temp = contents.zip(names).map do |c, n|
|
183
|
+
temp_file(c, prefix: '', suffix: "_#{prefix}#{n}")
|
184
|
+
end
|
185
|
+
begin
|
186
|
+
yield b_temp, a_temp
|
187
|
+
ensure
|
188
|
+
File.unlink(b_temp.path)
|
189
|
+
File.unlink(a_temp.path)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def with_temp_files(*contents, prefix: FILE_PREFIX, suffix: FILE_SUFFIX)
|
195
|
+
files = contents.map.with_index do |content, i|
|
196
|
+
temp_file(content, prefix: "#{prefix}#{i}_", suffix: suffix)
|
197
|
+
end
|
198
|
+
begin
|
199
|
+
yield files
|
200
|
+
ensure
|
201
|
+
files.each { |f| File.unlink(f.path) }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def with_temp_dir(prefix: DIR_PREFIX, suffix: DIR_SUFFIX)
|
206
|
+
dir = temp_dir(prefix: prefix, suffix: suffix)
|
207
|
+
begin
|
208
|
+
yield dir
|
209
|
+
ensure
|
210
|
+
FileUtils.remove_entry_secure(dir)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def temp_file(content, prefix: FILE_PREFIX, suffix: FILE_SUFFIX)
|
215
|
+
f = Tempfile.create([prefix, suffix])
|
216
|
+
f.write(content)
|
217
|
+
f.close
|
218
|
+
f
|
219
|
+
end
|
220
|
+
|
221
|
+
def temp_dir(prefix: DIR_PREFIX, suffix: DIR_SUFFIX)
|
222
|
+
Dir.mktmpdir([prefix, suffix])
|
223
|
+
end
|
224
|
+
|
225
|
+
def yardoc_cmd(files, db_dir)
|
226
|
+
[
|
227
|
+
'bundle', 'exec', 'yardoc',
|
228
|
+
*files.map(&:path),
|
229
|
+
'--db', db_dir,
|
230
|
+
'--quiet',
|
231
|
+
'--no-output',
|
232
|
+
'--no-cache',
|
233
|
+
'--fail-on-warning',
|
234
|
+
'--embed-mixins'
|
235
|
+
]
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
data/lib/semdiff.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Semdiff
|
4
|
+
# typeguard gem for type specifications
|
5
|
+
require 'typeguard'
|
6
|
+
|
7
|
+
# external
|
8
|
+
require 'prism'
|
9
|
+
# suppress warning (re: https://github.com/glebm/i18n-tasks/pull/613):
|
10
|
+
# warning: parser/current is loading parser/ruby34, which recognizes 3.4.0-dev-compliant syntax, but you are running 3.4.1.
|
11
|
+
# Please see https://github.com/whitequark/parser#compatibility-with-ruby-mri.
|
12
|
+
prev = $VERBOSE
|
13
|
+
$VERBOSE = nil
|
14
|
+
require 'unparser'
|
15
|
+
$VERBOSE = prev
|
16
|
+
|
17
|
+
# utils
|
18
|
+
require_relative 'semdiff/utils/compiler_utils'
|
19
|
+
require_relative 'semdiff/utils/io_utils'
|
20
|
+
|
21
|
+
# prism compilers and visitors
|
22
|
+
require_relative 'semdiff/aliasing_compiler'
|
23
|
+
require_relative 'semdiff/constants_compiler'
|
24
|
+
require_relative 'semdiff/identity_compiler'
|
25
|
+
require_relative 'semdiff/structures_compiler'
|
26
|
+
require_relative 'semdiff/algebra_compiler'
|
27
|
+
require_relative 'semdiff/type_visitor'
|
28
|
+
|
29
|
+
# command line module
|
30
|
+
require_relative 'semdiff/cli/cli'
|
31
|
+
end
|
data/sig/semdiff.rbs
ADDED
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: semdiff
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tesorion
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-07-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: optparse
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: prism
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rbs
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: typeguard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: unparser
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- QmanageDevelopment@tesorion.nl
|
100
|
+
executables:
|
101
|
+
- semdiff
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- ".editorconfig"
|
106
|
+
- ".rubocop.yml"
|
107
|
+
- ".rubocop_todo.yml"
|
108
|
+
- ".ruby-version"
|
109
|
+
- Gemfile
|
110
|
+
- LICENSE
|
111
|
+
- README.md
|
112
|
+
- Rakefile
|
113
|
+
- bin/semdiff
|
114
|
+
- lib/semdiff.rb
|
115
|
+
- lib/semdiff/algebra_compiler.rb
|
116
|
+
- lib/semdiff/aliasing_compiler.rb
|
117
|
+
- lib/semdiff/cli/cli.rb
|
118
|
+
- lib/semdiff/constants_compiler.rb
|
119
|
+
- lib/semdiff/identity_compiler.rb
|
120
|
+
- lib/semdiff/structures_compiler.rb
|
121
|
+
- lib/semdiff/type_visitor.rb
|
122
|
+
- lib/semdiff/utils/compiler_utils.rb
|
123
|
+
- lib/semdiff/utils/io_utils.rb
|
124
|
+
- lib/semdiff/version.rb
|
125
|
+
- sig/semdiff.rbs
|
126
|
+
homepage: https://github.com/tesorion/semdiff
|
127
|
+
licenses:
|
128
|
+
- MIT
|
129
|
+
metadata:
|
130
|
+
homepage_uri: https://github.com/tesorion/semdiff
|
131
|
+
source_code_uri: https://github.com/tesorion/semdiff
|
132
|
+
rubygems_mfa_required: 'true'
|
133
|
+
post_install_message:
|
134
|
+
rdoc_options: []
|
135
|
+
require_paths:
|
136
|
+
- lib
|
137
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 2.7.0
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
requirements: []
|
148
|
+
rubygems_version: 3.3.7
|
149
|
+
signing_key:
|
150
|
+
specification_version: 4
|
151
|
+
summary: Diff two files with AST normalizations
|
152
|
+
test_files: []
|