Skip to content

Fix UnitParser.ParseUnit for multiple-worded units #254

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion UnitsNet.Tests/CustomCode/ParseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class ParseTests
[TestCase("500,005 m", Result = 500005)]
[TestCase(null, ExpectedExceptionName = "System.ArgumentNullException")]
[TestCase("1", ExpectedExceptionName = "System.ArgumentException")]
[TestCase("km", ExpectedExceptionName = "UnitsNet.UnitsNetException")]
[TestCase("km", ExpectedExceptionName = "System.ArgumentException")]
[TestCase("1 kg", ExpectedExceptionName = "UnitsNet.UnitsNetException")]
public double ParseLengthToMetersUsEnglish(string s)
{
Expand Down Expand Up @@ -116,5 +116,16 @@ public bool TryParseLengthUnitUsEnglish(string s)
Length result;
return Length.TryParse(s, usEnglish, out result);
}

[TestCase("333 short tn", Result = 333)]
public double ParseMassShortTon(string s)
{
return Mass.Parse(s).ShortTons;
}
[TestCase("333 long tn", Result = 333)]
public double ParseMassLongTon(string s)
{
return Mass.Parse(s).LongTons;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

}
}
}
6 changes: 6 additions & 0 deletions UnitsNet.Tests/CustomCode/SpeedTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ public class SpeedTests : SpeedTestsBase

protected override double MillimetersPerHourInOneMeterPerSecond => 3600000;

protected override double InchesPerSecondInOneMeterPerSecond => 39.3700787;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you've mixed two pieces of work here. I saw you were working on the master branch, but it would probably be better for you to work on a feature branch to separate the two bulks of changes and create separate pull requests.
We can proceed like this if you are not familiar with how to do it, no biggie, but just a heads up for next time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I messed up with the branches. I'm not familiar using Git yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, I might as well ask you how should I have done the two pieces of work?
Should I have created two forks? one for the bugfix and one for the addfeature?

Copy link
Owner

@angularsen angularsen May 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend googling for some guides on git, github, forks and pull requests. I haven't read this one, but at first glance it seems to cover the basics: https://gist.github.com/Chaser324/ce0505fbed06b947d962

The basic gist of it is:

  • Add official repo as remote so you can sync in changes, I prefer to call this origin and if I have a fork I call that my, but that is just my preference: git remote set-url origin https://github.com/anjdreas/unitsnet and git remote add my https://github.com/gojanpaolo/unitsnet
  • Create a local branch (based on origin/master) for any new work you want to create a pull request for, fix-unit-parsing or add-pascal-unit: git checkout -b fix-unit-parsing origin/master
  • Do your work as one or more commits
  • When you are ready for review, rebase your branch on top of any new commits on the official repo, then push that branch up to your github fork: git rebase origin/master && git push -u my
  • Visit github.com to create a pull request from that branch

It's a bit boilerplate the first time, especially setting up the remotes and stuff, but it gets easier with practice. You might also want to use some GUI clients to make things easier, but I personally prefer the command line.

Copy link
Owner

@angularsen angularsen May 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And, for the second pull request, repeat all but the first step, this way both branches are based on origin/master and don't have any commits from the other branch.


protected override double YardsPerMinuteInOneMeterPerSecond => 65.6167979;

protected override double YardsPerSecondInOneMeterPerSecond => 1.09361330;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I double checked these values though, looks good!


