Module: DevDoc::Test::Lints::JobDurationConstant

Defined in:
lib/dev_doc/test/lints/cron_schedule.rb

Overview

Locates a job class's source file under a jobs directory and reads a duration constant (e.g. STALENESS_THRESHOLD = 1.hour) from it. Split out of CronScheduleChecker: file location + duration parsing is a self-contained concern with no knowledge of cron.

Constant Summary collapse

DURATION_UNITS =

Seconds per unit for <n>.<unit> ActiveSupport::Duration literals (e.g. 45.minutes, 1.hour, 7.days).

{
  'second' => 1,   'seconds'  => 1,
  'minute' => 60,  'minutes'  => 60,
  'hour' => 3600, 'hours' => 3600,
  'day' => 86_400, 'days' => 86_400,
  'week' => 604_800, 'weeks' => 604_800
}.freeze

Class Method Summary collapse

Class Method Details

.class_name_to_file(class_name) ⇒ Object

Converts CamelCase class name to snake_case filename stem. E.g. WorkDiaryBackfillJob → work_diary_backfill_job



55
56
57
58
59
60
61
# File 'lib/dev_doc/test/lints/cron_schedule.rb', line 55

def class_name_to_file(class_name)
  # Strip leading module namespaces (Foo::BarJob → BarJob)
  base = class_name.split('::').last.to_s
  base.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
      .gsub(/([a-z\d])([A-Z])/, '\1_\2')
      .downcase
end

.job_source(class_name, jobs_root) ⇒ Object

Searches jobs_root recursively for a .rb file that defines class_name. Returns the file contents as a String, or nil.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/dev_doc/test/lints/cron_schedule.rb', line 35

def job_source(class_name, jobs_root)
  # Fast path: the conventional file name (MyFetchJob → my_fetch_job.rb).
  expected_file = "#{class_name_to_file(class_name)}.rb"
  Dir.glob(jobs_root.join('**', expected_file)).each do |path|
    content = File.read(path)
    return content if content.include?(class_name)
  end

  # Fallback: search all .rb files for a matching class definition.
  # Useful for non-conventional file layouts.
  Dir.glob(jobs_root.join('**', '*.rb')).each do |path|
    content = File.read(path)
    return content if content.include?("class #{class_name}")
  end

  nil
end

.parse_duration(source, constant) ⇒ Object



63
64
65
66
67
68
69
70
71
# File 'lib/dev_doc/test/lints/cron_schedule.rb', line 63

def parse_duration(source, constant)
  units_pattern = DURATION_UNITS.keys.join('|')
  pattern = /#{Regexp.escape(constant)}\s*=\s*(\d+(?:\.\d+)?)\.(#{units_pattern})\b/

  match = source.match(pattern)
  return nil unless match

  (match[1].to_f * DURATION_UNITS.fetch(match[2])).to_i
end

.read(class_name, jobs_root, constant) ⇒ Object

Returns the constant's value in seconds, or nil if the job file or constant is not found, or the value isn't a simple duration literal.



26
27
28
29
30
31
# File 'lib/dev_doc/test/lints/cron_schedule.rb', line 26

def read(class_name, jobs_root, constant)
  source = job_source(class_name, jobs_root)
  return nil unless source

  parse_duration(source, constant)
end