Skip to content

Commit 1cc44e2

Browse files
Merge pull request #72 from ktsu-dev/claude/issue-49-plural-units
feat(generator): plural From{Unit} factory naming + form matrix docs (closes #49, partial #58)
2 parents e55b50f + 77422b6 commit 1cc44e2

109 files changed

Lines changed: 705 additions & 564 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ var converted = sourceString.As<SourceType, TargetType>();
145145
- Edit `Semantics.SourceGenerators/Metadata/dimensions.json` to add a dimension, vector form, semantic overload, or relationship.
146146
- Rebuild `Semantics.SourceGenerators` and the consuming `Semantics.Quantities` project; emitted files appear in `Semantics.Quantities/Generated/Semantics.SourceGenerators/<GeneratorName>/`.
147147
- Treat generator output as committed source. Diff it before commit so accidental regressions are visible.
148+
- Factory names are **plural by convention** (#49). Each entry in `units.json` carries a `factoryName` field — the generator emits `From{factoryName}` (e.g. `Length.FromMeters`, `Mass.FromKilograms`, `Speed.FromMetersPerSecond`, `Length.FromFeet`, `Frequency.FromHertz`). Set it explicitly on every new unit; the generator falls back to `name + "s"` if absent, which is wrong for irregulars and "Per" compounds.
148149
- Generator diagnostics:
149150
- **SEM001** — a relationship in `dimensions.json` references a dimension that does not exist (typo or rename). The operator is silently dropped.
150151
- **SEM002** — schema-level validation issue (missing `name`/`symbol`, empty `availableUnits`, duplicate type names, no vector forms declared).

Semantics.Quantities/Generated/Semantics.SourceGenerators/Semantics.SourceGenerators.QuantitiesGenerator/AbsorbedDose.g.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public record AbsorbedDose<T> : PhysicalQuantity<AbsorbedDose<T>, T>, IVector0<A
2323
/// <param name="value">The value in Gray.</param>
2424
/// <returns>A new <see cref="AbsorbedDose{T}"/> instance.</returns>
2525
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
26-
public static AbsorbedDose<T> FromGray(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
26+
public static AbsorbedDose<T> FromGrays(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
2727
/// <summary>
2828
/// Subtracts two AbsorbedDose values, returning the absolute difference as a non-negative AbsorbedDose.
2929
/// Magnitude subtraction stays a magnitude (per the unified-vector model).

Semantics.Quantities/Generated/Semantics.SourceGenerators/Semantics.SourceGenerators.QuantitiesGenerator/Altitude.g.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,77 +24,77 @@ public record Altitude<T> : PhysicalQuantity<Altitude<T>, T>, IVector0<Altitude<
2424
/// <param name="value">The value in Meter.</param>
2525
/// <returns>A new Altitude instance.</returns>
2626
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
27-
public static Altitude<T> FromMeter(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
27+
public static Altitude<T> FromMeters(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
2828
/// <summary>
2929
/// Creates a new Altitude from a value in Kilometer.
3030
/// </summary>
3131
/// <param name="value">The value in Kilometer.</param>
3232
/// <returns>A new Altitude instance.</returns>
3333
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
34-
public static Altitude<T> FromKilometer(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(MetricMagnitudes.Kilo)), nameof(value)));
34+
public static Altitude<T> FromKilometers(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(MetricMagnitudes.Kilo)), nameof(value)));
3535
/// <summary>
3636
/// Creates a new Altitude from a value in Centimeter.
3737
/// </summary>
3838
/// <param name="value">The value in Centimeter.</param>
3939
/// <returns>A new Altitude instance.</returns>
4040
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
41-
public static Altitude<T> FromCentimeter(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(MetricMagnitudes.Centi)), nameof(value)));
41+
public static Altitude<T> FromCentimeters(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(MetricMagnitudes.Centi)), nameof(value)));
4242
/// <summary>
4343
/// Creates a new Altitude from a value in Millimeter.
4444
/// </summary>
4545
/// <param name="value">The value in Millimeter.</param>
4646
/// <returns>A new Altitude instance.</returns>
4747
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
48-
public static Altitude<T> FromMillimeter(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(MetricMagnitudes.Milli)), nameof(value)));
48+
public static Altitude<T> FromMillimeters(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(MetricMagnitudes.Milli)), nameof(value)));
4949
/// <summary>
5050
/// Creates a new Altitude from a value in Micrometer.
5151
/// </summary>
5252
/// <param name="value">The value in Micrometer.</param>
5353
/// <returns>A new Altitude instance.</returns>
5454
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
55-
public static Altitude<T> FromMicrometer(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(MetricMagnitudes.Micro)), nameof(value)));
55+
public static Altitude<T> FromMicrometers(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(MetricMagnitudes.Micro)), nameof(value)));
5656
/// <summary>
5757
/// Creates a new Altitude from a value in Nanometer.
5858
/// </summary>
5959
/// <param name="value">The value in Nanometer.</param>
6060
/// <returns>A new Altitude instance.</returns>
6161
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
62-
public static Altitude<T> FromNanometer(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(MetricMagnitudes.Nano)), nameof(value)));
62+
public static Altitude<T> FromNanometers(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(MetricMagnitudes.Nano)), nameof(value)));
6363
/// <summary>
6464
/// Creates a new Altitude from a value in Angstrom.
6565
/// </summary>
6666
/// <param name="value">The value in Angstrom.</param>
6767
/// <returns>A new Altitude instance.</returns>
6868
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
69-
public static Altitude<T> FromAngstrom(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.AngstromToMeters)), nameof(value)));
69+
public static Altitude<T> FromAngstroms(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.AngstromToMeters)), nameof(value)));
7070
/// <summary>
7171
/// Creates a new Altitude from a value in Foot.
7272
/// </summary>
7373
/// <param name="value">The value in Foot.</param>
7474
/// <returns>A new Altitude instance.</returns>
7575
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
76-
public static Altitude<T> FromFoot(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.FeetToMeters)), nameof(value)));
76+
public static Altitude<T> FromFeet(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.FeetToMeters)), nameof(value)));
7777
/// <summary>
7878
/// Creates a new Altitude from a value in Inch.
7979
/// </summary>
8080
/// <param name="value">The value in Inch.</param>
8181
/// <returns>A new Altitude instance.</returns>
8282
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
83-
public static Altitude<T> FromInch(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.InchesToMeters)), nameof(value)));
83+
public static Altitude<T> FromInches(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.InchesToMeters)), nameof(value)));
8484
/// <summary>
8585
/// Creates a new Altitude from a value in Yard.
8686
/// </summary>
8787
/// <param name="value">The value in Yard.</param>
8888
/// <returns>A new Altitude instance.</returns>
8989
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
90-
public static Altitude<T> FromYard(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.YardToMeters)), nameof(value)));
90+
public static Altitude<T> FromYards(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.YardToMeters)), nameof(value)));
9191
/// <summary>
9292
/// Creates a new Altitude from a value in Mile.
9393
/// </summary>
9494
/// <param name="value">The value in Mile.</param>
9595
/// <returns>A new Altitude instance.</returns>
9696
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
97-
public static Altitude<T> FromMile(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.MileToMeters)), nameof(value)));
97+
public static Altitude<T> FromMiles(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.MileToMeters)), nameof(value)));
9898
/// <summary>Implicit conversion to Length.</summary>
9999
public static implicit operator Length<T>(Altitude<T> value) => Length<T>.Create(value.Value);
100100
/// <summary>Explicit conversion from Length.</summary>

