Coder Social home page Coder Social logo

pointfreeco / swift-overture Goto Github PK

View Code? Open in Web Editor NEW
1.1K 1.1K 61.0 166 KB

๐ŸŽผ A library for function composition.

Home Page: https://www.pointfree.co/episodes/ep11-composition-without-operators

License: MIT License

Makefile 0.37% Swift 99.63%
function-composition functional-programming

swift-overture's Introduction

๐ŸŽฌ www.pointfree.co

Swift 5.7 CI @pointfreeco

This repo contains the full source code for the Point-Free website, a video series exploring advanced programming topics in Swift. The codebase is split into 3 pieces:

  • PointFree: This is the core application, and is responsible for routing requests, loading data and rendering HTML and CSS.
  • Styleguide: This library contains functions and data types for creating a consistent style across the entire website.
  • Server: This is the actual executable server. It uses NIO to handle the low-level server responsibilities, and hands everything else over to the PointFree package.

Point-Free Homepage

Getting Started

Interested in a video tour of the code base?

video poster image

The repo contains an extensive test suite and some playgrounds to explore. To get things running:

  • Open up a terminal window and grab the code:

    git clone https://github.com/pointfreeco/pointfreeco.git
    cd pointfreeco
  • Make sure cmark is installed. You can install it with Homebrew:

    brew install cmark # or your preferred installation method
  • Make sure Postgres is installed and running. It's our database of choice. You can install it with Homebrew:

    brew install postgres # or your preferred installation method
    brew services start postgresql # or your preferred launch method
    make db

    (If you use Postgres.app, EnterpriseDB, or another installation method, please follow some additional instructions in the CPostgreSQL README.)

With the project open in Xcode, you can:

  • Run the server locally
    • Select the Server target
    • Run: Command+R
    • Visit http://localhost:8080
  • Explore our playgrounds
    • Select the PointFree target
    • Build: Command+B
    • Open a playground!

Some fun things to explore

There're a lot of fun things to explore in this repo. For example:

  • We develop web pages in playgrounds for a continuous feedback loop. This is made possible by the fact that the entire server stack is composed of pure functions with side-effects pushed to the boundaries of the application. It allows us to load up any request in isolation, including POST requests, all without ever worrying about doing a side-effect. Server side Swift in a playground

  • We use snapshot testing to capture full data structures in order to verify their correctness. Not only do we do this in the traditional way of taking screenshots of web pages at various break points (e.g. on iPhone and desktop), but we can also snapshot any entire request-to-response lifecycle (e.g. the POST to a signup page does the correct redirect).

โ–ฟ Step
  ResponseEnded

โ–ฟ Request
  POST http://localhost:8080/launch-signup

  [email protected]

โ–ฟ Response
  Status 302 FOUND
  Location: /?success=true

Xcode Color Theme

Like the color theme we use in our episodes? Run make colortheme to install locally!

Related projects

Point-Free uses a bunch of interesting open-source software:

  • ๐Ÿ—บ swift-html: A Swift DSL for type-safe, extensible, and transformable HTML documents.
  • ๐Ÿ•ธ swift-web: A collection of types and functions for dealing with common web server concerns, such as HTML render, CSS preprocessing, middleware and more.
  • ๐ŸŽถ swift-prelude: Offers a standard library for experimental functional programming in Swift.
  • ๐Ÿท swift-tagged: Helps us create strong contracts with our data boundaries, like JSON from GitHub and Stripe, and our PostgreSQL data.
  • ๐Ÿ“ธ swift-snapshot-testing: Powers our testing infrastructure by taking snapshots of various data structures to guarantee the correctness of their output. We use this on everything from middleware to ensure requests are correctly transformed into responses, and even entire web pages to make sure the site looks correct at a variety of sizes (e.g. on iPhone and desktop).

Explore more of our open-source on the Point-Free organization.

Learn More

Brandon gave a talk about most of the core ideas that went into this project at Swift Summit 2017.

The two sides of writing testable code

Find this interesting?

Then check out Point-Free!

License

The content of this project itself is licensed under the CC BY-NC-SA 4.0 license, and the underlying source code used to format and display that content is licensed under the MIT license.

