All Projects â†’ dreymonde â†’ Alba

dreymonde / Alba

Licence: MIT License
🎙 Stateful event observing engine [DEPRECATED]

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Alba

most-behave
Experimental continuous Behaviors for most.js
Stars: ✭ 32 (+68.42%)
Mutual labels:  functional-reactive-programming
assembler
Functional, type-safe, stateless reactive Java API for efficient implementation of the API Composition Pattern for querying/merging data from multiple datasources/services, with a specific focus on solving the N + 1 query problem
Stars: ✭ 102 (+436.84%)
Mutual labels:  functional-reactive-programming
reflex-dom-semui
A reflex-dom API for Semantic UI components
Stars: ✭ 22 (+15.79%)
Mutual labels:  functional-reactive-programming
bot-trader
Simple bot trader for Bitmex
Stars: ✭ 14 (-26.32%)
Mutual labels:  functional-reactive-programming
functional-reactive-lib
A core java lib for the functional reactive coding ... JDK only
Stars: ✭ 25 (+31.58%)
Mutual labels:  functional-reactive-programming
purescript-pop
😃 A functional reactive programming (FRP) demo created with PureScript events and behaviors.
Stars: ✭ 33 (+73.68%)
Mutual labels:  functional-reactive-programming
frp agda
Functional Reactive Programming with Agda
Stars: ✭ 22 (+15.79%)
Mutual labels:  functional-reactive-programming
reflex-dom-ace
Reflex wrapper for the ACE editor
Stars: ✭ 12 (-36.84%)
Mutual labels:  functional-reactive-programming
mutable
State containers with dirty checking and more
Stars: ✭ 32 (+68.42%)
Mutual labels:  functional-reactive-programming
Swift-3-Functional-Programming
Code repository for Swift 3 Functional Programming, published by Packt
Stars: ✭ 78 (+310.53%)
Mutual labels:  functional-reactive-programming
RxUploader
Uploader for Android using RxJava
Stars: ✭ 72 (+278.95%)
Mutual labels:  functional-reactive-programming
reflex-native
Framework for writing fully native apps using Reflex, a Functional Reactive Programming library for Haskell.
Stars: ✭ 40 (+110.53%)
Mutual labels:  functional-reactive-programming
Airstream
State propagation and event streams with mandatory ownership and no glitches
Stars: ✭ 160 (+742.11%)
Mutual labels:  functional-reactive-programming
WhatFilm
Simple iOS app using TMDb API and RxSwift
Stars: ✭ 35 (+84.21%)
Mutual labels:  functional-reactive-programming
recurrent
A library for building functional-reactive (FRP) GUIs in Clojurescript
Stars: ✭ 49 (+157.89%)
Mutual labels:  functional-reactive-programming
yave
Functional visual programming language with FRP for multimedia
Stars: ✭ 29 (+52.63%)
Mutual labels:  functional-reactive-programming
demonstration-gsd
GSD (Get your Stuff Done) | Basic Todo list for demonstrating CQRS/Command Sourcing in Haskell
Stars: ✭ 46 (+142.11%)
Mutual labels:  functional-reactive-programming
MGCleanArchitecture
Clean Architecture with RxSwift & MVVM - Templates and Solutions
Stars: ✭ 156 (+721.05%)
Mutual labels:  functional-reactive-programming
thomas
Another A/B test library
Stars: ✭ 20 (+5.26%)
Mutual labels:  functional-reactive-programming
fpEs
Functional Programming for EcmaScript(Javascript)
Stars: ✭ 40 (+110.53%)
Mutual labels:  functional-reactive-programming

Alba

Alba is a tiny yet powerful library which allows you to create sophisticated, decoupled and complex architecture using functional-reactive paradigms. Alba is designed to work mostly with reference semantics instances (classes).

Usage

Create publisher

let publisher = Publisher<UUID>()
publisher.publish(UUID())

Subscribing

In order to subscribe, you should use Subscribe instances. The easiest way to get them is by using .proxy property on publishers:

final class NumbersPrinter {
    
    init(numbersPublisher: Subscribe<Int>) {
        numbersPublisher.subscribe(self, with: NumbersPrinter.print)
    }
    
    func print(_ uuid: Int) {
        print(uuid)
    }
    
}

let printer = NumbersPrinter(numbersPublisher: publisher.proxy)
publisher.publish(10) // prints "10"

If you're surprised by how NumbersPrinter.print looks - that's because this allows Alba to do some interesting stuff with reference cycles. Check out the implementation for details.

That functional things

The cool thing about publisher proxies is the ability to do interesting things on them, for example, filter and map:

let stringPublisher = Publisher<String>()

final class Listener {
    
    init(publisher: Subscribe<String>) {
        publisher
            .flatMap({ Int($0) })
            .filter({ $0 > 0 })
            .subscribe(self, with: Listener.didReceive)
    }
    
