Class: Bullematic::Detection
- Inherits:
-
Object
- Object
- Bullematic::Detection
- Defined in:
- lib/bullematic/detection.rb,
sig/generated/bullematic/detection.rbs
Instance Attribute Summary collapse
- #associations ⇒ Object readonly
- #base_class ⇒ Object readonly
- #call_stack ⇒ Object readonly
- #context_id ⇒ Object readonly
- #line_number ⇒ Object readonly
- #method_name ⇒ Object readonly
- #source_digest ⇒ Object readonly
- #source_file ⇒ Object readonly
- #type ⇒ Object readonly
Class Method Summary collapse
Instance Method Summary collapse
- #absolute_path(path) ⇒ Pathname
- #current_source_digest ⇒ String?
- #expand_path(path) ⇒ Pathname
-
#fingerprint ⇒ Array[untyped]
: () -> Array.
-
#fixable? ⇒ Boolean
: () -> bool.
-
#initialize(type:, base_class:, associations:, call_stack:, context_id: nil, source_digest: nil) ⇒ Detection
constructor
A new instance of Detection.
-
#model_class_name ⇒ String
: () -> String.
- #normalize_associations(assocs) ⇒ Array[Symbol]
-
#parse_source_location ⇒ void
: () -> void.
- #path_in?(filepath, paths) ⇒ Boolean
-
#skip_path? ⇒ Boolean
: () -> bool.
-
#target_path? ⇒ Boolean
: () -> bool.
- #to_h ⇒ Hash[String, untyped]
Constructor Details
#initialize(type:, base_class:, associations:, call_stack:, context_id: nil, source_digest: nil) ⇒ Detection
Returns a new instance of Detection.
39 40 41 42 43 44 45 46 47 |
# File 'lib/bullematic/detection.rb', line 39 def initialize(type:, base_class:, associations:, call_stack:, context_id: nil, source_digest: nil) @type = type @base_class = base_class @associations = normalize_associations(associations) @call_stack = call_stack @context_id = context_id parse_source_location @source_digest = source_digest || current_source_digest end |
Instance Attribute Details
#associations ⇒ Object (readonly)
29 30 31 |
# File 'lib/bullematic/detection.rb', line 29 def associations @associations end |
#base_class ⇒ Object (readonly)
29 30 31 |
# File 'lib/bullematic/detection.rb', line 29 def base_class @base_class end |
#call_stack ⇒ Object (readonly)
29 30 31 |
# File 'lib/bullematic/detection.rb', line 29 def call_stack @call_stack end |
#context_id ⇒ Object (readonly)
29 30 31 |
# File 'lib/bullematic/detection.rb', line 29 def context_id @context_id end |
#line_number ⇒ Object (readonly)
29 30 31 |
# File 'lib/bullematic/detection.rb', line 29 def line_number @line_number end |
#method_name ⇒ Object (readonly)
29 30 31 |
# File 'lib/bullematic/detection.rb', line 29 def method_name @method_name end |
#source_digest ⇒ Object (readonly)
29 30 31 |
# File 'lib/bullematic/detection.rb', line 29 def source_digest @source_digest end |
#source_file ⇒ Object (readonly)
29 30 31 |
# File 'lib/bullematic/detection.rb', line 29 def source_file @source_file end |
#type ⇒ Object (readonly)
29 30 31 |
# File 'lib/bullematic/detection.rb', line 29 def type @type end |
Class Method Details
.from_h(data) ⇒ Detection
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/bullematic/detection.rb', line 51 def self.from_h(data) type = data.fetch("type").to_s.to_sym associations = data.fetch("associations") call_stack = data.fetch("call_stack") raise ArgumentError, "invalid evidence type" unless %i[n_plus_one unused_eager_loading].include?(type) raise ArgumentError, "invalid evidence associations" unless associations.is_a?(Array) raise ArgumentError, "invalid evidence call stack" unless call_stack.is_a?(Array) source_digest = data["source_digest"] raise ArgumentError, "invalid evidence source digest" unless source_digest.is_a?(String) && source_digest.match?(/\A[0-9a-f]{64}\z/) new( type: type, base_class: data.fetch("base_class"), associations: associations, call_stack: call_stack, context_id: data["context_id"], source_digest: source_digest ) end |
Instance Method Details
#absolute_path(path) ⇒ Pathname
188 189 190 191 192 193 194 195 |
# File 'lib/bullematic/detection.rb', line 188 def absolute_path(path) pathname = Pathname.new(path) return pathname if path.match?(%r{\A[A-Za-z]:[\\/]}) return pathname. if pathname.absolute? root = defined?(Rails) && Rails.respond_to?(:root) && Rails.root ? Rails.root : Dir.pwd Pathname.new(root).join(pathname). end |
#current_source_digest ⇒ String?
198 199 200 201 202 203 204 |
# File 'lib/bullematic/detection.rb', line 198 def current_source_digest return unless source_file && File.file?(source_file) Digest::SHA256.hexdigest(File.binread(source_file)) rescue Errno::ENOENT, Errno::EACCES nil end |
#expand_path(path) ⇒ Pathname
175 176 177 178 179 180 181 182 183 184 |
# File 'lib/bullematic/detection.rb', line 175 def (path) = absolute_path(path) return unless .exist? begin .realpath rescue Errno::ENOENT, Errno::EACCES end end |
#fingerprint ⇒ Array[untyped]
: () -> Array
98 99 100 |
# File 'lib/bullematic/detection.rb', line 98 def fingerprint [type, context_id, source_file, line_number, model_class_name, associations.sort] end |
#fixable? ⇒ Boolean
: () -> bool
89 90 91 92 93 94 95 |
# File 'lib/bullematic/detection.rb', line 89 def fixable? !source_file.nil? && !source_file.empty? && !associations.empty? && target_path? && !skip_path? end |
#model_class_name ⇒ String
: () -> String
84 85 86 |
# File 'lib/bullematic/detection.rb', line 84 def model_class_name base_class.to_s end |
#normalize_associations(assocs) ⇒ Array[Symbol]
106 107 108 109 110 111 |
# File 'lib/bullematic/detection.rb', line 106 def normalize_associations(assocs) values = Array(assocs) #: Array[untyped] values.filter_map do |association| association.to_sym if association.is_a?(String) || association.is_a?(Symbol) end.uniq end |
#parse_source_location ⇒ void
This method returns an undefined value.
: () -> void
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/bullematic/detection.rb', line 114 def parse_source_location config = Bullematic.configuration return unless config target_paths = config.target_paths @call_stack.each do |raw_frame| frame = raw_frame.to_s match = frame.match(/\A(.+):(\d+)(?::in [`'](.+)')?\z/) next unless match filepath = match[1] line = match[2].to_i method = match[3] next unless filepath && path_in?(filepath, target_paths) @source_file = absolute_path(filepath).to_s @line_number = line @method_name = method break end end |
#path_in?(filepath, paths) ⇒ Boolean
162 163 164 165 166 167 168 169 170 171 |
# File 'lib/bullematic/detection.rb', line 162 def path_in?(filepath, paths) source = (filepath) paths.any? do |path| next false unless path.is_a?(String) && !path.empty? target = (path) source == target || source.to_s.start_with?("#{target}#{File::SEPARATOR}") end end |
#skip_path? ⇒ Boolean
: () -> bool
150 151 152 153 154 155 156 157 |
# File 'lib/bullematic/detection.rb', line 150 def skip_path? return false if source_file.nil? config = Bullematic.configuration return false unless config path_in?(source_file, config.skip_paths) end |
#target_path? ⇒ Boolean
: () -> bool
140 141 142 143 144 145 146 147 |
# File 'lib/bullematic/detection.rb', line 140 def target_path? return false if source_file.nil? config = Bullematic.configuration return false unless config path_in?(source_file, config.target_paths) end |
#to_h ⇒ Hash[String, untyped]
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/bullematic/detection.rb', line 72 def to_h { "type" => type.to_s, "base_class" => model_class_name, "associations" => associations.map(&:to_s), "call_stack" => call_stack.map(&:to_s), "context_id" => context_id, "source_digest" => source_digest } end |