swift-overture's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swift-overture's Issues

Compile times of with, concat & mut functions in swift4 are very high!!

I inherited some code, and compile time was crazy (90s - 120s, incremental. 3.5 min new) . So i ran
https://github.com/RobertGummesson/BuildTimeAnalyzer-for-Xcode

on our codebase and all the functions or lazy vars that used concat, mut, with from swift overture were taking considerable time to compile.

For ex. this stackview getter was taking >5 seconds to compile!!!!

var stackView = with(UIStackView(), concat(
        mut(\.axis, .vertical),
        mut(\.isLayoutMarginsRelativeArrangement, true),
        mut(\.layoutMargins, UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)),
        mut(\.spacing, 16),
        mut(\.alignment, .center)
    ))

Some other examples:

var titleLabel: UILabel = with(UILabel(), concat(
        autolayoutStyle,
        mut(\.font, .sg_font(size: 24, weight: .bold)),
        mut(\.textAlignment, .center),
        mut(\.numberOfLines, 0),
        mut(\.lineBreakMode, .byWordWrapping)
        )
    )

    var promptLabel: UILabel = with(UILabel(), concat(
        autolayoutStyle,
        mut(\.font, .sg_font(size: 14, weight: .regular)),
        mut(\.textAlignment, .center),
        mut(\.numberOfLines, 0),
        mut(\.lineBreakMode, .byWordWrapping)
        )
    )

    var stackView: UIStackView = with(UIStackView(), concat(
        autolayoutStyle,
        mut(\.axis, .vertical),
        mut(\.spacing, 7),
        mut(\.isLayoutMarginsRelativeArrangement, true),
        mut(\.layoutMargins, .init(top: 29, left: 16, bottom: 27, right: 16))
        )
    )

As this is a new framework/library for me, I'd love to hear if I'm the only one experiencing this?

getting EXC_BAD_ACCESS while calling overture methods in static vars

here are some examples of EXC_BAD_ACCESS crashes i'm getting while running my unit tests locally

image

image

I fixed the later one by changing:

static var burningDesirePostItem = with(BurningDesireFeedCellItem(), concat(
        mut(\.post, .mockRegular)
    ))

to

    static var burningDesirePostItem : BurningDesireFeedCellItem = {
        let burningDesireItem = BurningDesireFeedCellItem()
        burningDesireItem.post = SGPost.mockRegular
        return burningDesireItem
    }()

But I'm not sure if i even fully understand what the problem is? I'm assuming that in the static instances, something hasn't been setup for overture, which is expecting to be called in instance methods?

The former one i can't seem to figure out a good way to fix - it seems the last line in:

static let mock = {
        return with(
            CoachingAPI(),
            concat(
                mut(\.selectedCoachId, { return .init(String(Coach.mockCoaches.first!.id)) }),
                mut(\.subscriptionStatus, { return .enabled }),
                mut(\.fetchCoaches, { $0(.success(Coach.mockCoaches)) })
            )
        )
    }()

Is it effectively mocking out the return of fetchCoaches function on CoachingAPI?

Compilation failure using mut on a navigation controller

A bit confused with the following code:

  let baseNavigationBarStyle: (UINavigationBar) -> Void = { ... }

    var navigationController: UINavigationController = update(
      UINavigationController(rootViewController: controller),
      mver(\.navigationBar, baseNavigationBar)
    )

fails to compile:

Key path value type 'WritableKeyPath<UINavigationController, UINavigationBar>' cannot be converted to contextual type 'KeyPath<UINavigationController, UINavigationBar>'

The following works fine:

let baseNavigationBarStyle: (UINavigationBar) -> Void = { ... }

let baseNavigationBar: (inout UINavigationBar) -> Void = {
  with($0, baseNavigationBarStyle)
}
var navigationController = UINavigationController(rootViewController: controller)

with(navigationController.navigationBar, baseNavigationBarStyle)

Add @discardableResult to update()

Currently @discardableResult is set on the AnyObject update methods. I think having @discardableResult everywhere would would clear up the warnings result of call 'update' is not used:
image

WDYT?

Adding the operators counterpart

Small intro, before getting to the point:

