Skip to content
This repository has been archived by the owner on Sep 15, 2024. It is now read-only.

Commit

Permalink
Create Focusable abstract class and refactor Actor and Attribute
Browse files Browse the repository at this point in the history
Introduced a new abstract class called `Focusable` to encapsulate the common `Optional` usage in `Actor` and `Attribute` classes. The `Focusable` class represents focusable objects and gives access and modification of a property or element in a given subject via Optional. Refactoring in the `Actor` and `Attribute` classes removes duplicate code, enhancing code readability and maintainability.
  • Loading branch information
mysticfall committed Jan 1, 2024
1 parent bac81f8 commit 713b6d7
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 20 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ programming paradigms, it's purely experimental at this point and not suitable f

| Statements | Branches | Functions | Lines |
| --------------------------- | ----------------------- | ------------------------- | ----------------- |
| ![Statements](https://img.shields.io/badge/statements-98.62%25-brightgreen.svg?style=flat) | ![Branches](https://img.shields.io/badge/branches-96.92%25-brightgreen.svg?style=flat) | ![Functions](https://img.shields.io/badge/functions-87.5%25-yellow.svg?style=flat) | ![Lines](https://img.shields.io/badge/lines-98.62%25-brightgreen.svg?style=flat) |
| ![Statements](https://img.shields.io/badge/statements-98.54%25-brightgreen.svg?style=flat) | ![Branches](https://img.shields.io/badge/branches-95.52%25-brightgreen.svg?style=flat) | ![Functions](https://img.shields.io/badge/functions-85.29%25-yellow.svg?style=flat) | ![Lines](https://img.shields.io/badge/lines-98.54%25-brightgreen.svg?style=flat) |

## Motivation

Expand Down
1 change: 1 addition & 0 deletions src/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./range"
export * from "./error"
export * from "./optics"
export * from "./string"
26 changes: 26 additions & 0 deletions src/common/optics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {Optional} from "@fp-ts/optic"

/**
* Represents an abstract class for focusable objects.
*
* This class provides an {@link Optional} that allows accessing and modifying a property or element in a
* given subject.
*
* @template TSubject The type of the subject on which the focus will be applied.
* @template TFocus The type of the property or element that will be focused.
*/
export abstract class Focusable<TSubject, TFocus> {

/**
* Creates a new instance of the focusable object.
*/
protected constructor(
/**
* Represents an {@link Optional} that focuses on TFocus in a given TSubject.
*
* @readonly
*/
protected readonly optic: Optional<TSubject, TFocus>
) {
}
}
13 changes: 3 additions & 10 deletions src/game/actor/actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
* @module
*/
import * as Optic from "@fp-ts/optic"
import {Optional} from "@fp-ts/optic"
import {Either} from "fp-ts/Either"
import {Option} from "fp-ts/Option"
import {ReadonlyRecord} from "fp-ts/ReadonlyRecord"
import * as T from "io-ts"
import {Mixed} from "io-ts"
import {MaxLengthString, MinLengthString} from "../../common"
import {Focusable} from "../../common/optics"
import {NameAttribute, Named, NamedData, NamedDataT} from "../attribute"
import {UnknownActorError} from "./errors"

Expand Down Expand Up @@ -106,24 +106,17 @@ export interface Actor<
export abstract class AbstractActor<
TData extends ActorData = unknown & ActorData,
TContext extends ActorDataHolder<TData> = unknown & ActorDataHolder<TData>
> implements Actor<TData, TContext> {
> extends Focusable<TContext, TData> implements Actor<TData, TContext> {

readonly name: NameAttribute<ActorName, TData, TContext>

/**
* Represents an {@link Optional} that focuses on TData in a given TContext.
*
* @readonly
*/
protected readonly optic: Optional<TContext, TData>

/**
* Constructor for creating an instance of the class.
*
* @param {ActorId} id - The identifier of the actor.
*/
protected constructor(readonly id: ActorId) {
this.optic = Optic.id<TContext>().at("actors").key(id)
super(Optic.id<TContext>().at("actors").key(id))

this.name = new NameAttribute(this.optic, ActorNameT)
}
Expand Down
13 changes: 4 additions & 9 deletions src/game/attribute/attribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {Either} from "fp-ts/Either"
import {flow, pipe} from "fp-ts/function"
import {Decoder} from "io-ts"
import {PathReporter} from "io-ts/PathReporter"
import {Focusable} from "../../common/optics"
import {AttributeAccessError, InvalidAttributeError, ReadOnlyAttributeError} from "./errors"

/**
Expand Down Expand Up @@ -116,14 +117,7 @@ export abstract class AbstractAttribute<
TName extends string & keyof TData,
TData = unknown,
TContext = unknown
> implements Attribute<TData[TName], TContext> {

/**
* Represents an {@link Optional} that focuses on TData[TName] in a given TContext.
*
* @readonly
*/
protected readonly optic: Optional<TContext, TData[TName]>
> extends Focusable<TContext, TData[TName]> implements Attribute<TData[TName], TContext> {

/**
* Represents a decoder for converting unknown input into the corresponding typed data value.
Expand All @@ -147,7 +141,8 @@ export abstract class AbstractAttribute<
optic: Optional<TContext, TData>,
options?: AttributeOptions
) {
this.optic = optic.compose(Optic.id<TData>().at(name))
super(optic.compose(Optic.id<TData>().at(name)))

this.updatable = options?.updatable ?? true

// These methods are bound here to the instance to ensure that they maintain their "this" context
Expand Down

0 comments on commit 713b6d7

Please sign in to comment.