Semantics.Quantities/Generated/Semantics.SourceGenerators/Semantics.SourceGenerators.QuantitiesGenerator/AmountOfSubstance.g.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public record AmountOfSubstance<T> : PhysicalQuantity<AmountOfSubstance<T>, T>,
2323
/// <param name="value">The value in Mole.</param>
2424
/// <returns>A new <see cref="AmountOfSubstance{T}"/> instance.</returns>
2525
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
26-
public static AmountOfSubstance<T> FromMole(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
26+
public static AmountOfSubstance<T> FromMoles(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
2727
/// <summary>
2828
/// Subtracts two AmountOfSubstance values, returning the absolute difference as a non-negative AmountOfSubstance.
2929
/// Magnitude subtraction stays a magnitude (per the unified-vector model).

Semantics.Quantities/Generated/Semantics.SourceGenerators/Semantics.SourceGenerators.QuantitiesGenerator/Angle.g.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ public record Angle<T> : PhysicalQuantity<Angle<T>, T>, IVector0<Angle<T>, T>
2323
/// <param name="value">The value in Radian.</param>
2424
/// <returns>A new <see cref="Angle{T}"/> instance.</returns>
2525
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
26-
public static Angle<T> FromRadian(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
26+
public static Angle<T> FromRadians(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
2727
/// <summary>
2828
/// Creates a new <see cref="Angle{T}"/> from a value in Degree.
2929
/// </summary>
3030
/// <param name="value">The value in Degree.</param>
3131
/// <returns>A new <see cref="Angle{T}"/> instance.</returns>
3232
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
33-
public static Angle<T> FromDegree(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.DegreeToRadians)), nameof(value)));
33+
public static Angle<T> FromDegrees(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.DegreeToRadians)), nameof(value)));
3434
/// <summary>
3535
/// Subtracts two Angle values, returning the absolute difference as a non-negative Angle.
3636
/// Magnitude subtraction stays a magnitude (per the unified-vector model).