From some of tweets @stephencelis sent and the overall idea of this library, is to make FP more accessible. There is also this tweet:

If our Prelude library seems a lil too intense with all of its custom operators, then perhaps its Overture is more your tune!

โ€” Point-Free (@pointfreeco) April 9, 2018

There is indeed a big difference between them, both in terms of size, but also necessary knowledge to use one over the other.

What I propose is to provide the operators counterparts of these functions (e.g. pipe, composition). When an Overture user feels confident about using operators, he/she can still use Overture to make that switch, instead of importing Prelude.

In my particular case, I use a very small subset of what Prelude provides, so Overture actually makes sense for my use case. Not having operators, is upsetting.

What do you think?

Redefine `set` without `over`

While it's really nice that set can be derived from over, the implicit key-path get is not only doing extra work, but can crash when dealing with implicitly-unwrapped optionals.

let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "")
with(formatter, set(\.currencyCode, "USD"))
// crash due to `currencyCode` being a `String!`

We should redefine our setters to not leverage over.

`with` is different from how it's portrayed in readme

Issue

Considering the example code from the readme:
image

Expected behavior
Expected label to have type UILabel

Actual behavior
label is of type Void:
image

Current workaround

adding return $0 below $0.textColor = .red however, this results in a lot of unneeded boilerplate when with is used often.

Proposed solution

Replacing with(UILabel()) with update(UILabel) in the readme. Since update does result in the expected behavior.

Xcode requiring `@escaping` for closure passed to `update`

Writing a function that uses update, and the compiler complains that I have to annotate my closure as @escaping to use it with update, but update doesn't declare the parameter as @escaping. Any idea why this is or how to work around this? I can definitely make my updateClient parameter @escaping, but it seems like this should be unnecessary.

    @MainActor open func testStore(
        initialState: Component.State = .mock,
        updateClient: (inout Component.Client) -> Void
    ) -> TestStoreOf<Component> where Component.State: Equatable & HasMock, Component.Client: HasMock {
        Component.testStore(
            initialState: initialState,
            client: update(.mock, updateClient) // Passing non-escaping parameter 'updateClient' to function expecting an @escaping closure
        )
    }

zip(with:) are not public ?

Hi!

First, thanks for this great library, very helpful!

I was wondering why all the zip(with:) methods on sequence are not public ? Is it intentional? if yes, why?

Throwing overloads

First of all: thank you for your great work!

Currently there are no overloads for chain, compose, pipe, concat, ... that work with throwing functions.

If you want, I can open a PR that adds these overloads.

Ambiguous use of `with`

on latest version (xcode 10.1, Swift4.2, Overture 0.3.1), even the basic example from your readme fails:

import Overture
class MyViewController: UIViewController {
    let label = with(UILabel()) {
        $0.font = .systemFont(ofSize: 24)
        $0.textColor = .red
    }
}

I think theres ambiguity between the standard and inout versions of with. I would have to annotate the type, e.g let with(UILabel) { (l: inout UILabel) in ...} to fix it.

But its such an obvious issue, Im sure you or others must have seen it. Any suggestions?

Potentially add `rethrows` to `over` and similar functions

Context

I'm trying to update some code that I think could really benefit from a functional style. Here's the current code:

let keyPaths: [WritableKeyPath<Config, String>] // ...

for keyPath in keyPaths {
  config[keyPath: keyPath] = try evaluator.evaluateExpression(config[keyPath: keyPath])
}

The problem

I've tried a few different approaches and none of them compile because evaluateExpression is a throwing function, and the overture functions I'm trying to use don't have rethrows. Here's my best attempt:

let evaluators = keyPaths.map { over($0, evaluator.evaluateExpression) }

for evaluateField in evaluators {
  config = try evaluateField(config)
}

Potential solutions

  1. I'm missing something and there's a better way to do this with a function that does have rethrows
  2. Add rethrows to all of the methods except where it doesn't make sense (I feel like over and co make sense to have rethrows)

Currying higher order functions obscures type.

Swift (4.2.1 and 5.0-SNAPSHOT 12/28/18) seems to get really confused about the types of curry'd higher-order functions:

func lowerOrder(_ x: String, _ y: String) { }
lowerOrder is (String, String) -> Void //> true
curry(lowerOrder) is (String) -> (String) -> Void //> true

