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_name_to_file(class_name) ⇒ Object
Converts CamelCase class name to snake_case filename stem.
-
.job_source(class_name, jobs_root) ⇒ Object
Searches
jobs_rootrecursively for a .rb file that definesclass_name. - .parse_duration(source, constant) ⇒ Object
-
.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.
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 |