Module: Philiprehberger::CronParser

Defined in:
lib/philiprehberger/cron_parser.rb,
lib/philiprehberger/cron_parser/field.rb,
lib/philiprehberger/cron_parser/version.rb,
lib/philiprehberger/cron_parser/expression.rb

Defined Under Namespace

Classes: Error, Expression, Field

Constant Summary collapse

FIELD_ORDER =
%i[minute hour day month weekday].freeze
VERSION =
'0.4.0'

Class Method Summary collapse

Class Method Details

.new(expr) ⇒ Expression

Parse a cron expression and return an Expression instance

Parameters:

  • expr (String)

    a 5-field cron expression (minute hour day month weekday)

Returns:

Raises:

  • (Error)

    if the expression is invalid



18
19
20
# File 'lib/philiprehberger/cron_parser.rb', line 18

def self.new(expr)
  Expression.new(expr)
end

.valid?(expr) ⇒ Boolean

Check if a cron expression is valid without raising

Parameters:

  • expr (String)

    a 5-field cron expression

Returns:

  • (Boolean)


26
27
28
29
30
31
# File 'lib/philiprehberger/cron_parser.rb', line 26

def self.valid?(expr)
  Expression.new(expr)
  true
rescue Error
  false
end

.validate(expr) ⇒ Hash

Validate a cron expression and return structured errors

Parameters:

  • expr (String)

    a 5-field cron expression

Returns:

  • (Hash)

    { valid: true/false, errors: [String] }



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/philiprehberger/cron_parser.rb', line 37

def self.validate(expr)
  errors = []
  stripped = expr.strip
  if stripped.start_with?('@')
    alias_expanded = Expression::ALIASES[stripped.downcase]
    return { valid: false, errors: ["Unknown cron alias: #{stripped}"] } if alias_expanded.nil?

    stripped = alias_expanded
  end
  parts = stripped.split(/\s+/)

  unless parts.size == 5
    return { valid: false, errors: ["Expected 5 fields, got #{parts.size}"] }
  end

  FIELD_ORDER.each_with_index do |name, index|
    range = Expression::FIELD_RANGES[name]
    names_map = Expression::FIELD_NAMES_MAP[name]
    Field.new(parts[index], min: range[:min], max: range[:max], names: names_map)
  rescue Error => e
    errors << "#{name} field: #{e.message}"
  end

  { valid: errors.empty?, errors: errors }
end