ClarityActivator

public class ClarityActivator : JSONAccess

A class initialised as a single instance conforming to JSONAccess that is used by the Clarity framework to access client application Clarity JSON files.

The Clarity JSON files contain all the information required to format and print client application logs to the console.

  • The client application main bundle.

    This is the bundle property used by ClarityActivator to access the client application ClarityJSON directory. It is set by the client application calling the custom ClarityActivator initialiser that acts as the framework activator.

    Note

    Note This variable remains nil when the Clarity framework is not embedded in a client. When this variable is nil the framework uses its own bundle to access its own ClarityJSON directory for the purposes of testing a simulated environment.

    Declaration

    Swift

    static var externalBundle: Bundle? { get set }
  • A constant that stores the bundle that ClarityActivator uses to access the ClarityJSON directory.

    The constant is assigned the variable externalBundle when embedded in a client as the active scheme or assigned the Clarity framework bundle when Clarity framework is running unit tests as the active scheme.

    Declaration

    Swift

    static let jsonBundle: Bundle
  • A constant that stores the result of a closure that computes whether the client application is in DEBUG mode.

    The closure calls _isDebugAssertConfiguration() – this function must be called from within the client to return the correct value for the client application.

    The isClientInDebugMode constant is lazily set when first accessed on assignment to the parameter inPrintMode of the ClarityActivator initialiser by the client application.

    Note

    When accessed by the Clarity framework test target the constant will return the DEBUG build mode state of the framework test target. Evaluating the build mode state of the test target is necessary for the correct operation of certain unit tests including testing the operation of verifyClarityJSONDirectory(forBundle:) .

    Declaration

    Swift

    public static let isClientInDebugMode: Bool
  • A Bool that signifies whether the ClarityActivator initialiser parameter inPrintMode: is set manually to true rather than via the closure constant isClientInDebugMode.

    If the value of the parameter inPrintMode: is set to true Clarity will print messages to the console when a client application is in RELEASE build mode overriding the usual behaviour of disabling Clarity print statements.

    Declaration

    Swift

    static var isClientOverrideRelease: Bool
  • A Bool that signifies whether the ClarityActivator initialiser parameter inPrintMode: is set manually to false rather than via the closure constant isClientInDebugMode.

    If the value of the parameter inPrintMode: is set to false Clarity will disable Clarity print statements when a client application is in DEBUG build mode overriding the usual behaviour of printing messages to the console.

    Declaration

    Swift

    static var isClientOverrideDebug: Bool
  • A static variable that lazily stores the result of a closure that returns an array of EntityLogService instances decoded from JSON files in the ClarityJSON folder.

    The closure returns the result of calling decoderServicesFromBundle<T: Decodable>(_: inSubDirectory:excludingFiles:) -> [T].

    Important

    The variable is not an optional unlike the other decoder service type variables.

    In the event that a client application contains Clarity print statements but the referenced EntityLogService JSON files are missing from the ClarityJSON folder (orphaned print numbers) MessageCollator will hand an empty dictionary of messages to the print logic. The print logic will then simply ignore any Clarity print calls rather than crash.

    The referenced EntityLogService JSON files can then be restored to the ClarityJSON folder and any print statements contained in a client application will print logs to the console as before. An alert will be printed to the console for every orphaned print number if the setting alertOrphanedPrintNumbersDetected is true.

    This behaviour means that Clarity print statements with their index arguments can remain in place without defaulting to Swift.print() for as long as the Clarity framework remains embedded and referenced with an import statement.

    The closure is also the point where internal print setting warning checks are made if Clarity printing is active in the client application. Internal printing is for Clarity framework development print logs and is included because it would be inadvisable to use a compiled version of Clarity itself to print logs to the console. This alert is a reminder to reset internal printing to false so that unnecessary logs are not printed in a client application.

    Declaration

    Swift

    static var entityLogServiceArray: [EntityLogService]
  • A static variable that lazily stores the result of a closure that returns an optional SettingsManagerService instance decoded from the JSON file named Settings.json in the ClarityJSON folder.

    The closure returns the result of calling decoderServiceFromBundle<T: Decodable>(_: inSubdirectory:forResourceName:) -> T?.

    Note

    If the variable is set to nil the JSONAccess protocol extension method printAlertForCorruptJSON(for: ) or the method verifyClarityJSONDirectory(forBundle:)-> Bool will present an alert and take action depending on the circumstance.

    Declaration

    Swift

    static var settings: SettingsManagerService?
  • A static variable that lazily stores the result of a closure that returns an optional FormattingManagerService instance decoded from the JSON file named Formatting.json in the ClarityJSON folder.

    The closure returns the result of calling decoderServiceFromBundle<T: Decodable>(_: inSubdirectory:forResourceName:) -> T?.

    If the variable is set to nil the JSONAccess protocol extension method printAlertForCorruptJSON(for: ) or the method verifyClarityJSONDirectory(forBundle:)-> Bool will present an alert and take action depending on the circumstance.

    Declaration

    Swift

    static var formatting: FormattingManagerService?
  • A custom failable initialiser for ClarityActivator that is used by client applications to activate the Clarity logging framework with the given specifications.
    
    - Parameters:
       - externalBundle: The client application main bundle.
       - inPrintMode: The print mode status: usually set in accordance with the application DEBUG status. If set to the value `true` Clarity will be made active and print messages to the console.
       - displayStatus: A bool that determines whether or not to display the print mode and activation status of Clarity on initialisation. This parameter defaults to `true` and its inclusion in the activation expression is optional unless setting it to `false`.
    
    
       The main bundle is used to access the user Clarity json files stored in the ClarityJSON folder: these files are used to calculate, format and print to the console details correlating to the index of Clarity print statements and user preferences.
    
       This initialiser is not required by the Clarity framework test target during internal testing of the functionality of the framework. The JSON data derived properties are set lazily by calling JSONAccess protocol generic decoding methods.
    
        The initialiser is set  `@discardableResult` as a convenience for the client application activation API.
    
    - Note:
       Setting `isClientInDebugMode` as the argument to `inPrintMode` will disable Clarity print statements when the client application is in RELEASE mode. If printing Clarity logs is required in RELEASE mode simply pass `true`. Conversely if disabling Clarity print statements is required in DEBUG mode simply pass `false`.
    
       Client application DEBUG mode status must be accessed using the `ClarityActivator` computed var `isClientInDebugMode` and NOT via the `DEBUG` macro nor calling `_isDebugAssertConfiguration()` directly within the framework in order to provide the correct value for the client application.
    - Important:
       Setting `isClientInDebugMode` as the argument to `inPrintMode` functions as described only when using the Clarity project source code and the client application within the same Workspace during development. In all other cases it is currently impossible for a framework to detect the build configuration of a client and therefore necessary to set  `inPrintMode` manually to either `true` or `false` as required. For maximum efficiency ensure that Clarity remains embedded and that `inPrintMode` is set manually to `false` when archiving for release.
    
    
    The main tasks of this initialiser are:
     - to check whether `inPrintMode` has been set manually to override the application DEBUG status.
     - to assign the client application main bundle internally so the framework can access the client JSON files.
     - to verify that the necessary JSON files exist in the client application main bundle. (Detecting corrupt or invalid JSON is handled by the protocol decoder methods).
    

    Activation workflow examples

    The Clarity activation initialiser should only be called once in an application.

    *SwiftUI App @main workflow*
    
        import Clarity
        //...
       @main
       struct ClientForBigSuriOSApp: App {
       init() {
               //Either Automatic activation
               ClarityActivator(withBundle: Bundle.main, inPrintMode: ClarityActivator.isClientInDebugMode, displayStatus:false)
    
               //Or Manual activation (NOT both!)
                ClarityActivator(withBundle: Bundle.main, inPrintMode: true, displayStatus:false)
       }
       //...
    
    *App Delegate workflow*
    
       import Clarity
       //...
    
       func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
                //Either Automatic activation
                ClarityActivator(withBundle: Bundle.main, inPrintMode: ClarityActivator.isClientInDebugMode, displayStatus:false)
    
                //Or Manual activation (NOT both!)
                 ClarityActivator(withBundle: Bundle.main, inPrintMode: true, displayStatus:false)
       //...
    

    Framework as a client workflow

    Framework applications that have a single entry point method should activate Clarity in the same way as shown above in the entry point method implementation.

    Framework applications that do not have a single entry point will need to implement a class that includes a static variable that lazily stores the result of a closure containing the activation initialiser. This closure will then need to be accessed by all classes, structs or enums that use Clarity. This technique will ensure that Clarity is activated only once and that any failure to activate Clarity will not adversely affect the client framework.

       - Important:
    

    Framework applications will need to call the Bundle initialiser init(for:) supplying the implementing class as argument to the aClass parameter to access the correct Bundle for the framework.

    Framework as a client without a single entry point workflow

        // Activation
        import Clarity
    
        class ClarityServiceExample {
    
            static let clarityActivation: ClarityActivator? = {
                return ClarityActivator(withBundle: Bundle(for: ClarityServiceExample.self), inPrintMode: true)
            }()
        }
    
    
        // Accessing the activation
        import Clarity
    
        class MyClass {
           public init(parameterName:Type) {
    
           // All essential work here …
    
            guard let _ = ClarityService.clarityActivation else{
                print("Clarity activation failed")
                return
            }
    
            // Place Clarity print statement for the initialiser here if required.
        }
    
           // Clarity print statements can now be placed anywhere in the class.
        }
            //...
    
    

    Declaration

    Swift

    @discardableResult
    public init?(withBundle externalBundle: Bundle?, inPrintMode: Bool, displayStatus: Bool = true)
  • An enum for storing the state of the missing item status of the ClarityJSON directory.

    See more

    Declaration

    Swift

    enum ClarityJSONDirectoryState : Equatable
  • An enum for storing the state of a successful file copy procedure.

    This enum is used by ClarityActivator to pass the outcome of a successful file copy procedure to the printAlertForMissingFile(_: forDirectoryState:withResult:) -> String method for printing an alert to the console.

    If the copy procedure involved renaming an existing file or folder it passes the new name as an associated value to the replaceCopy case.

    See more

    Declaration

    Swift

    enum FileCopySuccess
  • A method that verifies whether the client application contains the ClarityJSON directory and JSON files required by the Clarity framework.

    If this method detects any required file is missing it will print an alert to the console and copy a default version of the missing item or items to the developer machine desktop. These items can then be copied back into the client project in Xcode.

    This method also acts as a utility to copy the necessary JSON files to the desktop in a folder named ClarityJSON on the first run of a client application after the framework has been embedded. This folder can then be dragged into the client project as a copied folder reference.

    Important

    This method will only attempt to verify the ClarityJSON directory, copy missing items to the desktop and print an alert when the value of inPrintMode resolves to true.

    Note

    There is no system level API that can directly identify whether a named subdirectory exists in a bundle. Therefore this method checks for the content expected in the subdirectory ClarityJSON to verify that the subdirectory itself exists.

    The actions taken as a consequence of running this method are:

    • if there is no directory or it is empty: a full copy is made of the ClarityJSON template folder including template and example entity log JSON files.
    • if there are no entity log JSON files: a copy is made of the ClarityJSON template folder containing template and example entity log JSON files.
    • if there are no entity log JSON files and either of the user preference JSON files are missing: a copy is made of the ClarityJSON template folder containing default versions of the user preference JSON file that is missing and template and example entity log JSON files.
    • if either or both of the user preference JSON files are missing and there is a valid entity log JSON file: a copy is made of the ClarityJSON template folder containing default versions of the missing user preference JSON file(s).

    Declaration

    Swift

    @discardableResult
    public static func verifyClarityJSONDirectory(forBundle externalBundle: Bundle) -> Bool

    Parameters

    externalBundle

    The client application main bundle

    Return Value

    A Bool signifying whether the ClarityJSON has been verified successfully. The return is a @discardableResult

  • A helper method used by verifyClarityJSONDirectory(forBundle:) to set the state of the directoryState ClarityJSONDirectoryState enum.

    This method sets the directoryState enum according to the client application required ClarityJSON directory JSON missing file status.

    Declaration

    Swift

    static func verifyClarityFiles(_ settingsFilePresent: Bool, _ formattingFilePresent: Bool, _ entityLogFilePresent: Bool, _ directoryState: inout ClarityActivator.ClarityJSONDirectoryState)

    Parameters

    settingsFilePresent

    The file present status of Settings.json

    formattingFilePresent

    The file present status of Formatting.json

    entityLogFilePresent

    The file present status of EntityLogService JSON files: there must be at least one file containing JSON that can be decoded by EntityLogService for isEntityLogFiles to be set to true.

    directoryState

    An inout parameter that sets and returns a ClarityJSONDirectoryState enum with the correct case calculated from the other parameters passed into this method including any associated values.

  • An intermediary method called by copyReplacementJSONToDesktop(forDirectoryState:) that is necessary to print the correct combination of messages to the console in the event of a file copy error.

    The method first calls printAlertForMissingFile(_:forDirectoryState:withResult:) passing on its parameter arguments before evaluating the error.

    If the error is the unauthorised permission error code 513 it will then call printManualTemplateCopyInstructionsScript().

    Declaration

    Swift

    fileprivate static func printAlertsForCopyFileError(_ missingFileName: String, _ directoryState: ClarityActivator.ClarityJSONDirectoryState, _ error: Error)

    Parameters

    missingfile

    The name of the missing preference file.

    directoryState

    A ClarityJSONDirectoryState enum containing the correct case for the client application missing file status.

    error

    The Error caught and thrown by the failed copy file attempt.

  • A method used by copyReplacementJSONToDesktop(forDirectoryState:) to select and call the correct helper method to use to remove default files that are not required for replacing missing files from the default ClarityJSON directory copied to the desktop.

    It calls a specific helper method depending on the value of the ClarityJSONDirectoryState enum and then calls appropriate print alert methods passing the required parameter arguments in each case.

    Declaration

    Swift

    fileprivate static func removeRedundantFiles(_ directoryState: ClarityActivator.ClarityJSONDirectoryState, _ newFileURL: URL, _ fileManager: FileManager, _ missingFileName: String, _ result: Result<ClarityActivator.FileCopySuccess, Error>) throws

    Parameters

    directoryState

    A ClarityJSONDirectoryState enum containing the correct case for the client application missing file status.

    newFileURL

    The URL to the default ClarityJSON directory copied to the desktop.

    fileManager

    The shared file manager object.

    missingFileName

    The name of the missing preference file.

    result

    A Result enum where Success is of type ClarityActivator.FileCopySuccess and is used to pass the result of the file copy attempt.

  • A method that copies a default version of the ClarityJSON directory and / or any of its required JSON files to the developer desktop if they are missing from the client application.

    This method takes a ClarityJSONDirectoryState enum and uses it to identify missing items. It then attempts to copy any missing JSON file from the TemplateJSON folder resource into a new folder on the desktop that it names ClarityJSON.

    If any item already exists on the desktop with the same name as a missing item the existing item will be renamed.

    An alert is then printed to the console that describes the action taken and the steps required to copy any missing item(s) back into the project.

    If only a single preference file is missing from the client ClarityJSON directory then a default copy of that file will be made and placed on the desktop (and not placed in an enclosing folder).

    Important

    Copying the TemplateJSON folder to the desktop will currently work when running client applications in device simulators. The copy attempt is likely to fail with a permission error when running macOS applications. If the attempt fails instructions on how to copy the TemplateJSON folder from derived data are printed to the console.

    Note

    The variable sourceDirectoryURL is assigned via a relative path of the TemplateJSON to the file location as an alternative path if the path cannot be derived from the bundle. The alternative path can only be created if the framework and client reside in the same workspace. If both paths return nil the URL remains initialised from an empty string and the method will catch the copy file error and print manual copy instructions to the console.

It is currently not possible to access the developer machine home directory path programmatically when the framework code is run from within a client application. NSHomeDirectory resolves to the home directory of the device or simulated device instead of the developer machine.

    There are six main task phases to the method:

    1. Get the source url TemplateJSON folder (from derived data path or relative to the file location)
    2. Get the destination URLs for specific files/folder to be copied on to the desktop).
    3. Create backup name URL for any pre-existing ClarityJSON folder on the desktop.
    4. Switch on the ClarityJSONDirectoryState and assign final source and destination URLs and components depending on what item(s|) are missing.
    5. Assign a pre-existing file enquiry path: either for a missing preference file or for the ClarityJSON folder
    6. Attempt to copy missing items, removing and renaming any pre existing items.

    Declaration

    Swift

    fileprivate static func copyReplacementJSONToDesktop(forDirectoryState directoryState: ClarityJSONDirectoryState)

    Parameters

    directoryState

    A ClarityJSONDirectoryState enum containing the correct case for the client application missing file status.

  • A helper method used by copyReplacementJSONToDesktop(forDirectoryState:) to remove default preference files that are not required for replacing missing files from the default ClarityJSON directory copied to the desktop.

    This method reads the name of any missing preference file and then removes any non-missing preference file contained in the default directory. If the missingFileName parameter is omitted both preference files are removed.

    Note

    This method propagates any error thrown by removeItem(at:)

    Declaration

    Swift

    fileprivate static func removePreferenceFiles(_ newFileURL: URL, _ fileManager: FileManager, _ missingFileName: String = "") throws

    Parameters

    newFileURL

    The URL to the default ClarityJSON directory copied to the desktop

    fileManager

    The shared file manager object

    missingFileName

    The name of the missing preference file

  • A helper method used by copyReplacementJSONToDesktop(forDirectoryState:) to remove template and example EntityLogService JSON files from the default ClarityJSON directory copied to the desktop (when they do not require replacing). The default ClarityJSON directory will then only contain preference files that are missing and need replacing.

    Note

    This method propagates any error thrown by removeItem(at:)

    Declaration

    Swift

    fileprivate static func removeEntityLogFiles(_ newFileURL: URL, _ fileManager: FileManager) throws

    Parameters

    newFileURL

    The URL to the default ClarityJSON directory copied to the desktop

    fileManager

    The shared file manager object

  • An implementation of the JSONAccess protocol method that prints an alert to the console if an attempt to decode a JSON file returns nil.

    Declaration

    Swift

    internal static func printAlertForCorruptJSON(for missingFile: String)

    Parameters

    missingFile

    The last path component of the URL to the JSON file that returned nil on an attempt to decode it.

  • A method that prints copyright information about the Clarity framework to console on launch of a client application.

    Declaration

    Swift

    private func printCopyrightHeader()
  • A method that compiles an alert and advice message that displays the active state of the Clarity framework.

    The method compiles a message that outlines the reasons for the current activation state derived from the client application build configuration DEBUG status and the state of inPrintMode.

    The method also provides an explanation of the steps to take to toggle the activation state.

    Declaration

    Swift

    private func printClarityActiveState(_ inPrintMode: Bool)

    Parameters

    inPrintMode

    The state resolved by the initialiser parameter inPrintMode.

  • A method that compiles an alert and advice message when either the ClarityJSON directory or any of its contained JSON files required by the Clarity framework has been detected as being missing.

    This method composes and returns a single message string for all combinations of missing file or directory and file copy success or fail outcome.

    Note

    The FileCopySuccess enum replaceCopy(newName:) used in the Result type returns an associated string value containing the new name of any file that already existed on the desktop with the same name as a replaced missing item.

    Declaration

    Swift

    static func printAlertForMissingFile(_ missingfile: String, forDirectoryState directoryState: ClarityJSONDirectoryState, withResult result: Result<FileCopySuccess, Error>) -> String

    Parameters

    missingfile

    The name of the missing preference file.

    directoryState

    A ClarityJSONDirectoryState enum containing the correct case for the client application missing file status.

    result

    A Result enum that uses a custom FileCopySuccess enum for its .success case associated value and an Error type for its .failure case associated value.

  • A method that prints to the console the instructions for adding the ClarityJSON folder and JSON files to the client project. It also explains behaviours relating to missing files and their replacement.

    Declaration

    Swift

    static func printInstructionsScript()
  • A method that prints to the console the instructions for manually copying and renaming the TemplateJSON folder. This will be printed in the event that a permissions issue prevented Clarity from copying it to the developer desktop automatically.

    Declaration

    Swift

    static func printManualTemplateCopyInstructionsScript()