    func didReceive(positiveNumber: Int) {
        print(positiveNumber)
    }
    
}

let listener = Listener(publisher: stringPublisher.proxy)
stringPublisher.publish("14aq") // nothing
stringPublisher.publish("-5")   // nothing
stringPublisher.publish("15")   // prints "15"

Cool, huh?

Lightweight observing

let publisher = Publisher<Int>()
publisher.proxy.listen { (number) in
    print(number)
}
publisher.publish(112) // prints "112"

Be careful with listen. Don't prefer it over subscribe as it can introduce memory leaks to your application.

Writing your own Subscribe extensions

If you want to write your own Subscribe extensions, you should use rawModify method:

public func rawModify<OtherEvent>(subscribe: (ObjectIdentifier, EventHandler<OtherEvent>) -> (), entry: @autoclosure @escaping ProxyPayload.Entry) -> Subscribe<OtherEvent>

Here is, for example, how you can implement map:

public extension Subscribe {
    
    public func map<OtherEvent>(_ transform: @escaping (Event) -> OtherEvent) -> Subscribe<OtherEvent> {
        return rawModify(subscribe: { (identifier, handle) in
            let handler: EventHandler<Event> = { event in
                handle(transform(event))
            }
            self._subscribe(identifier, handler)
        }, entry: .transformation(label: "mapped", .transformed(fromType: Event.self, toType: OtherEvent.self)))
    }
    
}

entry here is purely for debugging purposes -- you're describing the intention of your method.

Inform Bureau

One of the main drawbacks of the functional-reactive style is an elevated level of indirection -- you can't easily detect the information flow in your application. Alba aims to solve this problem with the help of a handy feature called Inform Bureau. Inform Bureau collects information about every subscription and publishing inside your application, so it's easy for you to detect what's actually going on (and to detect any problems easily, of course).

Enabling Inform Bureau

Inform Bureau is an optional feature, so it should be enabled in your code in order to work. It's actually just one line of code -- make sure to put this in your AppDelegate's init (application(_:didFinishLaunchingWithOptions) is too late):

Alba.InformBureau.isEnabled = true

Just this line will no have any immediate effect -- in order for Inform Bureau to become useful, you should also enable it's Logger:

Alba.InformBureau.Logger.enable()

And that's it! Now you're going to see beautiful messages like these in your output:

(S) ManagedObjectContextObserver.changes (Publisher<(NSChangeSet, Int)>)
(S) --> mapped from (NSChangeSet, Int) to NSSpecificChangeSet<CleaningPoint>
(S) !-> subscribed by PointsListViewController:4929411136
(S) +AppDelegate.applicationWillTerminate (Publisher<UIApplication>)
(S) --> mapped from UIApplication to ()
(S) merged with:
(S)    +AppDelegate.applicationDidEnterBackground (Publisher<UIApplication>)
(S)    --> mapped from UIApplication to ()
(S) !-> subscribed by ContextSaver:6176536960
(P) ContextSaver.didSaveContext (Publisher<()>) published ()

Hint: (S) are subscriptions events, and (P) are publications.

Getting your code ready for Inform Bureau

Inform Bureau can be enabled with two lines of code. However, in order for it to be useful, there is a little amount of work required from you. First and foremost, you should create all your publishers with descriptive label:

let didFailToSaveImage = Publisher<Error>(label: "ImageSaver.didFailToSaveImage")

You should name your publishers using the next convention: [type_name].[publisher_name]

If your publisher is declared as static, then add + to the beginning:

static let applicationWillTerminate = Publisher<UIApplication>(label: "+AppDelegate.applicationWillTerminate")

OSLogger

Alba's Inform Bureau takes full advantage of Apple's latest Unified Logging system. The support for this system comes via Alba.OSLogger object. If you want your app to write Alba logs via os_log, enable it after enabling InformBureau:

Alba.InformBureau.isEnabled = true
Alba.OSLogger.enable()

In order for os_log to work, you should also do this.

Now you can see Alba logs of your program in a Console application.

Installation

Alba is available through Carthage. To install, just write into your Cartfile:

github "dreymonde/Alba" ~> 0.3.3

You can also use SwiftPM. Just add to your Package.swift:

import PackageDescription

let package = Package(
    dependencies: [
        .Package(url: "https://github.com/dreymonde/Alba.git", majorVersion: 0, minor: 3),
    ]
)

Contributing

Alba is in early stage of development and is opened for any ideas. If you want to contribute, you can:

  • Propose idea/bugfix in issues
  • Make a pull request
  • Review any other pull request (very appreciated!), since no change to this project is made without a PR.

Actually, any help is welcomed! Feel free to contact us, ask questions and propose new ideas. If you don't want to raise a public issue, you can reach me at [email protected].

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].