[Test]
public void DurationSpeedTimesEqualsLength()
{
Expand Down
18 changes: 18 additions & 0 deletions UnitsNet.Tests/GeneratedCode/SpeedTestsBase.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public abstract partial class SpeedTestsBase
protected abstract double DecimetersPerMinutesInOneMeterPerSecond { get; }
protected abstract double DecimetersPerSecondInOneMeterPerSecond { get; }
protected abstract double FeetPerSecondInOneMeterPerSecond { get; }
protected abstract double InchesPerSecondInOneMeterPerSecond { get; }
protected abstract double KilometersPerHourInOneMeterPerSecond { get; }
protected abstract double KilometersPerMinutesInOneMeterPerSecond { get; }
protected abstract double KilometersPerSecondInOneMeterPerSecond { get; }
Expand All @@ -74,6 +75,8 @@ public abstract partial class SpeedTestsBase
protected abstract double MillimetersPerSecondInOneMeterPerSecond { get; }
protected abstract double NanometersPerMinutesInOneMeterPerSecond { get; }
protected abstract double NanometersPerSecondInOneMeterPerSecond { get; }
protected abstract double YardsPerMinuteInOneMeterPerSecond { get; }
protected abstract double YardsPerSecondInOneMeterPerSecond { get; }

// ReSharper disable VirtualMemberNeverOverriden.Global
protected virtual double CentimetersPerHourTolerance { get { return 1e-5; } }
Expand All @@ -82,6 +85,7 @@ public abstract partial class SpeedTestsBase
protected virtual double DecimetersPerMinutesTolerance { get { return 1e-5; } }
protected virtual double DecimetersPerSecondTolerance { get { return 1e-5; } }
protected virtual double FeetPerSecondTolerance { get { return 1e-5; } }
protected virtual double InchesPerSecondTolerance { get { return 1e-5; } }
protected virtual double KilometersPerHourTolerance { get { return 1e-5; } }
protected virtual double KilometersPerMinutesTolerance { get { return 1e-5; } }
protected virtual double KilometersPerSecondTolerance { get { return 1e-5; } }
Expand All @@ -97,6 +101,8 @@ public abstract partial class SpeedTestsBase
protected virtual double MillimetersPerSecondTolerance { get { return 1e-5; } }
protected virtual double NanometersPerMinutesTolerance { get { return 1e-5; } }
protected virtual double NanometersPerSecondTolerance { get { return 1e-5; } }
protected virtual double YardsPerMinuteTolerance { get { return 1e-5; } }
protected virtual double YardsPerSecondTolerance { get { return 1e-5; } }
// ReSharper restore VirtualMemberNeverOverriden.Global

[Test]
Expand All @@ -109,6 +115,7 @@ public void MeterPerSecondToSpeedUnits()
Assert.AreEqual(DecimetersPerMinutesInOneMeterPerSecond, meterpersecond.DecimetersPerMinutes, DecimetersPerMinutesTolerance);
Assert.AreEqual(DecimetersPerSecondInOneMeterPerSecond, meterpersecond.DecimetersPerSecond, DecimetersPerSecondTolerance);
Assert.AreEqual(FeetPerSecondInOneMeterPerSecond, meterpersecond.FeetPerSecond, FeetPerSecondTolerance);
Assert.AreEqual(InchesPerSecondInOneMeterPerSecond, meterpersecond.InchesPerSecond, InchesPerSecondTolerance);
Assert.AreEqual(KilometersPerHourInOneMeterPerSecond, meterpersecond.KilometersPerHour, KilometersPerHourTolerance);
Assert.AreEqual(KilometersPerMinutesInOneMeterPerSecond, meterpersecond.KilometersPerMinutes, KilometersPerMinutesTolerance);
Assert.AreEqual(KilometersPerSecondInOneMeterPerSecond, meterpersecond.KilometersPerSecond, KilometersPerSecondTolerance);
Expand All @@ -124,6 +131,8 @@ public void MeterPerSecondToSpeedUnits()
Assert.AreEqual(MillimetersPerSecondInOneMeterPerSecond, meterpersecond.MillimetersPerSecond, MillimetersPerSecondTolerance);
Assert.AreEqual(NanometersPerMinutesInOneMeterPerSecond, meterpersecond.NanometersPerMinutes, NanometersPerMinutesTolerance);
Assert.AreEqual(NanometersPerSecondInOneMeterPerSecond, meterpersecond.NanometersPerSecond, NanometersPerSecondTolerance);
Assert.AreEqual(YardsPerMinuteInOneMeterPerSecond, meterpersecond.YardsPerMinute, YardsPerMinuteTolerance);
Assert.AreEqual(YardsPerSecondInOneMeterPerSecond, meterpersecond.YardsPerSecond, YardsPerSecondTolerance);
}

