Declarative Text Kit: Expression and Evaluation

Teaser image

In DeclarativeTextKit, I found the abstraction of an “expression” in my vocabulary to represent the Domain-Specific Language’s instructions useful. Here is an example of a valid block of changes: This uses two kinds of Swift Result Builder to define the DSL’s grammar: The rules of the grammar are essentially this:

Continue reading …

Swift Package: FastSpring In-App Purchase

The recent release of TableFlip v1.6 is the first one that includes a new in-app purchase (IAP) component I assembled for my projects. It’s used in TableFlip to purchase a lifetime license within the app.

With future releases, the package will support in-app purchases of consumables or individual features, too.

Find package source code here: https://github.com/CleanCocoa/FastSpringStore

The Swift Package Index listing: https://swiftpackageindex.com/CleanCocoa/FastSpringStore

To use this in your app, all you need is:

  • A FastSpring account with the modern backend that everyone gets. (If you are still on “Classic”, you’ll know.)
  • Create an Embedded Storefront to display a very minimal shopping UI on a HTML page. Put this on your website or another trusted source: You will have to tell FastSpring that the form is legit with a domain-based allow-list, so you should really own the source.
  • Include the package in your app and point to the URL of your self-hosted embedded storefront.
  • Bonus: if you use my Trial and Licensing package, you can quickly unlock the app after a purchase has been made. The IAP component notifies your app on success.

With that in place, you can display a dedicated purchase window inside your app that doesn’t require a large context switch to the browser to make a sale:

TableFlip’s dedicated purchase window

The setup is quite short. I use a dedicated service object:

class PurchaseLicense {
    let store: FastSpringStore

    init() {
        self.store = FastSpringStore(
            storeURL: storeURL,
            purchaseCallback: { store, purchases in
                // Could have multiple purchased items, e.g. if you
                // offer in-app purchases of bundled features.
                assert(purchases.count == 1)
                guard let purchase = purchases.first else { return }

                for license in purchase.licenses {
                    // Unlock via license.licenseName & license.licenseCode, e.g.
                    // using the https://github.com/CleanCocoa/TrialLicensing package:
                    //
                    //   TrialLicensing.AppLicensing.register(
                    //       name: license.licenseName,
                    //       licenseCode: license.licenseCode
                    //   )
                }
            })
    }

    func showStore() {
        // Localize and customize the window title:
        store.showStore(title: "Purchase MyApp")
    }
}

I introduced this feature to my apps because its predecessor was a popular choice to purchase a license among WordCounter users. There, it is being picked for about 50% of license sales in total.

It appears that if the option exists, it will be used. I can’t tell whether having this option actually increases sales or not, though.

Declarative Text Kit: Inserting Strings and Lines With a Result Builder

Teaser image

There’s been progress on the Declarative Text Kit API idea, and today I want to share an insight into building a DSL with Swift Result Builders. A detail that I didn’t grok until I built it. {{TOC}} Inserting text into a string, text view, or other kind of text buffer is simple enough: you need a location and then use the appropriate API to put a string into the target there.

Continue reading …

It’s Easier With Meaning

It is easier to close Threads if you have a great book waiting for you.

It is easier to press pause on Spotify if you can play the piano.

It is easier to avoid Uber Eats if you know how to cook.

It can be hard, but it’s easier if you have something meaningful to do.


This is almost verbatom from iA’s “No Thanks”. I merely rearranged the sentences to highlight the beauty.

Use and Then Reduce Open Source Dependencies

Teaser image

Use open source liberally to make progress. Avoid open source dependencies in the long run if you can. Start a project by ingesting open source libraries to make progress fast and see if your product works. That’s fine. If it’s not too much, you can leave them in. But when the product matures, and if you offer a library yourself, you may benefit from reducing dependencies to ease product maintenance. Pick what you really need:

Continue reading …

Zettelkasten (Not) Needed?

As the saying goes, if the title of a post is a question, the answer is “no”. I don’t know how you would sensibly apply that to this one 🙂 Most of the days, for most of the time, I’m a software developer. I code, I plan, I think and learn. At other times, I’m writing things: on this blog, for book manuscripts, as letters and email; to plan, to help, to teach and to share.

Continue reading …