tng 0.4.5 → 0.4.6
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/bin/tng +162 -3
- data/binaries/go-ui-darwin-amd64 +0 -0
- data/binaries/go-ui-darwin-arm64 +0 -0
- data/binaries/go-ui-linux-amd64 +0 -0
- data/binaries/go-ui-linux-arm64 +0 -0
- data/binaries/tng-darwin-arm64.bundle +0 -0
- data/binaries/tng-darwin-x86_64.bundle +0 -0
- data/binaries/tng-linux-arm64.so +0 -0
- data/binaries/tng-linux-x86_64.so +0 -0
- data/binaries/tng.bundle +0 -0
- data/lib/tng/services/direct_generation.rb +40 -5
- data/lib/tng/ui/go_ui_session.rb +48 -6
- data/lib/tng/ui/json_session.rb +4 -0
- data/lib/tng/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a4de2429d2ed196847183d8142115e1b99266d474704b0d2b9dfc6a794b1904c
|
|
4
|
+
data.tar.gz: 001e994ec388b5e5bed712a506f6acb3267c0d163377390bff45c87e980fa52b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 58dd488f1924aa1680f0f3f327042af5133bfc92f2c9eb56540f5b49d89f24905cd20a8baa88deb69d8cbe3bb519693a6b8fea98e14a852bbe5731cb4343d0ed
|
|
7
|
+
data.tar.gz: 1e45869a87e3787f642bdeb245daa1b4776187b73a4a07712e81aa6518b7e9720c41d8ab1747460df5b12d803e158eb778fbc4c96816932aadaf93fe5e729369
|
data/bin/tng
CHANGED
|
@@ -44,6 +44,10 @@ class CLI
|
|
|
44
44
|
example " bundle exec tng app/controllers/users_controller.rb index", ""
|
|
45
45
|
example " bundle exec tng f=users_controller.rb m=show", ""
|
|
46
46
|
example " bundle exec tng --file=app/models/user.rb --method=validate", ""
|
|
47
|
+
example ""
|
|
48
|
+
example "Duplicate Detection:", ""
|
|
49
|
+
example " bundle exec tng app/services/pricing_service.rb --clones", ""
|
|
50
|
+
example " bundle exec tng --file=users_controller.rb --clones --level=2", ""
|
|
47
51
|
end
|
|
48
52
|
|
|
49
53
|
option :file do
|
|
@@ -58,6 +62,18 @@ class CLI
|
|
|
58
62
|
desc "Method name (for per-method tests)"
|
|
59
63
|
end
|
|
60
64
|
|
|
65
|
+
flag :clones do
|
|
66
|
+
short "-c"
|
|
67
|
+
long "--clones"
|
|
68
|
+
desc "Run in clone detection mode (find code duplication)"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
option :level do
|
|
72
|
+
short "-l"
|
|
73
|
+
long "--level=LEVEL"
|
|
74
|
+
desc "Analysis level: 1 (Token), 2 (Structural), all (Both)"
|
|
75
|
+
end
|
|
76
|
+
|
|
61
77
|
flag :audit do
|
|
62
78
|
short "-a"
|
|
63
79
|
long "--audit"
|
|
@@ -70,6 +86,7 @@ class CLI
|
|
|
70
86
|
end
|
|
71
87
|
|
|
72
88
|
flag :json do
|
|
89
|
+
short "-j"
|
|
73
90
|
long "--json"
|
|
74
91
|
desc "Output results in JSON format"
|
|
75
92
|
end
|
|
@@ -88,8 +105,8 @@ class CLI
|
|
|
88
105
|
|
|
89
106
|
def initialize
|
|
90
107
|
@pastel = Pastel.new
|
|
91
|
-
# Check for --json flag raw before parsing
|
|
92
|
-
if ARGV.any? { |arg| arg == "--json" }
|
|
108
|
+
# Check for --json or -j flag raw before parsing
|
|
109
|
+
if ARGV.any? { |arg| arg == "--json" || arg == "-j" }
|
|
93
110
|
require "tng/ui/json_session"
|
|
94
111
|
@go_ui = Tng::UI::JsonSession.new
|
|
95
112
|
else
|
|
@@ -158,10 +175,14 @@ class CLI
|
|
|
158
175
|
normalized << "--audit"
|
|
159
176
|
when /^(?:--)?(trace)$/
|
|
160
177
|
normalized << "--trace"
|
|
161
|
-
when /^(?:--)?(json)$/
|
|
178
|
+
when /^(?:--)?(json|j)$/
|
|
162
179
|
normalized << "--json"
|
|
163
180
|
when /^(?:--)?(fix|x)$/
|
|
164
181
|
normalized << "--fix"
|
|
182
|
+
when /^(?:--)?(clones|c)$/
|
|
183
|
+
normalized << "--clones"
|
|
184
|
+
when /^(?:--)?(level|l)=(.+)$/
|
|
185
|
+
normalized << "--level=#{::Regexp.last_match(2)}"
|
|
165
186
|
when /^(help|h)=(.+)$/
|
|
166
187
|
normalized << "--help=#{::Regexp.last_match(2)}"
|
|
167
188
|
when /^--file$/, /^-f$/
|
|
@@ -219,6 +240,8 @@ class CLI
|
|
|
219
240
|
handle_audit_method
|
|
220
241
|
when "trace"
|
|
221
242
|
handle_trace_method
|
|
243
|
+
when "clones"
|
|
244
|
+
handle_clone_detection
|
|
222
245
|
when "stats"
|
|
223
246
|
user_stats
|
|
224
247
|
when "about"
|
|
@@ -249,6 +272,142 @@ class CLI
|
|
|
249
272
|
end
|
|
250
273
|
end
|
|
251
274
|
|
|
275
|
+
def handle_clone_detection
|
|
276
|
+
# Pick a file type first to narrow down
|
|
277
|
+
choice = @go_ui.show_test_type_menu("clones")
|
|
278
|
+
return if choice == "back"
|
|
279
|
+
|
|
280
|
+
case choice
|
|
281
|
+
when "controller"
|
|
282
|
+
detect_controller_clones
|
|
283
|
+
when "model"
|
|
284
|
+
detect_model_clones
|
|
285
|
+
when "service"
|
|
286
|
+
detect_service_clones
|
|
287
|
+
when "other"
|
|
288
|
+
detect_other_clones
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def detect_controller_clones
|
|
293
|
+
controllers = nil
|
|
294
|
+
@go_ui.show_spinner("Analyzing controllers...") do
|
|
295
|
+
controllers = Tng::Analyzers::Controller.files_in_dir("app/controllers").map do |file|
|
|
296
|
+
relative_path = file[:path].gsub(%r{^.*app/controllers/}, "").gsub(".rb", "")
|
|
297
|
+
namespaced_name = relative_path.split("/").map(&:camelize).join("::")
|
|
298
|
+
{ name: namespaced_name, path: file[:path] }
|
|
299
|
+
end
|
|
300
|
+
{ success: true, message: "Found #{controllers.length} controllers" }
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
return @go_ui.show_no_items("controllers") if controllers.empty?
|
|
304
|
+
|
|
305
|
+
items = controllers.map { |c| { name: c[:name], path: c[:path] } }
|
|
306
|
+
selected = @go_ui.show_list_view("Select Controller to Check Duplicates", items)
|
|
307
|
+
return if selected == "back"
|
|
308
|
+
|
|
309
|
+
choice = controllers.find { |c| c[:name] == selected }
|
|
310
|
+
return unless choice
|
|
311
|
+
|
|
312
|
+
level = @go_ui.show_clone_menu
|
|
313
|
+
return if level == "back"
|
|
314
|
+
|
|
315
|
+
run_clone_detection_for_file(choice, level)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def detect_model_clones
|
|
319
|
+
models = nil
|
|
320
|
+
@go_ui.show_spinner("Analyzing models...") do
|
|
321
|
+
models = Tng::Analyzers::Model.files_in_dir("app/models").map do |file|
|
|
322
|
+
relative_path = file[:path].gsub(%r{^.*app/models/}, "").gsub(".rb", "")
|
|
323
|
+
namespaced_name = relative_path.split("/").map(&:camelize).join("::")
|
|
324
|
+
{ name: namespaced_name, path: file[:path] }
|
|
325
|
+
end
|
|
326
|
+
{ success: true, message: "Found #{models.length} models" }
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
return @go_ui.show_no_items("models") if models.empty?
|
|
330
|
+
|
|
331
|
+
items = models.map { |m| { name: m[:name], path: m[:path] } }
|
|
332
|
+
selected = @go_ui.show_list_view("Select Model to Check Duplicates", items)
|
|
333
|
+
return if selected == "back"
|
|
334
|
+
|
|
335
|
+
choice = models.find { |m| m[:name] == selected }
|
|
336
|
+
return unless choice
|
|
337
|
+
|
|
338
|
+
level = @go_ui.show_clone_menu
|
|
339
|
+
return if level == "back"
|
|
340
|
+
|
|
341
|
+
run_clone_detection_for_file(choice, level)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def detect_service_clones
|
|
345
|
+
services = nil
|
|
346
|
+
@go_ui.show_spinner("Analyzing services...") do
|
|
347
|
+
services = Tng::Analyzers::Service.files_in_dir.map do |file|
|
|
348
|
+
relative_path = file[:path].gsub(%r{^.*app/services?/}, "").gsub(".rb", "")
|
|
349
|
+
namespaced_name = relative_path.split("/").map(&:camelize).join("::")
|
|
350
|
+
{ name: namespaced_name, path: file[:path] }
|
|
351
|
+
end
|
|
352
|
+
{ success: true, message: "Found #{services.length} services" }
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
return @go_ui.show_no_items("services") if services.empty?
|
|
356
|
+
|
|
357
|
+
items = services.map { |s| { name: s[:name], path: s[:path] } }
|
|
358
|
+
selected = @go_ui.show_list_view("Select Service to Check Duplicates", items)
|
|
359
|
+
return if selected == "back"
|
|
360
|
+
|
|
361
|
+
choice = services.find { |s| s[:name] == selected }
|
|
362
|
+
return unless choice
|
|
363
|
+
|
|
364
|
+
level = @go_ui.show_clone_menu
|
|
365
|
+
return if level == "back"
|
|
366
|
+
|
|
367
|
+
run_clone_detection_for_file(choice, level)
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def detect_other_clones
|
|
371
|
+
files = nil
|
|
372
|
+
@go_ui.show_spinner("Analyzing other files...") do
|
|
373
|
+
files = Tng::Analyzers::Other.files_in_dir.map do |file|
|
|
374
|
+
relative_path = file[:relative_path].gsub(".rb", "")
|
|
375
|
+
namespaced_name = relative_path.split("/").map(&:camelize).join("::")
|
|
376
|
+
{ name: namespaced_name, path: file[:path], type: file[:type] }
|
|
377
|
+
end
|
|
378
|
+
{ success: true, message: "Found #{files.length} other files" }
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
return @go_ui.show_no_items("other files") if files.empty?
|
|
382
|
+
|
|
383
|
+
items = files.map { |f| { name: f[:name], path: f[:path] } }
|
|
384
|
+
selected = @go_ui.show_list_view("Select File to Check Duplicates", items)
|
|
385
|
+
return if selected == "back"
|
|
386
|
+
|
|
387
|
+
choice = files.find { |f| f[:name] == selected }
|
|
388
|
+
return unless choice
|
|
389
|
+
|
|
390
|
+
level = @go_ui.show_clone_menu
|
|
391
|
+
return if level == "back"
|
|
392
|
+
|
|
393
|
+
run_clone_detection_for_file(choice, level)
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
def run_clone_detection_for_file(file_info, level = "all")
|
|
397
|
+
result = nil
|
|
398
|
+
@go_ui.show_progress("Analyzing #{file_info[:name]} for duplicates (Level #{level})") do |progress|
|
|
399
|
+
progress.update("Parsing file structure...", 50)
|
|
400
|
+
|
|
401
|
+
matches = Tng::Analyzer::Context.analyze_clones(Dir.pwd, File.expand_path(file_info[:path]), level)
|
|
402
|
+
result = { matches: matches }
|
|
403
|
+
|
|
404
|
+
progress.update("Analysis complete!", 100)
|
|
405
|
+
{ message: "Found #{matches.length} duplicate blocks" }
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
@go_ui.show_clones(file_info[:path], result) if result
|
|
409
|
+
end
|
|
410
|
+
|
|
252
411
|
def handle_audit_method
|
|
253
412
|
choice = @go_ui.show_test_type_menu("audit")
|
|
254
413
|
|
data/binaries/go-ui-darwin-amd64
CHANGED
|
Binary file
|
data/binaries/go-ui-darwin-arm64
CHANGED
|
Binary file
|
data/binaries/go-ui-linux-amd64
CHANGED
|
Binary file
|
data/binaries/go-ui-linux-arm64
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/binaries/tng-linux-arm64.so
CHANGED
|
Binary file
|
|
Binary file
|
data/binaries/tng.bundle
CHANGED
|
Binary file
|
|
@@ -28,11 +28,10 @@ module Tng
|
|
|
28
28
|
file_path = @params[:file]
|
|
29
29
|
method_name = @params[:method]
|
|
30
30
|
|
|
31
|
-
unless file_path && method_name
|
|
32
|
-
@go_ui.display_error(@pastel.red("❌
|
|
31
|
+
unless file_path && (method_name || @params[:clones])
|
|
32
|
+
@go_ui.display_error(@pastel.red("❌ File parameter is required#{@params[:clones] ? "" : " along with method"}"))
|
|
33
33
|
@go_ui.display_warning(@pastel.yellow("Usage: bundle exec tng app/controllers/users_controller.rb index"))
|
|
34
|
-
@go_ui.display_warning(@pastel.yellow(" or: bundle exec tng --file=users_controller.rb --
|
|
35
|
-
@go_ui.display_warning(@pastel.yellow(" or: bundle exec tng f=users_controller.rb m=index"))
|
|
34
|
+
@go_ui.display_warning(@pastel.yellow(" or: bundle exec tng --file=users_controller.rb --clones [--level=1|2|all]"))
|
|
36
35
|
return
|
|
37
36
|
end
|
|
38
37
|
|
|
@@ -45,7 +44,12 @@ module Tng
|
|
|
45
44
|
end
|
|
46
45
|
|
|
47
46
|
type = FileTypeDetector.detect_type(resolved_path)
|
|
48
|
-
|
|
47
|
+
|
|
48
|
+
if @params[:clones]
|
|
49
|
+
run_clones_for_file(resolved_path, type)
|
|
50
|
+
else
|
|
51
|
+
generate_test_for_file(resolved_path, method_name, type)
|
|
52
|
+
end
|
|
49
53
|
end
|
|
50
54
|
|
|
51
55
|
def suggest_similar_files(file_path)
|
|
@@ -114,6 +118,21 @@ module Tng
|
|
|
114
118
|
end
|
|
115
119
|
end
|
|
116
120
|
|
|
121
|
+
def run_clones_for_file(file_path, type)
|
|
122
|
+
file_object = FileTypeDetector.build_file_object(file_path, type)
|
|
123
|
+
@go_ui.display_info(@pastel.bright_white("🎯 Analyzing clones in #{file_object[:name]}..."))
|
|
124
|
+
|
|
125
|
+
result = @go_ui.show_progress("Processing...") do |progress|
|
|
126
|
+
perform_clone_analysis(file_object, progress)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
if result&.dig(:error)
|
|
130
|
+
@go_ui.display_error(@pastel.red("❌ Clone analysis failed: #{result[:message]}"))
|
|
131
|
+
else
|
|
132
|
+
@go_ui.show_clones(file_object[:path], result)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
117
136
|
def extract_methods_for_type(file_object, type)
|
|
118
137
|
case type
|
|
119
138
|
when "controller" then extract_controller_methods(file_object)
|
|
@@ -145,6 +164,22 @@ module Tng
|
|
|
145
164
|
end
|
|
146
165
|
end
|
|
147
166
|
|
|
167
|
+
def perform_clone_analysis(file_object, progress)
|
|
168
|
+
progress.update("Analyzing file for duplicates...", 50)
|
|
169
|
+
|
|
170
|
+
project_root = Dir.pwd
|
|
171
|
+
path = File.expand_path(file_object[:path])
|
|
172
|
+
|
|
173
|
+
level = @params[:level] || "all"
|
|
174
|
+
begin
|
|
175
|
+
matches = Tng::Analyzer::Context.analyze_clones(project_root, path, level)
|
|
176
|
+
progress.update("Analysis complete!", 100)
|
|
177
|
+
{ matches: matches }
|
|
178
|
+
rescue => e
|
|
179
|
+
{ error: true, message: e.message }
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
148
183
|
def perform_trace_analysis(file_object, method_info, progress)
|
|
149
184
|
progress.update("Tracing method execution...", 50)
|
|
150
185
|
|
data/lib/tng/ui/go_ui_session.rb
CHANGED
|
@@ -65,6 +65,25 @@ module Tng
|
|
|
65
65
|
File.unlink(output_path) if File.exist?(output_path)
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
|
+
# Returns: "1", "2", "all", "back"
|
|
69
|
+
def show_clone_menu
|
|
70
|
+
output_file = Tempfile.new(["go_ui_clone_menu", ".json"])
|
|
71
|
+
output_path = output_file.path
|
|
72
|
+
output_file.close
|
|
73
|
+
|
|
74
|
+
begin
|
|
75
|
+
system(@binary_path, "clone-menu", "--output", output_path)
|
|
76
|
+
|
|
77
|
+
return "back" unless File.exist?(output_path) && File.size(output_path) > 0
|
|
78
|
+
|
|
79
|
+
choice = File.read(output_path).strip
|
|
80
|
+
choice.empty? ? "back" : choice
|
|
81
|
+
rescue StandardError
|
|
82
|
+
"back"
|
|
83
|
+
ensure
|
|
84
|
+
File.unlink(output_path) if File.exist?(output_path)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
68
87
|
|
|
69
88
|
# @return [String] Selected item name or "back"
|
|
70
89
|
def show_list_view(title, items)
|
|
@@ -261,6 +280,25 @@ module Tng
|
|
|
261
280
|
puts "Trace results error: #{e.message}"
|
|
262
281
|
end
|
|
263
282
|
|
|
283
|
+
# Show clone detection results
|
|
284
|
+
# @param file_path [String] Original file path analyzed
|
|
285
|
+
# @param results [Hash] Clone detection results { matches: [...] }
|
|
286
|
+
def show_clones(file_path, results)
|
|
287
|
+
data = { file_path: file_path, matches: results[:matches] }
|
|
288
|
+
data_json = JSON.generate(data)
|
|
289
|
+
|
|
290
|
+
input_file = Tempfile.new(["go_ui_clones", ".json"])
|
|
291
|
+
input_path = input_file.path
|
|
292
|
+
File.write(input_path, data_json)
|
|
293
|
+
input_file.close
|
|
294
|
+
|
|
295
|
+
system(@binary_path, "clones", "--file", input_path)
|
|
296
|
+
rescue StandardError => e
|
|
297
|
+
puts "Clones results error: #{e.message}"
|
|
298
|
+
ensure
|
|
299
|
+
File.unlink(input_path) if input_path && File.exist?(input_path)
|
|
300
|
+
end
|
|
301
|
+
|
|
264
302
|
# Show authentication error
|
|
265
303
|
# @param message [String] Error message to display
|
|
266
304
|
def show_auth_error(message = "Authentication failed")
|
|
@@ -334,7 +372,8 @@ module Tng
|
|
|
334
372
|
{ cmd: "bundle exec tng", desc: "Interactive mode" },
|
|
335
373
|
{ cmd: "bundle exec tng --file=FILE --method=METHOD", desc: "Direct test generation" },
|
|
336
374
|
{ cmd: "bundle exec tng --file=FILE --method=METHOD --audit", desc: "Direct audit mode" },
|
|
337
|
-
{ cmd: "bundle exec tng --file=FILE --method=METHOD --trace", desc: "Symbolic trace mode" }
|
|
375
|
+
{ cmd: "bundle exec tng --file=FILE --method=METHOD --trace", desc: "Symbolic trace mode" },
|
|
376
|
+
{ cmd: "bundle exec tng --file=FILE --clones", desc: "Check for code duplicates" }
|
|
338
377
|
],
|
|
339
378
|
features: [
|
|
340
379
|
"Controllers, Models, Services",
|
|
@@ -342,6 +381,7 @@ module Tng
|
|
|
342
381
|
"Per-method test generation",
|
|
343
382
|
"Code audit for issues & behaviors",
|
|
344
383
|
"Symbolic execution traces",
|
|
384
|
+
"Duplicate code detection (Clones)",
|
|
345
385
|
"Searchable method lists"
|
|
346
386
|
],
|
|
347
387
|
options: [
|
|
@@ -349,13 +389,15 @@ module Tng
|
|
|
349
389
|
{ flag: "--file=PATH", desc: "Target file path (enables direct CLI mode)" },
|
|
350
390
|
{ flag: "--method=NAME", desc: "Method name to generate test for" },
|
|
351
391
|
{ flag: "--audit", desc: "Run audit mode instead of test generation" },
|
|
352
|
-
{ flag: "--trace", desc: "Run symbolic trace mode" }
|
|
392
|
+
{ flag: "--trace", desc: "Run symbolic trace mode" },
|
|
393
|
+
{ flag: "--clones", desc: "Run clone detection mode" },
|
|
394
|
+
{ flag: "--level=1|2|all", desc: "Set clone detection level (default: all)" }
|
|
353
395
|
],
|
|
354
396
|
how_to: [
|
|
355
|
-
"Run 'bundle exec tng'
|
|
356
|
-
"
|
|
357
|
-
"
|
|
358
|
-
"
|
|
397
|
+
"Run 'bundle exec tng' for interactive mode",
|
|
398
|
+
"Run 'tng [file] --clones' for duplicate detection",
|
|
399
|
+
"Select Controller, Model, or Service to start",
|
|
400
|
+
"Choose a method to generate/audit or select 'Check Duplicates'"
|
|
359
401
|
],
|
|
360
402
|
footer: "Happy testing! "
|
|
361
403
|
}
|
data/lib/tng/ui/json_session.rb
CHANGED
|
@@ -92,6 +92,10 @@ module Tng
|
|
|
92
92
|
emit_event("result", audit_result)
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
+
def show_clones(file_path, results)
|
|
96
|
+
emit_event("clones", { file_path: file_path, matches: results[:matches] })
|
|
97
|
+
end
|
|
98
|
+
|
|
95
99
|
def show_test_results(title, passed, failed, errors, total, results = [])
|
|
96
100
|
emit_event("test_results", {
|
|
97
101
|
title: title,
|
data/lib/tng/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tng
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ralucab
|
|
@@ -222,7 +222,7 @@ post_install_message: "┌ TNG ────────────────
|
|
|
222
222
|
\ │\n│ • bundle exec
|
|
223
223
|
tng --help - Show help information │\n│ │\n│
|
|
224
224
|
\ \U0001F4A1 Generate tests for individual methods with precision │\n└────────────────────────────────────────────────────────────
|
|
225
|
-
v0.4.
|
|
225
|
+
v0.4.6 ┘\n"
|
|
226
226
|
rdoc_options: []
|
|
227
227
|
require_paths:
|
|
228
228
|
- lib
|