[Test]
Expand All @@ -135,6 +144,7 @@ public void FromValueAndUnit()
Assert.AreEqual(1, Speed.From(1, SpeedUnit.DecimeterPerMinute).DecimetersPerMinutes, DecimetersPerMinutesTolerance);
Assert.AreEqual(1, Speed.From(1, SpeedUnit.DecimeterPerSecond).DecimetersPerSecond, DecimetersPerSecondTolerance);
Assert.AreEqual(1, Speed.From(1, SpeedUnit.FootPerSecond).FeetPerSecond, FeetPerSecondTolerance);
Assert.AreEqual(1, Speed.From(1, SpeedUnit.InchPerSecond).InchesPerSecond, InchesPerSecondTolerance);
Assert.AreEqual(1, Speed.From(1, SpeedUnit.KilometerPerHour).KilometersPerHour, KilometersPerHourTolerance);
Assert.AreEqual(1, Speed.From(1, SpeedUnit.KilometerPerMinute).KilometersPerMinutes, KilometersPerMinutesTolerance);
Assert.AreEqual(1, Speed.From(1, SpeedUnit.KilometerPerSecond).KilometersPerSecond, KilometersPerSecondTolerance);
Expand All @@ -150,6 +160,8 @@ public void FromValueAndUnit()
Assert.AreEqual(1, Speed.From(1, SpeedUnit.MillimeterPerSecond).MillimetersPerSecond, MillimetersPerSecondTolerance);
Assert.AreEqual(1, Speed.From(1, SpeedUnit.NanometerPerMinute).NanometersPerMinutes, NanometersPerMinutesTolerance);
Assert.AreEqual(1, Speed.From(1, SpeedUnit.NanometerPerSecond).NanometersPerSecond, NanometersPerSecondTolerance);
Assert.AreEqual(1, Speed.From(1, SpeedUnit.YardPerMinute).YardsPerMinute, YardsPerMinuteTolerance);
Assert.AreEqual(1, Speed.From(1, SpeedUnit.YardPerSecond).YardsPerSecond, YardsPerSecondTolerance);
}

[Test]
Expand All @@ -162,6 +174,7 @@ public void As()
Assert.AreEqual(DecimetersPerMinutesInOneMeterPerSecond, meterpersecond.As(SpeedUnit.DecimeterPerMinute), DecimetersPerMinutesTolerance);
Assert.AreEqual(DecimetersPerSecondInOneMeterPerSecond, meterpersecond.As(SpeedUnit.DecimeterPerSecond), DecimetersPerSecondTolerance);
Assert.AreEqual(FeetPerSecondInOneMeterPerSecond, meterpersecond.As(SpeedUnit.FootPerSecond), FeetPerSecondTolerance);
Assert.AreEqual(InchesPerSecondInOneMeterPerSecond, meterpersecond.As(SpeedUnit.InchPerSecond), InchesPerSecondTolerance);
Assert.AreEqual(KilometersPerHourInOneMeterPerSecond, meterpersecond.As(SpeedUnit.KilometerPerHour), KilometersPerHourTolerance);
Assert.AreEqual(KilometersPerMinutesInOneMeterPerSecond, meterpersecond.As(SpeedUnit.KilometerPerMinute), KilometersPerMinutesTolerance);
Assert.AreEqual(KilometersPerSecondInOneMeterPerSecond, meterpersecond.As(SpeedUnit.KilometerPerSecond), KilometersPerSecondTolerance);
Expand All @@ -177,6 +190,8 @@ public void As()
Assert.AreEqual(MillimetersPerSecondInOneMeterPerSecond, meterpersecond.As(SpeedUnit.MillimeterPerSecond), MillimetersPerSecondTolerance);
Assert.AreEqual(NanometersPerMinutesInOneMeterPerSecond, meterpersecond.As(SpeedUnit.NanometerPerMinute), NanometersPerMinutesTolerance);
Assert.AreEqual(NanometersPerSecondInOneMeterPerSecond, meterpersecond.As(SpeedUnit.NanometerPerSecond), NanometersPerSecondTolerance);
Assert.AreEqual(YardsPerMinuteInOneMeterPerSecond, meterpersecond.As(SpeedUnit.YardPerMinute), YardsPerMinuteTolerance);
Assert.AreEqual(YardsPerSecondInOneMeterPerSecond, meterpersecond.As(SpeedUnit.YardPerSecond), YardsPerSecondTolerance);
}