Semantics.Quantities/Generated/Semantics.SourceGenerators/Semantics.SourceGenerators.QuantitiesGenerator/ApertureAngle.g.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ public record ApertureAngle<T> : PhysicalQuantity<ApertureAngle<T>, T>, IVector0
2424
/// <param name="value">The value in Radian.</param>
2525
/// <returns>A new ApertureAngle instance.</returns>
2626
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
27-
public static ApertureAngle<T> FromRadian(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
27+
public static ApertureAngle<T> FromRadians(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
2828
/// <summary>
2929
/// Creates a new ApertureAngle from a value in Degree.
3030
/// </summary>
3131
/// <param name="value">The value in Degree.</param>
3232
/// <returns>A new ApertureAngle instance.</returns>
3333
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
34-
public static ApertureAngle<T> FromDegree(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.DegreeToRadians)), nameof(value)));
34+
public static ApertureAngle<T> FromDegrees(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.DegreeToRadians)), nameof(value)));
3535
/// <summary>Implicit conversion to Angle.</summary>
3636
public static implicit operator Angle<T>(ApertureAngle<T> value) => Angle<T>.Create(value.Value);
3737
/// <summary>Explicit conversion from Angle.</summary>

Semantics.Quantities/Generated/Semantics.SourceGenerators/Semantics.SourceGenerators.QuantitiesGenerator/Area.g.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,21 @@ public record Area<T> : PhysicalQuantity<Area<T>, T>, IVector0<Area<T>, T>
2323
/// <param name="value">The value in SquareMeter.</param>
2424
/// <returns>A new <see cref="Area{T}"/> instance.</returns>
2525
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
26-
public static Area<T> FromSquareMeter(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
26+
public static Area<T> FromSquareMeters(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
2727
/// <summary>
2828
/// Creates a new <see cref="Area{T}"/> from a value in SquareFoot.
2929
/// </summary>
3030
/// <param name="value">The value in SquareFoot.</param>
3131
/// <returns>A new <see cref="Area{T}"/> instance.</returns>
3232
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
33-
public static Area<T> FromSquareFoot(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.SquareFootToSquareMeters)), nameof(value)));
33+
public static Area<T> FromSquareFeet(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.SquareFootToSquareMeters)), nameof(value)));
3434
/// <summary>
3535
/// Creates a new <see cref="Area{T}"/> from a value in SquareInch.
3636
/// </summary>
3737
/// <param name="value">The value in SquareInch.</param>
3838
/// <returns>A new <see cref="Area{T}"/> instance.</returns>
3939
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
40-
public static Area<T> FromSquareInch(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.SquareInchToSquareMeters)), nameof(value)));
40+
public static Area<T> FromSquareInches(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.SquareInchToSquareMeters)), nameof(value)));
4141
/// <summary>
4242
/// Subtracts two Area values, returning the absolute difference as a non-negative Area.
4343
/// Magnitude subtraction stays a magnitude (per the unified-vector model).

Semantics.Quantities/Generated/Semantics.SourceGenerators/Semantics.SourceGenerators.QuantitiesGenerator/AtmosphericPressure.g.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,21 @@ public record AtmosphericPressure<T> : PhysicalQuantity<AtmosphericPressure<T>,
2424
/// <param name="value">The value in Pascal.</param>
2525
/// <returns>A new AtmosphericPressure instance.</returns>
2626
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
27-
public static AtmosphericPressure<T> FromPascal(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
27+
public static AtmosphericPressure<T> FromPascals(T value) => Create(Vector0Guards.EnsureNonNegative(value, nameof(value)));
2828
/// <summary>
2929
/// Creates a new AtmosphericPressure from a value in Bar.
3030
/// </summary>
3131
/// <param name="value">The value in Bar.</param>
3232
/// <returns>A new AtmosphericPressure instance.</returns>
3333
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
34-
public static AtmosphericPressure<T> FromBar(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.BarToPascals)), nameof(value)));
34+
public static AtmosphericPressure<T> FromBars(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.BarToPascals)), nameof(value)));
3535
/// <summary>
3636
/// Creates a new AtmosphericPressure from a value in Atmosphere.
3737
/// </summary>
3838
/// <param name="value">The value in Atmosphere.</param>
3939
/// <returns>A new AtmosphericPressure instance.</returns>
4040
/// <exception cref="System.ArgumentException">Thrown when the resulting magnitude would be negative.</exception>
41-
public static AtmosphericPressure<T> FromAtmosphere(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.AtmosphereToPascals)), nameof(value)));
41+
public static AtmosphericPressure<T> FromAtmospheres(T value) => Create(Vector0Guards.EnsureNonNegative((value * T.CreateChecked(Units.ConversionConstants.AtmosphereToPascals)), nameof(value)));
4242
/// <summary>
4343
/// Creates a new AtmosphericPressure from a value in Psi.
4444
/// </summary>

0 commit comments

Comments
 (0)