Class: RemLint::Rules::HebrewDate

Inherits:
RemLint::Rule show all
Defined in:
lib/remlint/rules/hebrew_date.rb

Overview

Hebrew dates that cannot exist.

hebdate(day, month, year) returns Invalid Hebrew date for a month Remind does not know and for a day past that month's length. Both are decidable from literals, and both fail on the day the reminder would otherwise have fired.

The lengths are MaxMonLen[] from src/hbcal.c, and they are not the textbook fixed ones: Heshvan and Kislev are recomputed from each year's length -- a Hebrew year runs 353, 354 or 355 days -- so this reports the maximum any year allows. Confirmed against the binary across seven consecutive years.

The names are all three of Remind's tables: HebMonthNames, IvritMonthNames in Hebrew script, and AltMonthSpellings, which is why Tishri, Cheshvan, Shevat, Tammuz, Iyyar, Adar I and their Hebrew equivalents are all accepted. Missing that third table reports 31 offences against Remind's own tests/test.rem.

hebmon() returns the canonical transliteration, so a comparison against an accepted-but-non-canonical spelling is never true even where hebdate takes it -- which the message says.

Constant Summary collapse

MAX_LENGTHS =

MaxMonLen[] from src/hbcal.c, in the order its month constants define: Tishrey, Heshvan, Kislev, Tevet, Shvat, Adar A, Adar B, Nisan, Iyar, Sivan, Tamuz, Av, Elul, Adar.

[30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29, 29].freeze
CANONICAL =
[
  "Tishrey", "Heshvan", "Kislev", "Tevet", "Shvat", "Adar A", "Adar B",
  "Nisan", "Iyar", "Sivan", "Tamuz", "Av", "Elul", "Adar"
].freeze
IVRIT =

IvritMonthNames -- the same months in Hebrew script.

[
  "\u05EA\u05E9\u05E8\u05D9", "\u05D7\u05E9\u05D5\u05D5\u05DF",
  "\u05DB\u05E1\u05DC\u05D5", "\u05D8\u05D1\u05EA",
  "\u05E9\u05D1\u05D8", "\u05D0\u05D3\u05E8 \u05D0'",
  "\u05D0\u05D3\u05E8 \u05D1'", "\u05E0\u05D9\u05E1\u05DF",
  "\u05D0\u05D9\u05D9\u05E8", "\u05E1\u05D9\u05D5\u05DF",
  "\u05EA\u05DE\u05D5\u05D6", "\u05D0\u05D1",
  "\u05D0\u05DC\u05D5\u05DC", "\u05D0\u05D3\u05E8"
].freeze
ALTERNATES =

AltMonthSpellings -- name => the month index it resolves to.

{
  "Tishri"                    => 0,
  "Tishrei"                   => 0,
  "Cheshvan"                  => 1,
  "Kheshvan"                  => 1,
  "Shevat"                    => 4,
  "Tammuz"                    => 10,
  "Adar 1"                    => 5,
  "Adar I"                    => 5,
  "\u05D0\u05D3\u05E8 \u05D0" => 5,
  "\u05D0\u05D3\u05E8 1"      => 5,
  "\u05D0\u05D3\u05E8 I"      => 5,
  "Adar 2"                    => 6,
  "Adar II"                   => 6,
  "\u05D0\u05D3\u05E8 \u05D1" => 6,
  "\u05D0\u05D3\u05E8 2"      => 6,
  "\u05D0\u05D3\u05E8 II"     => 6,
  "Iyyar"                     => 8,
}.freeze
MONTHS =
(
  CANONICAL.each_with_index.to_h { |name, index| [name.downcase, MAX_LENGTHS[index]] }
    .merge(IVRIT.each_with_index.to_h { |name, index| [name, MAX_LENGTHS[index]] })
    .merge(ALTERNATES.transform_keys(&:downcase)
                     .transform_values { |index| MAX_LENGTHS[index] })
).freeze
CALL =

hebdate(30, "Elul", 5790) and the two-argument form.

/\bhebdate\s*\(\s*(?<day>\d+)\s*,\s*"(?<month>[^"]+)"/i

Constants inherited from RemLint::Rule

RemLint::Rule::REGISTRY

Instance Attribute Summary

Attributes inherited from RemLint::Rule

#config, #document, #offenses

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from RemLint::Rule

all, enabled_by_default?, find, inherited, #initialize, rule_name, #rule_name, #run

Constructor Details

This class inherits a constructor from RemLint::Rule

Class Method Details

.default_severityObject



82
83
84
# File 'lib/remlint/rules/hebrew_date.rb', line 82

def self.default_severity
  "error"
end

.descriptionObject



86
87
88
# File 'lib/remlint/rules/hebrew_date.rb', line 86

def self.description
  "A Hebrew month Remind does not know, or a day past that month's length."
end

Instance Method Details

#checkObject



90
91
92
93
94
95
96
# File 'lib/remlint/rules/hebrew_date.rb', line 90

def check
  document.logical_lines.each_with_index do |logical_line, index|
    if document.commands[index].code?
      check_line(logical_line)
    end
  end
end