func higherOrder(_ x: String, _ y: (String) -> Int) { }
higherOrder is (String, (String) -> Int) -> Void //> true
curry(higherOrder) is (String) -> ((String) -> Int) -> Void //> false
print(type(of: curry(higherOrder))) //> "(String) -> ((String) -> Int) -> ()\n" 

Is this a problem with curry? A problem with Swift? A problem with me not grokking some subtlety of function types?

iOS target for Carthage

I know, SwiftPM does not support iOS yet, but do you want to support it for Carthage?

Currently Carthage works fine until one tries to create an archive and distribute it. Builds work and run on device via Xcode. When converting archive using bitcode option I get this odd error:

 warning: Failed to resolve linkage dependency Overture arm64 -> @rpath/libswiftCore.dylib: Could not find MachO for /Applications/Xcode-10.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx/libswiftCore.dylib

Somehow Overture tries to link to macosx libs of Swift. I was able to resolve this by manually making a separate iOS framework target to the xcodeproj. Not an optimal solution. Any ideas?

Is there a better way to style UINavigation's bar appearance?

Loved your Overture showcase video and started to apply to one of my project.

I was wondering if there was a better way to initialise \UINavigationBar.*Appearance to avoid the verbosity and stuttering?

let baseNavigationBarStyle = concat(
  mut(\UINavigationBar.standardAppearance, .init()),
  mut(\UINavigationBar.compactAppearance, .init()),
  mut(\UINavigationBar.scrollEdgeAppearance, .init()),

  mver(\UINavigationBar.standardAppearance, opaqueNavigationBar),
  mver(\UINavigationBar.compactAppearance!, opaqueNavigationBar),
  mver(\UINavigationBar.scrollEdgeAppearance!, opaqueNavigationBar),

  mut(\UINavigationBar.titleTextAttributes, .init()),
  mut(\UINavigationBar.largeTitleTextAttributes, .init()),
  mut(\UINavigationBar.prefersLargeTitles, true)
)

Also setting those titleTextAttributes was a bit confusing.

Here is the full code so far:

import Foundation
import Overture
import AsyncDisplayKit
import UIKit

let neutralTintColor = mut(\UIView.tintColor, .label)

// TabBar
let baseTabBarStyle = concat(
  neutralTintColor,
  mut(\UITabBar.standardAppearance, .init()),
  mver(\UITabBar.standardAppearance, opaqueTabBar)
)

let opaqueTabBar: (inout UITabBarAppearance) -> Void = {
  with($0, baseBarAppearance)
}

let opaqueNavigationBar: (inout UINavigationBarAppearance) -> Void = {
  with($0, baseBarAppearance)
}

// NavigationBar
let baseNavigationBarStyle = concat(
  mut(\UINavigationBar.standardAppearance, .init()),
  mut(\UINavigationBar.compactAppearance, .init()),
  mut(\UINavigationBar.scrollEdgeAppearance, .init()),

  mver(\UINavigationBar.standardAppearance, opaqueNavigationBar),
  mver(\UINavigationBar.compactAppearance!, opaqueNavigationBar),
  mver(\UINavigationBar.scrollEdgeAppearance!, opaqueNavigationBar),

  mut(\UINavigationBar.titleTextAttributes, .init()),
  mut(\UINavigationBar.largeTitleTextAttributes, .init()),
  mut(\UINavigationBar.prefersLargeTitles, true)
)

// UIBarAppearance
let baseBarAppearance = concat(
  mut(\UIBarAppearance.shadowColor, nil),
  { $0.configureWithOpaqueBackground() }
)

let baseNavigationBarAppearance = concat(
  baseBarAppearance,
  mut(\UINavigationBarAppearance.largeTitleTextAttributes, labelTextAttribute()),
  mut(\UINavigationBarAppearance.titleTextAttributes, labelTextAttribute())
)

let labelTextAttribute: () -> [NSAttributedString.Key : Any] = {
  [.foregroundColor: UIColor.label]
}

// UIView
let baseNavigationBar: (inout UINavigationBar) -> Void = {
  with($0, baseNavigationBarStyle)
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.