recheck 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 229b7b48547c7da457bff99e2d10cef1d46a915ad4f3699dd0ae3ad29b7075af
4
- data.tar.gz: 55d665725da5fe601a0c86ba9c4f62943702b56c7ae239aa3c8c1fe31e01b94c
3
+ metadata.gz: 4f6d708bcbdaeb426979687daffc616bf45829d7d3cc82f36bbf5331664ac737
4
+ data.tar.gz: dc56ce8289e425936891ecb106f1b4a7a7c82b58035bd4b4f4c90d0353312bbd
5
5
  SHA512:
6
- metadata.gz: b2b403ea3658c20f66b825f1198c3c6ea341161b84face61a83529c284135f230b069bd4db13f2550dde0e7965944ac36d3de56b3ec0cb4b579a99796e16dc5a
7
- data.tar.gz: 1dbfd3a4dd3252b9e8603a9b9bbb28fb35255acdb4d068dfe74d55fde7e0683b53ff66b59c89eae29848070193a0ea48c8da51a78195e88ede9e3f8c35b6039a
6
+ metadata.gz: 4a368e70331a30b93eeeafc5f75cc92fe94fa06ceba27d66a334367f17b84c666e4cbeb32106826fd779b0c3ffd40e5b04656b63c08b3fd214f71fc6cde83898
7
+ data.tar.gz: e6b8607c5338ac141da261503da2c8e820b2397adef3a2e6926577bca5e97162a2024c3eec34bfba36e705b7d2d09b99ee377f681c1f9f99582a83bd337f5433
@@ -0,0 +1,10 @@
1
+ require "rails"
2
+ require "recheck"
3
+
4
+ module Recheck
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ load File.expand_path("../../tasks/recheck_tasks.rake", __FILE__)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,143 @@
1
+ require "pathname"
2
+
3
+ require "erb"
4
+
5
+ require_relative "validation"
6
+
7
+ module Recheck
8
+ module Command
9
+ class Setup
10
+ # override the base gem's method; with the Rails env booted we can
11
+ # introspect the models to create much better initial checks
12
+ def setup_model_checks
13
+ puts "Introspecting ApplicationRecord..."
14
+
15
+ # surely there's a better way to find the gem's root
16
+ template_dir = File.join(File.expand_path("../../..", __dir__), "template")
17
+ model_template = File.read("#{template_dir}/application_record_check.rb.erb")
18
+ validation_template = File.read("#{template_dir}/validation_checker.rb.erb")
19
+
20
+ # Get all non-abstract ActiveRecord model classes
21
+ models = ApplicationRecord.descendants.each do |model|
22
+ puts model
23
+ puts " skipping abstract class" or next if model.abstract_class?
24
+ puts " skipping readonly model (probably a view)" or next if model.new.send(:readonly?)
25
+
26
+ source_location = Object.const_source_location(model.to_s)
27
+ model_root_filename = source_location[0].sub(%r{#{Rails.root}/}, "")
28
+ # kind of a bad variable name here, but support the default model path + others
29
+ model_filename = model_root_filename.sub(%r{^app/models/}, "")
30
+
31
+ if %r{/zeitwerk/}.match?(source_location.first)
32
+ puts " Warning: model class wasn't loaded; apparently saw a zeitwerk placeholder for its source_location: #{souce_location}"
33
+ puts "Your app boots/preloads in an unexpected way, if you can help debug please open an issue on recheck."
34
+ exit 1
35
+ end
36
+
37
+ model_check_filename = "recheck/model/#{model_filename}"
38
+ class_name = model.name.sub("::", "_") # to differentiate AccountName and Account::Name
39
+ depth = 1 + model_filename.count("/")
40
+
41
+ puts " #{model_check_filename}"
42
+ FileUtils.mkdir_p(File.dirname(model_check_filename))
43
+ rendered = ERB.new(model_template).result_with_hash({class_name:, depth:, model:, model_root_filename:})
44
+ File.write(model_check_filename, rendered)
45
+
46
+ validation_check_filename = "recheck/validation/#{model_filename}"
47
+ puts " #{validation_check_filename}"
48
+ FileUtils.mkdir_p(File.dirname(validation_check_filename))
49
+ binding = Validation.new(class_name:, depth:, model:, model_root_filename:, queries: queries(model:)).get_binding
50
+ rendered = ERB.new(validation_template, trim_mode: "-").result(binding)
51
+ File.write(validation_check_filename, rendered)
52
+ end
53
+ end
54
+
55
+ def queries model:
56
+ model.validators.map do |validator|
57
+ # validators take a list of attributes but operate on them individually
58
+ validator.attributes.map do |attr|
59
+ name = "query_#{validator.kind}_#{attr}"
60
+ # remove memory addresses; just noise
61
+ inspect = validator.inspect.gsub(/(#<[\w:]+):0x[0-9a-f]+ /, '\1 ')
62
+
63
+ column = model.columns_hash[attr.to_s]
64
+ next Placeholder.new inspect:, comment: "Can't query attribute #{attr}, it's not a database column" if column.nil?
65
+ type = column.sql_type_metadata.type
66
+
67
+ if validator.options[:if] || validator.options[:unless]
68
+ next Placeholder.new inspect:, comment: "Can't automatically translate this validation's :if or :unless into a query"
69
+ end
70
+
71
+ # normalizing - if not specified or [], on: means [:create, :udpate]
72
+ on = validator.options[:on] || []
73
+ on = [:create, :update] if on.empty?
74
+ if validator.options[:on] == [:create]
75
+ next Placeholder.new inspect:, comment: "Only validates on: :create, so there's nothing to validate for persisted records"
76
+ end
77
+
78
+ warning = if validator.options[:allow_nil] && !column.null
79
+ "Warning: model #{model.name} validates #{attr} with :allow_nil but column #{column.name} is NOT NULL, so a 'valid' record can't be saved.\nRemove :allow_nil or make the column nullable."
80
+ end
81
+
82
+ case validator
83
+ when ActiveModel::BlockValidator
84
+ Placeholder.new inspect:, comment: "Can't automatically translate a Ruby block into a query."
85
+ when ActiveModel::Validations::ConfirmationValidator
86
+ FunctionPlaceholder.new inspect:, name:, comment: "Coming soon to Recheck beta"
87
+ when ActiveModel::Validations::FormatValidator
88
+ FunctionPlaceholder.new inspect:, name:, comment: "Coming soon to Recheck beta"
89
+ when ActiveModel::Validations::InclusionValidator
90
+ FunctionPlaceholder.new inspect:, name:, comment: "Coming soon to Recheck beta"
91
+ when ActiveRecord::Validations::AbsenceValidator
92
+ FunctionPlaceholder.new inspect:, name:, comment: "Coming soon to Recheck beta"
93
+ when ActiveRecord::Validations::AssociatedValidator
94
+ FunctionPlaceholder.new inspect:, name:, comment: "Coming soon to Recheck beta"
95
+ when ActiveRecord::Validations::LengthValidator
96
+ or_clauses = []
97
+ if type == :stirng || type == :integer
98
+ if validator.options[:is]
99
+ or_clauses << %{"LENGTH(`#{column.name}`) = '')"}
100
+ end
101
+ if validator.options[:minimum] && validator.options[:maximum]
102
+ or_clauses << %{"LENGTH(`#{column.name}`) >= #{validator.options[:minimum]} and "LENGTH(`#{column.name}`) <= #{validator.options[:maximum]}}
103
+ elsif validator.options[:minimum]
104
+ or_clauses << %{"LENGTH(`#{column.name}`) >= #{validator.options[:minimum]}}
105
+ elsif validator.options[:maximum]
106
+ or_clauses << %{"LENGTH(`#{column.name}`) <= #{validator.options[:maximum]}}
107
+ end
108
+ elsif type == :boolean
109
+ comment = "Validating length of a boolean is backend-dependednt and a strange idea."
110
+ else
111
+ comment = "Recheck doesn't know how to handle presence on a #{type}, please report."
112
+ end
113
+ if !validator.options[:allow_nil] && !validator.options[:allow_blank]
114
+ or_clauses << "#{column.name}: nil"
115
+ end
116
+ when ActiveRecord::Validations::NumericalityValidator
117
+ FunctionPlaceholder.new inspect:, name:, comment: "Coming soon to Recheck beta"
118
+ when ActiveRecord::Validations::PresenceValidator
119
+ if validator.options[:allow_blank]
120
+ next Placeholder.new inspect:, comment: "Validates presence of #{attr} with :allow_blank, which can never fail."
121
+ end
122
+ or_clauses = []
123
+ if !validator.options[:allow_nil]
124
+ or_clauses << "#{column.name}: nil"
125
+ end
126
+ case type
127
+ when :string
128
+ or_clauses << %{"TRIM(`#{column.name}`) = ''"}
129
+ when :boolean
130
+ or_clauses << "#{column.name}: false"
131
+ else
132
+ comment = "Recheck doesn't know how to handle presence on a #{type}, please report."
133
+ end
134
+ Query.new inspect:, name:, warning:, comment:, or_clauses:
135
+ when ActiveRecord::Validations::UniquenessValidator
136
+ FunctionPlaceholder.new inspect:, name:, comment: "Coming soon to Recheck beta"
137
+ end
138
+ end
139
+ end.flatten
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,11 @@
1
+ module Recheck
2
+ Placeholder = Data.define(:inspect, :comment)
3
+ FunctionPlaceholder = Data.define(:inspect, :name, :comment)
4
+ Query = Data.define(:inspect, :warning, :name, :comment, :or_clauses)
5
+
6
+ Validation = Data.define(:class_name, :depth, :model, :model_root_filename, :queries) do
7
+ def get_binding
8
+ binding
9
+ end
10
+ end
11
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Recheck
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  end
data/lib/recheck.rb CHANGED
@@ -9,12 +9,14 @@ module Recheck
9
9
  end
10
10
  end
11
11
 
12
- require_relative "../vendor/optimist"
13
- require_relative "recheck/checkers"
14
- require_relative "recheck/cli"
15
- require_relative "recheck/commands"
16
- require_relative "recheck/results"
17
- require_relative "recheck/count_stats"
18
- require_relative "recheck/reporters"
19
- require_relative "recheck/runner"
20
- require_relative "recheck/version"
12
+ require "recheck/vendor/optimist"
13
+ require "recheck/checkers"
14
+ require "recheck/cli"
15
+ require "recheck/commands"
16
+ require "recheck/results"
17
+ require "recheck/count_stats"
18
+ require "recheck/reporters"
19
+ require "recheck/runner"
20
+ require "recheck/version"
21
+
22
+ require "recheck/rails/railtie" if defined?(::Rails)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recheck
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Bhat Harkins
@@ -66,9 +66,13 @@ files:
66
66
  - lib/recheck/cli.rb
67
67
  - lib/recheck/commands.rb
68
68
  - lib/recheck/count_stats.rb
69
+ - lib/recheck/rails/railtie.rb
70
+ - lib/recheck/rails/setup.rb
71
+ - lib/recheck/rails/validation.rb
69
72
  - lib/recheck/reporters.rb
70
73
  - lib/recheck/results.rb
71
74
  - lib/recheck/runner.rb
75
+ - lib/recheck/vendor/optimist.rb
72
76
  - lib/recheck/version.rb
73
77
  - template/recheck_helper.rb
74
78
  - template/regression_checker_sample.rb
@@ -76,7 +80,6 @@ files:
76
80
  - template/site/dns_checker.rb
77
81
  - template/site/tls_checker.rb
78
82
  - template/site/whois_checker.rb
79
- - vendor/optimist.rb
80
83
  homepage: https://recheck.dev
81
84
  licenses:
82
85
  - LGPL-3.0
File without changes