Skip to content
Merged
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,13 @@ public partial class DataStoreManager : MonoBehaviour, IDataStoreManager

 

When the generator synthesises the interface, it has to decide which members of your class show up on it. By default that's every public method and property. `[SingletonInclude]` and `[SingletonIgnore]` give you fine-grained control. They are mutually exclusive *per class* — using `[SingletonInclude]` anywhere on the class flips the generator into **explicit mode**.
When the generator synthesises the interface, it has to decide which members of your class show up on it. By default that's every public method, property, and event. `[SingletonInclude]` and `[SingletonIgnore]` give you fine-grained control. They are mutually exclusive *per class* — using `[SingletonInclude]` anywhere on the class flips the generator into **explicit mode**.

> **Note** — Neither attribute applies when you supply your own interface via `[Singleton(typeof(IFoo))]`; in that case the interface contract is whatever you typed.

**Auto mode** *(default — no `[SingletonInclude]` on the class)*

Every public instance method and property is on the interface. Use `[SingletonIgnore]` to hide individual members:
Every public instance method, property, and event is on the interface. Use `[SingletonIgnore]` to hide individual members:

```csharp
[Singleton]
Expand Down Expand Up @@ -255,7 +255,7 @@ public partial class SoundManager : MonoBehaviour

**Constraints**

- Both attributes target methods and properties only.
- Both attributes target methods, properties, and events only.
- `[SingletonInclude]` members must be **public** and **non-static** — the analyzer raises `ER0xxx` diagnostics otherwise.

</details>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public static string FormatAsInterfaceMember(ISymbol symbol)
{
IMethodSymbol method => FormatMethod(method),
IPropertySymbol property => FormatProperty(property),
IEventSymbol @event => FormatEvent(@event),
_ => string.Empty,
};
}
Expand Down Expand Up @@ -81,6 +82,17 @@ private static string FormatProperty(IPropertySymbol property)
return builder.ToString();
}

private static string FormatEvent(IEventSymbol @event)
{
var builder = new StringBuilder();
builder.Append("event ");
builder.Append(@event.Type.ToDisplayString(FullyQualifiedType));
builder.Append(' ');
builder.Append(@event.Name);
builder.Append(';');
return builder.ToString();
}

private static string FormatParameter(IParameterSymbol parameter)
{
var builder = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ private static bool IsAutoIncludeCandidate(INamedTypeSymbol classSymbol, ISymbol
{
IMethodSymbol method => method.MethodKind == MethodKind.Ordinary,
IPropertySymbol property => !property.IsIndexer,
IEventSymbol => true,
_ => false,
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using EngineRoom.Runtime.Singleton;
using UnityEngine;

Expand All @@ -6,6 +7,8 @@ namespace EngineRoom.Demo.Singletons
[Singleton]
public partial class GameManager : MonoBehaviour
{
public event Action<int> CountChanged;

public int Count => _count;

[Dependency] private ISoundManager _soundManager;
Expand All @@ -26,6 +29,7 @@ public void RegisterTap()
_dataStoreManager.SetScore(_count);
_soundManager.PlayTap();
_uiManager.SetCount(_count);
CountChanged?.Invoke(_count);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
"references": [
"EngineRoom.Demo.Singletons",
"EngineRoom.Generators.Runtime",
"UnityEngine.TestRunner",
"UnityEditor.TestRunner"
],
"includePlatforms": [
"Editor"
"UnityEngine.TestRunner"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;

namespace EngineRoom.Demo.Singletons.Tests
{
public class GameManagerTests
{
[Test]
public void RegisterTap_IncrementsCount_AndNotifiesSoundAndUi()
[UnityTest]
public IEnumerator RegisterTap_IncrementsCount_AndNotifiesSoundAndUi()
{
var store = MockDataStoreManager.Install();
var sound = MockSoundManager.Install();
var ui = MockUIManager.Install();

var game = GameManager.Create();

yield return null;

try
{
game.RegisterTap();
Expand All @@ -28,5 +32,32 @@ public void RegisterTap_IncrementsCount_AndNotifiesSoundAndUi()
Object.DestroyImmediate(((GameManager)game).gameObject);
}
}

[UnityTest]
public IEnumerator RegisterTap_RaisesCountChangedEventOnInterface()
{
MockDataStoreManager.Install();
MockSoundManager.Install();
MockUIManager.Install();

var game = GameManager.Create();

yield return null;

try
{
var observed = -1;
game.CountChanged += value => observed = value;

game.RegisterTap();
game.RegisterTap();

Assert.AreEqual(2, observed);
}
finally
{
Object.DestroyImmediate(((GameManager)game).gameObject);
}
}
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ namespace EngineRoom.Runtime.Singleton
{
/// <summary>
/// On a <see cref="SingletonAttribute"/>-decorated class that has no member
/// tagged with <see cref="SingletonIncludeAttribute"/>, marks a public method or
/// property to be excluded from the generated singleton interface. Has no
/// effect when the class is in explicit mode (i.e. uses
/// tagged with <see cref="SingletonIncludeAttribute"/>, marks a public method,
/// property, or event to be excluded from the generated singleton interface.
/// Has no effect when the class is in explicit mode (i.e. uses
/// <see cref="SingletonIncludeAttribute"/> elsewhere).
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event)]
public sealed class SingletonIgnoreAttribute : Attribute
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
namespace EngineRoom.Runtime.Singleton
{
/// <summary>
/// Marks a method or property on a <see cref="SingletonAttribute"/>-decorated class
/// Marks a method, property, or event on a <see cref="SingletonAttribute"/>-decorated class
/// to be projected onto the generated singleton interface.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event)]
public sealed class SingletonIncludeAttribute : Attribute
{
}
Expand Down