[Test]
Expand All @@ -189,6 +204,7 @@ public void ConversionRoundTrip()
Assert.AreEqual(1, Speed.FromDecimetersPerMinutes(meterpersecond.DecimetersPerMinutes).MetersPerSecond, DecimetersPerMinutesTolerance);
Assert.AreEqual(1, Speed.FromDecimetersPerSecond(meterpersecond.DecimetersPerSecond).MetersPerSecond, DecimetersPerSecondTolerance);
Assert.AreEqual(1, Speed.FromFeetPerSecond(meterpersecond.FeetPerSecond).MetersPerSecond, FeetPerSecondTolerance);
Assert.AreEqual(1, Speed.FromInchesPerSecond(meterpersecond.InchesPerSecond).MetersPerSecond, InchesPerSecondTolerance);
Assert.AreEqual(1, Speed.FromKilometersPerHour(meterpersecond.KilometersPerHour).MetersPerSecond, KilometersPerHourTolerance);
Assert.AreEqual(1, Speed.FromKilometersPerMinutes(meterpersecond.KilometersPerMinutes).MetersPerSecond, KilometersPerMinutesTolerance);
Assert.AreEqual(1, Speed.FromKilometersPerSecond(meterpersecond.KilometersPerSecond).MetersPerSecond, KilometersPerSecondTolerance);
Expand All @@ -204,6 +220,8 @@ public void ConversionRoundTrip()
Assert.AreEqual(1, Speed.FromMillimetersPerSecond(meterpersecond.MillimetersPerSecond).MetersPerSecond, MillimetersPerSecondTolerance);
Assert.AreEqual(1, Speed.FromNanometersPerMinutes(meterpersecond.NanometersPerMinutes).MetersPerSecond, NanometersPerMinutesTolerance);
Assert.AreEqual(1, Speed.FromNanometersPerSecond(meterpersecond.NanometersPerSecond).MetersPerSecond, NanometersPerSecondTolerance);
Assert.AreEqual(1, Speed.FromYardsPerMinute(meterpersecond.YardsPerMinute).MetersPerSecond, YardsPerMinuteTolerance);
Assert.AreEqual(1, Speed.FromYardsPerSecond(meterpersecond.YardsPerSecond).MetersPerSecond, YardsPerSecondTolerance);
}

