mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Make toolshed's CommandImplementationAttribute optional (#6218)
This commit is contained in:
@@ -9,7 +9,7 @@ namespace Robust.Shared.Toolshed;
|
||||
/// Used to mark a class so that <see cref="ToolshedManager"/> automatically discovers and registers it.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
[MeansImplicitUse]
|
||||
[MeansImplicitUse(ImplicitUseTargetFlags.WithMembers)]
|
||||
public sealed class ToolshedCommandAttribute : Attribute
|
||||
{
|
||||
public string? Name = null;
|
||||
|
||||
@@ -30,10 +30,24 @@ public abstract partial class ToolshedCommand
|
||||
return true;
|
||||
}
|
||||
|
||||
internal IEnumerable<MethodInfo> GetGenericImplementations()
|
||||
internal MethodInfo[] GetMethods()
|
||||
{
|
||||
var methods = GetType().GetMethods(MethodFlags);
|
||||
|
||||
// CommandImplementationAttribute is optional if there is only a single method defined by the type,
|
||||
return methods.Length == 1
|
||||
? methods
|
||||
: methods.Where(x => x.HasCustomAttribute<CommandImplementationAttribute>()).ToArray();
|
||||
}
|
||||
|
||||
internal MethodInfo[] GetMethods(string? subCommand)
|
||||
{
|
||||
if (subCommand == null)
|
||||
return GetMethods();
|
||||
|
||||
return GetType()
|
||||
.GetMethods(MethodFlags)
|
||||
.Where(x => x.HasCustomAttribute<CommandImplementationAttribute>());
|
||||
.Where(x => x.GetCustomAttribute<CommandImplementationAttribute>()?.SubCommand == subCommand)
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ public abstract partial class ToolshedCommand
|
||||
throw new InvalidCommandImplementation($"{nameof(TypeParameterParsers)} element {typeParser} is not {nameof(TypeTypeParser)} or assignable to {typeof(CustomTypeParser<Type>).PrettyName()}");
|
||||
}
|
||||
|
||||
var impls = GetGenericImplementations().ToArray();
|
||||
var impls = GetMethods();
|
||||
if (impls.Length == 0)
|
||||
throw new Exception($"Command has no implementations?");
|
||||
|
||||
|
||||
@@ -51,10 +51,7 @@ internal sealed class ToolshedCommandImplementor
|
||||
FullName = SubCommand == null ? Owner.Name : $"{Owner.Name}:{SubCommand}";
|
||||
_toolshed = toolshed;
|
||||
|
||||
Methods = Owner.GetType()
|
||||
.GetMethods(ToolshedCommand.MethodFlags)
|
||||
.Where(x => x.GetCustomAttribute<CommandImplementationAttribute>() is { } attr &&
|
||||
attr.SubCommand == SubCommand)
|
||||
Methods = Owner.GetMethods(SubCommand)
|
||||
.Select(x => new CommandMethod(x, this))
|
||||
.ToArray();
|
||||
|
||||
|
||||
@@ -215,3 +215,18 @@ public sealed class TestNestedEnumerableCommand : ToolshedCommand
|
||||
[CommandImplementation]
|
||||
public IEnumerable<ProtoId<EntityCategoryPrototype>> Impl() => _arr.OrderByDescending(x => x.Id);
|
||||
}
|
||||
|
||||
[ToolshedCommand]
|
||||
public sealed class TestImplicitImplCommand : ToolshedCommand
|
||||
{
|
||||
public int Impl() => 1;
|
||||
}
|
||||
|
||||
[ToolshedCommand]
|
||||
public sealed class TestExplicitImplCommand : ToolshedCommand
|
||||
{
|
||||
public int Impl() => 1;
|
||||
|
||||
[CommandImplementation]
|
||||
public int Impl2() => 2;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,10 @@ public sealed class ToolshedTests : ToolshedTest
|
||||
Assert.Throws<AssertionException>(() => ParseError<OutOfInputError>("i 2"));
|
||||
Assert.That(ExpectedErrors.Count, Is.EqualTo(1));
|
||||
ExpectedErrors.Clear();
|
||||
|
||||
// Check that the CommandImplementationAttibute is optional when the type only defines one method.
|
||||
AssertResult("testimplicitimpl", 1);
|
||||
AssertResult("testexplicitimpl", 2);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user