-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Composing generators playground #48
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
9b2ce00
Merge branch 'main' into composing-generators-playground
rafaelol1veira 9a54996
Add Composing with generators playground
rafaelol1veira ec31e5d
playground 2 improvements
rafaelol1veira 2852cbc
adapt
rafaelol1veira 137ce63
fix misspell
rafaelol1veira b9137ac
Merge branch 'main' into composing-generators-playground
rafaelol1veira 75acf52
revert files commited
rafaelol1veira 34dbd4f
Modifications
rafaelol1veira File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
151 changes: 150 additions & 1 deletion
151
Example/Playground.playground/Pages/Composing with Operators.xcplaygroundpage/Contents.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,152 @@ | ||
import Foundation | ||
import Genything | ||
import GenythingTest | ||
import Trickery | ||
import XCTest | ||
|
||
// Just show how every operation returns a generator, and how the numerous operators can be used to produce more complex results | ||
/*: | ||
# Composing With Operators Introduction | ||
|
||
With Genything, we can generate any random value for each type, for example: | ||
|
||
*/ | ||
|
||
let integer = Int.arbitrary.next(.random()) | ||
let double = Double.arbitrary.next(.random()) | ||
let string = String.arbitrary.next(.random()) | ||
let character = Character.arbitrary.next(.random()) | ||
|
||
/*: Including Optionals */ | ||
|
||
let integerOptional = Int.arbitrary.orNil().next(.random()) | ||
|
||
/*: And even more complex types with different syntax, like: */ | ||
|
||
let integerArray: [Int] = Array.arbitrary.next(.random()) | ||
let charArray: [Character] = .arbitrary.next(.random()) | ||
let integerOptionalArray = [Int?].arbitrary.next(.random()) | ||
let dictionary: Dictionary<Int, String> = Dictionary.arbitrary.next(.random()) | ||
|
||
/*: | ||
# Operators Examples | ||
## Expand | ||
While working with arrays, the lib allows to create an array with a fixed size | ||
*/ | ||
|
||
let fixedSizeArray = Int.arbitrary.expand(toSize: 2).next(.random()) | ||
|
||
/*: or with the size inside a range */ | ||
|
||
let rangeSizedArray = Int.arbitrary.expand(toSizeInRange: 3...5).next(.random()) | ||
|
||
/*: | ||
## Weighted | ||
This method allows to attribute weight to each element to be generated. For this example, this would generate twice as many apples as bananas. | ||
|
||
The size was setted randomly to show the example 🪄 | ||
*/ | ||
|
||
let weighted = Generators | ||
.weighted([ | ||
(2, "Apple"), | ||
(1, "Banana"), | ||
]) | ||
.take(6, randomSource: .random()) | ||
|
||
/*: | ||
## Loop | ||
The loop method would create an array of a random size containing a loop of the previously selected values. | ||
For this example, the size was setted in order to show the expected result 🪄 | ||
*/ | ||
|
||
let loop = Generators | ||
.loop(0...3) | ||
.take(10, randomSource: .random()) | ||
|
||
/*: | ||
# Mutating Operators. | ||
Moving forward, the lib allows to mutate the data using some Rx programming functions, as: | ||
|
||
## Map | ||
|
||
Map returns an object with the results of mapping the given closure over the previous elements | ||
*/ | ||
|
||
let mapCountValue = Generators | ||
.constant(32) // starts at 32 | ||
.map { $0 + 1 } | ||
.map { $0 + 1 } | ||
.map { $0 + 1 } | ||
.next(.random()) | ||
|
||
/*: | ||
Map returns an array containing the results of mapping the given closure over sequence. In this case, the array of characters would be transformed into a String | ||
*/ | ||
|
||
|
||
let mapCharToString = Character.arbitrary | ||
.expand(toSizeInRange: 1 ... 5) | ||
.map { (chars: [Character]) -> String in String(chars) } | ||
.next(.random()) | ||
/*: | ||
## FlatMap | ||
Flat map would flatten up the result of the map, and it would turn the received value into a Generator. For this example. There is an array of integer generators that would be flatten up on a single integer generator | ||
*/ | ||
|
||
let arrayOfGenerators: [AnyGenerator<Int>] = [ | ||
(0..<5).arbitrary, | ||
(6..<10).arbitrary, | ||
(11..<15).arbitrary, | ||
(16..<20).arbitrary | ||
] | ||
|
||
/*: | ||
Let's choose a random generator by turning it into a generator. | ||
*/ | ||
let generatorOfRandomGenerators: AnyGenerator<AnyGenerator<Int>> = arrayOfGenerators.arbitrary | ||
|
||
/*: | ||
Then we generate a random generator. | ||
From that generator, we can generate a random value | ||
*/ | ||
|
||
generatorOfRandomGenerators.next(.random()).next(.predetermined()) | ||
|
||
/*: | ||
The approach shown above has two problems: | ||
1. The syntax is not very ergonomic - there are 2 .next calls | ||
2. The need to send the same random source to both if we want to maintain predictability. | ||
|
||
We can solve both aforementioned problems using flatMap. | ||
*/ | ||
|
||
let flattenArray = generatorOfRandomGenerators.flatMap { $0 } | ||
let generateFlattenArray = flattenArray.next(.predetermined()) | ||
|
||
/*: | ||
## Zip. | ||
Zip operators combine two generators and emit a single element for each combination. | ||
When you zip two Generators, it returns a single Generator with an array of the two elements zipped. Here is a demonstration that the zip return is correct. | ||
*/ | ||
struct Point { | ||
var x: Int | ||
var y: Int | ||
} | ||
|
||
let xPoint = (1...3).arbitrary | ||
let yPoint = (5...8).arbitrary | ||
|
||
xPoint | ||
.zip(yPoint) { x, y in | ||
Point(x: x, y: y) | ||
} | ||
.next(.random()) | ||
|
||
|
||
let a = Int.arbitrary.expand(toSize: 1) | ||
let b = Int.arbitrary.expand(toSize: 2) | ||
|
||
let result = Generators.zip(a, b) | ||
.map { $0.0.count == 1 && $0.1.count == 2 } | ||
.next(.random()) | ||
//: [Modelling Production Data](@next) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could mention meta-generators or inception here 🤣