[Test]
Expand Down
19 changes: 6 additions & 13 deletions UnitsNet/CustomCode/UnitParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@ internal static TUnit ParseUnit<TUnit>([NotNull] string str,

const string exponentialRegex = @"(?:[eE][-+]?\d+)?)";

string regexString = string.Format(@"(?:\s*(?<value>[-+]?{0}{1}{2}{3})?{4}{5}",
string regexString = string.Format(@"(?:\s*(?<value>[-+]?{0}{1}{2}{3})?",
numRegex, // capture base (integral) Quantity value
exponentialRegex, // capture exponential (if any), end of Quantity capturing
@"\s?", // ignore whitespace (allows both "1kg", "1 kg")
@"(?<unit>[^\s\d,]+)", // capture Unit (non-whitespace) input
@"(and)?,?", // allow "and" & "," separators between quantities
@"(?<invalid>[a-z]*)?"); // capture invalid input
@"(?<unit>[^\d]+)"); // capture Unit (non-numeric)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works with our current cases, but we might stumble onto problems here later if we get abbreviations with numbers in them. As an example, we currently only list in Area.Squaremeter, but for convenience sake we might want to also add m^2 so that they can parse both variants. The latter would not work with this implementation.
I'm fine with postponing that until we cross that bridge, but one option is to define the regex as a number immediately followed by any of the known unit abbreviations for the specified culture (IFormatProvider).

Something like this should work:

string valueRegex = $"{numRegex}{exponentialRegex}";
string unitRegex = "(m²|m\^2|cm²|cm\^2)";
string valueUnitRegex = $"(?<value>{valueRegex})\s?(?<unit>{unitRegex})"`;

The unitRegex string values can be enumerated by something like this:

var unitSystem = UnitSystem.GetCached(formatProvider);
string[] abbrevsForAllUnits = 
    Enum.GetValues(typeof(TUnit))
    .Cast<TUnit>()
    .SelectMany(unitSystem.GetAllAbbreviations)
    .Select(Regex.Escape)
    .ToArray();

And you'd need to refactor the UnitParser.ParseUnit() method a bit:

  • Add where TUnit : struct, IComparable, IFormattable (should have been added to begin with)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whenever I add where TUnit : struct, IComparable, IFormattable, I get a bunch of errors.
I think you're mistaking TUnit in UnitParser.ParseUnit() as the Unit Enums (i.e. LengthUnit, MassUnit, etc) but TUnit is actually the UnitClasses (Length, Mass).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok.. so I tried hacking into the UnitSystem class to get all the abbreviation given a UnitClasses type.
The problem is, using the format of regex you suggested. It will fail on test "1ft 1invalid" since it recognizes the "INvalid" as inches. It also fails the test "1ft monkey 1in" since it recognizes "FT monkey".
I thought about restricting it to match only exact abbreviation but how will it handle something like "m" and "mm"?

I think having a single regex or parse algorithm for all the Unit types will have its limitations.
If we want the parsing to handle special cases then maybe it will be easier to implement one parse method for each Unit type.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you raise some good points here.

I think you're mistaking TUnit in UnitParser.ParseUnit() as the Unit Enums

You are right, I was probably too quick here, but UnitSystem should be able to provide this information as you found out.

It will fail on test "1ft 1invalid" since it recognizes the "INvalid" as inches. It also fails the test "1ft monkey 1in" since it recognizes "FT monkey". It also fails the test "1ft monkey 1in" since it recognizes "FT monkey".
I thought about restricting it to match only exact abbreviation but how will it handle something like "m" and "mm"?

I think your suggestion should work, we just need ensure we don't match on text that is not part of a valid pair of {value}{unit} or the accepted delimiters between pairs or between value and unit. I tried a few things and wound up with this: ^((?<value>\d+)\s?(?<unit>m²|m\^2|cm²|cm\^2|ft|in|m|mm)\s?)+$ and I added unit tests for the cases you listed above that you can view here: https://regex101.com/r/EMLIwt/1

With the start/end boundaries, a + repeater to match on at least one pair and an optional whitespace \s? between each pair, the regex now seems to properly match on full abbreviations, and it should not incorrectly match m on 1mm.

I think having a single regex or parse algorithm for all the Unit types will have its limitations.
If we want the parsing to handle special cases then maybe it will be easier to implement one parse method for each Unit type.

I hear you and I agree that might be something we eventually have to reach for, but I also do think my updated regex might just work. The upside of the complexity is that it allows for parsing any number of valid pairs of value+unit and that the implementation is uniform across units, so it is consistent and easier to reason about. The downside is the complexity of the regex itself, performance and the fact that it might not make sense or at least not be commonly used to parse all kinds of pairs of quantities from a string, like we are used to from 1ft 2in and 1' 2''.

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I have been working on another project last week thus the late response. I'll get back to this once I finished the said project (maybe a couple weeks more). :)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, thanks for posting an update! Did my proposal make sense to you?

Copy link
Contributor Author

@gojanpaolo gojanpaolo May 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it allows for parsing any number of valid pairs of value+unit and that the implementation is uniform across units, so it is consistent and easier to reason about.

Yes! especially that sentence. I'll try using your regex and add unit tests for it when I get the time. 👍


//remove separators
str = str.Replace("and", "");

List<TUnit> quantities = ParseWithRegex(regexString, str, parseUnit, formatProvider);
if (quantities.Count == 0)
Expand Down Expand Up @@ -89,15 +90,7 @@ private static List<TUnit> ParseWithRegex<TUnit>(string regexString, string str,

string valueString = groups["value"].Value;
string unitString = groups["unit"].Value;
if (groups["invalid"].Value != "")
{
var newEx = new UnitsNetException("Invalid string detected: " + groups["invalid"].Value);
newEx.Data["input"] = str;
newEx.Data["matched value"] = valueString;
newEx.Data["matched unit"] = unitString;
newEx.Data["formatprovider"] = formatProvider?.ToString();
throw newEx;
}

if ((valueString == "") && (unitString == "")) continue;

try
Expand Down
3 changes: 3 additions & 0 deletions UnitsNet/GeneratedCode/Enums/SpeedUnit.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public enum SpeedUnit
DecimeterPerMinute,
DecimeterPerSecond,
FootPerSecond,
InchPerSecond,
KilometerPerHour,
KilometerPerMinute,
KilometerPerSecond,
Expand All @@ -63,5 +64,7 @@ public enum SpeedUnit
MillimeterPerSecond,
NanometerPerMinute,
NanometerPerSecond,
YardPerMinute,
YardPerSecond,
}
}
102 changes: 102 additions & 0 deletions UnitsNet/GeneratedCode/Extensions/Number/NumberToSpeedExtensions.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,40 @@ public static class NumberToSpeedExtensions

#endregion

#region InchPerSecond

/// <inheritdoc cref="Speed.FromInchesPerSecond(double)"/>
public static Speed InchesPerSecond(this int value) => Speed.FromInchesPerSecond(value);

/// <inheritdoc cref="Speed.FromInchesPerSecond(double?)"/>
public static Speed? InchesPerSecond(this int? value) => Speed.FromInchesPerSecond(value);

/// <inheritdoc cref="Speed.FromInchesPerSecond(double)"/>
public static Speed InchesPerSecond(this long value) => Speed.FromInchesPerSecond(value);

/// <inheritdoc cref="Speed.FromInchesPerSecond(double?)"/>
public static Speed? InchesPerSecond(this long? value) => Speed.FromInchesPerSecond(value);

/// <inheritdoc cref="Speed.FromInchesPerSecond(double)"/>
public static Speed InchesPerSecond(this double value) => Speed.FromInchesPerSecond(value);

/// <inheritdoc cref="Speed.FromInchesPerSecond(double?)"/>
public static Speed? InchesPerSecond(this double? value) => Speed.FromInchesPerSecond(value);

/// <inheritdoc cref="Speed.FromInchesPerSecond(double)"/>
public static Speed InchesPerSecond(this float value) => Speed.FromInchesPerSecond(value);

/// <inheritdoc cref="Speed.FromInchesPerSecond(double?)"/>
public static Speed? InchesPerSecond(this float? value) => Speed.FromInchesPerSecond(value);

/// <inheritdoc cref="Speed.FromInchesPerSecond(double)"/>
public static Speed InchesPerSecond(this decimal value) => Speed.FromInchesPerSecond(Convert.ToDouble(value));

/// <inheritdoc cref="Speed.FromInchesPerSecond(double?)"/>
public static Speed? InchesPerSecond(this decimal? value) => Speed.FromInchesPerSecond(value == null ? (double?)null : Convert.ToDouble(value.Value));

#endregion

#region KilometerPerHour

/// <inheritdoc cref="Speed.FromKilometersPerHour(double)"/>
Expand Down Expand Up @@ -758,6 +792,74 @@ public static class NumberToSpeedExtensions

#endregion

#region YardPerMinute

/// <inheritdoc cref="Speed.FromYardsPerMinute(double)"/>
public static Speed YardsPerMinute(this int value) => Speed.FromYardsPerMinute(value);

/// <inheritdoc cref="Speed.FromYardsPerMinute(double?)"/>
public static Speed? YardsPerMinute(this int? value) => Speed.FromYardsPerMinute(value);

/// <inheritdoc cref="Speed.FromYardsPerMinute(double)"/>
public static Speed YardsPerMinute(this long value) => Speed.FromYardsPerMinute(value);

/// <inheritdoc cref="Speed.FromYardsPerMinute(double?)"/>
public static Speed? YardsPerMinute(this long? value) => Speed.FromYardsPerMinute(value);

/// <inheritdoc cref="Speed.FromYardsPerMinute(double)"/>
public static Speed YardsPerMinute(this double value) => Speed.FromYardsPerMinute(value);

/// <inheritdoc cref="Speed.FromYardsPerMinute(double?)"/>
public static Speed? YardsPerMinute(this double? value) => Speed.FromYardsPerMinute(value);

/// <inheritdoc cref="Speed.FromYardsPerMinute(double)"/>
public static Speed YardsPerMinute(this float value) => Speed.FromYardsPerMinute(value);

/// <inheritdoc cref="Speed.FromYardsPerMinute(double?)"/>
public static Speed? YardsPerMinute(this float? value) => Speed.FromYardsPerMinute(value);

/// <inheritdoc cref="Speed.FromYardsPerMinute(double)"/>
public static Speed YardsPerMinute(this decimal value) => Speed.FromYardsPerMinute(Convert.ToDouble(value));

/// <inheritdoc cref="Speed.FromYardsPerMinute(double?)"/>
public static Speed? YardsPerMinute(this decimal? value) => Speed.FromYardsPerMinute(value == null ? (double?)null : Convert.ToDouble(value.Value));

#endregion

#region YardPerSecond

/// <inheritdoc cref="Speed.FromYardsPerSecond(double)"/>
public static Speed YardsPerSecond(this int value) => Speed.FromYardsPerSecond(value);

/// <inheritdoc cref="Speed.FromYardsPerSecond(double?)"/>
public static Speed? YardsPerSecond(this int? value) => Speed.FromYardsPerSecond(value);

/// <inheritdoc cref="Speed.FromYardsPerSecond(double)"/>
public static Speed YardsPerSecond(this long value) => Speed.FromYardsPerSecond(value);

/// <inheritdoc cref="Speed.FromYardsPerSecond(double?)"/>
public static Speed? YardsPerSecond(this long? value) => Speed.FromYardsPerSecond(value);

/// <inheritdoc cref="Speed.FromYardsPerSecond(double)"/>
public static Speed YardsPerSecond(this double value) => Speed.FromYardsPerSecond(value);

/// <inheritdoc cref="Speed.FromYardsPerSecond(double?)"/>
public static Speed? YardsPerSecond(this double? value) => Speed.FromYardsPerSecond(value);

/// <inheritdoc cref="Speed.FromYardsPerSecond(double)"/>
public static Speed YardsPerSecond(this float value) => Speed.FromYardsPerSecond(value);

/// <inheritdoc cref="Speed.FromYardsPerSecond(double?)"/>
public static Speed? YardsPerSecond(this float? value) => Speed.FromYardsPerSecond(value);

/// <inheritdoc cref="Speed.FromYardsPerSecond(double)"/>
public static Speed YardsPerSecond(this decimal value) => Speed.FromYardsPerSecond(Convert.ToDouble(value));

/// <inheritdoc cref="Speed.FromYardsPerSecond(double?)"/>
public static Speed? YardsPerSecond(this decimal? value) => Speed.FromYardsPerSecond(value == null ? (double?)null : Convert.ToDouble(value.Value));

#endregion

}
}
#endif
Loading