Skip to content

Instantly share code, notes, and snippets.

@flavorjones
Created May 9, 2022 12:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save flavorjones/dcadd295ec734bebba2de4271a17f1dc to your computer and use it in GitHub Desktop.
Save flavorjones/dcadd295ec734bebba2de4271a17f1dc to your computer and use it in GitHub Desktop.
rough script to examine Ruby regexp literals with https://makenowjust-labs.github.io/recheck/
#! /usr/bin/env ruby
# coding: utf-8
# Copyright 2022 Mike Dalessio
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
require "bundler/inline"
gemfile do
source "https://rubygems.org/"
gem "syntax_tree"
end
require "open3"
class Rechecker
PATH_TO_RECHECK = "/home/flavorjones/Downloads/recheck"
def check(regexp)
Open3.capture2(PATH_TO_RECHECK, regexp)
end
end
class Reporter
def initialize
@passes = []
@fails = []
@skips = []
end
def pass(filename, location, message, regexp)
@passes << [filename, location, message, regexp]
putc "."
end
def fail(filename, location, message, regexp)
@fails << [filename, location, message, regexp]
putc "F"
end
def skip(filename, location, message)
@skips << [filename, location, message]
putc "S"
end
def finish
total = @passes.length + @fails.length + @skips.length
puts "\n\n"
printf "%d tests, %d failures, %d skips\n", total, @fails.length, @skips.length
puts
@skips.each { |event| report("Skipped", event) }
puts
@fails.each { |event| report("Failed", event) }
end
def report(message, event)
puts
puts [message, "#{event[0]}:#{event[1].start_line}", event[3]].compact.join(": ")
puts event[2]
end
end
require "syntax_tree"
class RegexpVisitor < SyntaxTree::Visitor
def initialize(filename, reporter)
@filename = filename
@reporter = reporter
@rechecker = Rechecker.new
end
def visit_regexp_literal(node)
if node.child_nodes.length != 1 || !node.child_nodes.first.is_a?(SyntaxTree::TStringContent)
@reporter.skip(@filename, node.location, node.pretty_inspect)
return
end
# recheck doesn't understand ruby's "\A" and "\z" regexp anchors,
# so let's use the similar "^" and "$" anchors instead.
value = node.child_nodes.first.value
value = "^" + value[2..] if value.start_with?("\\A")
value = value[..-3] + "$" if value.end_with?("\\z")
options = node.ending[1..-1]
regexp = "/#{value}/#{options}" # send the options to rechecker
result, status = @rechecker.check(regexp)
if status.success?
@reporter.pass(@filename, node.location, result, regexp)
else
@reporter.fail(@filename, node.location, result, regexp)
end
rescue Exception => e
pp e
end
end
reporter = Reporter.new
ruby_files = if ARGV[0]
Dir.glob(ARGV[0].split.map { |d| "#{d}/**/*.rb" })
else
Dir.glob("lib/**/*.rb")
end
ruby_files.each do |fn|
visitor = RegexpVisitor.new(fn, reporter)
visitor.visit(SyntaxTree.parse(SyntaxTree.read(fn)))
end
reporter.finish
@flavorjones
Copy link
Author

flavorjones commented May 9, 2022

If you find this script useful, please let me know. I'm trying to determine whether it would be valuable to ship as a standalone checker, or as a rubocop cop, or in some other form.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment