diff --git a/examples/do_constructor_pitfalls/bin/do_constructor_pitfalls.dart b/examples/do_constructor_pitfalls/bin/do_constructor_pitfalls.dart deleted file mode 100644 index f130b599..00000000 --- a/examples/do_constructor_pitfalls/bin/do_constructor_pitfalls.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -/// This file demonstrates some common pitfalls when using the `Do` constructor in the `fpdart` package. -/// These are practices that should be avoided when using it. - -void main(List args) {} - -/// This function demonstrates that the `Do` constructor should not contain a `throw` statement. -/// Throwing an exception inside a `Do` constructor can lead to unexpected behavior and should be avoided. -/// Instead, use the `Option` type to handle errors. -void doConstructorShouldNotContainThrow() { - const testOption = const Option.of('test'); - Option.Do( - ($) { - if ($(testOption) == 'test') { - // Do not throw inside a Do constructor - throw Exception('Error'); - } - return 'success'; - }, - ); -} - -/// This function demonstrates that the `Do` constructor should not contain an `await` statement without executing the `$` function. -void doConstructorShouldNotAwaitWithoutExecutingDollarFunction() { - Future future = Future.value('test'); - const testOption = const Option.of('test'); - Option.Do( - ($) async { - // Do not use `await` without executing the `$` function - await future; - return $(testOption); - }, - ); -} - -// This function demonstrates that the `Do` constructor should not be nested. -/// Nesting `Do` constructors can lead to unexpected behavior and should be avoided. -void doConstructorShouldNotBeNested() { - const testOption = const Option.of('test'); - // Do not nest Do constructors - Option.Do( - ($) => Option.Do( - ($) => $(testOption), - ), - ); -} - -/// This function demonstrates that the `Do` constructor should not call the `$` function inside a callback. -void doConstructorShouldNotCallDollarFunctionInCallback() { - const testOption = const Option>.of(['test']); - Option.Do( - ($) => $(testOption).map( - // Do not call the `$` function inside a callback - (stringValue) => $(optionOf(stringValue)), - ), - ); -} diff --git a/examples/do_constructor_pitfalls/pubspec.yaml b/examples/do_constructor_pitfalls/pubspec.yaml deleted file mode 100644 index bfc18f84..00000000 --- a/examples/do_constructor_pitfalls/pubspec.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: fpdart_do_constructor_pitfalls -publish_to: none -version: 0.1.0 -homepage: https://www.sandromaglione.com/ -repository: https://github.com/SandroMaglione/fpdart -description: Example of Functional programming in Dart and Flutter using fpdart. Pitfalls to avoid when using the do constructor. - -environment: - sdk: ">=3.0.0 <4.0.0" - -dependencies: - fpdart: - path: ../../packages/fpdart - -dev_dependencies: - lint: ^2.1.2 - test: ^1.24.3 - mocktail: ^0.3.0 diff --git a/examples/do_constructor_pitfalls/test/do_constructor_pitfalls_test.dart b/examples/do_constructor_pitfalls/test/do_constructor_pitfalls_test.dart deleted file mode 100644 index ab73b3a2..00000000 --- a/examples/do_constructor_pitfalls/test/do_constructor_pitfalls_test.dart +++ /dev/null @@ -1 +0,0 @@ -void main() {} diff --git a/examples/file_read_stream/.gitignore b/examples/file_read_stream/.gitignore new file mode 100644 index 00000000..66e4ee6b --- /dev/null +++ b/examples/file_read_stream/.gitignore @@ -0,0 +1 @@ +lib/output.json \ No newline at end of file diff --git a/examples/file_read_stream/analysis_options.yaml b/examples/file_read_stream/analysis_options.yaml new file mode 100644 index 00000000..027c612f --- /dev/null +++ b/examples/file_read_stream/analysis_options.yaml @@ -0,0 +1,12 @@ +include: package:lints/recommended.yaml + +linter: + rules: + annotate_overrides: true + prefer_void_to_null: false + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true diff --git a/examples/file_read_stream/lib/main.dart b/examples/file_read_stream/lib/main.dart new file mode 100644 index 00000000..b8350a15 --- /dev/null +++ b/examples/file_read_stream/lib/main.dart @@ -0,0 +1,130 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:fpdart/fpdart.dart'; + +import './word.dart'; + +typedef Env = ({ + String wordPairCsv, + String wordsCsv, + String outputPath, +}); + +final wordPairs = Effect>.gen(($) async { + final env = $.sync(Effect.env()); + final inputFile = File(env.wordPairCsv); + + final lines = inputFile.openRead().transform(utf8.decoder).transform( + LineSplitter(), + ); + + final wordCollection = []; + await for (var line in lines) { + final split = line.split(','); + if (split.length != 3) { + return $.sync(Effect.fail("Missing word-pair info at: '$line'")); + } + + final wordInfo = $ + .sync(Effect.all([ + Effect.fromNullable( + int.tryParse(split[0]), + onNull: () => "Missing id collection", + ), + Effect.fromNullable( + int.tryParse(split[1]), + onNull: () => "Missing id word1", + ), + Effect.fromNullable( + int.tryParse(split[2]), + onNull: () => "Missing id word2", + ), + ])) + .toList(); + + wordCollection.add(WordPair(wordInfo[0], wordInfo[1], wordInfo[2])); + } + + return wordCollection; +}); + +final words = Effect>.gen(($) async { + final env = $.sync(Effect.env()); + final wordCollection = await $.async(wordPairs); + + final inputFile = File(env.wordsCsv); + final lines = inputFile.openRead().transform(utf8.decoder).transform( + LineSplitter(), + ); + + final wordMap = {}; + await for (var line in lines) { + final split = line.split(','); + if (split.length < 2) { + return $.sync(Effect.fail("Missing word info at: '$line'")); + } + + final idWord = $.sync(Effect.fromNullable( + int.tryParse(split[0]), + onNull: () => "Missing id word", + )); + final word = split[1]; + + wordMap[idWord] = word; + } + + final wordFullList = []; + for (var entry in wordCollection) { + final word1 = $.sync(Effect.fromNullable( + wordMap[entry.idWord1], + onNull: () => "Missing word 1 at: $entry", + )); + final word2 = $.sync(Effect.fromNullable( + wordMap[entry.idWord2], + onNull: () => "Missing word 2 at: $entry", + )); + + wordFullList.add( + WordFull( + entry.idCollection, + Word(entry.idWord1, word1), + Word(entry.idWord2, word2), + ), + ); + } + + return wordFullList.toSet().toList(); +}); + +final program = Effect.gen(($) async { + final env = $.sync(Effect.env()); + final wordFullList = await $.async(words); + + final outputFile = File(env.outputPath); + await $.async( + Effect.tryCatch( + execute: () => outputFile.writeAsString( + "[${wordFullList.map((e) => e.toJson()).join(",\n")}]", + ), + onError: (_, __) => "Error while writing output file", + ), + ); + + return unit; +}); + +void main() async { + await program.provideEnv(( + wordPairCsv: "./lib/word_pairs.csv", + wordsCsv: "./lib/words.csv", + outputPath: "./lib/output.json", + )).matchCause( + onFailure: (cause) { + print(cause); + }, + onSuccess: (_) { + print("Success"); + }, + ).runFutureExit(); +} diff --git a/examples/file_read_stream/lib/word.dart b/examples/file_read_stream/lib/word.dart new file mode 100644 index 00000000..80e2d1b8 --- /dev/null +++ b/examples/file_read_stream/lib/word.dart @@ -0,0 +1,53 @@ +import 'package:equatable/equatable.dart'; + +class WordPair { + final int idCollection; + final int idWord1; + final int idWord2; + const WordPair(this.idCollection, this.idWord1, this.idWord2); + + @override + String toString() { + return "($idCollection)$idWord1|$idWord2"; + } +} + +class Word extends Equatable { + final int idWord; + final String word; + const Word(this.idWord, this.word); + + @override + String toString() { + return "($idWord)$word"; + } + + @override + List get props => [idWord]; + + Map toJson() => { + '"idWord"': idWord, + '"word"': '"$word"', + }; +} + +class WordFull extends Equatable { + final int idCollection; + final Word word1; + final Word word2; + const WordFull(this.idCollection, this.word1, this.word2); + + @override + String toString() { + return "👉 $idCollection\n $word1\n $word2"; + } + + @override + List get props => [word1, word2]; + + Map toJson() => { + '"idCollection"': idCollection, + '"word1"': word1.toJson(), + '"word2"': word2.toJson(), + }; +} diff --git a/examples/file_read_stream/lib/word_pairs.csv b/examples/file_read_stream/lib/word_pairs.csv new file mode 100644 index 00000000..1bee4c61 --- /dev/null +++ b/examples/file_read_stream/lib/word_pairs.csv @@ -0,0 +1,6377 @@ +1,1,2048 +1,2,2049 +1,3,2050 +1,4,2051 +1,5,2052 +1,6,2053 +1,7,2054 +1,8,2055 +57,8,2055 +168,8,2055 +1,9,2056 +1,10,2057 +1,11,2058 +1,12,2059 +1,13,2060 +181,13,2060 +1,14,2061 +90,14,2061 +1,15,2062 +44,15,2062 +1,16,2063 +57,16,2063 +1,17,2064 +1,18,2065 +57,18,2065 +1,19,2066 +1,20,2067 +57,20,2067 +1,21,2068 +1,22,2069 +1,23,2070 +57,23,2070 +1,24,2071 +1,25,2072 +1,26,2073 +1,27,2074 +38,27,2074 +220,27,2074 +1,28,2075 +1,29,2076 +81,29,2076 +159,29,2076 +2,30,2077 +144,30,2077 +2,31,2078 +2,32,2079 +2,33,2080 +2,34,2081 +2,35,2082 +2,36,2083 +171,36,2083 +2,37,2084 +103,37,2084 +2,38,2085 +105,38,2085 +150,38,2085 +2,39,2086 +57,39,2086 +2,40,2087 +2,41,2088 +164,41,2088 +2,42,2089 +154,42,2089 +2,43,2090 +125,43,2090 +2,44,2091 +2,45,2092 +191,45,2092 +2,46,2093 +2,47,2094 +57,47,2094 +2,48,2095 +159,48,2095 +2,49,2096 +2,50,2097 +2,51,2098 +2,52,2099 +49,52,2099 +2,53,2100 +44,53,2100 +2,54,2101 +171,54,2101 +2,55,2102 +2,56,2103 +50,56,2103 +168,56,2103 +210,56,2103 +2,57,2104 +41,57,2104 +57,57,2104 +2,58,2105 +38,58,2105 +2,59,2106 +215,59,2106 +3,60,2107 +41,60,2107 +164,60,2107 +3,61,2108 +119,61,2108 +153,61,2108 +3,62,2109 +57,62,2109 +160,62,2109 +3,63,2110 +3,64,2111 +3,65,2112 +185,65,2112 +3,66,2113 +91,66,2113 +152,66,2113 +3,67,2114 +147,67,2114 +3,68,2115 +3,69,2116 +227,69,2116 +3,70,2117 +44,70,2117 +152,70,2117 +3,71,2118 +3,72,2119 +159,72,2119 +3,73,2120 +3,74,2121 +39,74,2121 +128,74,2121 +3,75,2122 +57,75,2122 +3,76,2123 +110,76,2123 +3,77,2124 +3,78,2125 +3,79,2126 +3,80,2127 +3,81,2128 +110,81,2128 +128,81,2128 +3,82,2129 +3,83,2130 +212,83,2130 +3,84,2131 +3,85,2132 +57,85,2132 +220,85,2132 +3,86,2133 +66,86,2133 +3,87,2134 +57,87,2134 +71,87,2134 +230,87,2134 +3,88,2135 +49,88,2135 +3,89,2136 +4,90,2137 +155,90,2137 +4,91,2138 +35,91,2138 +69,91,2138 +4,92,2139 +4,93,2140 +51,93,2140 +164,93,2140 +203,93,2140 +4,94,2141 +4,95,2142 +34,95,2142 +153,95,2142 +4,96,2143 +162,96,2143 +4,97,2144 +48,97,2144 +147,97,2144 +4,98,2145 +4,99,2146 +57,99,2146 +4,100,2147 +135,100,2147 +4,101,2148 +121,101,2148 +226,101,2148 +4,102,2149 +105,102,2149 +4,103,2150 +128,103,2150 +4,104,2151 +79,104,2151 +153,104,2151 +4,105,2152 +42,105,2152 +142,105,2152 +4,106,2153 +4,107,2154 +90,107,2154 +4,108,2155 +4,109,2156 +4,110,2157 +102,110,2157 +148,110,2157 +4,111,2158 +76,111,2158 +4,112,2159 +47,112,2159 +142,112,2159 +4,113,2160 +68,113,2160 +4,114,2161 +158,114,2161 +4,115,2162 +139,115,2162 +4,116,2163 +4,117,2164 +57,117,2164 +117,117,2164 +4,118,2165 +46,118,2165 +57,118,2165 +160,118,2165 +4,119,2166 +57,119,2166 +122,119,2166 +5,120,2167 +5,121,2168 +39,121,2168 +159,121,2168 +5,122,2169 +39,122,2169 +158,122,2169 +5,123,2170 +62,123,2170 +5,124,2171 +159,124,2171 +5,125,2172 +63,125,2172 +5,126,2173 +5,127,2174 +70,127,2174 +5,128,2175 +77,128,2175 +5,129,2176 +57,129,2176 +5,130,2177 +36,130,2177 +170,130,2177 +5,131,2178 +37,131,2178 +125,131,2178 +5,132,2179 +5,133,2180 +92,133,2180 +164,133,2180 +5,134,2181 +5,135,2182 +46,135,2182 +183,135,2182 +5,136,2183 +40,136,2183 +129,136,2183 +5,137,2184 +49,137,2184 +5,138,2185 +5,139,2186 +5,140,2187 +130,140,2187 +5,141,2188 +90,141,2188 +194,141,2188 +5,142,2189 +48,142,2189 +154,142,2189 +218,142,2189 +5,143,2190 +47,143,2190 +5,144,2191 +62,144,2191 +5,145,2192 +5,146,2193 +105,146,2193 +193,146,2193 +5,147,2194 +5,148,2195 +90,148,2195 +166,148,2195 +5,149,2196 +6,150,2197 +57,150,2197 +6,151,2198 +38,151,2198 +6,152,2199 +6,153,2200 +92,153,2200 +165,153,2200 +6,154,2201 +6,155,2202 +122,155,2202 +6,156,2203 +157,156,2203 +6,157,2204 +64,157,2204 +6,158,2205 +61,158,2205 +6,159,2206 +96,159,2206 +6,160,2207 +123,160,2207 +6,161,2208 +160,161,2208 +6,162,2209 +62,162,2209 +126,162,2209 +6,163,2210 +41,163,2210 +6,164,2211 +175,164,2211 +217,164,2211 +6,165,2212 +168,165,2212 +219,165,2212 +6,166,2213 +6,167,2214 +6,168,2215 +37,168,2215 +6,169,2216 +175,169,2216 +6,170,2217 +233,170,2217 +6,171,2218 +123,171,2218 +127,171,2218 +6,172,2219 +68,172,2219 +6,173,2220 +6,174,2221 +178,174,2221 +6,175,2222 +90,175,2222 +6,176,2223 +174,176,2223 +6,177,2224 +6,178,2225 +6,179,2226 +35,179,2226 +147,179,2226 +7,180,2227 +83,180,2227 +211,180,2227 +7,181,2228 +7,182,2229 +35,182,2229 +142,182,2229 +7,183,2230 +178,183,2230 +7,184,2231 +72,184,2231 +7,185,2232 +84,185,2232 +150,185,2232 +7,186,2233 +70,186,2233 +168,186,2233 +7,187,2234 +169,187,2234 +7,188,2235 +34,188,2235 +57,188,2235 +155,188,2235 +7,189,2236 +57,189,2236 +71,189,2236 +140,189,2236 +7,190,2237 +79,190,2237 +7,191,2238 +90,191,2238 +123,191,2238 +7,192,2239 +64,192,2239 +127,192,2239 +7,193,2240 +175,193,2240 +7,194,2241 +226,194,2241 +7,195,2242 +92,195,2242 +7,196,2243 +7,197,2244 +7,198,2245 +198,198,2245 +200,198,2245 +7,199,2246 +96,199,2246 +7,200,2247 +39,200,2247 +7,201,2248 +39,201,2248 +65,201,2248 +7,202,2249 +65,202,2249 +203,202,2249 +7,203,2250 +81,203,2250 +168,203,2250 +7,204,2251 +7,205,2252 +109,205,2252 +7,206,2253 +127,206,2253 +7,207,2254 +36,207,2254 +57,207,2254 +180,207,2254 +7,208,2255 +115,208,2255 +7,209,2256 +36,209,2256 +55,209,2256 +8,210,2257 +8,211,2258 +165,211,2258 +8,212,2259 +81,212,2259 +209,212,2259 +8,213,2260 +8,214,2261 +40,214,2261 +130,214,2261 +8,215,2262 +41,215,2262 +8,216,2263 +8,217,2264 +45,217,2264 +8,218,2265 +8,219,2266 +8,220,2267 +60,220,2267 +8,221,2268 +162,221,2268 +8,222,2269 +90,222,2269 +179,222,2269 +8,223,2270 +117,223,2270 +8,224,2271 +65,224,2271 +8,225,2272 +51,225,2272 +8,226,2273 +42,226,2273 +8,227,2274 +8,228,2275 +83,228,2275 +8,229,2276 +42,229,2276 +8,230,2277 +8,231,2278 +62,231,2278 +179,231,2278 +8,232,2279 +8,233,2280 +8,234,2281 +67,234,2281 +135,234,2281 +8,235,2282 +8,236,2283 +44,236,2283 +164,236,2283 +8,237,2284 +96,237,2284 +8,238,2285 +8,239,2286 +9,240,2287 +147,240,2287 +9,241,2288 +9,242,2289 +87,242,2289 +201,242,2289 +9,243,2290 +9,244,2291 +37,244,2291 +144,244,2291 +9,245,2292 +43,245,2292 +57,245,2292 +9,246,2293 +89,246,2293 +9,247,2294 +215,247,2294 +9,248,2295 +9,249,2296 +41,249,2296 +9,250,2297 +9,251,2298 +72,251,2298 +9,252,2299 +110,252,2299 +230,252,2299 +9,253,2300 +9,254,2301 +57,254,2301 +9,255,2302 +41,255,2302 +57,255,2302 +9,256,2303 +82,256,2303 +9,257,2304 +60,257,2304 +152,257,2304 +9,258,2305 +49,258,2305 +9,259,2306 +78,259,2306 +173,259,2306 +9,260,2307 +9,261,2308 +9,262,2309 +41,262,2309 +9,263,2310 +9,264,2311 +173,264,2311 +9,265,2312 +125,265,2312 +9,266,2313 +115,266,2313 +9,267,2314 +43,267,2314 +160,267,2314 +9,268,2315 +58,268,2315 +66,268,2315 +9,269,2316 +218,269,2316 +10,270,2317 +230,270,2317 +10,271,2318 +10,272,2319 +169,272,2319 +10,273,2320 +10,274,2321 +10,275,2322 +10,276,2323 +10,277,2324 +10,278,2325 +61,278,2325 +10,279,2326 +10,280,2327 +10,281,2328 +159,281,2328 +10,282,2329 +95,282,2329 +10,283,2330 +231,283,2330 +10,284,2331 +49,284,2331 +10,285,2332 +10,286,2333 +61,286,2333 +10,287,2334 +10,288,2335 +10,289,2336 +66,289,2336 +10,290,2337 +10,291,2338 +10,292,2339 +10,293,2340 +223,293,2340 +10,294,2341 +169,294,2341 +10,295,2342 +10,296,2343 +10,297,2344 +128,297,2344 +10,298,2345 +10,299,2346 +159,299,2346 +11,300,2347 +11,301,2348 +11,302,2349 +79,302,2349 +11,303,2350 +79,303,2350 +11,304,2351 +11,305,2352 +163,305,2352 +11,306,2353 +91,306,2353 +11,307,2354 +122,307,2354 +11,308,2355 +11,309,2356 +192,309,2356 +11,310,2357 +11,311,2358 +51,311,2358 +11,312,2359 +76,312,2359 +11,313,2360 +178,313,2360 +1,314,2361 +11,314,2361 +11,315,2362 +11,316,2363 +11,317,2364 +169,317,2364 +11,318,2365 +11,319,2366 +60,319,2366 +11,320,2367 +11,321,2368 +82,321,2368 +11,322,2369 +11,323,2370 +128,323,2370 +11,324,2371 +168,324,2371 +11,325,2372 +178,325,2372 +11,326,2373 +11,327,2374 +167,327,2374 +192,327,2374 +11,328,2375 +89,328,2375 +11,329,2376 +12,330,2377 +12,331,2378 +12,332,2379 +12,333,2380 +12,334,2381 +12,335,2382 +12,336,2383 +12,337,2384 +78,337,2384 +12,338,2385 +60,338,2385 +214,338,2385 +12,339,2386 +34,339,2386 +181,339,2386 +228,339,2386 +12,340,2387 +151,340,2387 +12,341,2388 +156,341,2388 +12,342,2389 +168,342,2389 +12,343,2390 +95,343,2390 +229,343,2390 +12,344,2391 +149,344,2391 +12,345,2392 +12,346,2393 +12,347,2394 +205,347,2394 +12,348,2395 +207,348,2395 +12,349,2396 +12,350,2397 +128,350,2397 +12,351,2398 +128,351,2398 +176,351,2398 +12,352,2399 +181,352,2399 +223,352,2399 +12,353,2400 +67,353,2400 +12,354,2401 +61,354,2401 +152,354,2401 +12,355,2402 +87,355,2402 +12,356,2403 +72,356,2403 +12,357,2404 +107,357,2404 +12,358,2405 +118,358,2405 +180,358,2405 +12,359,2406 +13,360,2407 +13,361,2408 +107,361,2408 +13,362,2409 +181,362,2409 +13,363,2410 +39,363,2410 +203,363,2410 +13,364,2411 +13,365,2412 +160,365,2412 +13,366,2413 +13,367,2414 +161,367,2414 +13,368,2415 +42,368,2415 +147,368,2415 +13,369,2416 +188,369,2416 +13,370,2417 +188,370,2417 +13,371,2418 +13,372,2419 +35,372,2419 +130,372,2419 +13,373,2420 +51,373,2420 +165,373,2420 +13,374,2421 +13,375,2422 +13,376,2423 +149,376,2423 +13,377,2424 +13,378,2425 +13,379,2426 +63,379,2426 +138,379,2426 +225,379,2426 +13,380,2427 +13,381,2428 +95,381,2428 +13,382,2429 +81,382,2429 +13,383,2430 +57,383,2430 +70,383,2430 +13,384,2431 +13,385,2432 +78,385,2432 +13,386,2433 +165,386,2433 +13,387,2434 +61,387,2434 +211,387,2434 +13,388,2435 +38,388,2435 +13,389,2436 +14,390,2437 +40,390,2437 +47,390,2437 +14,391,2438 +50,391,2438 +14,392,2439 +14,393,2440 +43,393,2440 +14,394,2441 +96,394,2441 +14,395,2442 +216,395,2442 +14,396,2443 +108,396,2443 +174,396,2443 +14,397,2444 +46,397,2444 +69,397,2444 +14,398,2445 +45,398,2445 +14,399,2446 +14,400,2447 +87,400,2447 +156,400,2447 +14,401,2448 +39,401,2448 +170,401,2448 +14,402,2449 +34,402,2449 +75,402,2449 +14,403,2450 +175,403,2450 +14,404,2451 +72,404,2451 +14,405,2452 +116,405,2452 +14,406,2453 +207,406,2453 +14,407,2454 +82,407,2454 +132,407,2454 +232,407,2454 +14,408,2455 +46,408,2455 +148,408,2455 +14,409,2456 +63,409,2456 +173,409,2456 +14,410,2457 +42,410,2457 +212,410,2457 +14,411,2458 +44,411,2458 +207,411,2458 +14,412,2459 +60,412,2459 +14,413,2460 +146,413,2460 +14,414,2461 +95,414,2461 +14,415,2462 +73,415,2462 +14,416,2463 +14,417,2464 +55,417,2464 +129,417,2464 +14,418,2465 +14,419,2466 +35,419,2466 +164,419,2466 +15,420,2467 +15,421,2468 +66,421,2468 +162,421,2468 +15,422,2469 +164,422,2469 +15,423,2470 +57,423,2470 +15,424,2471 +95,424,2471 +15,425,2472 +15,426,2473 +15,427,2474 +142,427,2474 +15,428,2475 +142,428,2475 +15,429,2476 +87,429,2476 +15,430,2477 +80,430,2477 +15,431,2478 +150,431,2478 +15,432,2479 +140,432,2479 +15,433,2480 +166,433,2480 +15,434,2481 +35,434,2481 +15,435,2482 +58,435,2482 +15,436,2483 +111,436,2483 +15,437,2484 +40,437,2484 +15,438,2485 +213,438,2485 +15,439,2486 +184,439,2486 +15,440,2487 +207,440,2487 +15,441,2488 +106,441,2488 +15,442,2489 +15,443,2490 +106,443,2490 +15,444,2491 +15,445,2492 +15,446,2493 +15,447,2494 +15,448,2495 +35,448,2495 +57,448,2495 +189,448,2495 +15,449,2496 +95,449,2496 +16,450,2497 +136,450,2497 +163,450,2497 +16,451,2498 +39,451,2498 +16,452,2499 +48,452,2499 +16,453,2500 +95,453,2500 +16,454,2501 +51,454,2501 +16,455,2502 +48,455,2502 +70,455,2502 +16,456,2503 +38,456,2503 +57,456,2503 +183,456,2503 +16,457,2504 +39,457,2504 +16,458,2505 +80,458,2505 +183,458,2505 +16,459,2506 +77,459,2506 +16,460,2507 +78,460,2507 +16,461,2508 +213,461,2508 +16,462,2509 +68,462,2509 +16,463,2510 +130,463,2510 +16,464,2511 +171,464,2511 +16,465,2512 +128,465,2512 +16,466,2513 +44,466,2513 +16,467,2514 +47,467,2514 +16,468,2515 +36,468,2515 +16,469,2516 +36,469,2516 +58,469,2516 +16,470,2517 +95,470,2517 +16,471,2518 +16,472,2519 +43,472,2519 +16,473,2520 +129,473,2520 +16,474,2521 +65,474,2521 +159,474,2521 +16,475,2522 +45,475,2522 +126,475,2522 +16,476,2523 +163,476,2523 +16,477,2524 +107,477,2524 +16,478,2525 +57,478,2525 +58,478,2525 +148,478,2525 +223,478,2525 +16,479,2526 +44,479,2526 +17,480,2527 +41,480,2527 +17,481,2528 +70,481,2528 +156,481,2528 +17,482,2529 +36,482,2529 +149,482,2529 +17,483,2530 +17,484,2531 +47,484,2531 +203,484,2531 +17,485,2532 +34,485,2532 +57,485,2532 +176,485,2532 +17,486,2533 +17,487,2534 +58,487,2534 +162,487,2534 +222,487,2534 +17,488,2535 +17,489,2536 +17,490,2537 +62,490,2537 +17,491,2538 +48,491,2538 +17,492,2539 +73,492,2539 +17,493,2540 +149,493,2540 +17,494,2541 +145,494,2541 +17,495,2542 +107,495,2542 +17,496,2543 +17,497,2544 +91,497,2544 +17,498,2545 +149,498,2545 +17,499,2546 +213,499,2546 +17,500,2547 +48,500,2547 +173,500,2547 +17,501,2548 +95,501,2548 +187,501,2548 +17,502,2549 +17,503,2550 +82,503,2550 +17,504,2551 +17,505,2552 +86,505,2552 +17,506,2553 +35,506,2553 +157,506,2553 +17,507,2554 +17,508,2555 +65,508,2555 +17,509,2556 +61,509,2556 +153,509,2556 +18,510,2557 +35,510,2557 +57,510,2557 +18,511,2558 +118,511,2558 +153,511,2558 +18,512,2559 +148,512,2559 +18,513,2560 +132,513,2560 +18,514,2561 +18,515,2562 +35,515,2562 +169,515,2562 +18,516,2563 +57,516,2563 +18,517,2564 +40,517,2564 +144,517,2564 +18,518,2565 +73,518,2565 +18,519,2566 +57,519,2566 +64,519,2566 +18,520,2567 +76,520,2567 +156,520,2567 +18,521,2568 +70,521,2568 +211,521,2568 +18,522,2569 +40,522,2569 +132,522,2569 +18,523,2570 +39,523,2570 +18,524,2571 +72,524,2571 +18,525,2572 +18,526,2573 +34,526,2573 +177,526,2573 +18,527,2574 +40,527,2574 +177,527,2574 +18,528,2575 +22,528,2575 +34,528,2575 +18,529,2576 +18,530,2577 +204,530,2577 +18,531,2578 +46,531,2578 +154,531,2578 +18,532,2579 +18,533,2580 +47,533,2580 +149,533,2580 +18,534,2581 +47,534,2581 +160,534,2581 +18,535,2582 +78,535,2582 +18,536,2583 +80,536,2583 +208,536,2583 +18,537,2584 +36,537,2584 +181,537,2584 +18,538,2585 +41,538,2585 +18,539,2586 +19,540,2587 +187,540,2587 +19,541,2588 +77,541,2588 +19,542,2589 +19,543,2590 +38,543,2590 +125,543,2590 +19,544,2591 +118,544,2591 +19,545,2592 +59,545,2592 +178,545,2592 +19,546,2593 +58,546,2593 +160,546,2593 +19,547,2594 +95,547,2594 +146,547,2594 +19,548,2595 +109,548,2595 +19,549,2596 +19,550,2597 +19,551,2598 +65,551,2598 +19,552,2599 +105,552,2599 +19,553,2600 +98,553,2600 +181,553,2600 +19,554,2601 +19,555,2602 +45,555,2602 +19,556,2603 +134,556,2603 +19,557,2604 +66,557,2604 +141,557,2604 +19,558,2605 +132,558,2605 +19,559,2606 +113,559,2606 +208,559,2606 +19,560,2607 +45,560,2607 +19,561,2608 +71,561,2608 +186,561,2608 +19,562,2609 +63,562,2609 +19,563,2610 +92,563,2610 +141,563,2610 +19,564,2611 +49,564,2611 +19,565,2612 +38,565,2612 +57,565,2612 +177,565,2612 +19,566,2613 +98,566,2613 +144,566,2613 +19,567,2614 +43,567,2614 +139,567,2614 +19,568,2615 +57,568,2615 +64,568,2615 +229,568,2615 +19,569,2616 +104,569,2616 +166,569,2616 +20,570,2617 +64,570,2617 +20,571,2618 +109,571,2618 +20,572,2619 +20,573,2620 +145,573,2620 +20,574,2621 +42,574,2621 +20,575,2622 +50,575,2622 +187,575,2622 +20,576,2623 +20,577,2624 +71,577,2624 +20,578,2625 +20,579,2626 +141,579,2626 +20,580,2627 +160,580,2627 +187,580,2627 +20,581,2628 +128,581,2628 +145,581,2628 +20,582,2629 +98,582,2629 +20,583,2630 +83,583,2630 +20,584,2631 +94,584,2631 +20,585,2632 +130,585,2632 +20,586,2633 +72,586,2633 +20,587,2634 +145,587,2634 +20,588,2635 +36,588,2635 +20,589,2636 +96,589,2636 +20,590,2637 +34,590,2637 +20,591,2638 +20,592,2639 +20,593,2640 +141,593,2640 +20,594,2641 +115,594,2641 +20,595,2642 +94,595,2642 +226,595,2642 +20,596,2643 +41,596,2643 +176,596,2643 +20,597,2644 +20,598,2645 +91,598,2645 +20,599,2646 +101,599,2646 +21,600,2647 +43,600,2647 +129,600,2647 +21,601,2648 +73,601,2648 +225,601,2648 +21,602,2649 +189,602,2649 +21,603,2650 +21,604,2651 +118,604,2651 +220,604,2651 +21,605,2652 +188,605,2652 +21,606,2653 +145,606,2653 +21,607,2654 +167,607,2654 +21,608,2655 +83,608,2655 +136,608,2655 +21,609,2656 +63,609,2656 +182,609,2656 +21,610,2657 +81,610,2657 +203,610,2657 +21,611,2658 +40,611,2658 +139,611,2658 +21,612,2659 +72,612,2659 +21,613,2660 +21,614,2661 +66,614,2661 +167,614,2661 +21,615,2662 +101,615,2662 +21,616,2663 +58,616,2663 +21,617,2664 +62,617,2664 +142,617,2664 +21,618,2665 +58,618,2665 +21,619,2666 +125,619,2666 +21,620,2667 +21,621,2668 +132,621,2668 +21,622,2669 +116,622,2669 +197,622,2669 +199,622,2669 +21,623,2670 +50,623,2670 +21,624,2671 +186,624,2671 +21,625,2672 +59,625,2672 +150,625,2672 +21,626,2673 +88,626,2673 +21,627,2674 +38,627,2674 +144,627,2674 +21,628,2675 +215,628,2675 +21,629,2676 +22,630,2677 +100,630,2677 +176,630,2677 +22,631,2678 +145,631,2678 +22,632,2679 +102,632,2679 +173,632,2679 +22,633,2680 +22,634,2681 +151,634,2681 +228,634,2681 +22,635,2682 +221,635,2682 +22,636,2683 +153,636,2683 +22,637,2684 +74,637,2684 +22,638,2685 +22,639,2686 +121,639,2686 +22,640,2687 +107,640,2687 +182,640,2687 +22,641,2688 +66,641,2688 +163,641,2688 +22,642,2689 +22,643,2690 +130,643,2690 +22,644,2691 +57,644,2691 +71,644,2691 +173,644,2691 +22,645,2692 +60,645,2692 +151,645,2692 +22,646,2693 +75,646,2693 +212,646,2693 +22,647,2694 +22,648,2695 +122,648,2695 +22,649,2696 +100,649,2696 +22,650,2697 +121,650,2697 +163,650,2697 +22,651,2698 +135,651,2698 +22,652,2699 +22,653,2700 +47,653,2700 +182,653,2700 +22,654,2701 +49,654,2701 +22,655,2702 +77,655,2702 +22,656,2703 +22,657,2704 +67,657,2704 +160,657,2704 +22,658,2705 +59,658,2705 +23,659,2706 +93,659,2706 +125,659,2706 +23,660,2707 +130,660,2707 +23,661,2708 +48,661,2708 +145,661,2708 +23,662,2709 +66,662,2709 +23,663,2710 +193,663,2710 +23,664,2711 +45,664,2711 +23,665,2712 +23,666,2713 +67,666,2713 +23,667,2714 +23,668,2715 +23,669,2716 +23,670,2717 +70,670,2717 +23,671,2718 +68,671,2718 +141,671,2718 +23,672,2719 +37,672,2719 +23,673,2720 +56,673,2720 +23,674,2721 +149,674,2721 +23,675,2722 +23,676,2723 +72,676,2723 +23,677,2724 +128,677,2724 +23,678,2725 +23,679,2726 +68,679,2726 +175,679,2726 +23,680,2727 +23,681,2728 +149,681,2728 +23,682,2729 +149,682,2729 +23,683,2730 +87,683,2730 +23,684,2731 +23,685,2732 +56,685,2732 +149,685,2732 +23,686,2733 +128,686,2733 +23,687,2734 +66,687,2734 +23,688,2735 +136,688,2735 +24,689,2736 +112,689,2736 +24,690,2737 +37,690,2737 +147,690,2737 +24,691,2738 +67,691,2738 +141,691,2738 +24,692,2739 +100,692,2739 +171,692,2739 +190,692,2739 +24,693,2740 +24,694,2741 +78,694,2741 +178,694,2741 +24,695,2742 +141,695,2742 +24,696,2743 +57,696,2743 +189,696,2743 +206,696,2743 +24,697,2744 +76,697,2744 +24,698,2745 +224,698,2745 +24,699,2746 +34,699,2746 +24,700,2747 +112,700,2747 +24,701,2748 +24,702,2749 +24,703,2750 +144,703,2750 +24,704,2751 +142,704,2751 +24,705,2752 +24,706,2753 +50,706,2753 +24,707,2754 +51,707,2754 +152,707,2754 +24,708,2755 +137,708,2755 +24,709,2756 +57,709,2756 +69,709,2756 +24,710,2757 +24,711,2758 +57,711,2758 +24,712,2759 +57,712,2759 +24,713,2760 +87,713,2760 +170,713,2760 +24,714,2761 +116,714,2761 +24,715,2762 +72,715,2762 +24,716,2763 +69,716,2763 +24,717,2764 +81,717,2764 +198,717,2764 +24,718,2765 +130,718,2765 +25,719,2766 +130,719,2766 +171,719,2766 +25,720,2767 +138,720,2767 +25,721,2768 +51,721,2768 +173,721,2768 +25,722,2769 +25,723,2770 +25,724,2771 +79,724,2771 +25,725,2772 +181,725,2772 +25,726,2773 +25,727,2774 +57,727,2774 +25,728,2775 +74,728,2775 +134,728,2775 +25,729,2776 +25,730,2777 +57,730,2777 +71,730,2777 +25,731,2778 +104,731,2778 +25,732,2779 +36,732,2779 +25,733,2780 +43,733,2780 +221,733,2780 +25,734,2781 +25,735,2782 +210,735,2782 +25,736,2783 +37,736,2783 +57,736,2783 +153,736,2783 +25,737,2784 +42,737,2784 +64,737,2784 +25,738,2785 +166,738,2785 +25,739,2786 +84,739,2786 +225,739,2786 +25,740,2787 +113,740,2787 +183,740,2787 +25,741,2788 +25,742,2789 +114,742,2789 +178,742,2789 +25,743,2790 +181,743,2790 +232,743,2790 +25,744,2791 +38,744,2791 +59,744,2791 +25,745,2792 +81,745,2792 +25,746,2793 +102,746,2793 +25,747,2794 +100,747,2794 +25,748,2795 +98,748,2795 +139,748,2795 +26,749,2796 +132,749,2796 +26,750,2797 +26,751,2798 +26,752,2799 +89,752,2799 +26,753,2800 +134,753,2800 +26,754,2801 +125,754,2801 +26,755,2802 +26,756,2803 +51,756,2803 +137,756,2803 +26,757,2804 +45,757,2804 +157,757,2804 +26,758,2805 +43,758,2805 +126,758,2805 +26,759,2806 +104,759,2806 +165,759,2806 +26,760,2807 +122,760,2807 +26,761,2808 +26,762,2809 +132,762,2809 +222,762,2809 +26,763,2810 +51,763,2810 +56,763,2810 +26,764,2811 +50,764,2811 +140,764,2811 +26,765,2812 +26,766,2813 +26,767,2814 +48,767,2814 +26,768,2815 +150,768,2815 +26,769,2816 +173,769,2816 +26,770,2817 +127,770,2817 +26,771,2818 +96,771,2818 +26,772,2819 +113,772,2819 +26,773,2820 +76,773,2820 +191,773,2820 +26,774,2821 +26,775,2822 +42,775,2822 +26,776,2823 +62,776,2823 +26,777,2824 +26,778,2825 +63,778,2825 +27,779,2826 +85,779,2826 +134,779,2826 +27,780,2827 +37,780,2827 +58,780,2827 +27,781,2828 +98,781,2828 +27,782,2829 +27,783,2830 +27,784,2831 +170,784,2831 +27,785,2832 +57,785,2832 +27,786,2833 +150,786,2833 +205,786,2833 +27,787,2834 +38,787,2834 +27,788,2835 +60,788,2835 +204,788,2835 +27,789,2836 +125,789,2836 +27,790,2837 +51,790,2837 +27,791,2838 +93,791,2838 +126,791,2838 +27,792,2839 +49,792,2839 +57,792,2839 +167,792,2839 +27,793,2840 +27,794,2841 +46,794,2841 +27,795,2842 +57,795,2842 +65,795,2842 +136,795,2842 +27,796,2843 +125,796,2843 +27,797,2844 +27,798,2845 +86,798,2845 +27,799,2846 +85,799,2846 +27,800,2847 +115,800,2847 +184,800,2847 +229,800,2847 +27,801,2848 +100,801,2848 +27,802,2849 +84,802,2849 +27,803,2850 +83,803,2850 +27,804,2851 +49,804,2851 +190,804,2851 +27,805,2852 +111,805,2852 +174,805,2852 +27,806,2853 +96,806,2853 +27,807,2854 +27,808,2855 +59,808,2855 +158,808,2855 +28,809,2856 +28,810,2857 +28,811,2858 +28,812,2859 +152,812,2859 +191,812,2859 +208,812,2859 +28,813,2860 +85,813,2860 +28,814,2861 +28,815,2862 +79,815,2862 +28,816,2863 +28,817,2864 +130,817,2864 +28,818,2865 +28,819,2866 +135,819,2866 +28,820,2867 +148,820,2867 +28,821,2868 +28,822,2869 +83,822,2869 +28,823,2870 +213,823,2870 +28,824,2871 +149,824,2871 +28,825,2872 +44,825,2872 +161,825,2872 +28,826,2873 +88,826,2873 +28,827,2874 +28,828,2875 +105,828,2875 +28,829,2876 +28,830,2877 +66,830,2877 +28,831,2878 +28,832,2879 +37,832,2879 +57,832,2879 +28,833,2880 +40,833,2880 +178,833,2880 +28,834,2881 +28,835,2882 +28,836,2883 +28,837,2884 +28,838,2885 +29,839,2886 +101,839,2886 +29,840,2887 +29,841,2888 +64,841,2888 +199,841,2888 +29,842,2889 +199,842,2889 +29,843,2890 +37,843,2890 +175,843,2890 +29,844,2891 +63,844,2891 +141,844,2891 +29,845,2892 +29,846,2893 +62,846,2893 +215,846,2893 +29,847,2894 +29,848,2895 +57,848,2895 +70,848,2895 +136,848,2895 +29,849,2896 +227,849,2896 +29,850,2897 +150,850,2897 +29,851,2898 +29,852,2899 +29,853,2900 +29,854,2901 +49,854,2901 +29,855,2902 +150,855,2902 +29,856,2903 +29,857,2904 +74,857,2904 +186,857,2904 +29,858,2905 +146,858,2905 +167,858,2905 +29,859,2906 +46,859,2906 +138,859,2906 +29,860,2907 +84,860,2907 +29,861,2908 +149,861,2908 +29,862,2909 +29,863,2910 +125,863,2910 +29,864,2911 +140,864,2911 +192,864,2911 +29,865,2912 +74,865,2912 +29,866,2913 +84,866,2913 +29,867,2914 +64,867,2914 +166,867,2914 +29,868,2915 +82,868,2915 +136,868,2915 +30,869,2916 +81,869,2916 +30,870,2917 +85,870,2917 +195,870,2917 +30,871,2918 +100,871,2918 +149,871,2918 +201,871,2918 +30,872,2919 +64,872,2919 +176,872,2919 +30,873,2920 +93,873,2920 +30,874,2921 +133,874,2921 +30,875,2922 +30,876,2923 +30,877,2924 +34,877,2924 +181,877,2924 +30,878,2925 +30,879,2926 +59,879,2926 +232,879,2926 +30,880,2927 +194,880,2927 +30,881,2928 +148,881,2928 +30,882,2929 +46,882,2929 +30,883,2930 +30,884,2931 +30,885,2932 +37,885,2932 +133,885,2932 +30,886,2933 +127,886,2933 +30,887,2934 +30,888,2935 +45,888,2935 +30,889,2936 +74,889,2936 +184,889,2936 +30,890,2937 +48,890,2937 +203,890,2937 +30,891,2938 +56,891,2938 +148,891,2938 +30,892,2939 +110,892,2939 +30,893,2940 +42,893,2940 +59,893,2940 +30,894,2941 +30,895,2942 +30,896,2943 +140,896,2943 +30,897,2944 +152,897,2944 +30,898,2945 +131,898,2945 +31,899,2946 +40,899,2946 +59,899,2946 +31,900,2947 +31,901,2948 +148,901,2948 +31,902,2949 +67,902,2949 +123,902,2949 +31,903,2950 +86,903,2950 +156,903,2950 +31,904,2951 +31,905,2952 +101,905,2952 +31,906,2953 +50,906,2953 +135,906,2953 +31,907,2954 +150,907,2954 +31,908,2955 +133,908,2955 +31,909,2956 +108,909,2956 +139,909,2956 +31,910,2957 +44,910,2957 +31,911,2958 +31,912,2959 +101,912,2959 +145,912,2959 +31,913,2960 +44,913,2960 +161,913,2960 +31,914,2961 +140,914,2961 +31,915,2962 +122,915,2962 +31,916,2963 +106,916,2963 +31,917,2964 +36,917,2964 +131,917,2964 +31,918,2965 +131,918,2965 +31,919,2966 +31,920,2967 +31,921,2968 +105,921,2968 +31,922,2969 +78,922,2969 +168,922,2969 +31,923,2970 +42,923,2970 +31,924,2971 +138,924,2971 +31,925,2972 +122,925,2972 +31,926,2973 +31,927,2974 +74,927,2974 +31,928,2975 +215,928,2975 +32,929,2976 +32,930,2977 +91,930,2977 +32,931,2978 +32,932,2979 +215,932,2979 +32,933,2980 +32,934,2981 +32,935,2982 +43,935,2982 +32,936,2983 +131,936,2983 +32,937,2984 +184,937,2984 +32,938,2985 +102,938,2985 +177,938,2985 +32,939,2986 +98,939,2986 +149,939,2986 +200,939,2986 +32,940,2987 +50,940,2987 +32,941,2988 +116,941,2988 +32,942,2989 +182,942,2989 +32,943,2990 +32,944,2991 +181,944,2991 +32,945,2992 +89,945,2992 +179,945,2992 +32,946,2993 +32,947,2994 +32,948,2995 +32,949,2996 +193,949,2996 +32,950,2997 +32,951,2998 +47,951,2998 +164,951,2998 +32,952,2999 +32,953,3000 +131,953,3000 +32,954,3001 +32,955,3002 +46,955,3002 +173,955,3002 +32,956,3003 +32,957,3004 +151,957,3004 +32,958,3005 +78,958,3005 +33,959,3006 +67,959,3006 +33,960,3007 +61,960,3007 +134,960,3007 +33,961,3008 +60,961,3008 +33,962,3009 +60,962,3009 +129,962,3009 +225,962,3009 +33,963,3010 +33,964,3011 +85,964,3011 +33,965,3012 +43,965,3012 +175,965,3012 +33,966,3013 +74,966,3013 +226,966,3013 +33,967,3014 +46,967,3014 +127,967,3014 +33,968,3015 +50,968,3015 +33,969,3016 +130,969,3016 +33,970,3017 +68,970,3017 +169,970,3017 +218,970,3017 +33,971,3018 +69,971,3018 +33,972,3019 +83,972,3019 +33,973,3020 +83,973,3020 +158,973,3020 +33,974,3021 +80,974,3021 +229,974,3021 +33,975,3022 +69,975,3022 +33,976,3023 +127,976,3023 +33,977,3024 +80,977,3024 +154,977,3024 +33,978,3025 +59,978,3025 +151,978,3025 +192,978,3025 +33,979,3026 +61,979,3026 +203,979,3026 +33,980,3027 +180,980,3027 +196,980,3027 +207,980,3027 +33,981,3028 +63,981,3028 +133,981,3028 +33,982,3029 +80,982,3029 +33,983,3030 +57,983,3030 +71,983,3030 +33,984,3031 +48,984,3031 +140,984,3031 +33,985,3032 +33,986,3033 +50,986,3033 +133,986,3033 +33,987,3034 +45,987,3034 +155,987,3034 +33,988,3035 +34,989,3036 +129,989,3036 +34,990,3037 +34,991,3038 +63,991,3038 +34,992,3039 +205,992,3039 +34,993,3040 +34,994,3041 +57,994,3041 +117,994,3041 +34,995,3042 +132,995,3042 +205,995,3042 +34,996,3043 +34,997,3044 +100,997,3044 +34,998,3045 +65,998,3045 +161,998,3045 +34,999,3046 +137,999,3046 +34,1000,3047 +122,1000,3047 +161,1000,3047 +34,1001,3048 +159,1001,3048 +34,1002,3049 +68,1002,3049 +34,1003,3050 +34,1004,3051 +106,1004,3051 +34,1005,3052 +141,1005,3052 +34,1006,3053 +45,1006,3053 +34,1007,3054 +34,1008,3055 +134,1008,3055 +35,1009,3056 +64,1009,3056 +35,1010,3057 +112,1010,3057 +35,1011,3058 +35,1012,3059 +35,1013,3060 +198,1013,3060 +35,1014,3061 +35,1015,3062 +59,1015,3062 +147,1015,3062 +35,1016,3063 +135,1016,3063 +35,1017,3064 +94,1017,3064 +165,1017,3064 +35,1018,3065 +81,1018,3065 +35,1019,3066 +105,1019,3066 +233,1019,3066 +35,1020,3067 +35,1021,3068 +131,1021,3068 +35,1022,3069 +103,1022,3069 +35,1023,3070 +94,1023,3070 +35,1024,3071 +35,1025,3072 +206,1025,3072 +35,1026,3073 +80,1026,3073 +35,1027,3074 +205,1027,3074 +35,1028,3075 +224,1028,3075 +36,1029,3076 +195,1029,3076 +36,1030,3077 +79,1030,3077 +193,1030,3077 +36,1031,3078 +58,1031,3078 +36,1032,3079 +36,1033,3080 +36,1034,3081 +36,1035,3082 +162,1035,3082 +36,1036,3083 +36,1037,3084 +36,1038,3085 +36,1039,3086 +36,1040,3087 +138,1040,3087 +36,1041,3088 +129,1041,3088 +36,1042,3089 +36,1043,3090 +140,1043,3090 +36,1044,3091 +36,1045,3092 +118,1045,3092 +36,1046,3093 +69,1046,3093 +36,1047,3094 +191,1047,3094 +36,1048,3095 +99,1048,3095 +37,1049,3096 +140,1049,3096 +37,1050,3097 +119,1050,3097 +37,1051,3098 +75,1051,3098 +37,1052,3099 +81,1052,3099 +37,1053,3100 +172,1053,3100 +37,1054,3101 +131,1054,3101 +216,1054,3101 +37,1055,3102 +47,1055,3102 +212,1055,3102 +37,1056,3103 +37,1057,3104 +90,1057,3104 +182,1057,3104 +233,1057,3104 +37,1058,3105 +37,1059,3106 +89,1059,3106 +135,1059,3106 +37,1060,3107 +37,1061,3108 +172,1061,3108 +37,1062,3109 +158,1062,3109 +37,1063,3110 +131,1063,3110 +37,1064,3111 +37,1065,3112 +114,1065,3112 +37,1066,3113 +186,1066,3113 +218,1066,3113 +37,1067,3114 +111,1067,3114 +183,1067,3114 +37,1068,3115 +73,1068,3115 +38,1069,3116 +118,1069,3116 +127,1069,3116 +38,1070,3117 +38,1071,3118 +170,1071,3118 +38,1072,3119 +81,1072,3119 +38,1073,3120 +131,1073,3120 +38,1074,3121 +67,1074,3121 +38,1075,3122 +104,1075,3122 +38,1076,3123 +38,1077,3124 +38,1078,3125 +121,1078,3125 +175,1078,3125 +38,1079,3126 +57,1079,3126 +65,1079,3126 +138,1079,3126 +38,1080,3127 +38,1081,3128 +108,1081,3128 +38,1082,3129 +38,1083,3130 +75,1083,3130 +38,1084,3131 +172,1084,3131 +38,1085,3132 +57,1085,3132 +77,1085,3132 +38,1086,3133 +75,1086,3133 +219,1086,3133 +38,1087,3134 +38,1088,3135 +155,1088,3135 +39,1089,3136 +39,1090,3137 +39,1091,3138 +114,1091,3138 +39,1092,3139 +75,1092,3139 +39,1093,3140 +61,1093,3140 +39,1094,3141 +39,1095,3142 +102,1095,3142 +39,1096,3143 +69,1096,3143 +180,1096,3143 +39,1097,3144 +176,1097,3144 +211,1097,3144 +39,1098,3145 +92,1098,3145 +39,1099,3146 +187,1099,3146 +39,1100,3147 +148,1100,3147 +39,1101,3148 +39,1102,3149 +105,1102,3149 +39,1103,3150 +75,1103,3150 +182,1103,3150 +39,1104,3151 +74,1104,3151 +39,1105,3152 +39,1106,3153 +73,1106,3153 +39,1107,3154 +39,1108,3155 +76,1108,3155 +40,1109,3156 +123,1109,3156 +179,1109,3156 +40,1110,3157 +40,1111,3158 +87,1111,3158 +40,1112,3159 +62,1112,3159 +40,1113,3160 +73,1113,3160 +40,1114,3161 +94,1114,3161 +174,1114,3161 +40,1115,3162 +73,1115,3162 +93,1115,3162 +112,1115,3162 +40,1116,3163 +40,1117,3164 +79,1117,3164 +138,1117,3164 +40,1118,3165 +171,1118,3165 +208,1118,3165 +40,1119,3166 +60,1119,3166 +184,1119,3166 +40,1120,3167 +214,1120,3167 +40,1121,3168 +40,1122,3169 +70,1122,3169 +132,1122,3169 +40,1123,3170 +40,1124,3171 +133,1124,3171 +185,1124,3171 +40,1125,3172 +94,1125,3172 +229,1125,3172 +40,1126,3173 +99,1126,3173 +220,1126,3173 +40,1127,3174 +108,1127,3174 +40,1128,3175 +76,1128,3175 +41,1129,3176 +110,1129,3176 +158,1129,3176 +41,1130,3177 +137,1130,3177 +204,1130,3177 +41,1131,3178 +41,1132,3179 +129,1132,3179 +41,1133,3180 +97,1133,3180 +178,1133,3180 +41,1134,2686 +108,1134,2686 +123,1134,2686 +41,1135,3181 +180,1135,3181 +41,1136,3182 +63,1136,3182 +41,1137,3183 +41,1138,3184 +57,1138,3184 +133,1138,3184 +41,1139,3185 +62,1139,3185 +41,1140,3186 +106,1140,3186 +41,1141,3187 +131,1141,3187 +224,1141,3187 +41,1142,3188 +73,1142,3188 +41,1143,3189 +80,1143,3189 +41,1144,3190 +174,1144,3190 +41,1145,3191 +41,1146,3192 +203,1146,3192 +41,1147,3193 +41,1148,3194 +164,1148,3194 +42,1149,3195 +75,1149,3195 +42,1150,3196 +42,1151,3197 +170,1151,3197 +231,1151,3197 +42,1152,3198 +142,1152,3198 +42,1153,3199 +42,1154,3200 +88,1154,3200 +42,1155,3201 +42,1156,3202 +172,1156,3202 +42,1157,3203 +86,1157,3203 +137,1157,3203 +42,1158,3204 +69,1158,3204 +42,1159,3205 +42,1160,3206 +42,1161,3207 +172,1161,3207 +42,1162,3208 +123,1162,3208 +171,1162,3208 +42,1163,3209 +42,1164,3210 +120,1164,3210 +42,1165,3211 +215,1165,3211 +42,1166,3212 +80,1166,3212 +42,1167,3213 +84,1167,3213 +42,1168,3214 +82,1168,3214 +228,1168,3214 +43,1169,3215 +96,1169,3215 +43,1170,3216 +126,1170,3216 +43,1171,3217 +178,1171,3217 +43,1172,3218 +151,1172,3218 +43,1173,3219 +72,1173,3219 +43,1174,3220 +179,1174,3220 +43,1175,3221 +187,1175,3221 +219,1175,3221 +43,1176,3222 +153,1176,3222 +43,1177,3223 +96,1177,3223 +43,1178,3224 +104,1178,3224 +221,1178,3224 +43,1179,3225 +43,1180,3226 +43,1181,3227 +146,1181,3227 +43,1182,3228 +76,1182,3228 +43,1183,3229 +119,1183,3229 +43,1184,3230 +160,1184,3230 +43,1185,3231 +43,1186,3232 +43,1187,2945 +43,1188,3233 +44,1189,3234 +82,1189,3234 +44,1190,3235 +71,1190,3235 +125,1190,3235 +44,1191,3236 +44,1192,3237 +168,1192,3237 +44,1193,3238 +135,1193,3238 +44,1194,3239 +44,1195,3240 +197,1195,3240 +44,1196,3241 +57,1196,3241 +77,1196,3241 +44,1197,3242 +44,1198,3243 +92,1198,3243 +44,1199,3244 +126,1199,3244 +44,1200,3245 +65,1200,3245 +44,1201,3246 +185,1201,3246 +44,1202,3247 +94,1202,3247 +140,1202,3247 +44,1203,3248 +44,1204,3249 +44,1205,3250 +171,1205,3250 +44,1206,3251 +166,1206,3251 +44,1207,2533 +44,1208,3252 +154,1208,3252 +185,1208,3252 +45,1209,3253 +119,1209,3253 +45,1210,3254 +45,1211,3255 +140,1211,3255 +219,1211,3255 +45,1212,3256 +68,1212,3256 +134,1212,3256 +45,1213,3257 +45,1214,3258 +67,1214,3258 +161,1214,3258 +45,1215,3259 +225,1215,3259 +45,1216,3260 +116,1216,3260 +45,1217,3261 +45,1218,3262 +107,1218,3262 +45,1219,3263 +45,1220,3264 +77,1220,3264 +45,1221,3265 +106,1221,3265 +45,1222,3266 +57,1222,3266 +151,1222,3266 +200,1222,3266 +45,1223,3267 +137,1223,3267 +45,1224,3268 +45,1225,3269 +94,1225,3269 +153,1225,3269 +45,1226,3270 +67,1226,3270 +45,1227,3271 +69,1227,3271 +162,1227,3271 +45,1228,3272 +46,1229,3273 +68,1229,3273 +46,1230,3274 +46,1231,3275 +46,1232,3276 +56,1232,3276 +150,1232,3276 +46,1233,3277 +230,1233,3277 +46,1234,3278 +175,1234,3278 +46,1235,3279 +197,1235,3279 +207,1235,3279 +46,1236,3280 +56,1236,3280 +46,1237,3281 +153,1237,3281 +46,1238,3282 +105,1238,3282 +46,1239,3283 +56,1239,3283 +46,1240,3284 +177,1240,3284 +46,1241,3285 +97,1241,3285 +46,1242,3286 +56,1242,3286 +46,1243,3287 +127,1243,3287 +46,1244,3288 +61,1244,3288 +46,1245,3289 +132,1245,3289 +46,1246,3290 +205,1246,3290 +46,1247,3291 +84,1247,3291 +166,1247,3291 +46,1248,3292 +150,1248,3292 +47,1249,3293 +76,1249,3293 +47,1250,3294 +115,1250,3294 +47,1251,3295 +47,1252,3296 +170,1252,3296 +47,1253,3297 +56,1253,3297 +153,1253,3297 +47,1254,3298 +177,1254,3298 +47,1255,3299 +47,1256,3300 +56,1256,3300 +47,1257,3301 +47,1258,3302 +47,1259,3303 +117,1259,3303 +47,1260,3304 +170,1260,3304 +47,1261,3305 +148,1261,3305 +164,1261,3305 +47,1262,3306 +172,1262,3306 +47,1263,3307 +57,1263,3307 +210,1263,3307 +47,1264,3308 +47,1265,3309 +56,1265,3309 +103,1265,3309 +47,1266,3310 +101,1266,3310 +47,1267,3311 +116,1267,3311 +47,1268,3312 +159,1268,3312 +48,1269,3313 +48,1270,3314 +103,1270,3314 +176,1270,3314 +48,1271,3315 +176,1271,3315 +48,1272,3316 +97,1272,3316 +123,1272,3316 +48,1273,3317 +75,1273,3317 +48,1274,3318 +48,1275,3319 +48,1276,3320 +56,1276,3320 +48,1277,3321 +48,1278,3322 +48,1279,3323 +139,1279,3323 +48,1280,3324 +99,1280,3324 +48,1281,3325 +84,1281,3325 +48,1282,3326 +56,1282,3326 +48,1283,3327 +87,1283,3327 +48,1284,3328 +128,1284,3328 +48,1285,3329 +56,1285,3329 +48,1286,3330 +90,1286,3330 +48,1287,3331 +133,1287,3331 +159,1287,3331 +48,1288,3332 +73,1288,3332 +49,1289,3333 +85,1289,3333 +163,1289,3333 +49,1290,3334 +49,1291,3335 +86,1291,3335 +202,1291,3335 +49,1292,3336 +107,1292,3336 +185,1292,3336 +49,1293,3337 +68,1293,3337 +49,1294,3338 +132,1294,3338 +49,1295,3339 +82,1295,3339 +49,1296,3340 +93,1296,3340 +49,1297,3341 +206,1297,3341 +49,1298,3342 +57,1298,3342 +70,1298,3342 +155,1298,3342 +49,1299,3343 +111,1299,3343 +49,1300,3344 +98,1300,3344 +49,1301,3345 +49,1302,3346 +81,1302,3346 +49,1303,3347 +49,1304,3348 +141,1304,3348 +49,1305,3349 +121,1305,3349 +49,1306,3350 +151,1306,3350 +232,1306,3350 +49,1307,3351 +49,1308,3352 +146,1308,3352 +186,1308,3352 +50,1309,3353 +50,1310,3354 +50,1311,3355 +102,1311,3355 +50,1312,3356 +153,1312,3356 +50,1313,3357 +82,1313,3357 +50,1314,3358 +50,1315,3359 +102,1315,3359 +50,1316,3360 +151,1316,3360 +50,1317,3361 +97,1317,3361 +50,1318,3362 +50,1319,3363 +50,1320,3364 +50,1321,3365 +56,1321,3365 +50,1322,3366 +146,1322,3366 +50,1323,3367 +130,1323,3367 +50,1324,3368 +50,1325,3369 +83,1325,3369 +50,1326,3370 +148,1326,3370 +50,1327,3371 +165,1327,3371 +50,1328,3372 +85,1328,3372 +51,1329,3373 +74,1329,3373 +150,1329,3373 +51,1330,3374 +51,1331,3375 +127,1331,3375 +51,1332,3376 +76,1332,3376 +51,1333,3377 +86,1333,3377 +51,1334,3378 +74,1334,3378 +214,1334,3378 +51,1335,3379 +127,1335,3379 +213,1335,3379 +51,1336,3380 +142,1336,3380 +51,1337,3381 +51,1338,3382 +71,1338,3382 +51,1339,3383 +103,1339,3383 +146,1339,3383 +51,1340,3384 +51,1341,3385 +51,1342,3386 +51,1343,3387 +57,1343,3387 +51,1344,3388 +88,1344,3388 +155,1344,3388 +51,1345,3389 +78,1345,3389 +51,1346,3390 +208,1346,3390 +231,1346,3390 +51,1347,3391 +51,1348,3392 +58,3393,3394 +111,3393,3394 +155,3393,3394 +58,3395,3396 +136,3395,3396 +154,3395,3396 +218,3395,3396 +58,3397,3398 +58,3399,3400 +123,3399,3400 +58,3401,3402 +142,3401,3402 +58,3403,3404 +136,3403,3404 +58,3405,3406 +58,3407,3408 +58,3409,3410 +58,3411,3412 +144,3411,3412 +230,3411,3412 +58,3413,3414 +186,3413,3414 +58,3415,3416 +126,3415,3416 +58,3417,3418 +56,3419,3420 +58,3419,3420 +158,3419,3420 +58,3421,3422 +137,3421,3422 +172,3421,3422 +58,3423,3424 +58,3425,3426 +92,3425,3426 +58,3427,3428 +75,3427,3428 +158,3427,3428 +58,3429,3430 +58,3431,3432 +59,3433,3434 +101,3433,3434 +59,3435,3436 +139,3435,3436 +59,3437,3438 +103,3437,3438 +59,3439,3440 +179,3439,3440 +59,3441,3442 +59,3443,3444 +59,3445,3446 +160,3445,3446 +59,3447,3448 +59,3449,3450 +59,3451,3452 +59,3453,3454 +59,3455,3456 +59,3457,3458 +163,3457,3458 +59,3459,3460 +91,3459,3460 +59,3461,3462 +117,3461,3462 +59,3463,3464 +59,3465,3466 +158,3465,3466 +59,3467,3468 +59,3469,3470 +88,3469,3470 +59,3471,3472 +133,3471,3472 +60,3473,3474 +196,3473,3474 +200,3473,3474 +60,3475,3476 +60,3477,3478 +126,3477,3478 +60,3479,3480 +89,3479,3480 +60,3481,3482 +60,3483,3484 +73,3483,3484 +162,3483,3484 +60,3485,3486 +60,3487,3488 +83,3487,3488 +169,3487,3488 +60,3489,3490 +60,3491,3492 +151,3491,3492 +60,3493,3494 +93,3493,3494 +60,3495,3496 +77,3495,3496 +156,3495,3496 +60,3497,3498 +60,3499,3500 +97,3499,3500 +60,3501,3502 +60,3503,3504 +91,3503,3504 +60,3505,3506 +180,3505,3506 +60,3507,3508 +78,3507,3508 +60,3509,3510 +147,3509,3510 +60,3511,3512 +158,3511,3512 +61,3513,3514 +61,3515,3516 +61,3517,3518 +61,3519,3520 +127,3519,3520 +151,3519,3520 +61,3521,3522 +61,3523,3524 +61,3525,3526 +153,3525,3526 +61,3527,3528 +61,3529,3530 +91,3529,3530 +130,3529,3530 +227,3529,3530 +57,3531,3532 +61,3531,3532 +56,3533,3534 +61,3533,3534 +61,3535,3536 +181,3535,3536 +61,3537,3538 +186,3537,3538 +57,3539,3540 +61,3539,3540 +161,3539,3540 +56,3541,3542 +61,3541,3542 +61,3543,3544 +86,3543,3544 +61,3545,3546 +186,3545,3546 +61,3547,3548 +128,3547,3548 +56,3549,3550 +61,3549,3550 +61,3551,3552 +62,3553,3554 +144,3553,3554 +172,3553,3554 +62,3555,3556 +62,3557,3558 +62,3559,3560 +150,3559,3560 +62,3561,3562 +62,3563,3564 +185,3563,3564 +226,3563,3564 +62,3565,3566 +99,3565,3566 +154,3565,3566 +62,3567,3568 +177,3567,3568 +62,3569,3570 +62,3571,3572 +142,3571,3572 +224,3571,3572 +62,3573,3574 +62,3575,3576 +136,3575,3576 +182,3575,3576 +62,3577,3578 +62,3579,3580 +62,3581,3582 +220,3581,3582 +62,3583,3584 +112,3583,3584 +219,3583,3584 +62,3585,3586 +169,3585,3586 +57,3587,3588 +62,3587,3588 +71,3587,3588 +170,3587,3588 +190,3587,3588 +62,3589,3590 +62,3591,3592 +155,3591,3592 +63,3593,3594 +123,3593,3594 +63,3595,3596 +110,3595,3596 +63,3597,3598 +63,3599,3600 +84,3599,3600 +63,3601,3602 +79,3601,3602 +63,3603,3604 +161,3603,3604 +63,3605,3606 +63,3607,3608 +63,3609,3610 +85,3609,3610 +173,3609,3610 +63,3611,3612 +63,3613,3614 +183,3613,3614 +63,3615,3616 +63,3617,3618 +63,3619,3620 +63,3621,3622 +230,3621,3622 +63,3623,3624 +63,3625,3626 +165,3625,3626 +63,3627,3628 +93,3627,3628 +146,3627,3628 +63,3629,3630 +63,3631,3632 +161,3631,3632 +64,3633,3634 +77,3633,3634 +210,3633,3634 +64,3635,3636 +174,3635,3636 +64,3637,3638 +156,3637,3638 +64,3639,3640 +103,3639,3640 +64,3641,3642 +173,3641,3642 +64,3643,3644 +80,3643,3644 +174,3643,3644 +64,3645,3646 +170,3645,3646 +64,3647,3648 +64,3649,3650 +64,3651,3652 +64,3653,3654 +153,3653,3654 +64,3655,3656 +64,3657,3658 +146,3657,3658 +64,3659,3660 +137,3659,3660 +64,3661,3662 +82,3661,3662 +64,3663,3664 +158,3663,3664 +64,3665,3666 +64,3667,3668 +118,3667,3668 +64,3669,3670 +126,3669,3670 +64,3671,3672 +121,3671,3672 +57,3673,3674 +65,3673,3674 +152,3673,3674 +65,3675,3676 +112,3675,3676 +146,3675,3676 +210,3675,3676 +65,3677,3678 +65,3679,3680 +169,3679,3680 +65,3681,3682 +226,3681,3682 +65,3683,3684 +110,3683,3684 +141,3683,3684 +65,3685,3686 +132,3685,3686 +174,3685,3686 +65,3687,3688 +117,3687,3688 +65,3689,3690 +171,3689,3690 +65,3691,3692 +225,3691,3692 +65,3693,3694 +65,3695,3696 +107,3695,3696 +139,3695,3696 +65,3697,3698 +65,3699,3700 +175,3699,3700 +65,3701,3702 +65,3703,3704 +65,3705,3706 +185,3705,3706 +65,3707,3708 +125,3707,3708 +172,3707,3708 +65,3709,3710 +113,3709,3710 +65,3711,3712 +161,3711,3712 +66,3713,3714 +66,3715,3716 +66,3717,3718 +66,3719,3720 +144,3719,3720 +66,3721,3722 +66,3723,3724 +100,3723,3724 +165,3723,3724 +66,3725,3726 +191,3725,3726 +66,3727,3728 +97,3727,3728 +66,3729,3730 +109,3729,3730 +66,3731,3732 +77,3731,3732 +171,3731,3732 +221,3731,3732 +66,3733,3734 +88,3733,3734 +146,3733,3734 +66,3735,3736 +156,3735,3736 +66,3737,3738 +87,3737,3738 +66,3739,3740 +118,3739,3740 +66,3741,3742 +99,3741,3742 +140,3741,3742 +66,3743,3744 +66,3745,3746 +183,3745,3746 +66,3747,3748 +229,3747,3748 +66,3749,3750 +66,3751,3752 +67,3753,3754 +119,3753,3754 +67,3755,3756 +216,3755,3756 +67,3757,3758 +151,3757,3758 +67,3759,3760 +161,3759,3760 +67,3761,3762 +67,3763,3764 +67,3765,3766 +89,3765,3766 +57,3767,3768 +67,3767,3768 +104,3767,3768 +67,3769,3770 +67,3771,3772 +67,3773,3774 +67,3775,3776 +67,3777,3778 +67,3779,3780 +220,3779,3780 +67,3781,3782 +79,3781,3782 +67,3783,3784 +67,3785,3786 +67,3787,3788 +67,3789,3790 +67,3791,3792 +97,3791,3792 +166,3791,3792 +68,3793,3794 +68,3795,3796 +160,3795,3796 +68,3797,3798 +161,3797,3798 +229,3797,3798 +68,3799,3800 +68,3801,3802 +68,3803,3804 +176,3803,3804 +68,3805,3806 +68,3807,3808 +115,3807,3808 +68,3809,3810 +93,3809,3810 +68,3811,3812 +210,3811,3812 +68,3813,3814 +68,3815,3816 +166,3815,3816 +68,3817,3818 +135,3817,3818 +216,3817,3818 +68,3819,3820 +120,3819,3820 +193,3819,3820 +68,3821,3822 +68,3823,3824 +68,3825,3826 +89,3825,3826 +68,3827,3828 +120,3827,3828 +186,3827,3828 +68,3829,3830 +177,3829,3830 +68,3831,3832 +165,3831,3832 +69,3833,3834 +69,3835,3836 +108,3835,3836 +69,3837,3838 +111,3837,3838 +69,3839,3840 +69,3841,3842 +111,3841,3842 +69,3843,3844 +92,3843,3844 +56,3845,3846 +69,3845,3846 +109,3845,3846 +69,3847,3848 +69,3849,3850 +110,3849,3850 +165,3849,3850 +69,3851,3852 +86,3851,3852 +69,3853,3854 +187,3853,3854 +69,3855,3856 +69,3857,3858 +154,3857,3858 +69,3859,3860 +69,3861,3862 +88,3861,3862 +165,3861,3862 +223,3861,3862 +69,3863,3864 +114,3863,3864 +69,3865,3866 +69,3867,3868 +69,3869,3870 +69,3871,3872 +70,3873,3874 +146,3873,3874 +70,3875,3876 +70,3877,3878 +70,3879,3880 +57,3881,3882 +70,3881,3882 +200,3881,3882 +70,3883,3884 +70,3885,3886 +70,3887,3888 +70,3889,3890 +70,3891,3892 +70,3893,3894 +121,3893,3894 +70,3895,3896 +92,3895,3896 +228,3895,3896 +70,3897,3898 +70,3899,3900 +92,3899,3900 +70,3901,3902 +103,3901,3902 +70,3903,3904 +152,3903,3904 +163,3903,3904 +57,3905,3906 +70,3905,3906 +190,3905,3906 +70,3907,3908 +70,3909,3910 +89,3909,3910 +70,3911,3912 +71,3913,3914 +84,3913,3914 +156,3913,3914 +71,3915,3916 +116,3915,3916 +71,3917,3918 +71,3919,3920 +141,3919,3920 +71,3921,3922 +181,3921,3922 +208,3921,3922 +71,3923,3924 +93,3923,3924 +140,3923,3924 +71,3925,3926 +71,3927,3928 +123,3927,3928 +71,3929,3930 +154,3929,3930 +192,3929,3930 +71,3931,3932 +71,3933,3934 +71,3935,3936 +71,3937,3938 +191,3937,3938 +71,3939,3940 +71,3941,3942 +71,3943,3944 +196,3943,3944 +217,3943,3944 +71,3945,3946 +139,3945,3946 +71,3947,3948 +71,3949,3950 +109,3949,3950 +167,3949,3950 +71,3951,3952 +72,3953,3954 +97,3953,3954 +72,3955,3956 +137,3955,3956 +72,3957,3958 +162,3957,3958 +72,3959,3960 +163,3959,3960 +72,3961,3962 +113,3961,3962 +72,3963,3964 +131,3963,3964 +72,3965,3966 +99,3965,3966 +72,3967,3968 +111,3967,3968 +72,3969,3970 +97,3969,3970 +72,3971,3972 +98,3971,3972 +72,3973,3974 +201,3973,3974 +72,3975,3976 +145,3975,3976 +72,3977,3978 +101,3977,3978 +164,3977,3978 +72,3979,3980 +91,3979,3980 +72,3981,3982 +163,3981,3982 +72,3983,3984 +72,3985,3986 +135,3985,3986 +72,3987,3988 +103,3987,3988 +72,3989,3990 +72,3991,3992 +104,3991,3992 +195,3991,3992 +73,3993,3994 +73,3995,3996 +186,3995,3996 +73,3997,3998 +89,3997,3998 +73,3999,4000 +172,3999,4000 +73,4001,4002 +161,4001,4002 +73,4003,4004 +73,4007,4008 +109,4007,4008 +73,4009,4010 +152,4009,4010 +73,4011,4012 +134,4011,4012 +73,4013,4014 +129,4013,4014 +184,4013,4014 +73,4015,4016 +73,4017,4018 +147,4017,4018 +73,4019,4020 +128,4019,4020 +73,4021,4022 +85,4021,4022 +73,4023,4024 +73,4025,4026 +145,4025,4026 +73,4027,4028 +73,4029,4030 +73,4031,4032 +74,4033,4034 +123,4033,4034 +213,4033,4034 +74,4035,4036 +152,4035,4036 +74,4037,4038 +74,4039,4040 +145,4039,4040 +74,4041,4042 +157,4041,4042 +74,4043,4044 +93,4043,4044 +180,4043,4044 +74,4045,4046 +74,4047,4048 +74,4049,4050 +134,4049,4050 +74,4051,4052 +74,4053,4054 +110,4053,4054 +74,4055,4056 +74,4057,4058 +74,4059,4060 +74,4061,4062 +74,4063,4064 +85,4063,4064 +231,4063,4064 +74,4065,4066 +74,4067,4068 +74,4069,4070 +74,4071,4072 +75,4073,4074 +182,4073,4074 +75,4075,4076 +126,4075,4076 +75,4077,4078 +170,4077,4078 +75,4079,4080 +149,4079,4080 +75,4081,4082 +75,4083,4084 +75,4085,4086 +206,4085,4086 +75,4087,4088 +75,4089,4090 +86,4089,4090 +75,4091,4092 +132,4091,4092 +75,4093,4094 +96,4093,4094 +75,4095,4096 +144,4095,4096 +75,4097,4098 +86,4097,4098 +75,4099,4100 +75,4101,4102 +130,4101,4102 +75,4103,4104 +75,4105,4106 +130,4105,4106 +75,4107,4108 +126,4107,4108 +75,4109,4110 +166,4109,4110 +75,4111,4112 +90,4111,4112 +170,4111,4112 +76,4113,4114 +87,4113,4114 +179,4113,4114 +76,4115,4116 +76,4117,4118 +76,4119,4120 +98,4119,4120 +155,4119,4120 +76,4121,4122 +102,4121,4122 +233,4121,4122 +76,4123,4124 +129,4123,4124 +211,4123,4124 +76,4125,4126 +127,4125,4126 +76,4127,4128 +106,4127,4128 +76,4129,4130 +76,4131,4132 +156,4131,4132 +76,4133,4134 +76,4135,4136 +161,4135,4136 +76,4137,4138 +216,4137,4138 +76,4139,4140 +115,4139,4140 +76,4141,4142 +106,4141,4142 +76,4143,4144 +116,4143,4144 +76,4145,4146 +109,4145,4146 +76,4147,4148 +94,4147,4148 +76,4149,4150 +138,4149,4150 +76,4151,4152 +126,4151,4152 +167,4151,4152 +77,4153,4154 +187,4153,4154 +77,4155,4156 +88,4155,4156 +176,4155,4156 +77,4157,4158 +77,4159,4160 +109,4159,4160 +219,4159,4160 +77,4161,4162 +156,4161,4162 +216,4161,4162 +77,4163,4164 +163,4163,4164 +77,4165,4166 +141,4165,4166 +77,4167,4168 +100,4167,4168 +77,4169,4170 +185,4169,4170 +77,4171,4172 +91,4171,4172 +169,4171,4172 +77,4173,4174 +77,4175,4176 +77,4177,4178 +216,4177,4178 +77,4179,4180 +106,4179,4180 +77,4181,4182 +178,4181,4182 +77,4183,4184 +77,4185,4186 +77,4187,4188 +77,4189,4190 +107,4189,4190 +77,4191,4192 +78,4193,4194 +101,4193,4194 +78,4195,4196 +78,4197,4198 +115,4197,4198 +78,4199,4200 +78,4201,4202 +100,4201,4202 +78,4203,4204 +94,4203,4204 +78,4205,4206 +78,4207,4208 +184,4207,4208 +78,4209,4210 +78,4211,4212 +78,4213,4214 +78,4215,4216 +88,4215,4216 +179,4215,4216 +78,4217,4218 +78,4219,4220 +78,4221,4222 +78,4223,4224 +78,4225,4226 +78,4227,4228 +200,4227,4228 +78,4229,4230 +140,4229,4230 +78,4231,4232 +159,4231,4232 +79,4233,4234 +79,4235,4236 +162,4235,4236 +79,4237,4238 +123,4237,4238 +135,4237,4238 +79,4239,4240 +79,4241,4242 +105,4241,4242 +79,4243,4244 +79,4245,4246 +173,4245,4246 +209,4245,4246 +79,4247,4248 +120,4247,4248 +217,4247,4248 +79,4249,4250 +118,4249,4250 +79,4251,4252 +79,4253,4254 +79,4255,4256 +79,4257,4258 +79,4259,4260 +99,4259,4260 +137,4259,4260 +79,4261,4262 +102,4261,4262 +79,4263,4264 +116,4263,4264 +79,4265,4266 +79,4267,4268 +88,4267,4268 +79,4269,4270 +134,4269,4270 +79,4271,4272 +120,4271,4272 +80,4273,4274 +80,4275,4276 +80,4277,4278 +80,4279,4280 +80,4281,4282 +80,4283,4284 +158,4283,4284 +80,4285,4286 +160,4285,4286 +80,4287,4288 +154,4287,4288 +80,4289,4290 +114,4289,4290 +80,4291,4292 +80,4293,4294 +80,4295,4296 +129,4295,4296 +80,4297,4298 +113,4297,4298 +80,4299,4300 +80,4301,4302 +80,4303,4304 +80,4305,4306 +183,4305,4306 +80,4307,4308 +80,4309,4310 +147,4309,4310 +229,4309,4310 +80,4311,4312 +81,4313,4314 +119,4313,4314 +81,4315,4316 +81,4319,4320 +81,4321,4322 +81,4323,4324 +81,4325,4326 +119,4325,4326 +81,4327,4328 +168,4327,4328 +81,4329,4330 +190,4329,4330 +81,4333,4334 +81,4335,4336 +168,4335,4336 +81,4337,4338 +81,4339,4340 +81,4341,4342 +81,4343,4344 +157,4343,4344 +81,4345,4346 +81,4347,4348 +166,4347,4348 +81,4349,4350 +81,4351,4352 +82,4353,4354 +138,4353,4354 +82,4355,4356 +99,4355,4356 +82,4357,4358 +99,4357,4358 +157,4357,4358 +82,4359,4360 +162,4359,4360 +202,4359,4360 +82,4361,4362 +99,4361,4362 +82,4363,4364 +155,4363,4364 +82,4365,4366 +182,4365,4366 +82,4367,4368 +82,4369,4370 +82,4371,4372 +82,4373,4374 +104,4373,4374 +82,4375,4376 +82,4377,4378 +82,4379,4380 +103,4379,4380 +82,4381,4382 +82,4383,4384 +82,4385,4386 +135,4385,4386 +151,4385,4386 +82,4387,4388 +82,4389,4390 +123,4389,4390 +231,4389,4390 +82,4391,4392 +167,4391,4392 +83,4393,4394 +83,4395,4396 +83,4397,4398 +83,4399,4400 +83,4401,4402 +83,4403,4404 +186,4403,4404 +83,4405,4406 +108,4405,4406 +182,4405,4406 +217,4405,4406 +83,4407,4408 +83,4409,4410 +83,4411,4412 +83,4413,4414 +83,4415,4416 +83,4417,4418 +155,4417,4418 +217,4417,4418 +83,4419,4420 +83,4421,4422 +221,4421,4422 +83,4423,4424 +83,4425,4426 +83,4427,4428 +120,4427,4428 +83,4429,4430 +83,4431,4432 +169,4431,4432 +84,4433,4434 +84,4435,4436 +175,4435,4436 +84,4437,4438 +115,4437,4438 +84,4439,4440 +169,4439,4440 +84,4441,4442 +104,4441,4442 +84,4443,4444 +84,4445,4446 +84,4447,4448 +120,4447,4448 +201,4447,4448 +84,4449,4450 +84,4451,4452 +145,4451,4452 +84,4453,4454 +84,4455,4456 +205,4455,4456 +84,4457,4458 +84,4459,4460 +84,4461,4462 +147,4461,4462 +84,4463,4464 +101,4463,4464 +211,4463,4464 +84,4465,4466 +84,4467,4468 +84,4469,4470 +98,4469,4470 +217,4469,4470 +84,4471,4472 +85,4473,4474 +125,4473,4474 +142,4473,4474 +85,4475,4476 +85,4477,4478 +85,4479,4480 +171,4479,4480 +85,4481,4482 +112,4481,4482 +85,4483,4484 +85,4485,4486 +85,4487,4488 +114,4487,4488 +85,4489,4490 +85,4491,4492 +85,4493,4494 +195,4493,4494 +196,4493,4494 +85,4495,4496 +85,4497,4498 +110,4497,4498 +182,4497,4498 +85,4499,4500 +85,4501,4502 +85,4503,4504 +209,4503,4504 +222,4503,4504 +85,4505,4506 +85,4507,4508 +85,4509,4510 +85,4511,4512 +185,4511,4512 +86,4513,4514 +119,4513,4514 +86,4515,4516 +86,4517,4518 +132,4517,4518 +145,4517,4518 +86,4519,4520 +165,4519,4520 +86,4521,4522 +86,4523,4524 +163,4523,4524 +202,4523,4524 +86,4525,4526 +185,4525,4526 +86,4527,4528 +102,4527,4528 +86,4529,4530 +86,4531,4532 +86,4533,4534 +114,4533,4534 +86,4535,4536 +86,4537,4538 +113,4537,4538 +148,4537,4538 +86,4539,4540 +149,4539,4540 +179,4539,4540 +86,4541,4542 +156,4541,4542 +86,4543,4544 +138,4543,4544 +86,4545,4546 +120,4545,4546 +209,4545,4546 +86,4547,4548 +142,4547,4548 +86,4549,4550 +86,4551,4552 +104,4551,4552 +87,4553,4554 +120,4553,4554 +87,4555,4556 +108,4555,4556 +167,4555,4556 +87,4557,4558 +164,4557,4558 +87,4559,4560 +87,4561,4562 +174,4561,4562 +87,4563,4564 +87,4565,4566 +127,4565,4566 +142,4565,4566 +87,4567,4568 +87,4569,4570 +87,4571,4572 +87,4573,4574 +87,4575,4576 +87,4577,4578 +129,4577,4578 +87,4579,4580 +87,4581,4582 +87,4583,4584 +87,4585,4586 +177,4585,4586 +87,4587,4588 +87,4589,4590 +87,4591,4592 +174,4591,4592 +88,4593,4594 +127,4593,4594 +88,4595,4596 +88,4597,4598 +108,4597,4598 +187,4597,4598 +88,4599,4600 +88,4601,4602 +113,4601,4602 +88,4603,4604 +114,4603,4604 +88,4605,4606 +180,4605,4606 +88,4607,4608 +88,4609,4610 +88,4611,4612 +88,4613,4614 +115,4613,4614 +228,4613,4614 +88,4615,4616 +88,4617,4618 +88,4619,4620 +140,4619,4620 +88,4621,4622 +88,4623,4624 +88,4625,4626 +88,4627,4628 +139,4627,4628 +88,4629,4630 +155,4629,4630 +88,4631,4632 +106,4631,4632 +172,4631,4632 +89,4633,4634 +114,4633,4634 +89,4635,4636 +161,4635,4636 +209,4635,4636 +216,4635,4636 +89,4637,4638 +151,4637,4638 +89,4639,4640 +89,4641,4642 +144,4641,4642 +89,4643,4644 +134,4643,4644 +145,4643,4644 +89,4645,4646 +97,4645,4646 +89,4647,4648 +148,4647,4648 +89,4649,4650 +89,4651,4652 +138,4651,4652 +89,4653,4654 +89,4655,4656 +171,4655,4656 +89,4657,4658 +89,4659,4660 +89,4661,4662 +89,4663,4664 +89,4665,4666 +157,4665,4666 +89,4667,4668 +89,4669,4670 +89,4671,4672 +90,4673,4674 +90,4675,4676 +183,4675,4676 +90,4677,4678 +196,4677,4678 +90,4679,4680 +122,4679,4680 +90,4681,4682 +90,4683,4684 +90,4685,4686 +90,4687,4688 +90,4689,4690 +90,4691,4692 +197,4691,4692 +90,4693,4694 +90,4695,4696 +90,4697,4698 +111,4697,4698 +90,4699,4700 +90,4701,4702 +126,4701,4702 +90,4703,4704 +90,4705,4706 +90,4707,4708 +120,4707,4708 +90,4709,4710 +90,4711,4712 +166,4711,4712 +91,4713,4714 +185,4713,4714 +91,4715,4716 +191,4715,4716 +201,4715,4716 +91,4717,4718 +145,4717,4718 +91,4719,4720 +91,4721,4722 +91,4723,4724 +91,4725,4726 +119,4725,4726 +91,4727,4728 +122,4727,4728 +91,4729,4730 +202,4729,4730 +91,4731,4732 +91,4733,4734 +91,4735,4736 +91,4737,4738 +91,4739,4740 +91,4741,4742 +91,4743,4744 +142,4743,4744 +91,4745,4746 +161,4745,4746 +91,4747,4748 +91,4749,4750 +91,4751,4752 +159,4751,4752 +92,4753,4754 +188,4753,4754 +92,4755,4756 +119,4755,4756 +155,4755,4756 +92,4757,4758 +199,4757,4758 +92,4759,4760 +164,4759,4760 +193,4759,4760 +92,4761,4762 +92,4763,4764 +92,4765,4766 +92,4767,4768 +92,4769,4770 +92,4771,4772 +112,4771,4772 +92,4773,4774 +92,4775,4776 +202,4775,4776 +92,4777,4778 +92,4779,4780 +92,4781,4782 +92,4783,4784 +92,4785,4786 +131,4785,4786 +92,4787,4788 +92,4789,4790 +184,4789,4790 +92,4791,4792 +93,4793,4794 +93,4795,4796 +93,4797,4798 +93,4799,4800 +93,4801,4802 +93,4803,4804 +156,4803,4804 +93,4805,4806 +93,4807,4808 +113,4807,4808 +93,4809,4810 +162,4809,4810 +93,4811,4812 +150,4811,4812 +93,4813,4814 +93,4815,4816 +93,4817,4818 +93,4819,4820 +93,4821,4822 +148,4821,4822 +93,4823,4824 +93,4825,4826 +93,4827,4828 +184,4827,4828 +93,4829,4830 +93,4831,4832 +192,4831,4832 +94,4833,4834 +94,4835,4836 +94,4837,4838 +228,4837,4838 +94,4839,4840 +158,4839,4840 +94,4841,4842 +94,4843,4844 +94,4845,4846 +111,4845,4846 +94,4847,4848 +94,4849,4850 +94,4851,4852 +194,4851,4852 +94,4853,4854 +152,4853,4854 +94,4855,4856 +94,4857,4858 +152,4857,4858 +94,4859,4860 +212,4859,4860 +94,4861,4862 +94,4863,4864 +155,4863,4864 +94,4865,4866 +148,4865,4866 +94,4867,4868 +132,4867,4868 +184,4867,4868 +94,4869,4870 +94,4871,4872 +191,4871,4872 +95,4873,4874 +167,4873,4874 +95,4875,4876 +95,4877,4878 +169,4877,4878 +199,4877,4878 +95,4879,4880 +118,4879,4880 +95,4881,4882 +95,4883,4884 +187,4883,4884 +95,4885,4886 +154,4885,4886 +95,4887,4888 +95,4889,4890 +167,4889,4890 +95,4891,4892 +128,4891,4892 +95,4893,4894 +132,4893,4894 +95,4895,4896 +95,4897,4898 +191,4897,4898 +95,4899,4900 +158,4899,4900 +95,4901,4902 +95,4903,4904 +113,4903,4904 +95,4905,4906 +112,4905,4906 +175,4905,4906 +95,4907,4908 +95,4909,4910 +176,4909,4910 +95,4911,4912 +96,4913,4914 +138,4913,4914 +96,4915,4916 +96,4917,4918 +126,4917,4918 +96,4919,4920 +96,4921,4922 +96,4923,4924 +96,4925,4926 +96,4927,4928 +96,4929,4930 +117,4929,4930 +96,4931,4932 +96,4933,4934 +96,4935,4936 +146,4935,4936 +96,4937,4938 +174,4937,4938 +197,4937,4938 +96,4939,4940 +96,4941,4942 +96,4943,4944 +133,4943,4944 +177,4943,4944 +96,4945,4946 +96,4947,4948 +96,4949,4950 +146,4949,4950 +96,4951,4952 +97,4953,4954 +125,4953,4954 +97,4955,4956 +180,4955,4956 +97,4957,4958 +168,4957,4958 +97,4959,4960 +164,4959,4960 +213,4959,4960 +97,4961,4962 +198,4961,4962 +97,4963,4964 +97,4965,4966 +181,4965,4966 +97,4967,4968 +135,4967,4968 +97,4969,4970 +174,4969,4970 +97,4971,4972 +97,4973,4974 +97,4975,4976 +182,4975,4976 +97,4977,4978 +97,4979,4980 +97,4981,4982 +185,4981,4982 +97,4983,4984 +97,4985,4986 +114,4985,4986 +97,4987,4988 +97,4989,4990 +136,4989,4990 +97,4991,4992 +163,4991,4992 +98,4993,4994 +98,4995,4996 +218,4995,4996 +98,4997,4998 +121,4997,4998 +98,4999,5000 +158,4999,5000 +98,5001,5002 +98,5003,5004 +225,5003,5004 +98,5005,5006 +98,5007,5008 +139,5007,5008 +98,5009,5010 +98,5011,5012 +107,5011,5012 +98,5013,5014 +108,5013,5014 +98,5015,5016 +117,5015,5016 +98,5017,5018 +98,5019,5020 +98,5021,5022 +98,5023,5024 +152,5023,5024 +98,5025,5026 +178,5025,5026 +98,5027,5028 +98,5029,5030 +98,5031,5032 +206,5031,5032 +99,5033,5034 +99,5035,5036 +99,5037,5038 +99,5039,5040 +99,5041,5042 +206,5041,5042 +99,5043,5044 +99,5045,5046 +99,5047,5048 +187,5047,5048 +227,5047,5048 +99,5049,5050 +109,5049,5050 +99,5051,5052 +99,5053,5054 +99,5055,5056 +99,5057,5058 +99,5059,5060 +99,5061,5062 +99,5063,5064 +99,5065,5066 +99,5067,5068 +168,5067,5068 +99,5069,5070 +116,5069,5070 +187,5069,5070 +99,5071,5072 +131,5071,5072 +166,5071,5072 +100,5073,5074 +136,5073,5074 +100,5075,5076 +100,5077,5078 +163,5077,5078 +100,5079,5080 +100,5081,5082 +157,5081,5082 +100,5083,5084 +100,5085,5086 +100,5087,5088 +129,5087,5088 +100,5089,5090 +131,5089,5090 +100,5091,5092 +100,5093,5094 +100,5095,5096 +233,5095,5096 +100,5097,5098 +100,5099,5100 +206,5099,5100 +100,5101,5102 +197,5101,5102 +100,5103,5104 +112,5103,5104 +100,5105,5106 +100,5107,5108 +100,5109,5110 +100,5111,5112 +147,5111,5112 +101,5113,5114 +167,5113,5114 +101,5115,5116 +178,5115,5116 +101,5117,5118 +101,5119,5120 +101,5121,5122 +136,5121,5122 +146,5121,5122 +101,5123,5124 +101,5125,5126 +101,5127,5128 +101,5129,5130 +134,5129,5130 +101,5131,5132 +160,5131,5132 +101,5133,5134 +101,5135,5136 +101,5137,5138 +101,5139,5140 +101,5141,5142 +101,5143,5144 +209,5143,5144 +101,5145,5146 +101,5147,5148 +101,5149,5150 +176,5149,5150 +101,5151,5152 +198,5151,5152 +102,5153,5154 +102,5155,5156 +177,5155,5156 +102,5157,5158 +177,5157,5158 +102,5159,5160 +102,5161,5162 +136,5161,5162 +156,5161,5162 +102,5163,5164 +102,5165,5166 +136,5165,5166 +102,5167,5168 +170,5167,5168 +102,5169,5170 +102,5171,5172 +137,5171,5172 +102,5173,5174 +102,5175,5176 +102,5177,5178 +182,5177,5178 +102,5179,5180 +102,5181,5182 +117,5181,5182 +102,5183,5184 +102,5185,5186 +102,5187,5188 +164,5187,5188 +102,5189,5190 +134,5189,5190 +102,5191,5192 +136,5191,5192 +103,5193,5194 +179,5193,5194 +233,5193,5194 +103,5195,5196 +103,5197,5198 +103,5199,5200 +125,5199,5200 +103,5201,5202 +151,5201,5202 +103,5203,5204 +103,5205,5206 +103,5207,5208 +154,5207,5208 +103,5209,5210 +103,5211,5212 +103,5213,5214 +126,5213,5214 +103,5215,5216 +103,5217,5218 +103,5219,5220 +103,5221,5222 +103,5223,5224 +127,5223,5224 +103,5225,5226 +214,5225,5226 +103,5227,5228 +194,5227,5228 +198,5227,5228 +103,5229,5230 +103,5231,5232 +104,5233,5234 +104,5235,5236 +185,5235,5236 +104,5237,5238 +104,5239,5240 +219,5239,5240 +104,5241,5242 +104,5243,5244 +228,5243,5244 +104,5245,5246 +167,5245,5246 +104,5247,5248 +135,5247,5248 +104,5249,5250 +192,5249,5250 +104,5251,5252 +104,5253,5254 +177,5253,5254 +104,5255,5256 +104,5257,5258 +104,5259,5260 +104,5261,5262 +117,5261,5262 +104,5263,5264 +138,5263,5264 +104,5265,5266 +184,5265,5266 +104,5267,5268 +104,5269,5270 +104,5271,5272 +227,5271,5272 +105,5273,5274 +105,5275,5276 +134,5275,5276 +105,5277,5278 +105,5279,5280 +105,5281,5282 +105,5283,5284 +105,5285,5286 +105,5287,5288 +105,5289,5290 +105,5291,5292 +105,5293,5294 +105,5295,5296 +105,5297,5298 +105,5299,5300 +159,5299,5300 +105,5301,5302 +172,5301,5302 +105,5303,5304 +138,5303,5304 +105,5305,5306 +105,5307,5308 +197,5307,5308 +199,5307,5308 +105,5309,5310 +105,5311,5312 +165,5311,5312 +204,5311,5312 +106,5313,5314 +213,5313,5314 +106,5315,5316 +106,5317,5318 +121,5317,5318 +229,5317,5318 +106,5319,5320 +106,5321,5322 +106,5323,5324 +106,5325,5326 +106,5327,5328 +106,5329,5330 +214,5329,5330 +106,5331,5332 +106,5333,5334 +175,5333,5334 +106,5335,5336 +220,5335,5336 +106,5337,5338 +106,5339,5340 +218,5339,5340 +106,5341,5342 +227,5341,5342 +106,5343,5344 +106,5345,5346 +106,5347,5348 +138,5347,5348 +106,5349,5350 +106,5351,5352 +134,5351,5352 +107,5353,5354 +222,5353,5354 +107,5355,5356 +107,5357,5358 +179,5357,5358 +107,5359,5360 +107,5361,5362 +107,5363,5364 +173,5363,5364 +107,5365,5366 +107,5367,5368 +141,5367,5368 +107,5369,5370 +107,5371,5372 +107,5373,5374 +123,5373,5374 +107,5375,5376 +153,5375,5376 +107,5377,5378 +107,5379,5380 +107,5381,5382 +107,5383,5384 +125,5383,5384 +201,5383,5384 +107,5385,5386 +107,5387,5388 +138,5387,5388 +107,5389,5390 +186,5389,5390 +107,5391,5392 +108,5393,5394 +165,5393,5394 +108,5395,5396 +108,5397,5398 +108,5399,5400 +233,5399,5400 +108,5401,5402 +133,5401,5402 +157,5401,5402 +108,5403,5404 +108,5405,5406 +137,5405,5406 +108,5407,5408 +133,5407,5408 +108,5409,5410 +129,5409,5410 +202,5409,5410 +108,5411,5412 +177,5411,5412 +108,5413,5414 +128,5413,5414 +108,5415,5416 +225,5415,5416 +108,5417,5418 +108,5419,5420 +108,5421,5422 +108,5423,5424 +108,5425,5426 +108,5427,5428 +108,5429,5430 +226,5429,5430 +108,5431,5432 +109,5433,5434 +109,5435,5436 +109,5437,5438 +109,5439,5440 +133,5439,5440 +224,5439,5440 +109,5441,5442 +184,5441,5442 +109,5443,5444 +109,5445,5446 +109,5447,5448 +109,5449,5450 +109,5451,5452 +109,5453,5454 +187,5453,5454 +109,5455,5456 +154,5455,5456 +109,5457,5458 +109,5459,5460 +133,5459,5460 +200,5459,5460 +109,5461,5462 +109,5463,5464 +109,5465,5466 +109,5467,5468 +109,5469,5470 +109,5471,5472 +166,5471,5472 +207,5471,5472 +110,5473,5474 +110,5475,5476 +110,5477,5478 +173,5477,5478 +187,5477,5478 +110,5479,5480 +154,5479,5480 +110,5481,5482 +110,5483,5484 +156,5483,5484 +110,5485,5486 +144,5485,5486 +110,5487,5488 +110,5489,5490 +194,5489,5490 +110,5491,5492 +110,5493,5494 +121,5493,5494 +110,5495,5496 +158,5495,5496 +185,5495,5496 +220,5495,5496 +110,5497,5498 +229,5497,5498 +110,5499,5500 +180,5499,5500 +110,5501,5502 +223,5501,5502 +110,5503,5504 +133,5503,5504 +169,5503,5504 +110,5505,5506 +183,5505,5506 +110,5507,5508 +110,5509,5510 +152,5509,5510 +110,5511,5512 +188,5511,5512 +111,5513,5514 +111,5515,5516 +228,5515,5516 +111,5517,5518 +111,5519,5520 +111,5521,5522 +144,5521,5522 +111,5523,5524 +157,5523,5524 +111,5525,5526 +154,5525,5526 +111,5527,5528 +207,5527,5528 +111,5529,5530 +147,5529,5530 +111,5531,5532 +111,5533,5534 +133,5533,5534 +111,5535,5536 +111,5537,5538 +123,5537,5538 +111,5539,5540 +111,5541,5542 +126,5541,5542 +111,5543,5544 +111,5545,5546 +111,5547,5548 +111,5549,5550 +137,5549,5550 +111,5551,5552 +135,5551,5552 +144,5551,5552 +112,5555,5556 +204,5555,5556 +210,5555,5556 +112,5557,5558 +150,5557,5558 +112,5559,5560 +189,5559,5560 +226,5559,5560 +112,5561,5562 +112,5563,5564 +129,5563,5564 +112,5565,5566 +184,5565,5566 +112,5567,5568 +213,5567,5568 +112,5569,5570 +112,5571,5572 +194,5571,5572 +112,5573,5574 +204,5573,5574 +112,5575,5576 +112,5577,5578 +112,5579,5580 +112,5581,5582 +189,5581,5582 +198,5581,5582 +112,5583,5584 +112,5585,5586 +112,5587,5588 +112,5589,5590 +112,5591,5592 +137,5591,5592 +112,5593,5594 +176,5593,5594 +113,5595,5596 +113,5597,5598 +210,5597,5598 +223,5597,5598 +113,5599,5600 +113,5601,5602 +113,5603,5604 +113,5605,5606 +113,5607,5608 +140,5607,5608 +113,5609,5610 +164,5609,5610 +113,5611,5612 +113,5613,5614 +196,5613,5614 +113,5615,5616 +113,5617,5618 +181,5617,5618 +113,5619,5620 +174,5619,5620 +113,5621,5622 +113,5623,5624 +113,5625,5626 +130,5625,5626 +192,5625,5626 +205,5625,5626 +113,5627,5628 +139,5627,5628 +113,5629,5630 +136,5629,5630 +113,5631,5632 +113,5633,5634 +141,5633,5634 +184,5633,5634 +114,5635,5636 +114,5637,5638 +114,5639,5640 +114,5641,5642 +159,5641,5642 +114,5643,5644 +183,5643,5644 +217,5643,5644 +114,5645,5646 +131,5645,5646 +114,5647,5648 +114,5649,5650 +212,5649,5650 +114,5651,5652 +114,5653,5654 +114,5655,5656 +114,5657,5658 +114,5659,5660 +142,5659,5660 +231,5659,5660 +114,5661,5662 +114,5663,5664 +114,5665,5666 +114,5667,5668 +114,5669,5670 +233,5669,5670 +114,5671,5672 +114,5673,5674 +115,5675,5676 +115,5677,5678 +115,5679,5680 +115,5681,5682 +115,5683,5684 +115,5685,5686 +115,5687,5688 +115,5689,5690 +115,5691,5692 +190,5691,5692 +115,5693,5694 +115,5695,5696 +131,5695,5696 +115,5697,5698 +115,5699,5700 +115,5701,5702 +215,5701,5702 +115,5703,5704 +115,5705,5706 +115,5707,5708 +137,5707,5708 +115,5709,5710 +115,5711,5712 +115,5713,5714 +116,5715,5716 +116,5717,5718 +116,5719,5720 +116,5721,5722 +116,5723,5724 +116,5725,5726 +129,5725,5726 +116,5727,5728 +189,5727,5728 +116,5729,5730 +116,5731,5732 +174,5731,5732 +116,5733,5734 +214,5733,5734 +116,5735,5736 +160,5735,5736 +116,5737,5738 +116,5739,5740 +157,5739,5740 +189,5739,5740 +116,5741,5742 +216,5741,5742 +116,5743,5744 +116,5745,5746 +116,5747,5748 +116,5749,5750 +116,5751,5752 +116,5753,5754 +117,5755,5756 +117,5757,5758 +117,5759,5760 +117,5761,5762 +117,5763,5764 +117,5765,5766 +117,5767,5768 +117,5769,5770 +117,5771,5772 +117,5773,5774 +117,5775,5776 +117,5777,5778 +117,5779,5780 +117,5781,5782 +117,5783,5784 +117,5785,5786 +207,5785,5786 +117,5787,5788 +117,5789,5790 +117,5791,5792 +171,5791,5792 +117,5793,5794 +118,5795,5796 +180,5795,5796 +118,5797,5798 +169,5797,5798 +118,5799,5800 +118,5801,5802 +118,5803,5804 +118,5805,5806 +118,5807,5808 +118,5809,5810 +118,5811,5812 +154,5811,5812 +118,5813,5814 +118,5815,5816 +118,5817,5818 +118,5819,5820 +118,5821,5822 +208,5821,5822 +118,5823,5824 +118,5825,5826 +118,5827,5828 +157,5827,5828 +118,5829,5830 +118,5831,5832 +118,5833,5834 +119,5835,5836 +119,5837,5838 +119,5839,5840 +119,5841,5842 +203,5841,5842 +119,5843,5844 +168,5843,5844 +119,5845,5846 +119,5847,5848 +167,5847,5848 +119,5849,5850 +119,5851,5852 +119,5853,5854 +183,5853,5854 +119,5855,5856 +190,5855,5856 +200,5855,5856 +221,5855,5856 +119,5857,5858 +208,5857,5858 +119,5859,5860 +119,5861,5862 +222,5861,5862 +119,5863,5864 +119,5865,5866 +119,5867,5868 +185,5867,5868 +119,5869,5870 +141,5869,5870 +189,5869,5870 +119,5871,5872 +227,5871,5872 +119,5873,5874 +120,5875,5876 +120,5877,5878 +180,5877,5878 +120,5879,5880 +120,5881,5882 +201,5881,5882 +217,5881,5882 +120,5883,5884 +120,5885,5886 +120,5887,5888 +120,5889,5890 +169,5889,5890 +196,5889,5890 +120,5891,5892 +120,5893,5894 +120,5895,5896 +196,5895,5896 +198,5895,5896 +120,5897,5898 +120,5899,5900 +120,5901,5902 +120,5903,5904 +120,5905,5906 +134,5905,5906 +120,5907,5908 +135,5907,5908 +120,5909,5910 +183,5909,5910 +120,5911,5912 +120,5913,5914 +121,5915,5916 +180,5915,5916 +121,5917,5918 +121,5919,5920 +121,5921,5922 +201,5921,5922 +121,5923,5924 +121,5925,5926 +121,5927,5928 +121,5929,5930 +201,5929,5930 +121,5931,5932 +121,5933,5934 +121,5935,5936 +121,5937,5938 +121,5939,5940 +224,5939,5940 +121,5941,5942 +139,5941,5942 +121,5943,5944 +121,5945,5946 +121,5947,5948 +121,5949,5950 +190,5949,5950 +121,5951,5952 +121,5953,5954 +122,5955,5956 +122,5957,5958 +122,5959,5960 +122,5961,5962 +182,5961,5962 +122,5963,5964 +174,5963,5964 +233,5963,5964 +122,5965,5966 +122,5967,5968 +122,5969,5970 +122,5971,5972 +173,5971,5972 +122,5973,5974 +122,5975,5976 +122,5977,5978 +122,5979,5980 +122,5981,5982 +168,5981,5982 +122,5983,5984 +122,5985,5986 +174,5985,5986 +122,5987,5988 +181,5987,5988 +122,5989,5990 +122,5991,5992 +122,5993,5994 +123,5995,5996 +123,5997,5998 +123,5999,6000 +157,5999,6000 +123,6001,6002 +197,6001,6002 +123,6003,6004 +123,6005,6006 +123,6007,6008 +123,6009,6010 +123,6011,6012 +157,6011,6012 +194,6011,6012 +123,6013,6014 +123,6015,6016 +188,6015,6016 +123,6017,6018 +168,6017,6018 +123,6019,6020 +123,6021,6022 +181,6021,6022 +125,6035,6036 +125,6037,6038 +125,6039,6040 +125,6041,6042 +146,6041,6042 +125,6043,6044 +125,6045,6046 +125,6047,6048 +125,6049,6050 +125,6051,6052 +125,6053,6054 +125,6055,6056 +139,6055,6056 +125,6057,6058 +125,6059,6060 +152,6059,6060 +125,6061,6062 +126,6075,6076 +126,6077,6078 +126,6079,6080 +126,6081,6082 +126,6083,6084 +186,6083,6084 +126,6085,6086 +226,6085,6086 +126,6087,6088 +126,6089,6090 +194,6089,6090 +126,6091,6092 +215,6091,6092 +126,6093,6094 +126,6095,6096 +126,6097,6098 +175,6097,6098 +126,6099,6100 +147,6099,6100 +126,6101,6102 +127,6115,6116 +127,6117,6118 +127,6119,6120 +194,6119,6120 +199,6119,6120 +207,6119,6120 +127,6121,6122 +179,6121,6122 +127,6123,6124 +189,6123,6124 +127,6125,6126 +127,6127,6128 +127,6129,6130 +127,6131,6132 +127,6133,6134 +202,6133,6134 +127,6135,6136 +193,6135,6136 +198,6135,6136 +226,6135,6136 +127,6137,6138 +127,6139,6140 +127,6141,6142 +167,6141,6142 +128,6143,6144 +147,6143,6144 +128,6145,6146 +165,6145,6146 +128,6147,6148 +178,6147,6148 +128,6149,6150 +128,6151,6152 +183,6151,6152 +128,6153,6154 +128,6155,6156 +224,6155,6156 +128,6157,6158 +128,6159,6160 +128,6161,6162 +128,6163,6164 +128,6165,6166 +220,6165,6166 +128,6167,6168 +128,6169,6170 +129,6171,6172 +129,6173,6174 +129,6175,6176 +179,6175,6176 +129,6177,6178 +144,6177,6178 +129,6179,6180 +129,6181,6182 +171,6181,6182 +129,6183,6184 +129,6185,6186 +129,6187,6188 +129,6189,6190 +129,6191,6192 +163,6191,6192 +129,6193,6194 +188,6193,6194 +129,6195,6196 +129,6197,6198 +182,6197,6198 +130,6199,6200 +130,6201,6202 +130,6203,6204 +130,6205,6206 +130,6207,6208 +130,6209,6210 +206,6209,6210 +130,6211,6212 +130,6213,6214 +130,6215,6216 +202,6215,6216 +130,6217,6218 +130,6219,6220 +130,6221,6222 +130,6223,6224 +130,6225,6226 +131,6227,6228 +217,6227,6228 +131,6229,6230 +131,6231,6232 +131,6233,6234 +139,6233,6234 +157,6233,6234 +131,6235,6236 +147,6235,6236 +131,6237,6238 +131,6239,6240 +131,6241,6242 +131,6243,6244 +139,6243,6244 +155,6243,6244 +131,6245,6246 +131,6247,6248 +131,6249,6250 +131,6251,6252 +188,6251,6252 +131,6253,6254 +132,6255,6256 +132,6257,6258 +132,6259,6260 +132,6261,6262 +144,6261,6262 +132,6263,6264 +132,6265,6266 +132,6267,6268 +148,6267,6268 +197,6267,6268 +132,6269,6270 +132,6271,6272 +132,6273,6274 +132,6275,6276 +132,6277,6278 +171,6277,6278 +132,6279,6280 +132,6281,6282 +133,6283,6284 +137,6283,6284 +133,6285,6286 +133,6287,6288 +133,6289,6290 +133,6291,6292 +133,6293,6294 +133,6295,6296 +133,6297,6298 +179,6297,6298 +133,6299,6300 +133,6301,6302 +133,6303,6304 +133,6305,6306 +133,6307,6308 +133,6309,6310 +134,6311,6312 +134,6313,6314 +134,6315,6316 +159,6315,6316 +134,6317,6318 +134,6319,6320 +134,6321,6322 +134,6323,6324 +134,6325,6326 +134,6327,6328 +134,6329,6330 +134,6331,6332 +218,6331,6332 +134,6333,6334 +134,6335,6336 +134,6337,6338 +135,6339,6340 +135,6341,6342 +155,6341,6342 +135,6343,6344 +177,6343,6344 +135,6345,6346 +135,6347,6348 +145,6347,6348 +135,6349,6350 +135,6351,6352 +162,6351,6352 +135,6353,6354 +135,6355,6356 +135,6357,6358 +214,6357,6358 +135,6359,6360 +135,6361,6362 +135,6363,6364 +135,6365,6366 +136,6367,6368 +136,6369,6370 +136,6371,6372 +170,6371,6372 +136,6373,6374 +136,6375,6376 +136,6377,6378 +136,6379,6380 +136,6381,6382 +136,6383,6384 +136,6385,6386 +162,6385,6386 +136,6387,6388 +136,6389,6390 +136,6391,6392 +136,6393,6394 +137,6395,6396 +150,6395,6396 +137,6397,6398 +195,6397,6398 +232,6397,6398 +137,6399,6400 +153,6399,6400 +137,6401,6402 +175,6401,6402 +211,6401,6402 +137,6403,6404 +219,6403,6404 +137,6405,6406 +137,6407,6408 +157,6407,6408 +137,6409,6410 +137,6411,6412 +219,6411,6412 +137,6413,6414 +137,6415,6416 +223,6415,6416 +137,6417,6418 +137,6419,6420 +137,6421,6422 +138,6423,6424 +138,6425,6426 +179,6425,6426 +138,6427,6428 +138,6429,6430 +138,6431,6432 +138,6433,6434 +138,6435,6436 +206,6435,6436 +138,6437,6438 +138,6439,6440 +183,6439,6440 +138,6441,6442 +138,6443,6444 +138,6445,6446 +138,6447,6448 +138,6449,6450 +139,6451,6452 +218,6451,6452 +139,6453,6454 +216,6453,6454 +139,6455,6456 +139,6457,6458 +139,6459,6460 +139,6461,6462 +139,6463,6464 +139,6465,6466 +193,6465,6466 +199,6465,6466 +139,6467,6468 +139,6469,6470 +139,6471,6472 +139,6473,6474 +139,6475,6476 +139,6477,6478 +140,6479,6480 +204,6479,6480 +140,6481,6482 +140,6483,6484 +140,6485,6486 +151,6485,6486 +140,6487,6488 +140,6489,6490 +182,6489,6490 +140,6491,6492 +205,6491,6492 +140,6493,6494 +140,6495,6496 +185,6495,6496 +140,6497,6498 +140,6499,6500 +140,6501,6502 +140,6503,6504 +140,6505,6506 +141,6507,6508 +141,6509,6510 +141,6511,6512 +141,6513,6514 +141,6515,6516 +232,6515,6516 +141,6517,6518 +141,6519,6520 +141,6521,6522 +141,6523,6524 +141,6525,6526 +210,6525,6526 +141,6527,6528 +141,6529,6530 +141,6531,6532 +195,6531,6532 +141,6533,6534 +230,6533,6534 +142,6535,6536 +192,6535,6536 +142,6537,6538 +142,6539,6540 +224,6539,6540 +142,6541,6542 +142,6543,6544 +160,6543,6544 +142,6545,6546 +142,6547,6548 +142,6549,6550 +221,6549,6550 +142,6551,6552 +142,6553,6554 +231,6553,6554 +142,6555,6556 +142,6557,6558 +142,6559,6560 +167,6559,6560 +142,6561,6562 +178,6561,6562 +144,6563,6564 +144,6565,6566 +144,6567,6568 +176,6567,6568 +144,6569,6570 +144,6571,6572 +144,6573,6574 +144,6575,6576 +144,6577,6578 +144,6579,6580 +144,6581,6582 +144,6583,6584 +144,6585,6586 +144,6587,6588 +144,6589,6590 +163,6589,6590 +145,6591,6592 +208,6591,6592 +145,6593,6594 +145,6595,6596 +145,6597,6598 +145,6599,6600 +156,6599,6600 +145,6601,6602 +145,6603,6604 +218,6603,6604 +145,6605,6606 +145,6607,6608 +145,6609,6610 +145,6611,6612 +145,6613,6614 +145,6615,6616 +178,6615,6616 +232,6615,6616 +145,6617,6618 +193,6617,6618 +222,6617,6618 +146,6619,6620 +180,6619,6620 +146,6621,6622 +146,6623,6624 +146,6625,6626 +146,6627,6628 +146,6629,6630 +146,6631,6632 +146,6633,6634 +146,6635,6636 +146,6637,6638 +171,6637,6638 +208,6637,6638 +146,6639,6640 +146,6641,6642 +146,6643,6644 +146,6645,6646 +147,6647,6648 +147,6649,6650 +195,6649,6650 +147,6651,6652 +147,6653,6654 +172,6653,6654 +147,6655,6656 +172,6655,6656 +147,6657,6658 +147,6659,6660 +166,6659,6660 +147,6661,6662 +147,6663,6664 +147,6665,6666 +147,6667,6668 +147,6669,6670 +147,6671,6672 +147,6673,6674 +148,6675,6676 +148,6677,6678 +170,6677,6678 +148,6679,6680 +148,6681,6682 +180,6681,6682 +148,6683,6684 +148,6685,6686 +148,6687,6688 +148,6689,6690 +202,6689,6690 +148,6691,6692 +148,6693,6694 +148,6695,6696 +148,6697,6698 +148,6699,6700 +148,6701,6702 +149,6703,6704 +149,6705,6706 +149,6707,6708 +149,6709,6710 +149,6711,6712 +149,6713,6714 +149,6715,6716 +204,6715,6716 +149,6717,6718 +149,6719,6720 +149,6721,6722 +149,6723,6724 +149,6725,6726 +186,6725,6726 +149,6727,6728 +149,6729,6730 +150,6731,6732 +150,6733,6734 +150,6735,6736 +222,6735,6736 +150,6737,6738 +150,6739,6740 +184,6739,6740 +150,6741,6742 +211,6741,6742 +150,6743,6744 +221,6743,6744 +150,6745,6746 +150,6747,6748 +222,6747,6748 +150,6749,6750 +187,6749,6750 +150,6751,6752 +150,6753,6754 +150,6755,6756 +150,6757,6758 +151,6759,6760 +151,6761,6762 +162,6761,6762 +151,6763,6764 +151,6765,6766 +151,6767,6768 +151,6769,6770 +151,6771,6772 +172,6771,6772 +151,6773,6774 +151,6775,6776 +151,6777,6778 +151,6779,6780 +151,6781,6782 +151,6783,6784 +175,6783,6784 +151,6785,6786 +204,6785,6786 +152,6787,6788 +152,6789,6790 +197,6789,6790 +152,6791,6792 +152,6793,6794 +152,6795,6796 +166,6795,6796 +152,6797,6798 +152,6799,6800 +213,6799,6800 +152,6801,6802 +214,6801,6802 +152,6803,6804 +162,6803,6804 +152,6805,6806 +152,6807,6808 +152,6809,6810 +212,6809,6810 +152,6811,6812 +162,6811,6812 +225,6811,6812 +152,6813,6814 +153,6815,6816 +153,6817,6818 +153,6819,6820 +153,6821,6822 +177,6821,6822 +153,6823,6824 +153,6825,6826 +153,6827,6828 +153,6829,6830 +188,6829,6830 +153,6831,6832 +153,6833,6834 +153,6835,6836 +153,6837,6838 +153,6839,6840 +153,6841,6842 +212,6841,6842 +154,6843,6844 +221,6843,6844 +154,6845,6846 +180,6845,6846 +154,6847,6848 +154,6849,6850 +154,6851,6852 +154,6853,6854 +154,6855,6856 +154,6857,6858 +154,6859,6860 +154,6861,6862 +154,6863,6864 +154,6865,6866 +189,6865,6866 +154,6867,6868 +154,6869,6870 +155,6871,6872 +155,6873,6874 +188,6873,6874 +155,6875,6876 +155,6877,6878 +155,6879,6880 +155,6881,6882 +155,6883,6884 +155,6885,6886 +155,6887,6888 +155,6889,6890 +155,6891,6892 +155,6893,6894 +155,6895,6896 +172,6895,6896 +155,6897,6898 +212,6897,6898 +228,6897,6898 +156,6899,6900 +156,6901,6902 +156,6903,6904 +156,6905,6906 +176,6905,6906 +156,6907,6908 +156,6909,6910 +156,6911,6912 +156,6913,6914 +156,6915,6916 +156,6917,6918 +214,6917,6918 +156,6919,6920 +156,6921,6922 +220,6921,6922 +156,6923,6924 +156,6925,6926 +157,6927,6928 +157,6929,6930 +173,6929,6930 +157,6931,6932 +157,6933,6934 +157,6935,6936 +157,6937,6938 +157,6939,6940 +157,6941,6942 +232,6941,6942 +157,6943,6944 +157,6945,6946 +157,6947,6948 +157,6949,6950 +157,6951,6952 +157,6953,6954 +158,6955,6956 +210,6955,6956 +158,6957,6958 +158,6959,6960 +158,6961,6962 +158,6963,6964 +158,6965,6966 +158,6967,6968 +158,6969,6970 +158,6971,6972 +158,6973,6974 +222,6973,6974 +158,6975,6976 +158,6977,6978 +158,6979,6980 +158,6981,6982 +159,6983,6984 +159,6985,6986 +159,6987,6988 +176,6987,6988 +159,6989,6990 +159,6991,6992 +159,6993,6994 +195,6993,6994 +159,6995,6996 +159,6997,6998 +159,6999,7000 +159,7001,7002 +159,7003,7004 +159,7005,7006 +183,7005,7006 +159,7007,7008 +199,7007,7008 +159,7009,7010 +170,7009,7010 +198,7009,7010 +160,7011,7012 +160,7013,7014 +160,7015,7016 +160,7017,7018 +160,7019,7020 +160,7021,7022 +160,7023,7024 +160,7025,7026 +160,7027,7028 +160,7029,7030 +217,7029,7030 +160,7031,7032 +160,7033,7034 +160,7035,7036 +187,7035,7036 +160,7037,7038 +161,7039,7040 +161,7041,7042 +231,7041,7042 +161,7043,7044 +179,7043,7044 +161,7045,7046 +161,7047,7048 +161,7049,7050 +161,7051,7052 +161,7053,7054 +195,7053,7054 +161,7055,7056 +161,7057,7058 +161,7059,7060 +161,7061,7062 +191,7061,7062 +161,7063,7064 +161,7065,7066 +162,7067,7068 +162,7069,7070 +231,7069,7070 +162,7071,7072 +162,7073,7074 +162,7075,7076 +162,7077,7078 +162,7079,7080 +228,7079,7080 +162,7081,7082 +195,7081,7082 +162,7083,7084 +162,7085,7086 +223,7085,7086 +162,7087,7088 +162,7089,7090 +162,7091,7092 +162,7093,7094 +163,7095,7096 +163,7097,7098 +163,7099,7100 +230,7099,7100 +163,7101,7102 +163,7103,7104 +163,7105,7106 +163,7107,7108 +163,7109,7110 +201,7109,7110 +163,7111,7112 +163,7113,7114 +190,7113,7114 +163,7115,7116 +163,7117,7118 +163,7119,7120 +163,7121,7122 +164,7123,7124 +164,7125,7126 +164,7127,7128 +164,7129,7130 +186,7129,7130 +164,7131,7132 +164,7133,7134 +164,7135,7136 +164,7137,7138 +196,7137,7138 +164,7139,7140 +223,7139,7140 +164,7141,7142 +164,7143,7144 +164,7145,7146 +164,7147,7148 +164,7149,7150 +165,7151,7152 +165,7153,7154 +165,7155,7156 +196,7155,7156 +165,7157,7158 +165,7159,7160 +165,7161,7162 +165,7163,7164 +165,7165,7166 +165,7167,7168 +165,7169,7170 +165,7171,7172 +165,7173,7174 +165,7175,7176 +165,7177,7178 +166,7179,7180 +166,7181,7182 +166,7183,7184 +166,7185,7186 +166,7187,7188 +166,7189,7190 +166,7191,7192 +166,7193,7194 +166,7195,7196 +166,7197,7198 +166,7199,7200 +166,7201,7202 +166,7203,7204 +166,7205,7206 +167,7207,7208 +167,7209,7210 +167,7211,7212 +167,7213,7214 +167,7215,7216 +206,7215,7216 +167,7217,7218 +167,7219,7220 +167,7221,7222 +167,7223,7224 +167,7225,7226 +167,7227,7228 +167,7229,7230 +167,7231,7232 +167,7233,7234 +192,7233,7234 +168,7235,7236 +168,7237,7238 +168,7239,7240 +168,7241,7242 +168,7243,7244 +168,7245,7246 +168,7247,7248 +168,7249,7250 +168,7251,7252 +168,7253,7254 +168,7255,7256 +168,7257,7258 +168,7259,7260 +168,7261,7262 +169,7263,7264 +169,7265,7266 +169,7267,7268 +169,7269,7270 +169,7271,7272 +184,7271,7272 +169,7273,7274 +169,7275,7276 +169,7277,7278 +169,7279,7280 +169,7281,7282 +169,7283,7284 +169,7285,7286 +169,7287,7288 +169,7289,7290 +200,7289,7290 +170,7291,7292 +170,7293,7294 +170,7295,7296 +170,7297,7298 +170,7299,7300 +170,7301,7302 +170,7303,7304 +170,7305,7306 +170,7307,7308 +170,7309,7310 +170,7311,7312 +170,7313,7314 +170,7315,7316 +170,7317,7318 +171,7319,7320 +171,7321,7322 +171,7323,7324 +171,7325,7326 +171,7327,7328 +171,7329,7330 +171,7331,7332 +200,7331,7332 +171,7333,7334 +171,7335,7336 +171,7337,7338 +171,7339,7340 +171,7341,7342 +190,7341,7342 +171,7343,7344 +171,7345,7346 +172,7347,7348 +199,7347,7348 +172,7349,7350 +172,7351,7352 +172,7353,7354 +172,7355,7356 +227,7355,7356 +172,7357,7358 +172,7359,7360 +172,7361,7362 +172,7363,7364 +172,7365,7366 +172,7367,7368 +172,7369,7370 +172,7371,7372 +172,7373,7374 +173,7375,7376 +173,7377,7378 +173,7379,7380 +209,7379,7380 +211,7379,7380 +173,7381,7382 +173,7383,7384 +173,7385,7386 +227,7385,7386 +173,7387,7388 +173,7389,7390 +173,7391,7392 +173,7393,7394 +173,7395,7396 +211,7395,7396 +173,7397,7398 +173,7399,7400 +173,7401,7402 +232,7401,7402 +174,7403,7404 +174,7405,7406 +174,7407,7408 +174,7409,7410 +174,7411,7412 +174,7413,7414 +174,7415,7416 +174,7417,7418 +174,7419,7420 +174,7421,7422 +174,7423,7424 +174,7425,7426 +174,7427,7428 +174,7429,7430 +175,7431,7432 +175,7433,7434 +209,7433,7434 +175,7435,7436 +175,7437,7438 +175,7439,7440 +175,7441,7442 +175,7443,7444 +175,7445,7446 +175,7447,7448 +175,7449,7450 +175,7451,7452 +175,7453,7454 +175,7455,7456 +175,7457,7458 +232,7457,7458 +176,7459,7460 +176,7461,7462 +176,7463,7464 +176,7465,7466 +176,7467,7468 +176,7469,7470 +176,7471,7472 +176,7473,7474 +176,7475,7476 +176,7477,7478 +176,7479,7480 +176,7481,7482 +176,7483,7484 +176,7485,7486 +177,7487,7488 +177,7489,7490 +204,7489,7490 +177,7491,7492 +186,7491,7492 +177,7493,7494 +177,7495,7496 +177,7497,7498 +177,7499,7500 +177,7501,7502 +177,7503,7504 +177,7505,7506 +177,7507,7508 +177,7509,7510 +177,7511,7512 +177,7513,7514 +178,7515,7516 +178,7517,7518 +178,7519,7520 +178,7521,7522 +178,7523,7524 +178,7525,7526 +178,7527,7528 +178,7529,7530 +178,7531,7532 +178,7533,7534 +178,7535,7536 +203,7535,7536 +178,7537,7538 +178,7539,7540 +178,7541,7542 +209,7541,7542 +179,7543,7544 +179,7545,7546 +179,7547,7548 +179,7549,7550 +179,7551,7552 +179,7553,7554 +179,7555,7556 +209,7555,7556 +179,7557,7558 +179,7559,7560 +179,7561,7562 +179,7563,7564 +179,7565,7566 +179,7567,7568 +179,7569,7570 +180,7571,7572 +180,7573,7574 +180,7575,7576 +180,7577,7578 +180,7579,7580 +180,7581,7582 +180,7583,7584 +180,7585,7586 +180,7587,7588 +180,7589,7590 +180,7591,7592 +180,7593,7594 +180,7595,7596 +180,7597,7598 +181,7599,7600 +181,7601,7602 +181,7603,7604 +181,7605,7606 +181,7607,7608 +181,7609,7610 +215,7609,7610 +181,7611,7612 +181,7613,7614 +181,7615,7616 +219,7615,7616 +181,7617,7618 +181,7619,7620 +181,7621,7622 +181,7623,7624 +181,7625,7626 +182,7627,7628 +182,7629,7630 +182,7631,7632 +182,7633,7634 +202,7633,7634 +182,7635,7636 +182,7637,7638 +182,7639,7640 +182,7641,7642 +182,7643,7644 +182,7645,7646 +194,7645,7646 +182,7647,7648 +182,7649,7650 +182,7651,7652 +182,7653,7654 +183,7655,7656 +183,7657,7658 +183,7659,7660 +183,7661,7662 +183,7663,7664 +183,7665,7666 +183,7667,7668 +183,7669,7670 +183,7671,7672 +183,7673,7674 +193,7673,7674 +183,7675,7676 +183,7677,7678 +183,7679,7680 +183,7681,7682 +184,7683,7684 +184,7685,7686 +184,7687,7688 +184,7689,7690 +184,7691,7692 +184,7693,7694 +184,7695,7696 +184,7697,7698 +184,7699,7700 +184,7701,7702 +184,7703,7704 +184,7705,7706 +184,7707,7708 +184,7709,7710 +185,7711,7712 +212,7711,7712 +185,7713,7714 +185,7715,7716 +185,7717,7718 +185,7719,7720 +185,7721,7722 +185,7723,7724 +185,7725,7726 +185,7727,7728 +185,7729,7730 +185,7731,7732 +185,7733,7734 +185,7735,7736 +185,7737,7738 +186,7739,7740 +186,7741,7742 +186,7743,7744 +186,7745,7746 +186,7747,7748 +186,7749,7750 +186,7751,7752 +186,7753,7754 +186,7755,7756 +186,7757,7758 +186,7759,7760 +186,7761,7762 +186,7763,7764 +186,7765,7766 +187,7767,7768 +187,7769,7770 +187,7771,7772 +187,7773,7774 +187,7775,7776 +187,7777,7778 +187,7779,7780 +187,7781,7782 +187,7783,7784 +187,7785,7786 +187,7787,7788 +187,7789,7790 +187,7791,7792 +187,7793,7794 +188,7795,7796 +188,7797,7798 +188,7799,7800 +188,7801,7802 +188,7803,7804 +188,7805,7806 +188,7807,7808 +188,7809,7810 +188,7811,7812 +188,7813,7814 +189,7815,7816 +189,7817,7818 +189,7819,7820 +189,7821,7822 +189,7823,7824 +189,7825,7826 +189,7827,7828 +189,7829,7830 +189,7831,7832 +225,7831,7832 +189,7833,7834 +190,7835,7836 +190,7837,7838 +190,7839,7840 +190,7841,7842 +190,7843,7844 +190,7845,7846 +190,7847,7848 +190,7849,7850 +190,7851,7852 +190,7853,7854 +191,7855,7856 +191,7857,7858 +224,7857,7858 +191,7859,7860 +191,7861,7862 +191,7863,7864 +191,7865,7866 +191,7867,7868 +191,7869,7870 +191,7871,7872 +191,7873,7874 +192,7875,7876 +192,7877,7878 +192,7879,7880 +192,7881,7882 +192,7883,7884 +192,7885,7886 +192,7887,7888 +192,7889,7890 +192,7891,7892 +192,7893,7894 +214,7893,7894 +193,7895,7896 +193,7897,7898 +193,7899,7900 +193,7901,7902 +193,7903,7904 +193,7905,7906 +193,7907,7908 +193,7909,7910 +193,7911,7912 +193,7913,7914 +194,7915,7916 +194,7917,7918 +194,7919,7920 +194,7921,7922 +194,7923,7924 +194,7925,7926 +194,7927,7928 +194,7929,7930 +194,7931,7932 +194,7933,7934 +195,7935,7936 +195,7937,7938 +195,7939,7940 +195,7941,7942 +205,7941,7942 +195,7943,7944 +195,7945,7946 +195,7947,7948 +195,7949,7950 +195,7951,7952 +230,7951,7952 +195,7953,7954 +196,7955,7956 +196,7957,7958 +196,7959,7960 +196,7961,7962 +196,7963,7964 +196,7965,7966 +196,7967,7968 +196,7969,7970 +196,7971,7972 +196,7973,7974 +197,7975,7976 +221,7975,7976 +197,7977,7978 +197,7979,7980 +197,7981,7982 +197,7983,7984 +197,7985,7986 +197,7987,7988 +197,7989,7990 +197,7991,7992 +197,7993,7994 +198,7995,7996 +198,7997,7998 +198,7999,8000 +198,8001,8002 +198,8003,8004 +198,8005,8006 +198,8007,8008 +198,8009,8010 +198,8011,8012 +198,8013,8014 +223,8013,8014 +199,8015,8016 +199,8017,8018 +199,8019,8020 +199,8021,8022 +199,8023,8024 +199,8025,8026 +199,8027,8028 +199,8029,8030 +199,8031,8032 +199,8033,8034 +200,8035,8036 +200,8037,8038 +200,8039,8040 +200,8041,8042 +200,8043,8044 +200,8045,8046 +200,8047,8048 +200,8049,8050 +200,8051,8052 +200,8053,8054 +201,8055,8056 +201,8057,8058 +201,8059,8060 +201,8061,8062 +201,8063,8064 +201,8065,8066 +201,8067,8068 +201,8069,8070 +201,8071,8072 +201,8073,8074 +202,8075,8076 +202,8077,8078 +202,8079,8080 +202,8081,8082 +202,8083,8084 +202,8085,8086 +202,8087,8088 +222,8087,8088 +202,8089,8090 +202,8091,8092 +202,8093,8094 +224,8093,8094 +203,8095,8096 +203,8097,8098 +203,8099,8100 +203,8101,8102 +203,8103,8104 +203,8105,8106 +203,8107,8108 +203,8109,8110 +203,8111,8112 +203,8113,8114 +204,8115,8116 +204,8117,8118 +204,8119,8120 +204,8121,8122 +204,8123,8124 +204,8125,8126 +204,8127,8128 +204,8129,8130 +204,8131,8132 +204,8133,8134 +205,8135,8136 +205,8137,8138 +205,8139,8140 +205,8141,8142 +205,8143,8144 +205,8145,8146 +205,8147,8148 +205,8149,8150 +205,8151,8152 +205,8153,8154 +206,8155,8156 +206,8157,8158 +206,8159,8160 +206,8161,8162 +206,8163,8164 +206,8165,8166 +206,8167,8168 +206,8169,8170 +206,8171,8172 +206,8173,8174 +207,8177,8178 +207,8179,8180 +207,8181,8182 +207,8183,8184 +207,8185,8186 +207,8187,8188 +207,8189,8190 +207,8191,8192 +207,8193,8194 +207,8195,8196 +208,8197,8198 +208,8199,8200 +208,8201,8202 +208,8203,8204 +208,8205,8206 +208,8207,8208 +208,8209,8210 +208,8211,8212 +208,8213,8214 +208,8215,8216 +209,8217,8218 +233,8217,8218 +209,8219,8220 +209,8221,8222 +209,8223,8224 +209,8225,8226 +209,8227,8228 +209,8229,8230 +209,8231,8232 +209,8233,8234 +209,8235,8236 +210,8237,8238 +210,8239,8240 +210,8241,8242 +210,8243,8244 +210,8245,8246 +210,8247,8248 +210,8249,8250 +210,8251,8252 +210,8253,8254 +210,8255,8256 +211,8257,8258 +211,8259,8260 +211,8261,8262 +211,8263,8264 +211,8265,8266 +211,8267,8268 +211,8269,8270 +211,8271,8272 +211,8273,8274 +211,8275,8276 +212,8277,8278 +212,8279,8280 +212,8281,8282 +212,8283,8284 +212,8285,8286 +212,8287,8288 +212,8289,8290 +212,8291,8292 +212,8293,8294 +212,8295,8296 +213,8297,8298 +213,8299,8300 +213,8301,8302 +213,8303,8304 +213,8305,8306 +213,8307,8308 +213,8309,8310 +213,8311,8312 +213,8313,8314 +213,8315,8316 +214,8317,8318 +214,8319,8320 +214,8321,8322 +214,8323,8324 +214,8325,8326 +214,8327,8328 +214,8329,8330 +214,8331,8332 +214,8333,8334 +214,8335,8336 +215,8337,8338 +215,8339,8340 +215,8341,8342 +215,8343,8344 +215,8345,8346 +215,8347,8348 +215,8349,8350 +215,8351,8352 +215,8353,8354 +215,8355,8356 +216,8357,8358 +216,8359,8360 +216,8361,8362 +216,8363,8364 +216,8365,8366 +216,8367,8368 +216,8369,8370 +216,8371,8372 +216,8373,8374 +216,8375,8376 +217,8377,8378 +217,8379,8380 +217,8381,8382 +217,8383,8384 +217,8385,8386 +217,8387,8388 +217,8389,8390 +217,8391,8392 +217,8393,8394 +217,8395,8396 +218,8397,8398 +218,8399,8400 +218,8401,8402 +218,8403,8404 +218,8405,8406 +218,8407,8408 +218,8409,8410 +218,8411,8412 +218,8413,8414 +218,8415,8416 +219,8417,8418 +219,8419,8420 +219,8421,8422 +219,8423,8424 +219,8425,8426 +219,8427,8428 +219,8429,8430 +219,8431,8432 +219,8433,8434 +219,8435,8436 +220,8437,8438 +220,8439,8440 +220,8441,8442 +220,8443,8444 +220,8445,8446 +220,8447,8448 +220,8449,8450 +220,8451,8452 +220,8453,8454 +220,8455,8456 +221,8457,8458 +221,8459,8460 +221,8461,8462 +221,8463,8464 +221,8465,8466 +221,8467,8468 +221,8469,8470 +221,8471,8472 +221,8473,8474 +221,8475,8476 +222,8477,8478 +222,8479,8480 +222,8481,8482 +222,8483,8484 +222,8485,8486 +227,8485,8486 +222,8487,8488 +222,8489,8490 +222,8491,8492 +222,8493,8494 +222,8495,8496 +223,8497,8498 +223,8499,8500 +223,8501,8502 +223,8503,8504 +223,8505,8506 +223,8507,8508 +223,8509,8510 +223,8511,8512 +223,8513,8514 +223,8515,8516 +224,8517,8518 +224,8519,8520 +224,8521,8522 +224,8523,8524 +224,8525,8526 +224,8527,8528 +224,8529,8530 +224,8531,8532 +224,8533,8534 +224,8535,8536 +225,8537,8538 +225,8539,8540 +225,8541,8542 +225,8543,8544 +225,8545,8546 +225,8547,8548 +225,8549,8550 +225,8551,8552 +225,8553,8554 +225,8555,8556 +226,8557,8558 +230,8557,8558 +226,8559,8560 +226,8561,8562 +226,8563,8564 +226,8565,8566 +226,8567,8568 +226,8569,8570 +226,8571,8572 +226,8573,8574 +226,8575,8576 +227,8577,8578 +227,8579,8580 +227,8581,8582 +227,8583,8584 +227,8585,8586 +227,8587,8588 +227,8589,8590 +227,8591,8592 +227,8593,8594 +227,8595,8596 +228,8597,8598 +228,8599,8600 +228,8601,8602 +228,8603,8604 +228,8605,8606 +228,8607,8608 +228,8609,8610 +228,8611,8612 +228,8613,8614 +228,8615,8616 +229,8617,8618 +229,8619,8620 +229,8621,8622 +229,8623,8624 +229,8625,8626 +231,8625,8626 +229,8627,8628 +229,8629,8630 +229,8631,8632 +229,8633,8634 +229,8635,8636 +230,8637,8638 +230,8639,8640 +230,8641,8642 +230,8643,8644 +230,8645,8646 +230,8647,8648 +230,8649,8650 +230,8651,8652 +230,8653,8654 +230,8655,8656 +231,8657,8658 +231,8659,8660 +231,8661,8662 +231,8663,8664 +231,8665,8666 +231,8667,8668 +231,8669,8670 +231,8671,8672 +231,8673,8674 +231,8675,8676 +232,8677,8678 +232,8679,8680 +232,8681,8682 +232,8683,8684 +232,8685,8686 +232,8687,8688 +232,8689,8690 +232,8691,8692 +232,8693,8694 +232,8695,8696 +233,8697,8698 +233,8699,8700 +233,8701,8702 +233,8703,8704 +233,8705,8706 +233,8707,8708 +233,8709,8710 +233,8711,8712 +233,8713,8714 +233,8715,8716 \ No newline at end of file diff --git a/examples/file_read_stream/lib/words.csv b/examples/file_read_stream/lib/words.csv new file mode 100644 index 00000000..2e244354 --- /dev/null +++ b/examples/file_read_stream/lib/words.csv @@ -0,0 +1,7971 @@ +1,anguish,3,1 +2,beloved,3,1 +3,cleanse,3,1 +4,cloak,3,1 +5,daybreak,3,1 +6,deed,3,1 +7,dwell,3,1 +8,harsh,3,1 +9,indeed,3,1 +10,jackal,3,1 +11,loincloth,3,1 +12,mercy,3,1 +13,partake,3,1 +14,protrude,3,1 +15,quench,3,1 +16,slender,3,1 +17,sorrow,3,1 +18,spare,3,1 +19,sprout,3,1 +20,stiff,3,1 +21,tan,3,1 +22,thorny,3,1 +23,thus,3,1 +24,unsound,3,1 +25,vain,3,1 +26,wail,3,1 +27,wane,3,1 +28,weave,3,1 +29,worship,3,1 +30,abound,3,1 +31,brewery,3,1 +32,cattle,3,1 +33,doable,3,1 +34,eerily,3,1 +35,expertise,3,1 +36,flick,3,1 +37,flung,3,1 +38,gibberish,3,1 +39,greedy,3,1 +40,halo,3,1 +41,harnessed,3,1 +42,inception,3,1 +43,jockeying,3,1 +44,limelight,3,1 +45,loan,3,1 +46,napkin,3,1 +47,pivotal,3,1 +48,plywood,3,1 +49,raw,3,1 +50,recipe,3,1 +51,saddle,3,1 +52,slick,3,1 +53,sprinkle,3,1 +54,stagger,3,1 +55,stray,3,1 +56,thaw,3,1 +57,thorough,3,1 +58,topple,3,1 +59,turmoil,3,1 +60,beneath,3,1 +61,bias,3,1 +62,brag,3,1 +63,breadth,3,1 +64,bury,3,1 +65,cope,3,1 +66,cramp,3,1 +67,deity,3,1 +68,embankment,3,1 +69,ferry,3,1 +70,foible,3,1 +71,garment,3,1 +72,grief,3,1 +73,handkerchief,3,1 +74,heed,3,1 +75,hone,3,1 +76,hump,3,1 +77,junkie,3,1 +78,loathe,3,1 +79,meekly,3,1 +80,mower,3,1 +81,oblivious,3,1 +82,riddle,3,1 +83,shelf,3,1 +84,soil,3,1 +85,sturdy,3,1 +86,tantrum,3,1 +87,trite,3,1 +88,warrant,3,1 +89,yield,3,1 +90,aisle,3,1 +91,aptly,3,1 +92,awe,3,1 +93,blunt,3,1 +94,crosswalk,3,1 +95,crummy,3,1 +96,cumbersome,3,1 +97,dogged,3,1 +98,evict,3,1 +99,fad,3,1 +100,flimsy,3,1 +101,gait,3,1 +102,gamble,3,1 +103,gruff,3,1 +104,hamper,3,1 +105,havoc,3,1 +106,jar,3,1 +107,laggard,3,1 +108,nuance,3,1 +109,obnoxious,3,1 +110,oust,3,1 +111,rebate,3,1 +112,renown,3,1 +113,rogue,3,1 +114,sleek,3,1 +115,steer,3,1 +116,stir,3,1 +117,surefire,3,1 +118,sway,3,1 +119,thrive,3,1 +120,abide,3,1 +121,awry,3,1 +122,balk,3,1 +123,battered,3,1 +124,byword,3,1 +125,chuckle,3,1 +126,clench,3,1 +127,clutter,3,1 +128,cram,3,1 +129,crave,3,1 +130,daunt,3,1 +131,devise,3,1 +132,ditch,3,1 +133,dumbfounded,3,1 +134,dusk,3,1 +135,enroll,3,1 +136,falter,3,1 +137,iffy,3,1 +138,loot,3,1 +139,marble,3,1 +140,pal,3,1 +141,pitch,3,1 +142,plead,3,1 +143,ruthless,3,1 +144,scant,3,1 +145,sin,3,1 +146,steep,3,1 +147,strive,3,1 +148,twitch,3,1 +149,wiggle,3,1 +150,albeit,3,1 +151,amuck,3,1 +152,behalf,3,1 +153,bribe,3,1 +154,cinch,3,1 +155,claim,3,1 +156,curb,3,1 +157,dabble,3,1 +158,ditto,3,1 +159,dross,3,1 +160,drought,3,1 +161,drudgery,3,1 +162,entail,3,1 +163,froth,3,1 +164,guise,3,1 +165,haze,3,1 +166,hence,3,1 +167,hiccups,3,1 +168,natch,3,1 +169,pond,3,1 +170,rear,3,1 +171,rehearse,3,1 +172,sloth,3,1 +173,splinter,3,1 +174,swell,3,1 +175,tow,3,1 +176,utterly,3,1 +177,wax,3,1 +178,wheat,3,1 +179,wily,3,1 +180,backdrop,3,1 +181,bog,3,1 +182,brash,3,1 +183,clog,3,1 +184,curl,3,1 +185,dismayed,3,1 +186,enhance,3,1 +187,exploit,3,1 +188,farfetched,3,1 +189,foster,3,1 +190,glitzy,3,1 +191,haphazard,3,1 +192,irksome,3,1 +193,lavish,3,1 +194,leash,3,1 +195,mugged,3,1 +196,n-fold,3,1 +197,notorious,3,1 +198,patent,3,1 +199,pesky,3,1 +200,ramble,3,1 +201,skew,3,1 +202,slope,3,1 +203,sloppy,3,1 +204,startle,3,1 +205,tailor,3,1 +206,tinker,3,1 +207,wary,3,1 +208,wellspring,3,1 +209,wry,3,1 +210,briefing,3,1 +211,clay,3,1 +212,cranny,3,1 +213,cripple,3,1 +214,delve,3,1 +215,demeanor,3,1 +216,disguise,3,1 +217,fickle,3,1 +218,haystack,3,1 +219,hum,3,1 +220,liable,3,1 +221,loafing,3,1 +222,looming,3,1 +223,nimble,3,1 +224,nook,3,1 +225,paramount,3,1 +226,penchant,3,1 +227,pitiful,3,1 +228,plaint,3,1 +229,ploy,3,1 +230,rummage,3,1 +231,rustle,3,1 +232,sewn,3,1 +233,spur,3,1 +234,stifle,3,1 +235,stubborn,3,1 +236,swindle,3,1 +237,tidbit,3,1 +238,welfare,3,1 +239,whereabouts,3,1 +240,bail,3,1 +241,bush,3,1 +242,coarse,3,1 +243,copper,3,1 +244,dawdle,3,1 +245,elicit,3,1 +246,fluke,3,1 +247,gloss,3,1 +248,halt,3,1 +249,hoard,3,1 +250,instance,3,1 +251,latch,3,1 +252,lurk,3,1 +253,nevertheless,3,1 +254,nurture,3,1 +255,pitfall,3,1 +256,prowess,3,1 +257,relapse,3,1 +258,reverie,3,1 +259,shrunk,3,1 +260,skim,3,1 +261,staircase,3,1 +262,tantalizing,3,1 +263,toss,3,1 +264,vicious,3,1 +265,wacky,3,1 +266,ward,3,1 +267,whiff,3,1 +268,wither,3,1 +269,wrinkle,3,1 +270,ash,3,1 +271,blanket,3,1 +272,boiler,3,1 +273,broom,3,1 +274,cabinet,3,1 +275,chandelier,3,1 +276,crockery,3,1 +277,cushion,3,1 +278,dish rack,3,1 +279,doorknob,3,1 +280,dove,3,1 +281,drawer,3,1 +282,ember,3,1 +283,footrest,3,1 +284,grumble,3,1 +285,hand,3,1 +286,keyhole,3,1 +287,knick-knack,3,1 +288,oven,3,1 +289,pantry,3,1 +290,radiator,3,1 +291,rucksack,3,1 +292,shutter,3,1 +293,sink,3,1 +294,slipper,3,1 +295,socket,3,1 +296,tap / faucet,3,1 +297,tile,3,1 +298,washtub,3,1 +299,woodstove,3,1 +300,apron,3,1 +301,barrow,3,1 +302,beech,3,1 +303,birch,3,1 +304,blackbird,3,1 +305,coal,3,1 +306,creeper,3,1 +307,fence,3,1 +308,hammock,3,1 +309,harvest,3,1 +310,hay,3,1 +311,hedge,3,1 +312,hoe,3,1 +313,hornet,3,1 +314,limb,3,1 +315,manure,3,1 +316,mud,3,1 +317,pebble,3,1 +318,pickaxe,3,1 +319,plow,3,1 +320,porch,3,1 +321,prune,3,1 +322,rake,3,1 +323,seesaw,3,1 +324,shrub,3,1 +325,sow,3,1 +326,spade,3,1 +327,straw,3,1 +328,terrace,3,1 +329,windowsill,3,1 +330,advance,3,1 +331,arduous,3,1 +332,arrival,3,1 +333,baggage,3,1 +334,book,3,1 +335,bureau,3,1 +336,busboy,3,1 +337,depart,3,1 +338,dispatch,3,1 +339,endorse,3,1 +340,expiry,3,1 +341,foreign,3,1 +342,harbor,3,1 +343,heady,3,1 +344,hitchhiking,3,1 +345,invigorate,3,1 +346,landing,3,1 +347,outward,3,1 +348,overseas,3,1 +349,pedestrian,3,1 +350,postpone,3,1 +351,sail,3,1 +352,sidewalk,3,1 +353,substantiate,3,1 +354,takeoff,3,1 +355,tollbooth,3,1 +356,toll,3,1 +357,troubled,3,1 +358,venture,3,1 +359,windshield,3,1 +360,adjournment,3,1 +361,apprentice,3,1 +362,breakthrough,3,1 +363,clerk,3,1 +364,clock,3,1 +365,commute,3,1 +366,dismiss,3,1 +367,duty,3,1 +368,entitlement,3,1 +369,executive,3,1 +370,fee,3,1 +371,furtherance,3,1 +372,grant,3,1 +373,grievance,3,1 +374,headquarter,3,1 +375,hierarchy,3,1 +376,injury,3,1 +377,insured,3,1 +378,labourer,3,1 +379,levy,3,1 +380,onus,3,1 +381,preferment,3,1 +382,reprimand,3,1 +383,retain,3,1 +384,retirement,3,1 +385,rig,3,1 +386,rookie,3,1 +387,uphold,3,1 +388,wage,3,1 +389,warhorse,3,1 +390,appease,3,1 +391,avenge,3,1 +392,berserk,3,1 +393,binge,3,1 +394,bitter,3,1 +395,blowout,3,1 +396,bustle,3,1 +397,cocky,3,1 +398,corny,3,1 +399,dismantle,3,1 +400,entrust,3,1 +401,gall,3,1 +402,grumpy,3,1 +403,lull,3,1 +404,nasty,3,1 +405,nefarious,3,1 +406,numb,3,1 +407,outsource,3,1 +408,plucky,3,1 +409,poised,3,1 +410,quell,3,1 +411,ravage,3,1 +412,retaliation,3,1 +413,ricochet,3,1 +414,rotten,3,1 +415,scrap,3,1 +416,swagger,3,1 +417,vengeance,3,1 +418,vengeful,3,1 +419,wicked,3,1 +420,avenue,3,1 +421,bland,3,1 +422,bolt,3,1 +423,cheerful,3,1 +424,clutch,3,1 +425,drill,3,1 +426,file,3,1 +427,flood,3,1 +428,frill,3,1 +429,gale,3,1 +430,gravel,3,1 +431,hail,3,1 +432,horn,3,1 +433,hose,3,1 +434,lawn,3,1 +435,livid,3,1 +436,monger,3,1 +437,mouldy,3,1 +438,nail,3,1 +439,pliers,3,1 +440,ripe,3,1 +441,screw,3,1 +442,screwdriver,3,1 +443,shovel,3,1 +444,signpost,3,1 +445,sneeze,3,1 +446,spleen,3,1 +447,vice,3,1 +448,weary,3,1 +449,windpipe,3,1 +450,belittle,3,1 +451,beware,3,1 +452,bleary,3,1 +453,bonehead,3,1 +454,chap,3,1 +455,coax,3,1 +456,deem,3,1 +457,dud,3,1 +458,eschew,3,1 +459,groggy,3,1 +460,midget,3,1 +461,navel,3,1 +462,nibble,3,1 +463,nonetheless,3,1 +464,preemptive,3,1 +465,quits,3,1 +466,savvy,3,1 +467,scatter,3,1 +468,sheepish,3,1 +469,snag,3,1 +470,squabble,3,1 +471,straddle,3,1 +472,sullen,3,1 +473,tweak,3,1 +474,twofold,3,1 +475,vow,3,1 +476,weakling,3,1 +477,whiny,3,1 +478,wit,3,1 +479,wrath,3,1 +480,aloof,3,1 +481,bargain,3,1 +482,bide,3,1 +483,clover,3,1 +484,countenance,3,1 +485,deceive,3,1 +486,doom,3,1 +487,fidget,3,1 +488,fled,3,1 +489,flog,3,1 +490,foil,3,1 +491,forgery,3,1 +492,frisk,3,1 +493,frisky,3,1 +494,hitherto,3,1 +495,huddled,3,1 +496,hullabaloo,3,1 +497,limber,3,1 +498,litter,3,1 +499,mingle,3,1 +500,outcry,3,1 +501,overthrow,3,1 +502,paw,3,1 +503,quarry,3,1 +504,ram,3,1 +505,seize,3,1 +506,shrewd,3,1 +507,tame,3,1 +508,treachery,3,1 +509,windfall,3,1 +510,akin,3,1 +511,allowance,3,1 +512,barley,3,1 +513,burden,3,1 +514,cellar,3,1 +515,chancy,3,1 +516,convey,3,1 +517,deject,3,1 +518,eavesdrop,3,1 +519,forbid,3,1 +520,foretell,3,1 +521,hapless,3,1 +522,hassle,3,1 +523,haste,3,1 +524,hazard,3,1 +525,heist,3,1 +526,henceforward,3,1 +527,hindsight,3,1 +528,hunch,3,1 +529,hush,3,1 +530,loose,3,1 +531,lure,3,1 +532,marvel,3,1 +533,poignant,3,1 +534,quarrel,3,1 +535,raffle,3,1 +536,resent,3,1 +537,stroll,3,1 +538,upend,3,1 +539,whence,3,1 +540,almond,3,1 +541,benchmark,3,1 +542,cadre,3,1 +543,cajole,3,1 +544,defer,3,1 +545,flummox,3,1 +546,grudge,3,1 +547,headlong,3,1 +548,jittery,3,1 +549,kale,3,1 +550,layman,3,1 +551,likewise,3,1 +552,maladroit,3,1 +553,meander,3,1 +554,moan,3,1 +555,moreover,3,1 +556,newfangled,3,1 +557,nigh,3,1 +558,otiose,3,1 +559,owing,3,1 +560,plainly,3,1 +561,slump,3,1 +562,staunch,3,1 +563,steadfast,3,1 +564,stoop,3,1 +565,thereby,3,1 +566,uncanny,3,1 +567,unfettered,3,1 +568,unviable,3,1 +569,winsome,3,1 +570,befuddle,3,1 +571,beg,3,1 +572,bicker,3,1 +573,candor,3,1 +574,chary,3,1 +575,crass,3,1 +576,crate,3,1 +577,endow,3,1 +578,grit,3,1 +579,harass,3,1 +580,harbinger,3,1 +581,hardship,3,1 +582,jolt,3,1 +583,jumble,3,1 +584,maudlin,3,1 +585,onslaught,3,1 +586,palliate,3,1 +587,scald,3,1 +588,scam,3,1 +589,scold,3,1 +590,slake,3,1 +591,slaughter,3,1 +592,slay,3,1 +593,spite,3,1 +594,subtle,3,1 +595,thereof,3,1 +596,unruffled,3,1 +597,unruly,3,1 +598,unscathed,3,1 +599,unscramble,3,1 +600,allegiance,3,1 +601,askew,3,1 +602,bare,3,1 +603,claw,3,1 +604,crow,3,1 +605,devoid,3,1 +606,dwindle,3,1 +607,feather,3,1 +608,flutter,3,1 +609,hobble,3,1 +610,jaw,3,1 +611,linger,3,1 +612,lunge,3,1 +613,nostrils,3,1 +614,nudge,3,1 +615,peck,3,1 +616,prickle,3,1 +617,recoil,3,1 +618,retort,3,1 +619,screech,3,1 +620,shrug,3,1 +621,sleeve,3,1 +622,slight,3,1 +623,sluggish,3,1 +624,slums,3,1 +625,sterner,3,1 +626,swoop,3,1 +627,testy,3,1 +628,throb,3,1 +629,yeast,3,1 +630,appoint,3,1 +631,ashamed,3,1 +632,beckon,3,1 +633,charm,3,1 +634,chasm,3,1 +635,creak,3,1 +636,decline,3,1 +637,despise,3,1 +638,eerie,3,1 +639,glare,3,1 +640,glint,3,1 +641,grimace,3,1 +642,lid,3,1 +643,malice,3,1 +644,menace,3,1 +645,restrain,3,1 +646,sag,3,1 +647,scowl,3,1 +648,shudder,3,1 +649,slither,3,1 +650,smirk,3,1 +651,sore,3,1 +652,taut,3,1 +653,thigh,3,1 +654,tousle,3,1 +655,trickle,3,1 +656,waist,3,1 +657,willowy,3,1 +658,writhe,3,1 +659,abreast,3,1 +660,alley,3,1 +661,asunder,3,1 +662,avert,3,1 +663,brow,3,1 +664,coerce,3,1 +665,dam,3,1 +666,dank,3,1 +667,doze,3,1 +668,dumpling,3,1 +669,estate,3,1 +670,forthcoming,3,1 +671,forthright,3,1 +672,gist,3,1 +673,goose bumps,3,1 +674,is about time,3,1 +675,juggernaut,3,1 +676,jutting,3,1 +677,ludicrous,3,1 +678,marrow,3,1 +679,muster,3,1 +680,oblige,3,1 +681,redeem,3,1 +682,shuffle,3,1 +683,skid,3,1 +684,teem,3,1 +685,time and again,3,1 +686,unbeknownst,3,1 +687,whim,3,1 +688,wobble,3,1 +689,anyhow,3,1 +690,avow,3,1 +691,beget,3,1 +692,bond,3,1 +693,bouncer,3,1 +694,cleave,3,1 +695,deadbeat,3,1 +696,demand,3,1 +697,dismal,3,1 +698,dough,3,1 +699,extol,3,1 +700,gargantuan,3,1 +701,gash,3,1 +702,heir,3,1 +703,hindrance,3,1 +704,inasmuch,3,1 +705,infamous,3,1 +706,inflame,3,1 +707,inquire,3,1 +708,jew,3,1 +709,mild,3,1 +710,murk,3,1 +711,offspring,3,1 +712,portray,3,1 +713,prattle,3,1 +714,raze,3,1 +715,relate,3,1 +716,rupture,3,1 +717,smooth,3,1 +718,taint,3,1 +719,bind,3,1 +720,blueprint,3,1 +721,bolster,3,1 +722,bound,3,1 +723,coherent,3,1 +724,dingy,3,1 +725,dodge,3,1 +726,doodle,3,1 +727,enforce,3,1 +728,engage,3,1 +729,extent,3,1 +730,foresee,3,1 +731,fortnight,3,1 +732,glimpse,3,1 +733,herd,3,1 +734,jargon,3,1 +735,overall,3,1 +736,painstaking,3,1 +737,reckon,3,1 +738,rewind,3,1 +739,sheer,3,1 +740,silly,3,1 +741,squeamish,3,1 +742,steady,3,1 +743,strike,3,1 +744,surmise,3,1 +745,thrill,3,1 +746,thrust,3,1 +747,truce,3,1 +748,ungainly,3,1 +749,attorney,3,1 +750,averse,3,1 +751,boar,3,1 +752,buff,3,1 +753,bundle,3,1 +754,crook,3,1 +755,cub,3,1 +756,disown,3,1 +757,distress,3,1 +758,encompass,3,1 +759,feat,3,1 +760,gory,3,1 +761,kindle,3,1 +762,leap,3,1 +763,let alone,3,1 +764,nuisance,3,1 +765,odd,3,1 +766,override,3,1 +767,peep,3,1 +768,placeholder,3,1 +769,preach,3,1 +770,regardless,3,1 +771,sap,3,1 +772,sneak,3,1 +773,stream,3,1 +774,sue,3,1 +775,thwart,3,1 +776,tuition,3,1 +777,vacuum,3,1 +778,warp,3,1 +779,ancillary,3,1 +780,bewilder,3,1 +781,blurt,3,1 +782,canned,3,1 +783,clout,3,1 +784,cutlery,3,1 +785,dire,3,1 +786,draft,3,1 +787,duvet,3,1 +788,entice,3,1 +789,fortitude,3,1 +790,hitch,3,1 +791,hustle,3,1 +792,jeopardize,3,1 +793,lush,3,1 +794,mesmerize,3,1 +795,naive,3,1 +796,outcast,3,1 +797,patch,3,1 +798,peddle,3,1 +799,poke,3,1 +800,puny,3,1 +801,roach,3,1 +802,shaky,3,1 +803,skimpy,3,1 +804,sly,3,1 +805,soothe,3,1 +806,spate,3,1 +807,steam,3,1 +808,tickle,3,1 +809,aubergine,3,1 +810,beef,3,1 +811,bleach,3,1 +812,bowl,3,1 +813,bulky,3,1 +814,courgette,3,1 +815,crunchy,3,1 +816,cucumber,3,1 +817,cunning,3,1 +818,farmhouse,3,1 +819,flake,3,1 +820,frankfurter,3,1 +821,ham,3,1 +822,huffy,3,1 +823,kettle,3,1 +824,loaf,3,1 +825,mighty,3,1 +826,mug,3,1 +827,pea,3,1 +828,peanut,3,1 +829,pepper,3,1 +830,pliable,3,1 +831,pot,3,1 +832,reckless,3,1 +833,rinse,3,1 +834,roll,3,1 +835,sponge,3,1 +836,stove,3,1 +837,tumbler,3,1 +838,wholewheat,3,1 +839,blotch,3,1 +840,chute,3,1 +841,conceal,3,1 +842,dare,3,1 +843,dim,3,1 +844,disposal,3,1 +845,dope,3,1 +846,exertion,3,1 +847,exile,3,1 +848,expend,3,1 +849,fizzy,3,1 +850,gingerly,3,1 +851,grim,3,1 +852,hood,3,1 +853,insurgent,3,1 +854,jostle,3,1 +855,keepsake,3,1 +856,laundry,3,1 +857,lukewarm,3,1 +858,mend,3,1 +859,outburst,3,1 +860,outer,3,1 +861,peel,3,1 +862,puffy,3,1 +863,scrape,3,1 +864,sharp,3,1 +865,slack,3,1 +866,tray,3,1 +867,withdraw,3,1 +868,withhold,3,1 +869,abduct,3,1 +870,amuse,3,1 +871,bid,3,1 +872,blatant,3,1 +873,bluster,3,1 +874,booze,3,1 +875,cabbage,3,1 +876,cauliflower,3,1 +877,cherish,3,1 +878,chickpeas,3,1 +879,disclose,3,1 +880,feeble,3,1 +881,freckle,3,1 +882,get lost,3,1 +883,graze,3,1 +884,hind,3,1 +885,keen,3,1 +886,ladle,3,1 +887,lift,3,1 +888,outage,3,1 +889,padlock,3,1 +890,pester,3,1 +891,poke around,3,1 +892,scorch,3,1 +893,slur,3,1 +894,squash,3,1 +895,tissue,3,1 +896,tummy,3,1 +897,tycoon,3,1 +898,verge,3,1 +899,astray,3,1 +900,brew,3,1 +901,capsize,3,1 +902,conceive,3,1 +903,concoction,3,1 +904,cuisine,3,1 +905,dazzle,3,1 +906,deplete,3,1 +907,disgruntled,3,1 +908,embed,3,1 +909,farewell,3,1 +910,flock,3,1 +911,folk,3,1 +912,forgo,3,1 +913,haughty,3,1 +914,interplay,3,1 +915,intrude,3,1 +916,jest,3,1 +917,mock,3,1 +918,onset,3,1 +919,poise,3,1 +920,respite,3,1 +921,savor,3,1 +922,shabby,3,1 +923,smug,3,1 +924,summon,3,1 +925,thrift,3,1 +926,typo,3,1 +927,upheaval,3,1 +928,warfare,3,1 +929,beat,3,1 +930,bother,3,1 +931,bumblebee,3,1 +932,colader,3,1 +933,discombobulate,3,1 +934,disease,3,1 +935,fleeting,3,1 +936,fluffy,3,1 +937,hammer,3,1 +938,homesick,3,1 +939,issue,3,1 +940,janky,3,1 +941,lame,3,1 +942,lullaby,3,1 +943,mill,3,1 +944,mood,3,1 +945,narrow,3,1 +946,rise,3,1 +947,scissor,3,1 +948,silky,3,1 +949,smell,3,1 +950,spine,3,1 +951,stale,3,1 +952,stink,3,1 +953,swarm,3,1 +954,tapestry,3,1 +955,unbearable,3,1 +956,unholy,3,1 +957,unspeakable,3,1 +958,wriggle,3,1 +959,allure,3,1 +960,audit,3,1 +961,bequeath,3,1 +962,bestow,3,1 +963,bloodlust,3,1 +964,bristle,3,1 +965,conceit,3,1 +966,deranged,3,1 +967,engender,3,1 +968,engulf,3,1 +969,firm,3,1 +970,fray,3,1 +971,gaudy,3,1 +972,hubris,3,1 +973,hurl,3,1 +974,leak,3,1 +975,lowly,3,1 +976,parsley,3,1 +977,plunder,3,1 +978,pour,3,1 +979,seep,3,1 +980,shore,3,1 +981,shun,3,1 +982,siege,3,1 +983,squander,3,1 +984,strife,3,1 +985,tattle,3,1 +986,toil,3,1 +987,unbridled,3,1 +988,wrought,3,1 +989,aghast,3,1 +990,amiable,3,1 +991,banter,3,1 +992,bark,3,1 +993,bootlicker,3,1 +994,cozy,3,1 +995,feign,3,1 +996,imp,3,1 +997,knack,3,1 +998,laxity,3,1 +999,overactive,3,1 +1000,paucity,3,1 +1001,paunch,3,1 +1002,plod,3,1 +1003,purse,3,1 +1004,rust,3,1 +1005,slouch,3,1 +1006,tease,3,1 +1007,tin,3,1 +1008,woo,3,1 +1009,appraisal,3,1 +1010,burglary,3,1 +1011,chronicle,3,1 +1012,drift,3,1 +1013,fare,3,1 +1014,foe,3,1 +1015,gainsay,3,1 +1016,gauge,3,1 +1017,gridlock,3,1 +1018,hatch,3,1 +1019,hijack,3,1 +1020,hinge,3,1 +1021,matter of fact,3,1 +1022,mishap,3,1 +1023,plight,3,1 +1024,ponder,3,1 +1025,remedy,3,1 +1026,rife,3,1 +1027,seethe,3,1 +1028,tear,3,1 +1029,aid,3,1 +1030,amid,3,1 +1031,belie,3,1 +1032,blanch,3,1 +1033,boulder,3,1 +1034,carve,3,1 +1035,fable,3,1 +1036,gaze,3,1 +1037,glee,3,1 +1038,irate,3,1 +1039,muddle,3,1 +1040,outmatch,3,1 +1041,peevish,3,1 +1042,rape,3,1 +1043,sage,3,1 +1044,sangfroid,3,1 +1045,scorn,3,1 +1046,stickler,3,1 +1047,strain,3,1 +1048,wraith,3,1 +1049,befall,3,1 +1050,bemoan,3,1 +1051,bogus,3,1 +1052,budge,3,1 +1053,comb,3,1 +1054,flinch,3,1 +1055,fret,3,1 +1056,grovel,3,1 +1057,haul,3,1 +1058,janitor,3,1 +1059,ominous,3,1 +1060,peg,3,1 +1061,physician,3,1 +1062,pique,3,1 +1063,quip,3,1 +1064,raid,3,1 +1065,rally,3,1 +1066,sinew,3,1 +1067,slog,3,1 +1068,stomp,3,1 +1069,acquiesce,3,1 +1070,backbone,3,1 +1071,bravado,3,1 +1072,brood,3,1 +1073,connive,3,1 +1074,dean,3,1 +1075,fiddle,3,1 +1076,flank,3,1 +1077,impasse,3,1 +1078,maverick,3,1 +1079,outlook,3,1 +1080,pin,3,1 +1081,privy,3,1 +1082,punk,3,1 +1083,purport,3,1 +1084,resign,3,1 +1085,shortcoming,3,1 +1086,solace,3,1 +1087,swoon,3,1 +1088,trailblazer,3,1 +1089,cater,3,1 +1090,chastise,3,1 +1091,drench,3,1 +1092,duly,3,1 +1093,giddy,3,1 +1094,glide,3,1 +1095,haggle,3,1 +1096,innuendo,3,1 +1097,inveterate,3,1 +1098,morose,3,1 +1099,slander,3,1 +1100,slip,3,1 +1101,snub,3,1 +1102,stow,3,1 +1103,sulk,3,1 +1104,swathe,3,1 +1105,throttle,3,1 +1106,weld,3,1 +1107,wherewithal,3,1 +1108,wring,3,1 +1109,belated,3,1 +1110,blacken,3,1 +1111,booth,3,1 +1112,chagrin,3,1 +1113,cling,3,1 +1114,curt,3,1 +1115,disparage,3,1 +1116,dispirited,3,1 +1117,flippant,3,1 +1118,fond,3,1 +1119,gust,3,1 +1120,husk,3,1 +1121,pouch,3,1 +1122,reliable,3,1 +1123,scrub,3,1 +1124,secretive,3,1 +1125,tack,3,1 +1126,thump,3,1 +1127,wheedle,3,1 +1128,wretch,3,1 +1129,ablaze,3,1 +1130,apricot,3,1 +1131,bystander,3,1 +1132,distraught,3,1 +1133,engrossed,3,1 +1134,flare,3,1 +1135,hilt,3,1 +1136,meddle,3,1 +1137,memento,3,1 +1138,overcast,3,1 +1139,perk,3,1 +1140,pretence,3,1 +1141,prone,3,1 +1142,pry,3,1 +1143,refrain,3,1 +1144,shambles,3,1 +1145,squat,3,1 +1146,sultry,3,1 +1147,tipsy,3,1 +1148,twine,3,1 +1149,allegedly,3,1 +1150,botch,3,1 +1151,chink,3,1 +1152,coalesce,3,1 +1153,conduit,3,1 +1154,conjure,3,1 +1155,daredevil,3,1 +1156,detour,3,1 +1157,dispute,3,1 +1158,enchant,3,1 +1159,golly,3,1 +1160,ledger,3,1 +1161,mortgage,3,1 +1162,picky,3,1 +1163,poll,3,1 +1164,topping,3,1 +1165,tug,3,1 +1166,undaunted,3,1 +1167,valiant,3,1 +1168,yelp,3,1 +1169,butler,3,1 +1170,callous,3,1 +1171,crib,3,1 +1172,disposable,3,1 +1173,enmity,3,1 +1174,equitable,3,1 +1175,hazel,3,1 +1176,hectic,3,1 +1177,impromptu,3,1 +1178,mettle,3,1 +1179,ooze,3,1 +1180,overhaul,3,1 +1181,pamphlet,3,1 +1182,proclivity,3,1 +1183,puff,3,1 +1184,purveyor,3,1 +1185,purview,3,1 +1186,quirk,3,1 +1187,rim,3,1 +1188,wunderkind,3,1 +1189,amend,3,1 +1190,ascribe,3,1 +1191,bartender,3,1 +1192,breed,3,1 +1193,crop,3,1 +1194,envisage,3,1 +1195,fetch,3,1 +1196,flaw,3,1 +1197,flea,3,1 +1198,hallow,3,1 +1199,hollow,3,1 +1200,humdrum,3,1 +1201,mayhem,3,1 +1202,misgiving,3,1 +1203,pawn,3,1 +1204,pinpoint,3,1 +1205,replete,3,1 +1206,withstand,3,1 +1207,woe,3,1 +1208,yolk,3,1 +1209,bedevil,3,1 +1210,bout,3,1 +1211,clearance,3,1 +1212,debunk,3,1 +1213,facade,3,1 +1214,fathom,3,1 +1215,fringe,3,1 +1216,fuss,3,1 +1217,hare,3,1 +1218,heinous,3,1 +1219,imbue,3,1 +1220,impinge,3,1 +1221,murky,3,1 +1222,notwithstanding,3,1 +1223,overdue,3,1 +1224,pundit,3,1 +1225,redress,3,1 +1226,snatch,3,1 +1227,supple,3,1 +1228,trifle,3,1 +1229,apprehend,3,1 +1230,beyond,3,1 +1231,bottom line,3,1 +1232,bundle up,3,1 +1233,by chance,3,1 +1234,catch up,3,1 +1235,chief,3,1 +1236,drop by,3,1 +1237,easy does it,3,1 +1238,gullible,3,1 +1239,lean towards,3,1 +1240,mark my words,3,1 +1241,mischievous,3,1 +1242,on a roll,3,1 +1243,repartee,3,1 +1244,rule out,3,1 +1245,set off,3,1 +1246,swab,3,1 +1247,ward off,3,1 +1248,whistleblower,3,1 +1249,assuage,3,1 +1250,clot,3,1 +1251,enlist,3,1 +1252,epitome,3,1 +1253,for a song,3,1 +1254,go with the flow,3,1 +1255,knead,3,1 +1256,make do,3,1 +1257,neck and neck,3,1 +1258,next of kin,3,1 +1259,nosey,3,1 +1260,plummet,3,1 +1261,prickly,3,1 +1262,reassure,3,1 +1263,resilient,3,1 +1264,seaweed,3,1 +1265,so to speak,3,1 +1266,under fire,3,1 +1267,vinegar,3,1 +1268,zip it,3,1 +1269,cry me a river,3,1 +1270,deadpan,3,1 +1271,double take,3,1 +1272,flabbergast,3,1 +1273,flush,3,1 +1274,hang up,3,1 +1275,mend fences,3,1 +1276,nick of time,3,1 +1277,over and out,3,1 +1278,parlor,3,1 +1279,patronize,3,1 +1280,plum,3,1 +1281,reek,3,1 +1282,sea change,3,1 +1283,sweatshirt,3,1 +1284,touchstone,3,1 +1285,up to the mark,3,1 +1286,vexed,3,1 +1287,wind up,3,1 +1288,wrench,3,1 +1289,besmirch,3,1 +1290,fan,3,1 +1291,feckless,3,1 +1292,forlorn,3,1 +1293,gristle,3,1 +1294,heel,3,1 +1295,holdover,3,1 +1296,impugn,3,1 +1297,jeer,3,1 +1298,petty,3,1 +1299,pun,3,1 +1300,rabble,3,1 +1301,sash,3,1 +1302,shrill,3,1 +1303,sissy,3,1 +1304,slant,3,1 +1305,sour,3,1 +1306,unravel,3,1 +1307,vagrant,3,1 +1308,wool,3,1 +1309,afloat,3,1 +1310,beet,3,1 +1311,clumsy,3,1 +1312,collateral,3,1 +1313,conundrum,3,1 +1314,corroborate,3,1 +1315,crutch,3,1 +1316,cudgel,3,1 +1317,disabuse,3,1 +1318,floss,3,1 +1319,hearsay,3,1 +1320,knit,3,1 +1321,learn by rote,3,1 +1322,lookup,3,1 +1323,lore,3,1 +1324,mimicry,3,1 +1325,rumple,3,1 +1326,serendipity,3,1 +1327,vie,3,1 +1328,vindicate,3,1 +1329,blend,3,1 +1330,broth,3,1 +1331,crumble,3,1 +1332,errand,3,1 +1333,gimmick,3,1 +1334,glean,3,1 +1335,glib,3,1 +1336,ironclad,3,1 +1337,maize,3,1 +1338,measly,3,1 +1339,mouthful,3,1 +1340,nostrum,3,1 +1341,pristine,3,1 +1342,pulp,3,1 +1343,shallow,3,1 +1344,shear,3,1 +1345,tenure,3,1 +1346,torn,3,1 +1347,twig,3,1 +1348,velvet,3,1 +2048,angoscia,3,2 +2049,amato,3,2 +2050,purificare,3,2 +2051,mantello,3,2 +2052,alba,3,2 +2053,azione / atto,3,2 +2054,dimorare,3,2 +2055,severo,3,2 +2056,in effetti,3,2 +2057,scagnozzo,3,2 +2058,perizoma,3,2 +2059,pieta',3,2 +2060,prendere parte,3,2 +2061,sporgere,3,2 +2062,attenuazione,3,2 +2063,snello,3,2 +2064,tristezza,3,2 +2065,risparmiare,3,2 +2066,germogliare,3,2 +2067,rigido,3,2 +2068,abbronzatura,3,2 +2069,spinosi,3,2 +2070,pertanto,3,2 +2071,instabile,3,2 +2072,vanitoso,3,2 +2073,lamento,3,2 +2074,scemare,3,2 +2075,tessere,3,2 +2076,culto,3,2 +2077,abbondare,3,2 +2078,birrificio,3,2 +2079,bestiame,3,2 +2080,fattibile,3,2 +2081,stranamente,3,2 +2082,competenza,3,2 +2083,colpetto,3,2 +2084,lanciato,3,2 +2085,borbottio,3,2 +2086,avido,3,2 +2087,alone,3,2 +2088,sfruttato,3,2 +2089,creazione,3,2 +2090,in lizza,3,2 +2091,ribalta,3,2 +2092,prestito,3,2 +2093,tovagliolo,3,2 +2094,fondamentale,3,2 +2095,compensato,3,2 +2096,grezzo,3,2 +2097,ricetta,3,2 +2098,sella,3,2 +2099,viscido,3,2 +2100,spargere,3,2 +2101,barcollare,3,2 +2102,randagio,3,2 +2103,scongelare,3,2 +2104,approfondito,3,2 +2105,rovesciare,3,2 +2106,subbuglio,3,2 +2107,sottostante,3,2 +2108,pregiudizio,3,2 +2109,vantarsi,3,2 +2110,ampiezza,3,2 +2111,seppellire,3,2 +2112,affrontare,3,2 +2113,impedire,3,2 +2114,divinita',3,2 +2115,argine,3,2 +2116,traghetto,3,2 +2117,mania,3,2 +2118,indumento,3,2 +2119,sofferenza,3,2 +2120,fazzolletto,3,2 +2121,fare attenzione,3,2 +2122,affinare,3,2 +2123,gobba,3,2 +2124,drogato,3,2 +2125,detestare,3,2 +2126,docilmente,3,2 +2127,tagliaerba,3,2 +2128,ignaro,3,2 +2129,enigma,3,2 +2130,mensola,3,2 +2131,suolo,3,2 +2132,robusto,3,2 +2133,capriccio,3,2 +2134,banale,3,2 +2135,garantire,3,2 +2136,rendimento,3,2 +2137,corridoio,3,2 +2138,giustamente,3,2 +2139,soggezione,3,2 +2140,schietto,3,2 +2141,strisce pedonali,3,2 +2142,scadente,3,2 +2143,ingombrante,3,2 +2144,ostinato,3,2 +2145,sfrattare,3,2 +2146,moda,3,2 +2147,fragile,3,2 +2148,andatura,3,2 +2149,scommettere,3,2 +2150,burbero,3,2 +2151,ostacolare,3,2 +2152,scompiglio,3,2 +2153,vasetto,3,2 +2154,ritardatario,3,2 +2155,sfumatura,3,2 +2156,odioso,3,2 +2157,spodestare,3,2 +2158,sconto,3,2 +2159,fama,3,2 +2160,ribelle,3,2 +2161,elegante,3,2 +2162,manovrare,3,2 +2163,mescolare,3,2 +2164,infallibile,3,2 +2165,influenzare,3,2 +2166,prosperare,3,2 +2167,rispettare,3,2 +2168,andare storto,3,2 +2169,scoraggiarsi,3,2 +2170,malconcio,3,2 +2171,sinonimo,3,2 +2172,risatina,3,2 +2173,stringere,3,2 +2174,disordine,3,2 +2175,stipare,3,2 +2176,bramare,3,2 +2177,intimidire,3,2 +2178,elaborare,3,2 +2179,fosso,3,2 +2180,allibito,3,2 +2181,tramonto,3,2 +2182,iscriversi,3,2 +2183,esitare,3,2 +2184,incerto,3,2 +2185,bottino,3,2 +2186,marmo,3,2 +2187,compagno,3,2 +2188,tono,3,2 +2189,appellarsi,3,2 +2190,spietato,3,2 +2191,scarso,3,2 +2192,peccato,3,2 +2193,ripido,3,2 +2194,sforzarsi,3,2 +2195,contrazione,3,2 +2196,ondeggiare,3,2 +2197,sebbene,3,2 +2198,sfrenato,3,2 +2199,per conto,3,2 +2200,corrompere,3,2 +2201,gioco da ragazzi,3,2 +2202,rivendicazione,3,2 +2203,frenare,3,2 +2204,dilettarsi,3,2 +2205,idem,3,2 +2206,scorie,3,2 +2207,siccita',3,2 +2208,fatica,3,2 +2209,comportare,3,2 +2210,schiuma,3,2 +2211,sembianze,3,2 +2212,foschia,3,2 +2213,quindi,3,2 +2214,singhiozzo,3,2 +2215,ovviamente,3,2 +2216,stagno,3,2 +2217,retro,3,2 +2218,provare,3,2 +2219,accidia,3,2 +2220,scheggia,3,2 +2221,gonfiare,3,2 +2222,trainare,3,2 +2223,completamente,3,2 +2224,cera,3,2 +2225,grano,3,2 +2226,astuto,3,2 +2227,fondale,3,2 +2228,palude,3,2 +2229,insolente,3,2 +2230,intasare,3,2 +2231,arricciare,3,2 +2232,costernato,3,2 +2233,rafforzare,3,2 +2234,valorizzare,3,2 +2235,inverosimile,3,2 +2236,favorire,3,2 +2237,appariscente,3,2 +2238,azzardato,3,2 +2239,seccante,3,2 +2240,sontuoso,3,2 +2241,guinzaglio,3,2 +2242,aggredito,3,2 +2243,ennuplicato,3,2 +2244,famigerato,3,2 +2245,brevetto,3,2 +2246,fastidioso,3,2 +2247,divagare,3,2 +2248,distorcere,3,2 +2249,pendenza,3,2 +2250,sciatto,3,2 +2251,spaventare,3,2 +2252,sarto,3,2 +2253,armeggiare,3,2 +2254,diffidente,3,2 +2255,sorgente,3,2 +2256,sarcastico,3,2 +2257,riunione,3,2 +2258,argilla,3,2 +2259,fessura,3,2 +2260,storpio,3,2 +2261,investigare,3,2 +2262,atteggiamento,3,2 +2263,travestimento,3,2 +2264,volubile,3,2 +2265,pagliaio,3,2 +2266,ronzio,3,2 +2267,responsabile,3,2 +2268,oziare,3,2 +2269,incombente,3,2 +2270,agile,3,2 +2271,angolino,3,2 +2272,prioritario,3,2 +2273,propensione,3,2 +2274,pietoso,3,2 +2275,querela,3,2 +2276,stratagemma,3,2 +2277,rovistare,3,2 +2278,fruscio,3,2 +2279,cucito,3,2 +2280,spronare,3,2 +2281,soffocare,3,2 +2282,testardo,3,2 +2283,truffa,3,2 +2284,leccornia,3,2 +2285,benessere,3,2 +2286,posizione,3,2 +2287,cauzione,3,2 +2288,cespuglio,3,2 +2289,grossolano,3,2 +2290,rame,3,2 +2291,gingillarsi,3,2 +2292,suscitare,3,2 +2293,colpo di fortuna,3,2 +2294,lucido,3,2 +2295,arrestare,3,2 +2296,accumulare,3,2 +2297,esempio,3,2 +2298,chiavistello,3,2 +2299,appostarsi,3,2 +2300,tuttavia,3,2 +2301,nutrire,3,2 +2302,insidia,3,2 +2303,abilita',3,2 +2304,ricaduta,3,2 +2305,fantasticheria,3,2 +2306,ristretto,3,2 +2307,scremare,3,2 +2308,scalinata,3,2 +2309,allettante,3,2 +2310,buttare,3,2 +2311,vizioso,3,2 +2312,strambo,3,2 +2313,reparto,3,2 +2314,sentore,3,2 +2315,appassire,3,2 +2316,ruga,3,2 +2317,cenere,3,2 +2318,coperta,3,2 +2319,caldaia,3,2 +2320,scopa,3,2 +2321,armadietto,3,2 +2322,lampadario,3,2 +2323,stoviglie,3,2 +2324,cuscino,3,2 +2325,scolapiatti,3,2 +2326,maniglia,3,2 +2327,colomba,3,2 +2328,cassetto,3,2 +2329,bracie,3,2 +2330,poggiapiedi,3,2 +2331,brontolare,3,2 +2332,lancetta,3,2 +2333,serratura,3,2 +2334,soprammobile,3,2 +2335,forno,3,2 +2336,dispensa,3,2 +2337,termosifone,3,2 +2338,zaino,3,2 +2339,persiana,3,2 +2340,lavandino,3,2 +2341,pantofola,3,2 +2342,presa,3,2 +2343,rubinetto,3,2 +2344,piastrella,3,2 +2345,lavatoio,3,2 +2346,stufa,3,2 +2347,piazzale,3,2 +2348,carriola,3,2 +2349,faggio,3,2 +2350,betulla,3,2 +2351,merlo,3,2 +2352,carbone,3,2 +2353,rampicante,3,2 +2354,recinzione,3,2 +2355,amaca,3,2 +2356,raccolto,3,2 +2357,fieno,3,2 +2358,siepe,3,2 +2359,zappare,3,2 +2360,calabrone,3,2 +2361,arto,3,2 +2362,letame,3,2 +2363,fango,3,2 +2364,ciottolo,3,2 +2365,piccone,3,2 +2366,arare,3,2 +2367,portico,3,2 +2368,potare,3,2 +2369,rastrello,3,2 +2370,altalena,3,2 +2371,arbusto,3,2 +2372,seminare,3,2 +2373,vanga,3,2 +2374,paglia,3,2 +2375,terrazza,3,2 +2376,davanzale,3,2 +2377,anticipo,3,2 +2378,arduo,3,2 +2379,arrivo,3,2 +2380,bagaglio,3,2 +2381,prenotare,3,2 +2382,ufficio,3,2 +2383,garzone,3,2 +2384,partire,3,2 +2385,spedizione,3,2 +2386,approvare,3,2 +2387,scadenza,3,2 +2388,estero,3,2 +2389,porto,3,2 +2390,inebriante,3,2 +2391,autostop,3,2 +2392,rinvigorire,3,2 +2393,atterraggio,3,2 +2394,verso l'esterno,3,2 +2395,oltremare,3,2 +2396,pedone,3,2 +2397,rimandare,3,2 +2398,navigare,3,2 +2399,marciapiede,3,2 +2400,comprovare,3,2 +2401,decollo,3,2 +2402,casello,3,2 +2403,pedaggio,3,2 +2404,travagliato,3,2 +2405,impresa,3,2 +2406,parabrezza,3,2 +2407,aggiornamento,3,2 +2408,apprendista,3,2 +2409,svolta,3,2 +2410,commesso,3,2 +2411,timbrare,3,2 +2412,pendolare,3,2 +2413,licenziare,3,2 +2414,dovere,3,2 +2415,diritto,3,2 +2416,dirigente,3,2 +2417,tassa,3,2 +2418,avanzamento,3,2 +2419,concedere,3,2 +2420,reclamo,3,2 +2421,sede,3,2 +2422,gerarchia,3,2 +2423,infortunio,3,2 +2424,assicurato,3,2 +2425,operaio,3,2 +2426,imposta,3,2 +2427,onere,3,2 +2428,promozione,3,2 +2429,ammonizione,3,2 +2430,conservare,3,2 +2431,pensione,3,2 +2432,impianto,3,2 +2433,novellino,3,2 +2434,sostenere,3,2 +2435,stipendio,3,2 +2436,veterano,3,2 +2437,placare,3,2 +2438,vendicare,3,2 +2439,impazzito,3,2 +2440,abbuffata,3,2 +2441,amaro,3,2 +2442,scoppio,3,2 +2443,trambusto,3,2 +2444,presuntuoso,3,2 +2445,risaputo,3,2 +2446,smantellare,3,2 +2447,affidare,3,2 +2448,irritare,3,2 +2449,scontroso,3,2 +2450,pausa,3,2 +2451,disgustoso,3,2 +2452,nefasto,3,2 +2453,insensibile,3,2 +2454,esternalizzare,3,2 +2455,impavido,3,2 +2456,composto,3,2 +2457,reprimere,3,2 +2458,devastare,3,2 +2459,ritorsione,3,2 +2460,rimbalzare,3,2 +2461,marcio,3,2 +2462,rottame,3,2 +2463,spavalderia,3,2 +2464,rivalsa,3,2 +2465,vendicativo,3,2 +2466,malvagio,3,2 +2467,viale,3,2 +2468,insipido,3,2 +2469,bullone,3,2 +2470,allegro,3,2 +2471,frizione,3,2 +2472,trapano,3,2 +2473,lima,3,2 +2474,alluvione,3,2 +2475,fronzolo,3,2 +2476,burrasca,3,2 +2477,ghiaia,3,2 +2478,grandine,3,2 +2479,clacson,3,2 +2480,canna,3,2 +2481,prato,3,2 +2482,furibondo,3,2 +2483,commerciante,3,2 +2484,ammuffito,3,2 +2485,chiodo,3,2 +2486,pinza,3,2 +2487,maturo,3,2 +2488,vite,3,2 +2489,cacciavite,3,2 +2490,pala,3,2 +2491,cartello stradale,3,2 +2492,starnutire,3,2 +2493,milza,3,2 +2494,morsa,3,2 +2495,esausto,3,2 +2496,trachea,3,2 +2497,sminuire,3,2 +2498,diffidare,3,2 +2499,annebbiato,3,2 +2500,tonto,3,2 +2501,tizio,3,2 +2502,blandire,3,2 +2503,ritenere,3,2 +2504,difettoso,3,2 +2505,rifuggire,3,2 +2506,intontito,3,2 +2507,nanerottolo,3,2 +2508,ombelico,3,2 +2509,sgranocchiare,3,2 +2510,ciononostante,3,2 +2511,preventivo,3,2 +2512,pari,3,2 +2513,esperto,3,2 +2514,sparpagliarsi,3,2 +2515,imbarazzato,3,2 +2516,imprevisto,3,2 +2517,battibecco,3,2 +2518,cavalcioni,3,2 +2519,imbronciato,3,2 +2520,pizzicare,3,2 +2521,duplice,3,2 +2522,giuramento,3,2 +2523,smidollato,3,2 +2524,piagnucoloso,3,2 +2525,arguzia,3,2 +2526,collera,3,2 +2527,disinteressato,3,2 +2528,accordo,3,2 +2529,attendere,3,2 +2530,trifoglio,3,2 +2531,espressione,3,2 +2532,ingannare,3,2 +2533,sventura,3,2 +2534,agitarsi,3,2 +2535,fuggire,3,2 +2536,frustare,3,2 +2537,sventare,3,2 +2538,falsificazione,3,2 +2539,perquisire,3,2 +2540,vivace,3,2 +2541,finora,3,2 +2542,rannicchiato,3,2 +2543,baccano,3,2 +2544,snodato,3,2 +2545,rifiuti,3,2 +2546,socializzare,3,2 +2547,protesta,3,2 +2548,deporre,3,2 +2549,zampa,3,2 +2550,cava,3,2 +2551,ariete,3,2 +2552,sequestrare,3,2 +2553,scaltro,3,2 +2554,domare,3,2 +2555,tradimento,3,2 +2556,imprevisti,3,2 +2557,simile,3,2 +2558,indennita',3,2 +2559,orzo,3,2 +2560,fardello,3,2 +2561,cantina,3,2 +2562,rischioso,3,2 +2563,trasmettere,3,2 +2564,demoralizzare,3,2 +2565,origliare,3,2 +2566,proibire,3,2 +2567,predire,3,2 +2568,sfortunato,3,2 +2569,scocciatura,3,2 +2570,fretta,3,2 +2571,rischio,3,2 +2572,rapina,3,2 +2573,d'ora in avanti,3,2 +2574,senno di poi,3,2 +2575,impressione,3,2 +2576,silenzio,3,2 +2577,sciolto,3,2 +2578,adescare,3,2 +2579,meraviglia,3,2 +2580,commovente,3,2 +2581,litigare,3,2 +2582,lotteria,3,2 +2583,risentirsi,3,2 +2584,passeggiata,3,2 +2585,capovolgere,3,2 +2586,da dove,3,2 +2587,mandorla,3,2 +2588,riferimento,3,2 +2589,squadra,3,2 +2590,persuadere,3,2 +2591,differire,3,2 +2592,sconcertare,3,2 +2593,rancore,3,2 +2594,a capofitto,3,2 +2595,agitato,3,2 +2596,verza,3,2 +2597,laico,3,2 +2598,similmente,3,2 +2599,maldestro,3,2 +2600,girovagare,3,2 +2601,gemere,3,2 +2602,oltretutto,3,2 +2603,moderno,3,2 +2604,imminente,3,2 +2605,superfluo,3,2 +2606,dovuto,3,2 +2607,chiaramente,3,2 +2608,crollo,3,2 +2609,fedele,3,2 +2610,deciso,3,2 +2611,chinarsi,3,2 +2612,in tal modo,3,2 +2613,inquietante,3,2 +2614,incondizionato,3,2 +2615,impraticabile,3,2 +2616,seducente,3,2 +2617,confondere,3,2 +2618,implorare,3,2 +2619,bisticciare,3,2 +2620,candore,3,2 +2621,cauto,3,2 +2622,volgare,3,2 +2623,cassa,3,2 +2624,dotare,3,2 +2625,grinta,3,2 +2626,molestare,3,2 +2627,precursore,3,2 +2628,disagio,3,2 +2629,scossa,3,2 +2630,guazzabuglio,3,2 +2631,sentimentale,3,2 +2632,assalto,3,2 +2633,mitigare,3,2 +2634,scottare,3,2 +2635,imbroglio,3,2 +2636,rimproverare,3,2 +2637,appagare,3,2 +2638,massacro,3,2 +2639,uccidere,3,2 +2640,dispetto,3,2 +2641,sottile,3,2 +2642,dello stesso,3,2 +2643,imperturbabile,3,2 +2644,indisciplinato,3,2 +2645,illeso,3,2 +2646,decodificare,3,2 +2647,fedelta',3,2 +2648,sbilenco,3,2 +2649,spoglio,3,2 +2650,artiglio,3,2 +2651,corvo,3,2 +2652,privo,3,2 +2653,ridursi,3,2 +2654,piuma,3,2 +2655,svolazzare,3,2 +2656,zoppicare,3,2 +2657,mascella,3,2 +2658,soffermarsi,3,2 +2659,balzare,3,2 +2660,narici,3,2 +2661,gomitata,3,2 +2662,beccare,3,2 +2663,formicolio,3,2 +2664,contraccolpo,3,2 +2665,ribattere,3,2 +2666,stridio,3,2 +2667,alzare le spalle,3,2 +2668,manica,3,2 +2669,lieve,3,2 +2670,fiacco,3,2 +2671,bassifondi,3,2 +2672,austero,3,2 +2673,piombare,3,2 +2674,suscettibile,3,2 +2675,pulsare,3,2 +2676,lievito,3,2 +2677,nominare,3,2 +2678,vergognarsi,3,2 +2679,cenno,3,2 +2680,fascino,3,2 +2681,abisso,3,2 +2682,scricchiolare,3,2 +2683,rifiutare,3,2 +2684,disprezzare,3,2 +2685,misterioso,3,2 +2686,bagliore,3,2 +2687,luccichio,3,2 +2688,smorfia,3,2 +2689,coperchio,3,2 +2690,malizia,3,2 +2691,minaccia,3,2 +2692,trattenere,3,2 +2693,cedere,3,2 +2694,cipiglio,3,2 +2695,rabbrividire,3,2 +2696,strisciare,3,2 +2697,sogghigno,3,2 +2698,dolorante,3,2 +2699,teso,3,2 +2700,coscia,3,2 +2701,scompigliare,3,2 +2702,gocciolare,3,2 +2703,vita,3,2 +2704,slanciato,3,2 +2705,contorcersi,3,2 +2706,affiancato,3,2 +2707,vicolo,3,2 +2708,a pezzi,3,2 +2709,evitare,3,2 +2710,fronte,3,2 +2711,costringere,3,2 +2712,diga,3,2 +2713,umido,3,2 +2714,pisolino,3,2 +2715,gnocco,3,2 +2716,tenuta,3,2 +2717,prossimo,3,2 +2718,franco,3,2 +2719,concetto,3,2 +2720,pelle d'oca,3,2 +2721,era ora,3,2 +2722,colosso,3,2 +2723,sporgente,3,2 +2724,ridicolo,3,2 +2725,midollo,3,2 +2726,radunare,3,2 +2727,obbligare,3,2 +2728,riscattare,3,2 +2729,mischiare,3,2 +2730,sbandare,3,2 +2731,pullulare,3,2 +2732,di volta in volta,3,2 +2733,all'insaputa,3,2 +2734,ghiribizzo,3,2 +2735,oscillare,3,2 +2736,comunque,3,2 +2737,confessare,3,2 +2738,generare,3,2 +2739,legame,3,2 +2740,buttafuori,3,2 +2741,fendere,3,2 +2742,fannullone,3,2 +2743,esigere,3,2 +2744,lugubre,3,2 +2745,impasto,3,2 +2746,esaltare,3,2 +2747,enorme,3,2 +2748,squarcio,3,2 +2749,erede,3,2 +2750,intralcio,3,2 +2751,in quanto,3,2 +2752,infame,3,2 +2753,eccitare,3,2 +2754,indagare,3,2 +2755,ebreo,3,2 +2756,mite,3,2 +2757,tenebre,3,2 +2758,prole,3,2 +2759,ritrarre,3,2 +2760,blaterare,3,2 +2761,demolire,3,2 +2762,riferirsi,3,2 +2763,rottura,3,2 +2764,liscio,3,2 +2765,contaminare,3,2 +2766,legare,3,2 +2767,modello,3,2 +2768,rinforzare,3,2 +2769,limite,3,2 +2770,coerente,3,2 +2771,squallido,3,2 +2772,schivare,3,2 +2773,scarabocchio,3,2 +2774,applicare,3,2 +2775,impegnarsi,3,2 +2776,estensione,3,2 +2777,prevedere,3,2 +2778,due settimane,3,2 +2779,intravedere,3,2 +2780,mandria,3,2 +2781,gergo,3,2 +2782,complessivamente,3,2 +2783,accurato,3,2 +2784,stimare,3,2 +2785,riavvolgere,3,2 +2786,puro,3,2 +2787,sciocco,3,2 +2788,schizzinoso,3,2 +2789,stabile,3,2 +2790,sciopero,3,2 +2791,supporre,3,2 +2792,fremito,3,2 +2793,spingere,3,2 +2794,tregua,3,2 +2795,goffo,3,2 +2796,avvocato,3,2 +2797,avverso,3,2 +2798,cinghiale,3,2 +2799,lucidare,3,2 +2800,fascio,3,2 +2801,truffatore,3,2 +2802,cucciolo,3,2 +2803,rinnegare,3,2 +2804,sconforto,3,2 +2805,comprendere,3,2 +2806,prodezza,3,2 +2807,cruento,3,2 +2808,incendiare,3,2 +2809,balzo,3,2 +2810,figuriamoci,3,2 +2811,seccatura,3,2 +2812,strano,3,2 +2813,scavalcare,3,2 +2814,sbirciare,3,2 +2815,segnaposto,3,2 +2816,predicare,3,2 +2817,indipendentemente,3,2 +2818,linfa,3,2 +2819,intrufolarsi,3,2 +2820,scorrere,3,2 +2821,denunciare,3,2 +2822,contrastare,3,2 +2823,insegnamento,3,2 +2824,vuoto,3,2 +2825,deformare,3,2 +2826,ausiliario,3,2 +2827,disorientare,3,2 +2828,sbottare,3,2 +2829,in scatola,3,2 +2830,schiaffo,3,2 +2831,posate,3,2 +2832,terribile,3,2 +2833,bozza,3,2 +2834,piumone,3,2 +2835,attirare,3,2 +2836,forza d'animo,3,2 +2837,intoppo,3,2 +2838,affrettarsi,3,2 +2839,compromettere,3,2 +2840,rigoglioso,3,2 +2841,incantare,3,2 +2842,ingenuo,3,2 +2843,emarginato,3,2 +2844,pezza,3,2 +2845,smerciare,3,2 +2846,ficcare,3,2 +2847,gracile,3,2 +2848,scarafaggio,3,2 +2849,traballante,3,2 +2850,striminzito,3,2 +2851,furbo,3,2 +2852,lenire,3,2 +2853,ondata,3,2 +2854,vapore,3,2 +2855,solletico,3,2 +2856,melanzana,3,2 +2857,manzo,3,2 +2858,candeggina,3,2 +2859,ciotola,3,2 +2860,massiccio,3,2 +2861,zucchina,3,2 +2862,croccante,3,2 +2863,cetriolo,3,2 +2864,subdolo,3,2 +2865,fattoria,3,2 +2866,fiocco,3,2 +2867,wurstel,3,2 +2868,prosciutto,3,2 +2869,stizzito,3,2 +2870,bollitore,3,2 +2871,pagnotta,3,2 +2872,potente,3,2 +2873,tazza,3,2 +2874,pisello,3,2 +2875,arachide,3,2 +2876,peperone,3,2 +2877,flessibile,3,2 +2878,pentola,3,2 +2879,spericolato,3,2 +2880,sciacquare,3,2 +2881,panino,3,2 +2882,spugna,3,2 +2883,fornello,3,2 +2884,bicchiere,3,2 +2885,integrale,3,2 +2886,macchia,3,2 +2887,scivolo,3,2 +2888,nascondere,3,2 +2889,osare,3,2 +2890,offuscare,3,2 +2891,eliminazione,3,2 +2892,droga,3,2 +2893,sforzo,3,2 +2894,esilio,3,2 +2895,impiegare,3,2 +2896,frizzante,3,2 +2897,cautamente,3,2 +2898,truce,3,2 +2899,cappuccio,3,2 +2900,insorto,3,2 +2901,spintonare,3,2 +2902,souvenir,3,2 +2903,lavanderia,3,2 +2904,tiepido,3,2 +2905,aggiustare,3,2 +2906,sfogo,3,2 +2907,esterno,3,2 +2908,sbucciare,3,2 +2909,gonfio,3,2 +2910,scrostare,3,2 +2911,affilato,3,2 +2912,allentare,3,2 +2913,vassoio,3,2 +2914,ritirare,3,2 +2915,trattenuto,3,2 +2916,rapire,3,2 +2917,divertire,3,2 +2918,offrire,3,2 +2919,sfacciato,3,2 +2920,furia,3,2 +2921,alcolico,3,2 +2922,cavolo,3,2 +2923,cavolfiore,3,2 +2924,apprezzare,3,2 +2925,ceci,3,2 +2926,divulgare,3,2 +2927,debole,3,2 +2928,lentiggine,3,2 +2929,va al diavolo,3,2 +2930,pascolare,3,2 +2931,posteriore,3,2 +2932,appassionato,3,2 +2933,mestolo,3,2 +2934,sollevare,3,2 +2935,interruzione,3,2 +2936,lucchetto,3,2 +2937,importunare,3,2 +2938,curiosare,3,2 +2939,bruciatura,3,2 +2940,affronto,3,2 +2941,schiacciare,3,2 +2942,tessuto,3,2 +2943,pancia,3,2 +2944,magnate,3,2 +2945,bordo,3,2 +2946,smarrito,3,2 +2947,infuso,3,2 +2948,rovesciarsi,3,2 +2949,ideare,3,2 +2950,miscuglio,3,2 +2951,cucina,3,2 +2952,abbagliare,3,2 +2953,esaurire,3,2 +2954,scontento,3,2 +2955,incorporare,3,2 +2956,congedo,3,2 +2957,gregge,3,2 +2958,popolare,3,2 +2959,rinunciare,3,2 +2960,altezzoso,3,2 +2961,interazione,3,2 +2962,intromettersi,3,2 +2963,scherzo,3,2 +2964,deridere,3,2 +2965,principio,3,2 +2966,portamento,3,2 +2967,respiro,3,2 +2968,assaporare,3,2 +2969,trasandato,3,2 +2970,compiaciuto,3,2 +2971,convocare,3,2 +2972,parsimonia,3,2 +2973,refuso,3,2 +2974,sconvolgimento,3,2 +2975,conflitto,3,2 +2976,battere,3,2 +2977,infastidire,3,2 +2978,bombo,3,2 +2979,scolapasta,3,2 +2980,scombussolare,3,2 +2981,malattia,3,2 +2982,fugace,3,2 +2983,soffice,3,2 +2984,martello,3,2 +2985,nostalgia di casa,3,2 +2986,emanare,3,2 +2987,inaffidabile,3,2 +2988,patetico,3,2 +2989,ninna nanna,3,2 +2990,fresa,3,2 +2991,umore,3,2 +2992,angusto,3,2 +2993,ascesa,3,2 +2994,forbice,3,2 +2995,setoso,3,2 +2996,odore,3,2 +2997,rachide,3,2 +2998,stantio,3,2 +2999,puzza,3,2 +3000,sciame,3,2 +3001,arazzo,3,2 +3002,insopportabile,3,2 +3003,empio,3,2 +3004,ineffabile,3,2 +3005,guizzo,3,2 +3006,allettare,3,2 +3007,revisione,3,2 +3008,tramandare,3,2 +3009,conferire,3,2 +3010,sete di sangue,3,2 +3011,setola,3,2 +3012,presunzione,3,2 +3013,squilibrato,3,2 +3014,produrre,3,2 +3015,travolgere,3,2 +3016,azienda,3,2 +3017,mischia,3,2 +3018,vistoso,3,2 +3019,arroganza,3,2 +3020,scagliare,3,2 +3021,perdita,3,2 +3022,modesto,3,2 +3023,prezzemolo,3,2 +3024,saccheggiare,3,2 +3025,versare,3,2 +3026,filtrare,3,2 +3027,riva,3,2 +3028,ripudiare,3,2 +3029,assedio,3,2 +3030,sperperare,3,2 +3031,contesa,3,2 +3032,spettegolare,3,2 +3033,faticare,3,2 +3034,incontenibile,3,2 +3035,battuto,3,2 +3036,inorridito,3,2 +3037,amabile,3,2 +3038,sfotto',3,2 +3039,abbaiare,3,2 +3040,leccapiedi,3,2 +3041,accogliente,3,2 +3042,fingere,3,2 +3043,folletto,3,2 +3044,talento,3,2 +3045,negligenza,3,2 +3046,iperattivo,3,2 +3047,scarsezza,3,2 +3048,pancione,3,2 +3049,arrancare,3,2 +3050,borsetta,3,2 +3051,ruggine,3,2 +3052,ciondolare,3,2 +3053,stuzzicare,3,2 +3054,lattina,3,2 +3055,corteggiare,3,2 +3056,valutazione,3,2 +3057,furto,3,2 +3058,cronaca,3,2 +3059,deriva,3,2 +3060,tariffa,3,2 +3061,antagonista,3,2 +3062,contraddire,3,2 +3063,misurare,3,2 +3064,ingorgo,3,2 +3065,botola,3,2 +3066,dirottare,3,2 +3067,cardine,3,2 +3068,anzi,3,2 +3069,contrattempo,3,2 +3070,dramma,3,2 +3071,ponderare,3,2 +3072,rimedio,3,2 +3073,dilagante,3,2 +3074,ribollire,3,2 +3075,lacrima,3,2 +3076,assistenza,3,2 +3077,tra,3,2 +3078,smentire,3,2 +3079,sbiancare,3,2 +3080,masso,3,2 +3081,scolpire,3,2 +3082,favola,3,2 +3083,sguardo,3,2 +3084,gioia,3,2 +3085,adirato,3,2 +3086,confusione,3,2 +3087,superare,3,2 +3088,irascibile,3,2 +3089,stupro,3,2 +3090,salvia,3,2 +3091,sangue freddo,3,2 +3092,disprezzo,3,2 +3093,pedante,3,2 +3094,tensione,3,2 +3095,spettro,3,2 +3096,capitare,3,2 +3097,lamentarsi,3,2 +3098,falso,3,2 +3099,spostarsi,3,2 +3100,pettine,3,2 +3101,sussulto,3,2 +3102,affliggere,3,2 +3103,umiliarsi,3,2 +3104,trascinare,3,2 +3105,custode,3,2 +3106,infausto,3,2 +3107,molletta,3,2 +3108,medico,3,2 +3109,puntiglio,3,2 +3110,battuta,3,2 +3111,incursione,3,2 +3112,manifestazione,3,2 +3113,tendine,3,2 +3114,sgobbare,3,2 +3115,calpestare,3,2 +3116,assecondare,3,2 +3117,colonna portante,3,2 +3118,spaccone,3,2 +3119,rimuginare,3,2 +3120,cospirare,3,2 +3121,rettore,3,2 +3122,violino,3,2 +3123,fianco,3,2 +3124,punto morto,3,2 +3125,anticonformista,3,2 +3126,prospettiva,3,2 +3127,spillo,3,2 +3128,consapevole,3,2 +3129,teppista,3,2 +3130,pretendere,3,2 +3131,dimettersi,3,2 +3132,difetto,3,2 +3133,conforto,3,2 +3134,svenire,3,2 +3135,pioniere,3,2 +3136,provvedere,3,2 +3137,castigare,3,2 +3138,inzuppare,3,2 +3139,adeguatamente,3,2 +3140,stordito,3,2 +3141,planare,3,2 +3142,contrattare,3,2 +3143,allusione,3,2 +3144,incallito,3,2 +3145,cupo,3,2 +3146,calunnia,3,2 +3147,scivolare,3,2 +3148,snobbare,3,2 +3149,riporre,3,2 +3150,broncio,3,2 +3151,fasciare,3,2 +3152,acceleratore,3,2 +3153,saldare,3,2 +3154,mezzi,3,2 +3155,strizzare,3,2 +3156,tardivo,3,2 +3157,annerire,3,2 +3158,bancarella,3,2 +3159,mortificazione,3,2 +3160,aggrappare,3,2 +3161,brusco,3,2 +3162,screditare,3,2 +3163,depresso,3,2 +3164,impertinente,3,2 +3165,affezionato,3,2 +3166,raffica,3,2 +3167,guscio,3,2 +3168,marsupio,3,2 +3169,affidabile,3,2 +3170,strofinare,3,2 +3171,riservato,3,2 +3172,puntina,3,2 +3173,tonfo,3,2 +3174,adulare,3,2 +3175,disgraziato,3,2 +3176,splendente,3,2 +3177,albicocca,3,2 +3178,passante,3,2 +3179,sconvolto,3,2 +3180,assorto,3,2 +3181,impugnatura,3,2 +3182,immischiarsi,3,2 +3183,ricordo,3,2 +3184,nuvoloso,3,2 +3185,incentivo,3,2 +3186,pretesto,3,2 +3187,incline,3,2 +3188,impicciarsi,3,2 +3189,ritornello,3,2 +3190,disastro,3,2 +3191,accovacciarsi,3,2 +3192,afoso,3,2 +3193,brillo,3,2 +3194,spago,3,2 +3195,presumibilmente,3,2 +3196,pasticcio,3,2 +3197,spiraglio,3,2 +3198,fondersi,3,2 +3199,tubatura,3,2 +3200,evocare,3,2 +3201,temerario,3,2 +3202,deviazione,3,2 +3203,controversia,3,2 +3204,affascinare,3,2 +3205,perbacco,3,2 +3206,registro,3,2 +3207,mutuo,3,2 +3208,esigente,3,2 +3209,sondaggio,3,2 +3210,condimento,3,2 +3211,strattone,3,2 +3212,imperterrito,3,2 +3213,valoroso,3,2 +3214,guaito,3,2 +3215,maggiordomo,3,2 +3216,cinico,3,2 +3217,culla,3,2 +3218,monouso,3,2 +3219,inimicizia,3,2 +3220,equo,3,2 +3221,nocciola,3,2 +3222,frenetico,3,2 +3223,improvvisato,3,2 +3224,tempra,3,2 +3225,colare,3,2 +3226,revisionare,3,2 +3227,opuscolo,3,2 +3228,tendenza,3,2 +3229,ansimare,3,2 +3230,fornitore,3,2 +3231,ambito,3,2 +3232,fisima,3,2 +3233,prodigio,3,2 +3234,emendare,3,2 +3235,attribuire,3,2 +3236,barista,3,2 +3237,allevare,3,2 +3238,coltura,3,2 +3239,figurarsi,3,2 +3240,portami,3,2 +3241,imperfezione,3,2 +3242,pulce,3,2 +3243,consacrare,3,2 +3244,cavo,3,2 +3245,monotono,3,2 +3246,caos,3,2 +3247,apprensione,3,2 +3248,pegno,3,2 +3249,localizzare,3,2 +3250,colmo,3,2 +3251,resistere,3,2 +3252,tuorlo,3,2 +3253,tormentare,3,2 +3254,incontro,3,2 +3255,autorizzazione,3,2 +3256,sfatare,3,2 +3257,facciata,3,2 +3258,afferrare,3,2 +3259,frangia,3,2 +3260,polverone,3,2 +3261,lepre,3,2 +3262,efferato,3,2 +3263,infondere,3,2 +3264,interferire,3,2 +3265,torbido,3,2 +3266,malgrado,3,2 +3267,in ritardo,3,2 +3268,opinionista,3,2 +3269,risarcimento,3,2 +3270,strappare,3,2 +3271,flessuoso,3,2 +3272,sciocchezza,3,2 +3273,catturare,3,2 +3274,oltre,3,2 +3275,risultato finale,3,2 +3276,coprirsi bene,3,2 +3277,per caso,3,2 +3278,recuperare,3,2 +3279,capo,3,2 +3280,fare un salto,3,2 +3281,fai piano,3,2 +3282,credulone,3,2 +3283,orientato,3,2 +3284,ricorda le mie parole,3,2 +3285,birichino,3,2 +3286,in forma,3,2 +3287,botta e risposta,3,2 +3288,escludere,3,2 +3289,avviarci,3,2 +3290,tampone,3,2 +3291,allontanare,3,2 +3292,informatore,3,2 +3293,alleviare,3,2 +3294,coagulare,3,2 +3295,arruolare,3,2 +3296,emblema,3,2 +3297,per quattro soldi,3,2 +3298,seguire la corrente,3,2 +3299,impastare,3,2 +3300,arrangiarsi,3,2 +3301,testa a testa,3,2 +3302,parente prossimo,3,2 +3303,ficcanaso,3,2 +3304,precipitare,3,2 +3305,permaloso,3,2 +3306,rassicurare,3,2 +3307,tenace,3,2 +3308,alga,3,2 +3309,cosi' per dire,3,2 +3310,sotto tiro,3,2 +3311,aceto,3,2 +3312,chiudi il becco,3,2 +3313,dacci un taglio,3,2 +3314,impassibile,3,2 +3315,a scoppio ritardato,3,2 +3316,sbalordire,3,2 +3317,sciacquone,3,2 +3318,riagganciare,3,2 +3319,ricucire i rapporti,3,2 +3320,all'ultimo secondo,3,2 +3321,passo e chiudo,3,2 +3322,salotto,3,2 +3323,fare la predica,3,2 +3324,prugna,3,2 +3325,fetore,3,2 +3326,cambiamento radicale,3,2 +3327,felpa,3,2 +3328,banco di prova,3,2 +3329,essere all'altezza,3,2 +3330,controverso,3,2 +3331,andare a finire,3,2 +3332,chiave inglese,3,2 +3333,infangare,3,2 +3334,ventilatore,3,2 +3335,inetto,3,2 +3336,abbandonato,3,2 +3337,cartilagine,3,2 +3338,tallone,3,2 +3339,superstite,3,2 +3340,mettere in dubbio,3,2 +3341,schernire,3,2 +3342,insignificante,3,2 +3343,gioco di parole,3,2 +3344,marmaglia,3,2 +3345,fascia,3,2 +3346,stridulo,3,2 +3347,femminuccia,3,2 +3348,pendere,3,2 +3349,aspro,3,2 +3350,sbrogliare,3,2 +3351,vagabondo,3,2 +3352,lana,3,2 +3353,a galla,3,2 +3354,barbabietola,3,2 +3355,impacciato,3,2 +3356,garanzia,3,2 +3357,dilemma,3,2 +3358,convalidare,3,2 +3359,stampella,3,2 +3360,randello,3,2 +3361,disingannare,3,2 +3362,filo interdentale,3,2 +3363,diceria,3,2 +3364,sferruzzare,3,2 +3365,imparare a memoria,3,2 +3366,consultare,3,2 +3367,tradizioni,3,2 +3368,imitazione,3,2 +3369,spiegazzare,3,2 +3370,buona sorte,3,2 +3371,gareggiare,3,2 +3372,scagionare,3,2 +3373,miscela,3,2 +3374,brodo,3,2 +3375,sgretolarsi,3,2 +3376,commissione,3,2 +3377,espediente,3,2 +3378,racimolare,3,2 +3379,frivolo,3,2 +3380,inviolabile,3,2 +3381,granturco,3,2 +3382,misero,3,2 +3383,boccone,3,2 +3384,panacea,3,2 +3385,immacolato,3,2 +3386,poltiglia,3,2 +3387,superficiale,3,2 +3388,tosare,3,2 +3389,mandato,3,2 +3390,lacero,3,2 +3391,ramoscello,3,2 +3392,velluto,3,2 +3393,bachelor,3,1 +3394,scapolo,3,2 +3395,bemused,3,1 +3396,perplesso,3,2 +3397,bilk,3,1 +3398,frodare,3,2 +3399,bite the bullet,3,1 +3400,stringere i denti,3,2 +3401,breach,3,1 +3402,violazione,3,2 +3403,bruise,3,1 +3404,livido,3,2 +3405,chicken out,3,1 +3406,tirarsi indietro,3,2 +3407,cork,3,1 +3408,sughero,3,2 +3409,crane,3,1 +3410,gru,3,2 +3411,dub,3,1 +3412,doppiare,3,2 +3413,embroider,3,1 +3414,ricamare,3,2 +3415,glower,3,1 +3416,guardare torvo,3,2 +3417,hatchet,3,1 +3418,accetta,3,2 +3419,kick back,3,1 +3420,rilassarsi,3,2 +3421,overpower,3,1 +3422,sopraffare,3,2 +3423,patrol,3,1 +3424,pattuglia,3,2 +3425,pittance,3,1 +3426,inezia,3,2 +3427,sewer,3,1 +3428,fogna,3,2 +3429,sorcerer,3,1 +3430,stregone,3,2 +3431,uncork,3,1 +3432,stappare,3,2 +3433,coy,3,1 +3434,schivo,3,2 +3435,dew,3,1 +3436,rugiada,3,2 +3437,entreaty,3,1 +3438,supplica,3,2 +3439,fierce,3,1 +3440,impetuoso,3,2 +3441,groin,3,1 +3442,inguine,3,2 +3443,maim,3,1 +3444,mutilare,3,2 +3445,mores,3,1 +3446,usanze,3,2 +3447,nanny,3,1 +3448,tata,3,2 +3449,ox,3,1 +3450,bue,3,2 +3451,pensive,3,1 +3452,pensieroso,3,2 +3453,peril,3,1 +3454,serio pericolo,3,2 +3455,ransom,3,1 +3456,riscatto,3,2 +3457,smith,3,1 +3458,fabbro,3,2 +3459,sprain,3,1 +3460,distorsione,3,2 +3461,stutter,3,1 +3462,balbettare,3,2 +3463,suffice,3,1 +3464,bastare,3,2 +3465,swamp,3,1 +3466,sommergere,3,2 +3467,tally,3,1 +3468,conteggio,3,2 +3469,tawdry,3,1 +3470,pacchiano,3,2 +3471,thimble,3,1 +3472,ditale,3,2 +3473,beside,3,1 +3474,accanto,3,2 +3475,beside the point,3,1 +3476,non c'entra,3,2 +3477,bladder,3,1 +3478,vescica,3,2 +3479,boast,3,1 +3480,vantare,3,2 +3481,daze,3,1 +3482,stordimento,3,2 +3483,fussy,3,1 +3484,pignolo,3,2 +3485,garrulous,3,1 +3486,chiacchierone,3,2 +3487,lecherous,3,1 +3488,lascivo,3,2 +3489,muzzle,3,1 +3490,museruola,3,2 +3491,noxious,3,1 +3492,nocivo,3,2 +3493,offset,3,1 +3494,compensare,3,2 +3495,ordeal,3,1 +3496,calvario,3,2 +3497,pantyhose,3,1 +3498,collant,3,2 +3499,repentant,3,1 +3500,pentito,3,2 +3501,ripple,3,1 +3502,increspatura,3,2 +3503,scabbard,3,1 +3504,fodero,3,2 +3505,sheath,3,1 +3506,guaina,3,2 +3507,sprawl,3,1 +3508,distendersi,3,2 +3509,talkative,3,1 +3510,loquace,3,2 +3511,uncouth,3,1 +3512,rozzo,3,2 +3513,breathtaking,3,1 +3514,mozzafiato,3,2 +3515,cougar,3,1 +3516,puma,3,2 +3517,crawl,3,1 +3518,gattonare,3,2 +3519,elsewhere,3,1 +3520,altrove,3,2 +3521,enclose,3,1 +3522,racchiudere,3,2 +3523,handcuff,3,1 +3524,ammanettare,3,2 +3525,hold on,3,1 +3526,tenere duro,3,2 +3527,midwife,3,1 +3528,ostetrica,3,2 +3529,outshine,3,1 +3530,mettere in ombra,3,2 +3531,resemble,3,1 +3532,assomigliare,3,2 +3533,right on cue,3,1 +3534,al momento giusto,3,2 +3535,roam,3,1 +3536,vagare,3,2 +3537,scrawny,3,1 +3538,pelle e ossa,3,2 +3539,shortage,3,1 +3540,carenza,3,2 +3541,sleep in,3,1 +3542,dormire fino a tardi,3,2 +3543,splurge,3,1 +3544,scialacquare,3,2 +3545,tablecloth,3,1 +3546,tovaglia,3,2 +3547,trespass,3,1 +3548,sconfinare,3,2 +3549,turn a blind eye,3,1 +3550,chiudere un occhio,3,2 +3551,upbeat,3,1 +3552,ottimista,3,2 +3553,aftermath,3,1 +3554,conseguenze,3,2 +3555,broadcast,3,1 +3556,trasmissione,3,2 +3557,circuitous,3,1 +3558,tortuoso,3,2 +3559,contempt,3,1 +3560,dispregio,3,2 +3561,curtain,3,1 +3562,tenda,3,2 +3563,deft,3,1 +3564,abile,3,2 +3565,defy,3,1 +3566,sfidare,3,2 +3567,dial,3,1 +3568,comporre,3,2 +3569,district,3,1 +3570,quartiere,3,2 +3571,dummy,3,1 +3572,manichino,3,2 +3573,firefly,3,1 +3574,lucciola,3,2 +3575,flaunt,3,1 +3576,sfoggiare,3,2 +3577,fur,3,1 +3578,pelliccia,3,2 +3579,gulp,3,1 +3580,sorso,3,2 +3581,hiss,3,1 +3582,sibilo,3,2 +3583,pack,3,1 +3584,branco,3,2 +3585,pierce,3,1 +3586,forare,3,2 +3587,praise,3,1 +3588,elogio,3,2 +3589,sidestep,3,1 +3590,eludere,3,2 +3591,watchful,3,1 +3592,vigile,3,2 +3593,advocate,3,1 +3594,sostenitore,3,2 +3595,ailment,3,1 +3596,indisposizione,3,2 +3597,coffer,3,1 +3598,forziere,3,2 +3599,dent,3,1 +3600,ammaccatura,3,2 +3601,dither,3,1 +3602,indecisione,3,2 +3603,feisty,3,1 +3604,esuberante,3,2 +3605,fief,3,1 +3606,feudo,3,2 +3607,funnel,3,1 +3608,imbuto,3,2 +3609,grope,3,1 +3610,brancolare,3,2 +3611,heyday,3,1 +3612,apogeo,3,2 +3613,maid,3,1 +3614,domestica,3,2 +3615,motley,3,1 +3616,eterogeneo,3,2 +3617,nick,3,1 +3618,intaccare,3,2 +3619,outermost,3,1 +3620,piu' esterno,3,2 +3621,plea,3,1 +3622,appello,3,2 +3623,rue,3,1 +3624,rimpiangere,3,2 +3625,seam,3,1 +3626,cucitura,3,2 +3627,standoff,3,1 +3628,stallo,3,2 +3629,tiptoe,3,1 +3630,in punta di piedi,3,2 +3631,vibe,3,1 +3632,atmosfera,3,2 +3633,abate,3,1 +3634,ridurre,3,2 +3635,abridge,3,1 +3636,abbreviare,3,2 +3637,abrupt,3,1 +3638,improvviso,3,2 +3639,bane,3,1 +3640,rovina,3,2 +3641,beguile,3,1 +3642,ammaliare,3,2 +3643,blunder,3,1 +3644,abbaglio,3,2 +3645,blurb,3,1 +3646,trafiletto,3,2 +3647,drool,3,1 +3648,sbavare,3,2 +3649,enliven,3,1 +3650,ravvivare,3,2 +3651,furniture,3,1 +3652,arredamento,3,2 +3653,glut,3,1 +3654,eccesso,3,2 +3655,jocular,3,1 +3656,scherzoso,3,2 +3657,mislay,3,1 +3658,smarrire,3,2 +3659,overstate,3,1 +3660,enfatizzare,3,2 +3661,pertain,3,1 +3662,riguardare,3,2 +3663,quagmire,3,1 +3664,pantano,3,2 +3665,rephrase,3,1 +3666,riformulare,3,2 +3667,soar,3,1 +3668,librarsi,3,2 +3669,unpalatable,3,1 +3670,sgradevole,3,2 +3671,utterance,3,1 +3672,affermazione,3,2 +3673,backlash,3,1 +3674,ripercussione,3,2 +3675,badmouth,3,1 +3676,sparlare,3,2 +3677,bereft of,3,1 +3678,privo di,3,2 +3679,blemish,3,1 +3680,pecca,3,2 +3681,deter,3,1 +3682,dissuadere,3,2 +3683,dishearten,3,1 +3684,avvilire,3,2 +3685,encroach,3,1 +3686,invadere,3,2 +3687,ensnare,3,1 +3688,intrappolare,3,2 +3689,fallacy,3,1 +3690,incongruenza,3,2 +3691,infringe,3,1 +3692,violare,3,2 +3693,likelihood,3,1 +3694,possibilita',3,2 +3695,offhand,3,1 +3696,su due piedi,3,2 +3697,onward,3,1 +3698,in avanti,3,2 +3699,prior,3,1 +3700,precedente,3,2 +3701,query,3,1 +3702,interrogare,3,2 +3703,ravenous,3,1 +3704,famelico,3,2 +3705,revere,3,1 +3706,riverire,3,2 +3707,sham,3,1 +3708,finzione,3,2 +3709,travesty,3,1 +3710,parodia,3,2 +3711,typify,3,1 +3712,caratterizzare,3,2 +3713,avail,3,1 +3714,avvalersi,3,2 +3715,chairman,3,1 +3716,presidente,3,2 +3717,clique,3,1 +3718,cricca,3,2 +3719,dab,3,1 +3720,tamponare,3,2 +3721,despicable,3,1 +3722,spregevole,3,2 +3723,enfeeble,3,1 +3724,indebolire,3,2 +3725,essay,3,1 +3726,tema,3,2 +3727,expendable,3,1 +3728,sacrificabile,3,2 +3729,fluster,3,1 +3730,agitazione,3,2 +3731,foolhardy,3,1 +3732,avventato,3,2 +3733,forbearance,3,1 +3734,tolleranza,3,2 +3735,forefront,3,1 +3736,prima linea,3,2 +3737,geek,3,1 +3738,secchione,3,2 +3739,hoarse,3,1 +3740,rauco,3,2 +3741,loath,3,1 +3742,restio,3,2 +3743,lockdown,3,1 +3744,isolamento,3,2 +3745,scarf,3,1 +3746,sciarpa,3,2 +3747,staple,3,1 +3748,di base,3,2 +3749,terse,3,1 +3750,conciso,3,2 +3751,womb,3,1 +3752,grembo,3,2 +3753,ajar,3,1 +3754,socchiuso,3,2 +3755,bootleg,3,1 +3756,di contrabbando,3,2 +3757,cocoon,3,1 +3758,bozzolo,3,2 +3759,commodity,3,1 +3760,merce,3,2 +3761,compass,3,1 +3762,bussola,3,2 +3763,connoisseur,3,1 +3764,intenditore,3,2 +3765,dandruff,3,1 +3766,forfora,3,2 +3767,devious,3,1 +3768,infido,3,2 +3769,garble,3,1 +3770,alterare,3,2 +3771,gate,3,1 +3772,cancello,3,2 +3773,glutton,3,1 +3774,ingordo,3,2 +3775,infer,3,1 +3776,dedurre,3,2 +3777,poppy,3,1 +3778,papavero,3,2 +3779,probe,3,1 +3780,sonda,3,2 +3781,renege,3,1 +3782,venire meno,3,2 +3783,shin,3,1 +3784,stinco,3,2 +3785,sickle,3,1 +3786,falcetto,3,2 +3787,skunk,3,1 +3788,puzzola,3,2 +3789,treatise,3,1 +3790,trattato,3,2 +3791,wield,3,1 +3792,detenere,3,2 +3793,ashtray,3,1 +3794,posacenere,3,2 +3795,binder,3,1 +3796,raccoglitore,3,2 +3797,bounty,3,1 +3798,taglia,3,2 +3799,clatter,3,1 +3800,sferragliare,3,2 +3801,cleavage,3,1 +3802,scollatura,3,2 +3803,convene,3,1 +3804,riunire,3,2 +3805,crevice,3,1 +3806,crepa,3,2 +3807,flagon,3,1 +3808,caraffa,3,2 +3809,flout,3,1 +3810,farsi beffa,3,2 +3811,frostbite,3,1 +3812,congelamento,3,2 +3813,hoist,3,1 +3814,issare,3,2 +3815,naughty,3,1 +3816,disobbediente,3,2 +3817,nifty,3,1 +3818,ingegnoso,3,2 +3819,oath,3,1 +3820,promessa,3,2 +3821,personnel,3,1 +3822,personale,3,2 +3823,rejuvenate,3,1 +3824,ringiovanire,3,2 +3825,scramble,3,1 +3826,arrampicarsi,3,2 +3827,snide,3,1 +3828,malizioso,3,2 +3829,snore,3,1 +3830,russare,3,2 +3831,worthwhile,3,1 +3832,vale la pena,3,2 +3833,apt,3,1 +3834,adatto,3,2 +3835,brunt,3,1 +3836,impatto,3,2 +3837,burrow,3,1 +3838,tana,3,2 +3839,chubby,3,1 +3840,paffuto,3,2 +3841,debar,3,1 +3842,bandire,3,2 +3843,dump,3,1 +3844,scaricare,3,2 +3845,fed up,3,1 +3846,stufo,3,2 +3847,gnat,3,1 +3848,moscerino,3,2 +3849,grime,3,1 +3850,sporcizia,3,2 +3851,impair,3,1 +3852,pregiudicare,3,2 +3853,kinship,3,1 +3854,parentela,3,2 +3855,landfill,3,1 +3856,discarica,3,2 +3857,lead,3,1 +3858,piombo,3,2 +3859,mole,3,1 +3860,talpa,3,2 +3861,nag,3,1 +3862,assillare,3,2 +3863,outwit,3,1 +3864,raggirare,3,2 +3865,pudding,3,1 +3866,budino,3,2 +3867,underuse,3,1 +3868,sottoutilizzare,3,2 +3869,uppity,3,1 +3870,arrogante,3,2 +3871,veritable,3,1 +3872,vero e proprio,3,2 +3873,although,3,1 +3874,anche se,3,2 +3875,billboard,3,1 +3876,manifesto,3,2 +3877,brook,3,1 +3878,ruscello,3,2 +3879,brush,3,1 +3880,pennello,3,2 +3881,concern,3,1 +3882,preoccupazione,3,2 +3883,debriefing,3,1 +3884,rapporto,3,2 +3885,dexterity,3,1 +3886,destrezza,3,2 +3887,duct,3,1 +3888,condotto,3,2 +3889,due,3,1 +3890,scadere,3,2 +3891,furthermore,3,1 +3892,inoltre,3,2 +3893,halve,3,1 +3894,dimezzare,3,2 +3895,handpick,3,1 +3896,selezionare,3,2 +3897,henceforth,3,1 +3898,d'ora in poi,3,2 +3899,leeway,3,1 +3900,margine d'azione,3,2 +3901,meanwhile,3,1 +3902,nel frattempo,3,2 +3903,otherwise,3,1 +3904,altrimenti,3,2 +3905,regard,3,1 +3906,considerare,3,2 +3907,scepter,3,1 +3908,scettro,3,2 +3909,severance,3,1 +3910,separazione,3,2 +3911,yearn,3,1 +3912,anelare,3,2 +3913,amiss,3,1 +3914,fuori luogo,3,2 +3915,assess,3,1 +3916,valutare,3,2 +3917,attain,3,1 +3918,raggiungere,3,2 +3919,chore,3,1 +3920,lavoretto,3,2 +3921,compelled,3,1 +3922,costretto,3,2 +3923,detrimental,3,1 +3924,dannoso,3,2 +3925,discern,3,1 +3926,discernere,3,2 +3927,dull,3,1 +3928,noioso,3,2 +3929,grasp,3,1 +3930,capire,3,2 +3931,intent,3,1 +3932,intenzione,3,2 +3933,nourish,3,1 +3934,coltivare,3,2 +3935,obtain,3,1 +3936,ottenere,3,2 +3937,profound,3,1 +3938,intenso,3,2 +3939,prompt,3,1 +3940,immediato,3,2 +3941,pudgy,3,1 +3942,grassottello,3,2 +3943,seldom,3,1 +3944,raramente,3,2 +3945,timeliness,3,1 +3946,tempestivita',3,2 +3947,topnotch,3,1 +3948,eccellente,3,2 +3949,unwind,3,1 +3950,staccare,3,2 +3951,verbose,3,1 +3952,prolisso,3,2 +3953,banister,3,1 +3954,ringhiera,3,2 +3955,burp,3,1 +3956,rutto,3,2 +3957,cuddle,3,1 +3958,coccolare,3,2 +3959,endeavor,3,1 +3960,impegno,3,2 +3961,ensue,3,1 +3962,conseguire,3,2 +3963,fondle,3,1 +3964,accarezzare,3,2 +3965,herald,3,1 +3966,annunciare,3,2 +3967,intertwine,3,1 +3968,intrecciare,3,2 +3969,liaison,3,1 +3970,intermediario,3,2 +3971,loiter,3,1 +3972,gironzolare,3,2 +3973,mainstream,3,1 +3974,convenzionale,3,2 +3975,puddle,3,1 +3976,pozzanghera,3,2 +3977,retailer,3,1 +3978,rivenditore,3,2 +3979,stain,3,1 +3980,macchiare,3,2 +3981,stalwart,3,1 +3982,prode,3,2 +3983,stir up,3,1 +3984,fomentare,3,2 +3985,stuffy,3,1 +3986,soffocante,3,2 +3987,throng,3,1 +3988,folla,3,2 +3989,upcoming,3,1 +3990,in arrivo,3,2 +3991,wipe,3,1 +3992,pulire,3,2 +3993,adrift,3,1 +3994,alla deriva,3,2 +3995,appliance,3,1 +3996,elettrodomestico,3,2 +3997,arouse,3,1 +3998,stimolare,3,2 +3999,barren,3,1 +4000,sterile,3,2 +4001,cluster,3,1 +4002,raggruppamento,3,2 +4003,dearth,3,1 +4004,scarsita',3,2 +4007,esplanade,3,1 +4008,lungomare,3,2 +4009,expenditure,3,1 +4010,spesa,3,2 +4011,lilt,3,1 +4012,cadenza,3,2 +4013,lump,3,1 +4014,grumo,3,2 +4015,muse,3,1 +4016,riflettere,3,2 +4017,namesake,3,1 +4018,omonimo,3,2 +4019,outlandish,3,1 +4020,stravagante,3,2 +4021,pander,3,1 +4022,assecondare,3,2 +4023,persevere,3,1 +4024,persistere,3,2 +4025,popsicle,3,1 +4026,ghiacciolo,3,2 +4027,reproach,3,1 +4028,rimprovero,3,2 +4029,swerve,3,1 +4030,sterzare,3,2 +4031,victimize,3,1 +4032,perseguitare,3,2 +4033,aplomb,3,1 +4034,disinvoltura,3,2 +4035,backslide,3,1 +4036,ricadere,3,2 +4037,barrel,3,1 +4038,barile,3,2 +4039,brat,3,1 +4040,moccioso,3,2 +4041,coldness,3,1 +4042,freddezza,3,2 +4043,covet,3,1 +4044,invidiare,3,2 +4045,crevasse,3,1 +4046,crepaccio,3,2 +4047,environs,3,1 +4048,dintorni,3,2 +4049,frigid,3,1 +4050,gelido,3,2 +4051,girth,3,1 +4052,circonferenza,3,2 +4053,grisly,3,1 +4054,macabro,3,2 +4055,lanky,3,1 +4056,dinoccolato,3,2 +4057,lass,3,1 +4058,fanciulla,3,2 +4059,majestic,3,1 +4060,maestoso,3,2 +4061,pejorative,3,1 +4062,dispregiativo,3,2 +4063,peruse,3,1 +4064,esaminare,3,2 +4065,refuge,3,1 +4066,riparo,3,2 +4067,reiterate,3,1 +4068,reiterare,3,2 +4069,skirmish,3,1 +4070,scaramuccia,3,2 +4071,slate,3,1 +4072,ardesia,3,2 +4073,askance,3,1 +4074,con sospetto,3,2 +4075,blindside,3,1 +4076,alla sprovvista,3,2 +4077,comply,3,1 +4078,attenersi,3,2 +4079,erasure,3,1 +4080,cancellatura,3,2 +4081,landslide,3,1 +4082,frana,3,2 +4083,lease,3,1 +4084,locazione,3,2 +4085,opt,3,1 +4086,optare,3,2 +4087,piggyback,3,1 +4088,a cavalluccio,3,2 +4089,rebuff,3,1 +4090,ripulsa,3,2 +4091,replenish,3,1 +4092,rifornire,3,2 +4093,scoundrel,3,1 +4094,farabutto,3,2 +4095,shibboleth,3,1 +4096,parola d'ordine,3,2 +4097,sightsee,3,1 +4098,giro turistico,3,2 +4099,spurn,3,1 +4100,respingere,3,2 +4101,tantamount,3,1 +4102,equivalente,3,2 +4103,telltale,3,1 +4104,spione,3,2 +4105,unspoilt,3,1 +4106,incontaminato,3,2 +4107,whatnot,3,1 +4108,via dicendo,3,2 +4109,whittle,3,1 +4110,intagliare,3,2 +4111,wreak,3,1 +4112,provocare,3,2 +4113,adamant,3,1 +4114,irremovibile,3,2 +4115,appetiser,3,1 +4116,aperitivo,3,2 +4117,bloodshot,3,1 +4118,occhi rossi,3,2 +4119,defile,3,1 +4120,profanare,3,2 +4121,demotion,3,1 +4122,retrocessione,3,2 +4123,embroil,3,1 +4124,coinvolgere,3,2 +4125,enact,3,1 +4126,promulgare,3,2 +4127,felony,3,1 +4128,crimine,3,2 +4129,fib,3,1 +4130,frottola,3,2 +4131,foresight,3,1 +4132,lungimiranza,3,2 +4133,gurney,3,1 +4134,barella,3,2 +4135,indict,3,1 +4136,incriminare,3,2 +4137,letdown,3,1 +4138,deludere,3,2 +4139,mar,3,1 +4140,guastare,3,2 +4141,outskirts,3,1 +4142,sobborghi,3,2 +4143,outspoken,3,1 +4144,esplicito,3,2 +4145,plunge,3,1 +4146,tuffo,3,2 +4147,rebut,3,1 +4148,confutare,3,2 +4149,smuggle,3,1 +4150,contrabbandare,3,2 +4151,vacate,3,1 +4152,sgombrare,3,2 +4153,aground,3,1 +4154,arenare,3,2 +4155,brazen,3,1 +4156,impudente,3,2 +4157,exempt,3,1 +4158,esonerare,3,2 +4159,fallow,3,1 +4160,incolto,3,2 +4161,foreclose,3,1 +4162,pignorare,3,2 +4163,lobby,3,1 +4164,atrio,3,2 +4165,lopsided,3,1 +4166,asimmetrico,3,2 +4167,outright,3,1 +4168,immediatamente,3,2 +4169,paltry,3,1 +4170,irrisorio,3,2 +4171,rant,3,1 +4172,inveire,3,2 +4173,rave,3,1 +4174,delirare,3,2 +4175,repository,3,1 +4176,deposito,3,2 +4177,seepage,3,1 +4178,infiltrazione,3,2 +4179,shred,3,1 +4180,brandello,3,2 +4181,sludge,3,1 +4182,melma,3,2 +4183,smear,3,1 +4184,spalmare,3,2 +4185,sniff,3,1 +4186,annusare,3,2 +4187,subsist,3,1 +4188,sussistere,3,2 +4189,waft,3,1 +4190,soffio,3,2 +4191,wag,3,1 +4192,scodinzolare,3,2 +4193,claptrap,3,1 +4194,sproloquio,3,2 +4195,curfew,3,1 +4196,coprifuoco,3,2 +4197,dainty,3,1 +4198,delicato,3,2 +4199,flunk,3,1 +4200,cannare,3,2 +4201,fuse,3,1 +4202,miccia,3,2 +4203,gloat,3,1 +4204,gongolare,3,2 +4205,grouchy,3,1 +4206,brontolone,3,2 +4207,lather,3,1 +4208,insaponare,3,2 +4209,munch,3,1 +4210,ruminare,3,2 +4211,noose,3,1 +4212,cappio,3,2 +4213,rasp,3,1 +4214,raspare,3,2 +4215,reel,3,1 +4216,vacillare,3,2 +4217,rehash,3,1 +4218,rimaneggiare,3,2 +4219,reprieve,3,1 +4220,grazia,3,2 +4221,ruinous,3,1 +4222,rovinoso,3,2 +4223,snorkel,3,1 +4224,boccaglio,3,2 +4225,somersault,3,1 +4226,capriola,3,2 +4227,tender,3,1 +4228,tenero,3,2 +4229,wallow,3,1 +4230,sguazzare,3,2 +4231,wont,3,1 +4232,consuetudine,3,2 +4233,artichoke,3,1 +4234,carciofo,3,2 +4235,blithe,3,1 +4236,sconsiderato,3,2 +4237,boisterous,3,1 +4238,chiassoso,3,2 +4239,bra,3,1 +4240,reggiseno,3,2 +4241,chafe,3,1 +4242,irritazione,3,2 +4243,choppy,3,1 +4244,increspato,3,2 +4245,condone,3,1 +4246,tollerare,3,2 +4247,crisp,3,1 +4248,nitido,3,2 +4249,dislodge,3,1 +4250,smuovere,3,2 +4251,easy going,3,1 +4252,affabile,3,2 +4253,egghead,3,1 +4254,intellettuale,3,2 +4255,glimmer,3,1 +4256,barlume,3,2 +4257,hurdle,3,1 +4258,ostacolo,3,2 +4259,overt,3,1 +4260,evidente,3,2 +4261,pucker,3,1 +4262,corrugare,3,2 +4263,rattle,3,1 +4264,tintinnare,3,2 +4265,shriek,3,1 +4266,strillare,3,2 +4267,starch,3,1 +4268,amido,3,2 +4269,tingle,3,1 +4270,fremere,3,2 +4271,unswerving,3,1 +4272,incrollabile,3,2 +4273,antsy,3,1 +4274,irrequieto,3,2 +4275,balmy,3,1 +4276,temperato,3,2 +4277,behemoth,3,1 +4278,gigante,3,2 +4279,cheetah,3,1 +4280,ghepardo,3,2 +4281,complacent,3,1 +4282,soddisfatto,3,2 +4283,corral,3,1 +4284,recinto,3,2 +4285,curtsy,3,1 +4286,riverenza,3,2 +4287,desultory,3,1 +4288,saltuario,3,2 +4289,elated,3,1 +4290,euforico,3,2 +4291,fennel,3,1 +4292,finocchio,3,2 +4293,haywire,3,1 +4294,fuori controllo,3,2 +4295,jaded,3,1 +4296,sfinito,3,2 +4297,lax,3,1 +4298,permissivo,3,2 +4299,lettuce,3,1 +4300,lattuga,3,2 +4301,mulch,3,1 +4302,concime,3,2 +4303,quake,3,1 +4304,sisma,3,2 +4305,revile,3,1 +4306,ingiuriare,3,2 +4307,salve,3,1 +4308,pomata,3,2 +4309,trinket,3,1 +4310,gingillo,3,2 +4311,unflappable,3,1 +4312,flemmatico,3,2 +4313,beseech,3,1 +4314,supplicare,3,2 +4315,breeze,3,1 +4316,brezza,3,2 +4319,caw,3,1 +4320,gracchiare,3,2 +4321,crimson,3,1 +4322,cremisi,3,2 +4323,dusky,3,1 +4324,scuro,3,2 +4325,fir,3,1 +4326,abete,3,2 +4327,garb,3,1 +4328,abbigliamento,3,2 +4329,glance,3,1 +4330,occhiata,3,2 +4333,hue,3,1 +4334,tonalita',3,2 +4335,lapel,3,1 +4336,risvolto,3,2 +4337,log,3,1 +4338,ceppo,3,2 +4339,mistress,3,1 +4340,padrona,3,2 +4341,oat,3,1 +4342,avena,3,2 +4343,pledge,3,1 +4344,promettere,3,2 +4345,pod,3,1 +4346,baccello,3,2 +4347,revamp,3,1 +4348,rinnovamento,3,2 +4349,sedulous,3,1 +4350,assiduo,3,2 +4351,visage,3,1 +4352,viso,3,2 +4353,airborne,3,1 +4354,per via aerea,3,2 +4355,appal,3,1 +4356,sconvolgere,3,2 +4357,begrudge,3,1 +4358,a malincuore,3,2 +4359,cast,3,1 +4360,gettare,3,2 +4361,crosswise,3,1 +4362,trasversale,3,2 +4363,entrails,3,1 +4364,viscere,3,2 +4365,fern,3,1 +4366,felce,3,2 +4367,handout,3,1 +4368,elemosina,3,2 +4369,lousy,3,1 +4370,pessimo,3,2 +4371,poplar,3,1 +4372,pioppo,3,2 +4373,ransack,3,1 +4374,frugare,3,2 +4375,sear,3,1 +4376,rosolare,3,2 +4377,swat,3,1 +4378,spiaccicare,3,2 +4379,tangy,3,1 +4380,pungente,3,2 +4381,thicket,3,1 +4382,boschetto,3,2 +4383,toothpick,3,1 +4384,stuzzicadente,3,2 +4385,warden,3,1 +4386,guardiano,3,2 +4387,wayward,3,1 +4388,capriccioso,3,2 +4389,wedge,3,1 +4390,cuneo,3,2 +4391,wistful,3,1 +4392,malinconico,3,2 +4393,brooch,3,1 +4394,spilla,3,2 +4395,chirp,3,1 +4396,cinguettio,3,2 +4397,chisel,3,1 +4398,scalpello,3,2 +4399,frenzy,3,1 +4400,frenesia,3,2 +4401,glaze,3,1 +4402,glassa,3,2 +4403,groove,3,1 +4404,scanalatura,3,2 +4405,leery,3,1 +4406,sospettoso,3,2 +4407,molten,3,1 +4408,fuso,3,2 +4409,mourn,3,1 +4410,compiangere,3,2 +4411,onlooker,3,1 +4412,spettatore,3,2 +4413,slab,3,1 +4414,lastra,3,2 +4415,soot,3,1 +4416,fuliggine,3,2 +4417,squirm,3,1 +4418,dimenarsi,3,2 +4419,stool,3,1 +4420,sgabello,3,2 +4421,stride,3,1 +4422,falcata,3,2 +4423,tiara,3,1 +4424,diadema,3,2 +4425,wanton,3,1 +4426,ingiustificato,3,2 +4427,whinge,3,1 +4428,frignare,3,2 +4429,whorl,3,1 +4430,spirale,3,2 +4431,wiry,3,1 +4432,scolpito,3,2 +4433,appendage,3,1 +4434,appendice,3,2 +4435,badger,3,1 +4436,tasso,3,2 +4437,bramble,3,1 +4438,rovo,3,2 +4439,cap,3,1 +4440,berretto,3,2 +4441,chalk,3,1 +4442,gesso,3,2 +4443,dagger,3,1 +4444,pugnale,3,2 +4445,doily,3,1 +4446,centrino,3,2 +4447,faze,3,1 +4448,turbare,3,2 +4449,grave,3,1 +4450,tomba,3,2 +4451,leech,3,1 +4452,sanguisuga,3,2 +4453,mat,3,1 +4454,tappetino,3,2 +4455,moisture,3,1 +4456,umidita',3,2 +4457,pitcher,3,1 +4458,brocca,3,2 +4459,riffraff,3,1 +4460,gentaglia,3,2 +4461,scuff,3,1 +4462,strascicare,3,2 +4463,shrivel,3,1 +4464,avvizzire,3,2 +4465,turnip,3,1 +4466,rapa,3,2 +4467,upstart,3,1 +4468,arrivista,3,2 +4469,wisp,3,1 +4470,ciocca,3,2 +4471,wondrous,3,1 +4472,meraviglioso,3,2 +4473,accolade,3,1 +4474,riconoscimento,3,2 +4475,ache,3,1 +4476,dolore,3,2 +4477,brandish,3,1 +4478,brandire,3,2 +4479,caveat,3,1 +4480,avvertimento,3,2 +4481,deluge,3,1 +4482,diluvio,3,2 +4483,drizzle,3,1 +4484,pioggerella,3,2 +4485,gag,3,1 +4486,bavaglio,3,2 +4487,heap,3,1 +4488,mucchio,3,2 +4489,jettison,3,1 +4490,disfarsi,3,2 +4491,laud,3,1 +4492,lodare,3,2 +4493,lest,3,1 +4494,per paura che,3,2 +4495,lighthearted,3,1 +4496,spensierato,3,2 +4497,lustre,3,1 +4498,lucentezza,3,2 +4499,maelstrom,3,1 +4500,vortice,3,2 +4501,posit,3,1 +4502,postulare,3,2 +4503,ream,3,1 +4504,risma,3,2 +4505,relinquish,3,1 +4506,abbandonare,3,2 +4507,seclusion,3,1 +4508,solitudine,3,2 +4509,whirlpool,3,1 +4510,mulinello,3,2 +4511,zeal,3,1 +4512,zelo,3,2 +4513,adage,3,1 +4514,detto,3,2 +4515,chill,3,1 +4516,raffreddare,3,2 +4517,entrench,3,1 +4518,consolidare,3,2 +4519,fester,3,1 +4520,infettare,3,2 +4521,flagship,3,1 +4522,ammiraglia,3,2 +4523,freight,3,1 +4524,merci,3,2 +4525,gooey,3,1 +4526,appiccicoso,3,2 +4527,gruelling,3,1 +4528,estenuante,3,2 +4529,kudos,3,1 +4530,gloria,3,2 +4531,lacklustre,3,1 +4532,scialbo,3,2 +4533,liken,3,1 +4534,paragonare,3,2 +4535,mercurial,3,1 +4536,mutevole,3,2 +4537,rebound,3,1 +4538,ripresa,3,2 +4539,revel,3,1 +4540,baldoria,3,2 +4541,satiate,3,1 +4542,saziare,3,2 +4543,standout,3,1 +4544,risaltare,3,2 +4545,trim,3,1 +4546,finitura,3,2 +4547,uproot,3,1 +4548,sradicare,3,2 +4549,wangle,3,1 +4550,procacciare,3,2 +4551,wrangle,3,1 +4552,disputa,3,2 +4553,abject,3,1 +4554,miserabile,3,2 +4555,augur,3,1 +4556,presagire,3,2 +4557,awning,3,1 +4558,veranda,3,2 +4559,babble,3,1 +4560,farfugliare,3,2 +4561,cabin,3,1 +4562,baita,3,2 +4563,cartridge,3,1 +4564,cartuccia,3,2 +4565,classified,3,1 +4566,confidenziale,3,2 +4567,crowbar,3,1 +4568,piede di porco,3,2 +4569,demise,3,1 +4570,decesso,3,2 +4571,dreary,3,1 +4572,tetro,3,2 +4573,duffel,3,1 +4574,borsone,3,2 +4575,martinet,3,1 +4576,despota,3,2 +4577,moot,3,1 +4578,discutibile,3,2 +4579,oar,3,1 +4580,remo,3,2 +4581,precinct,3,1 +4582,distretto,3,2 +4583,pushover,3,1 +4584,sempliciotto,3,2 +4585,site,3,1 +4586,cantiere,3,2 +4587,skillet,3,1 +4588,tegame,3,2 +4589,sleet,3,1 +4590,nevischio,3,2 +4591,tirade,3,1 +4592,invettiva,3,2 +4593,crumb,3,1 +4594,briciola,3,2 +4595,easel,3,1 +4596,cavalletto,3,2 +4597,ebb,3,1 +4598,riflusso,3,2 +4599,enamel,3,1 +4600,smalto,3,2 +4601,encase,3,1 +4602,rivestire,3,2 +4603,encrusted,3,1 +4604,incrostato,3,2 +4605,etch,3,1 +4606,incidere,3,2 +4607,goatee,3,1 +4608,pizzetto,3,2 +4609,goose,3,1 +4610,oca,3,2 +4611,lace,3,1 +4612,merletto,3,2 +4613,listless,3,1 +4614,svogliato,3,2 +4615,mop,3,1 +4616,mocio,3,2 +4617,probation,3,1 +4618,liberta' vigilata,3,2 +4619,shrimp,3,1 +4620,gamberetto,3,2 +4621,shrine,3,1 +4622,santuario,3,2 +4623,snuggle,3,1 +4624,accoccolarsi,3,2 +4625,strainer,3,1 +4626,colino,3,2 +4627,tide,3,1 +4628,marea,3,2 +4629,trailer,3,1 +4630,rimorchio,3,2 +4631,waver,3,1 +4632,titubare,3,2 +4633,acorn,3,1 +4634,ghianda,3,2 +4635,barter,3,1 +4636,permuta,3,2 +4637,copout,3,1 +4638,scappatoia,3,2 +4639,dimple,3,1 +4640,fossetta,3,2 +4641,disheveled,3,1 +4642,scompigliato,3,2 +4643,earnest,3,1 +4644,coscienzioso,3,2 +4645,feral,3,1 +4646,selvatico,3,2 +4647,heirloom,3,1 +4648,cimelio di famiglia,3,2 +4649,oak,3,1 +4650,quercia,3,2 +4651,outrageous,3,1 +4652,oltraggioso,3,2 +4653,pang,3,1 +4654,fitta,3,2 +4655,scour,3,1 +4656,perlustrare,3,2 +4657,sever,3,1 +4658,recidere,3,2 +4659,skylight,3,1 +4660,lucernario,3,2 +4661,sled,3,1 +4662,slitta,3,2 +4663,smoothie,3,1 +4664,frullato,3,2 +4665,speckled,3,1 +4666,maculato,3,2 +4667,stoned,3,1 +4668,sballato,3,2 +4669,tinfoil,3,1 +4670,stagnola,3,2 +4671,wad,3,1 +4672,mazzetta,3,2 +4673,belt,3,1 +4674,cintura,3,2 +4675,bungle,3,1 +4676,pasticciare,3,2 +4677,careful,3,1 +4678,attenzione,3,2 +4679,clamour,3,1 +4680,fragore,3,2 +4681,clue,3,1 +4682,indizio,3,2 +4683,earmark,3,1 +4684,destinare,3,2 +4685,fight,3,1 +4686,combattere,3,2 +4687,hidden,3,1 +4688,nascosto,3,2 +4689,ibex,3,1 +4690,stambecco,3,2 +4691,instead,3,1 +4692,anziche',3,2 +4693,plateau,3,1 +4694,altopiano,3,2 +4695,pothole,3,1 +4696,buca,3,2 +4697,reap,3,1 +4698,raccogliere,3,2 +4699,refurbish,3,1 +4700,ristrutturare,3,2 +4701,shout,3,1 +4702,gridare,3,2 +4703,steal,3,1 +4704,rubare,3,2 +4705,sunlit,3,1 +4706,soleggiato,3,2 +4707,trove,3,1 +4708,collezione,3,2 +4709,wake,3,1 +4710,svegliare,3,2 +4711,whimsy,3,1 +4712,fantasia,3,2 +4713,barely,3,1 +4714,a malapena,3,2 +4715,bill,3,1 +4716,conto,3,2 +4717,boon,3,1 +4718,beneficio,3,2 +4719,budding,3,1 +4720,in erba,3,2 +4721,cloudburst,3,1 +4722,nubifragio,3,2 +4723,creep in,3,1 +4724,insinuarsi,3,2 +4725,fade,3,1 +4726,svanire,3,2 +4727,fiat,3,1 +4728,decreto,3,2 +4729,field,3,1 +4730,campo,3,2 +4731,goad,3,1 +4732,pungolare,3,2 +4733,headland,3,1 +4734,promontorio,3,2 +4735,hill,3,1 +4736,collina,3,2 +4737,jinx,3,1 +4738,iella,3,2 +4739,legerdemain,3,1 +4740,gioco di prestigio,3,2 +4741,lineage,3,1 +4742,lignaggio,3,2 +4743,mold,3,1 +4744,muffa,3,2 +4745,slice,3,1 +4746,fetta,3,2 +4747,vanguard,3,1 +4748,avanguardia,3,2 +4749,varnish,3,1 +4750,vernice,3,2 +4751,zinger,3,1 +4752,frecciatina,3,2 +4753,allow,3,1 +4754,permettere,3,2 +4755,attune,3,1 +4756,in sintonia,3,2 +4757,awful,3,1 +4758,tremendo,3,2 +4759,cheap,3,1 +4760,economico,3,2 +4761,daydream,3,1 +4762,fantasticare,3,2 +4763,deaf,3,1 +4764,sordo,3,2 +4765,dive,3,1 +4766,tuffarsi,3,2 +4767,dustbin,3,1 +4768,pattumiera,3,2 +4769,fireplace,3,1 +4770,camino,3,2 +4771,grapple,3,1 +4772,essere alle prese,3,2 +4773,greengrocer,3,1 +4774,fruttivendolo,3,2 +4775,longing,3,1 +4776,nostalgia,3,2 +4777,moniker,3,1 +4778,appellativo,3,2 +4779,nuptials,3,1 +4780,nozze,3,2 +4781,parrot,3,1 +4782,pappagallo,3,2 +4783,perforce,3,1 +4784,necessariamente,3,2 +4785,seedling,3,1 +4786,piantina,3,2 +4787,straggler,3,1 +4788,fanalino di coda,3,2 +4789,tier,3,1 +4790,strato,3,2 +4791,watchword,3,1 +4792,motto,3,2 +4793,barn,3,1 +4794,stalla,3,2 +4795,bone,3,1 +4796,osso,3,2 +4797,calf,3,1 +4798,polpaccio,3,2 +4799,gamut,3,1 +4800,gamma,3,2 +4801,hereto,3,1 +4802,al presente,3,2 +4803,heretofore,3,1 +4804,fino ad allora,3,2 +4805,in a jiffy,3,1 +4806,in un attimo,3,2 +4807,joint,3,1 +4808,articolazione,3,2 +4809,lazy,3,1 +4810,pigro,3,2 +4811,mete out,3,1 +4812,infliggere,3,2 +4813,porter,3,1 +4814,facchino,3,2 +4815,proselytise,3,1 +4816,convertire,3,2 +4817,rebuttal,3,1 +4818,confutazione,3,2 +4819,stamp,3,1 +4820,francobollo,3,2 +4821,stark,3,1 +4822,assoluto,3,2 +4823,stronghold,3,1 +4824,roccaforte,3,2 +4825,stymie,3,1 +4826,boicottare,3,2 +4827,sweat,3,1 +4828,sudore,3,2 +4829,twin,3,1 +4830,gemello,3,2 +4831,yard,3,1 +4832,cortile,3,2 +4833,alas,3,1 +4834,ahime',3,2 +4835,augment,3,1 +4836,accrescere,3,2 +4837,depth,3,1 +4838,profondita',3,2 +4839,dole,3,1 +4840,sussidio,3,2 +4841,galore,3,1 +4842,in abbondanza,3,2 +4843,goat,3,1 +4844,capra,3,2 +4845,hang,3,1 +4846,appendere,3,2 +4847,mincing,3,1 +4848,lezioso,3,2 +4849,orchard,3,1 +4850,frutteto,3,2 +4851,perched,3,1 +4852,arroccato,3,2 +4853,proviso,3,1 +4854,condizione,3,2 +4855,ribbon,3,1 +4856,nastro,3,2 +4857,shelve,3,1 +4858,accantonare,3,2 +4859,shirk,3,1 +4860,sottrarsi,3,2 +4861,squib,3,1 +4862,petardo,3,2 +4863,supersede,3,1 +4864,rimpiazzare,3,2 +4865,tune,3,1 +4866,sintonizzare,3,2 +4867,uproar,3,1 +4868,tumulto,3,2 +4869,uptake,3,1 +4870,assorbimento,3,2 +4871,wise,3,1 +4872,saggio,3,2 +4873,celery,3,1 +4874,sedano,3,2 +4875,clad,3,1 +4876,rivestito,3,2 +4877,clever,3,1 +4878,perspicace,3,2 +4879,dispel,3,1 +4880,dissipare,3,2 +4881,foist on,3,1 +4882,rifilare,3,2 +4883,forbear,3,1 +4884,astenersi,3,2 +4885,forsake,3,1 +4886,lasciare,3,2 +4887,gathering,3,1 +4888,radunare,3,2 +4889,gloaming,3,1 +4890,imbrunire,3,2 +4891,headstrong,3,1 +4892,caparbio,3,2 +4893,inchoate,3,1 +4894,incipiente,3,2 +4895,nod,3,1 +4896,cenno del capo,3,2 +4897,seek,3,1 +4898,cercare di,3,2 +4899,setback,3,1 +4900,battuta d'arresto,3,2 +4901,sparrow,3,1 +4902,passero,3,2 +4903,stoked,3,1 +4904,entusiasta,3,2 +4905,strew,3,1 +4906,cospargere,3,2 +4907,surmount,3,1 +4908,sormontare,3,2 +4909,undertake,3,1 +4910,intraprendere,3,2 +4911,unwitting,3,1 +4912,inconsapevole,3,2 +4913,adjoined,3,1 +4914,annesso,3,2 +4915,cog,3,1 +4916,ingranaggio,3,2 +4917,covert,3,1 +4918,sotto copertura,3,2 +4919,earshot,3,1 +4920,portata d'orecchio,3,2 +4921,hourglass,3,1 +4922,clessidra,3,2 +4923,knuckle,3,1 +4924,nocca,3,2 +4925,littered,3,1 +4926,disseminato,3,2 +4927,mash,3,1 +4928,purea,3,2 +4929,mirth,3,1 +4930,ilarita',3,2 +4931,peacock,3,1 +4932,pavone,3,2 +4933,pigeon,3,1 +4934,piccione,3,2 +4935,rejoice,3,1 +4936,rallegrarsi,3,2 +4937,selfish,3,1 +4938,egoista,3,2 +4939,spat,3,1 +4940,screzio,3,2 +4941,spelt,3,1 +4942,farro,3,2 +4943,strut,3,1 +4944,pavoneggiarsi,3,2 +4945,survey,3,1 +4946,indagine,3,2 +4947,swivel chair,3,1 +4948,sedia girevole,3,2 +4949,wig,3,1 +4950,parrucca,3,2 +4951,windmill,3,1 +4952,mulino a vento,3,2 +4953,achieve,3,1 +4954,realizzare,3,2 +4955,acquaintance,3,1 +4956,conoscente,3,2 +4957,bench,3,1 +4958,panca,3,2 +4959,captive,3,1 +4960,prigioniero,3,2 +4961,ceiling,3,1 +4962,soffitto,3,2 +4963,deference,3,1 +4964,deferenza,3,2 +4965,deflate,3,1 +4966,sgonfiare,3,2 +4967,demeaning,3,1 +4968,umiliante,3,2 +4969,entrepreneur,3,1 +4970,imprenditore,3,2 +4971,feed,3,1 +4972,dare da mangiare,3,2 +4973,gurgle,3,1 +4974,gorgogliare,3,2 +4975,lacquer,3,1 +4976,lacca,3,2 +4977,maw,3,1 +4978,fauci,3,2 +4979,mushroom,3,1 +4980,fungo,3,2 +4981,naysayer,3,1 +4982,disfattista,3,2 +4983,pineapple,3,1 +4984,ananas,3,2 +4985,requite,3,1 +4986,contraccambiare,3,2 +4987,rind,3,1 +4988,scorza,3,2 +4989,splotch,3,1 +4990,chiazza,3,2 +4991,stick up for,3,1 +4992,supportare,3,2 +4993,accordion,3,1 +4994,fisarmonica,3,2 +4995,bonfire,3,1 +4996,falo',3,2 +4997,contrite,3,1 +4998,mortificato,3,2 +4999,coo,3,1 +5000,tubare,3,2 +5001,harm,3,1 +5002,danno,3,2 +5003,hoof,3,1 +5004,zoccolo,3,2 +5005,improve,3,1 +5006,migliorare,3,2 +5007,knob,3,1 +5008,pomello,3,2 +5009,mane,3,1 +5010,criniera,3,2 +5011,padded,3,1 +5012,imbottito,3,2 +5013,parch,3,1 +5014,inaridire,3,2 +5015,quibble,3,1 +5016,cavillo,3,2 +5017,rib,3,1 +5018,costa,3,2 +5019,rubble,3,1 +5020,macerie,3,2 +5021,shoulder blade,3,1 +5022,scapola,3,2 +5023,stub,3,1 +5024,mozzicone,3,2 +5025,tuft,3,1 +5026,ciuffo,3,2 +5027,twinkle,3,1 +5028,scintillare,3,2 +5029,whinny,3,1 +5030,nitrito,3,2 +5031,whip,3,1 +5032,frusta,3,2 +5033,beautician,3,1 +5034,estetista,3,2 +5035,chestnut,3,1 +5036,castagna,3,2 +5037,donkey,3,1 +5038,asino,3,2 +5039,flax,3,1 +5040,lino,3,2 +5041,inlay,3,1 +5042,intarsio,3,2 +5043,ladybird,3,1 +5044,coccinella,3,2 +5045,masquerade,3,1 +5046,messa in scena,3,2 +5047,meadow,3,1 +5048,prateria,3,2 +5049,mellow,3,1 +5050,tranquillo,3,2 +5051,phlegm,3,1 +5052,catarro,3,2 +5053,piffle,3,1 +5054,stupidaggini,3,2 +5055,shareholder,3,1 +5056,socio,3,2 +5057,skull,3,1 +5058,cranio,3,2 +5059,snout,3,1 +5060,muso,3,2 +5061,surgeon,3,1 +5062,chirurgo,3,2 +5063,timeworn,3,1 +5064,logoro,3,2 +5065,turkey,3,1 +5066,tacchino,3,2 +5067,tusk,3,1 +5068,zanna,3,2 +5069,untenable,3,1 +5070,insostenibile,3,2 +5071,yawn,3,1 +5072,sbadigliare,3,2 +5073,plaster,3,1 +5074,intonaco,3,2 +5075,hut,3,1 +5076,capanna,3,2 +5077,greet,3,1 +5078,accogliere,3,2 +5079,finery,3,1 +5080,abiti eleganti,3,2 +5081,gape,3,1 +5082,a bocca aperta,3,2 +5083,rod,3,1 +5084,asta,3,2 +5085,brass,3,1 +5086,ottone,3,2 +5087,demote,3,1 +5088,degradare,3,2 +5089,unbecoming,3,1 +5090,indecoroso,3,2 +5091,mob,3,1 +5092,orda,3,2 +5093,dragonfly,3,1 +5094,libellula,3,2 +5095,browse,3,1 +5096,sfogliare,3,2 +5097,superimpose,3,1 +5098,sovrapporre,3,2 +5099,squeeze,3,1 +5100,spremere,3,2 +5101,struggle,3,1 +5102,lotta,3,2 +5103,for the sake of,3,1 +5104,per il bene di,3,2 +5105,sidelong,3,1 +5106,di traverso,3,2 +5107,stack,3,1 +5108,pila,3,2 +5109,elm,3,1 +5110,olmo,3,2 +5111,slink,3,1 +5112,sgattaiolare,3,2 +5113,arsonist,3,1 +5114,piromane,3,2 +5115,blaze,3,1 +5116,vampata,3,2 +5117,blind,3,1 +5118,cieco,3,2 +5119,burgeon,3,1 +5120,svilupparsi,3,2 +5121,destitute,3,1 +5122,indigente,3,2 +5123,feel like,3,1 +5124,sentire come,3,2 +5125,fill,3,1 +5126,riempire,3,2 +5127,fingertip,3,1 +5128,polpastrello,3,2 +5129,gripping,3,1 +5130,avvincente,3,2 +5131,hawker,3,1 +5132,venditore ambulante,3,2 +5133,kneecap,3,1 +5134,rotula,3,2 +5135,lattice,3,1 +5136,reticolo,3,2 +5137,lie,3,1 +5138,bugia,3,2 +5139,mollify,3,1 +5140,quietare,3,2 +5141,phoenix,3,1 +5142,fenice,3,2 +5143,plush,3,1 +5144,peluche,3,2 +5145,riveting,3,1 +5146,affascinante,3,2 +5147,scan,3,1 +5148,scandire,3,2 +5149,verbatim,3,1 +5150,parola per parola,3,2 +5151,within,3,1 +5152,all'interno,3,2 +5153,blackmail,3,1 +5154,ricatto,3,2 +5155,call it a day,3,1 +5156,per oggi basta cosi',3,2 +5157,face it,3,1 +5158,ammettilo,3,2 +5159,fissure,3,1 +5160,spaccatura,3,2 +5161,foreshadow,3,1 +5162,prefigurare,3,2 +5163,gorge,3,1 +5164,gola,3,2 +5165,hideous,3,1 +5166,orrendo,3,2 +5167,leisure,3,1 +5168,tempo libero,3,2 +5169,make a beeline for,3,1 +5170,puntare dritto a,3,2 +5171,overfly,3,1 +5172,sorvolare,3,2 +5173,overwhelming,3,1 +5174,opprimente,3,2 +5175,pistachio,3,1 +5176,pistacchio,3,2 +5177,plough,3,1 +5178,aratro,3,2 +5179,rather,3,1 +5180,piuttosto,3,2 +5181,recluse,3,1 +5182,eremita,3,2 +5183,seismic,3,1 +5184,sismico,3,2 +5185,siphon,3,1 +5186,sifone,3,2 +5187,understate,3,1 +5188,sottostimare,3,2 +5189,whitewash,3,1 +5190,imbiancare,3,2 +5191,wiretap,3,1 +5192,intercettare,3,2 +5193,aloud,3,1 +5194,a voce alta,3,2 +5195,asbestos,3,1 +5196,amianto,3,2 +5197,astonishing,3,1 +5198,stupefacente,3,2 +5199,beforehand,3,1 +5200,in anticipo,3,2 +5201,beset,3,1 +5202,circondato da,3,2 +5203,county,3,1 +5204,contea,3,2 +5205,draconian,3,1 +5206,draconiano,3,2 +5207,drawback,3,1 +5208,inconveniente,3,2 +5209,envoy,3,1 +5210,emissario,3,2 +5211,idle,3,1 +5212,inattivo,3,2 +5213,liaise,3,1 +5214,cooperare,3,2 +5215,litigation,3,1 +5216,contenzioso,3,2 +5217,maritime,3,1 +5218,marittimo,3,2 +5219,pain,3,1 +5220,dolore fisico,3,2 +5221,rile,3,1 +5222,seccare,3,2 +5223,spearhead,3,1 +5224,capeggiare,3,2 +5225,stalk,3,1 +5226,gambo,3,2 +5227,tiny,3,1 +5228,minuscolo,3,2 +5229,waste,3,1 +5230,spreco,3,2 +5231,whisper,3,1 +5232,sussurrare,3,2 +5233,abuzz,3,1 +5234,in fermento,3,2 +5235,bravery,3,1 +5236,coraggio,3,2 +5237,cornerstone,3,1 +5238,pietra angolare,3,2 +5239,dig,3,1 +5240,scavare,3,2 +5241,fitted with,3,1 +5242,munito,3,2 +5243,mankind,3,1 +5244,genere umano,3,2 +5245,mince,3,1 +5246,tritare,3,2 +5247,no brainer,3,1 +5248,scelta ovvia,3,2 +5249,quote,3,1 +5250,citazione,3,2 +5251,resin,3,1 +5252,resina,3,2 +5253,runoff,3,1 +5254,ballottaggio,3,2 +5255,shed,3,1 +5256,capanno,3,2 +5257,squid,3,1 +5258,calamaro,3,2 +5259,tenet,3,1 +5260,fondamento,3,2 +5261,thickness,3,1 +5262,spessore,3,2 +5263,threaten,3,1 +5264,minacciare,3,2 +5265,tiebreaker,3,1 +5266,spareggio,3,2 +5267,timber,3,1 +5268,legname,3,2 +5269,wade,3,1 +5270,guadare,3,2 +5271,weed,3,1 +5272,diserbare,3,2 +5273,bride,3,1 +5274,sposa,3,2 +5275,denial,3,1 +5276,negazione,3,2 +5277,goal,3,1 +5278,obiettivo,3,2 +5279,gull,3,1 +5280,gabbiano,3,2 +5281,heron,3,1 +5282,airone,3,2 +5283,innermost,3,1 +5284,piu' interno,3,2 +5285,intersperse,3,1 +5286,inframezzare,3,2 +5287,masterpiece,3,1 +5288,capolavoro,3,2 +5289,pale,3,1 +5290,pallido,3,2 +5291,riot,3,1 +5292,rivolta,3,2 +5293,shaggy,3,1 +5294,arruffato,3,2 +5295,snowplow,3,1 +5296,spazzaneve,3,2 +5297,spellbound,3,1 +5298,incantato,3,2 +5299,stowaway,3,1 +5300,clandestino,3,2 +5301,stranded,3,1 +5302,bloccato,3,2 +5303,suitable,3,1 +5304,idoneo,3,2 +5305,tarmac,3,1 +5306,asfalto,3,2 +5307,taste,3,1 +5308,assaggio,3,2 +5309,tuxedo,3,1 +5310,smoking,3,2 +5311,worthy,3,1 +5312,degno,3,2 +5313,abet,3,1 +5314,favoreggiare,3,2 +5315,bowel,3,1 +5316,intestino,3,2 +5317,chime,3,1 +5318,rintoccare,3,2 +5319,darn,3,1 +5320,rammendare,3,2 +5321,deer,3,1 +5322,cervo,3,2 +5323,dwarf,3,1 +5324,nano,3,2 +5325,embezzle,3,1 +5326,intascare,3,2 +5327,flask,3,1 +5328,thermos,3,2 +5329,grab,3,1 +5330,agguantare,3,2 +5331,groom,3,1 +5332,sposo,3,2 +5333,haggard,3,1 +5334,sparuto,3,2 +5335,ivy,3,1 +5336,edera,3,2 +5337,kite,3,1 +5338,aquilone,3,2 +5339,miser,3,1 +5340,avaro,3,2 +5341,needle,3,1 +5342,ago,3,2 +5343,owl,3,1 +5344,gufo,3,2 +5345,parley,3,1 +5346,trattativa,3,2 +5347,propeller,3,1 +5348,elica,3,2 +5349,purr,3,1 +5350,fare le fusa,3,2 +5351,swap,3,1 +5352,scambiare,3,2 +5353,aft,3,1 +5354,a poppa,3,2 +5355,chainsaw,3,1 +5356,motosega,3,2 +5357,chimney,3,1 +5358,comignolo,3,2 +5359,countermand,3,1 +5360,revocare,3,2 +5361,crochet,3,1 +5362,uncinetto,3,2 +5363,cuckoo,3,1 +5364,cuculo,3,2 +5365,deckhand,3,1 +5366,mozzo,3,2 +5367,disrepute,3,1 +5368,cattiva fama,3,2 +5369,downfall,3,1 +5370,caduta dal potere,3,2 +5371,geld,3,1 +5372,castrare,3,2 +5373,giggle,3,1 +5374,ridacchiare,3,2 +5375,helm,3,1 +5376,timone,3,2 +5377,magpie,3,1 +5378,gazza,3,2 +5379,oyster,3,1 +5380,ostrica,3,2 +5381,robin,3,1 +5382,pettirosso,3,2 +5383,skein,3,1 +5384,matassa,3,2 +5385,squirrel,3,1 +5386,scoiattolo,3,2 +5387,standoffish,3,1 +5388,scostante,3,2 +5389,tadpole,3,1 +5390,girino,3,2 +5391,tapered,3,1 +5392,affusolato,3,2 +5393,aware,3,1 +5394,conscio,3,2 +5395,backbiting,3,1 +5396,maldicenza,3,2 +5397,bad omen,3,1 +5398,cattivo presagio,3,2 +5399,brawl,3,1 +5400,rissa,3,2 +5401,covenant,3,1 +5402,patto,3,2 +5403,eel,3,1 +5404,anguilla,3,2 +5405,effrontery,3,1 +5406,sfrontatezza,3,2 +5407,garish,3,1 +5408,sgargiante,3,2 +5409,in abeyance,3,1 +5410,in sospeso,3,2 +5411,on average,3,1 +5412,nella media,3,2 +5413,profligate,3,1 +5414,dissoluto,3,2 +5415,pumpkin,3,1 +5416,zucca,3,2 +5417,raft,3,1 +5418,zattera,3,2 +5419,seat belt,3,1 +5420,cintura di sicurezza,3,2 +5421,sentient,3,1 +5422,senziente,3,2 +5423,shiver,3,1 +5424,rabbrividire,3,2 +5425,snail,3,1 +5426,lumaca,3,2 +5427,transient,3,1 +5428,transitorio,3,2 +5429,uneven,3,1 +5430,irregolare,3,2 +5431,well,3,1 +5432,pozzo,3,2 +5433,accomplice,3,1 +5434,complice,3,2 +5435,awesome,3,1 +5436,fantastico,3,2 +5437,bottomless,3,1 +5438,senza fondo,3,2 +5439,cheat,3,1 +5440,barare,3,2 +5441,craft,3,1 +5442,mestiere,3,2 +5443,fiend,3,1 +5444,demonio,3,2 +5445,heathen,3,1 +5446,pagano,3,2 +5447,jaunt,3,1 +5448,gita,3,2 +5449,lily,3,1 +5450,giglio,3,2 +5451,linen,3,1 +5452,biancheria,3,2 +5453,mason,3,1 +5454,muratore,3,2 +5455,nettle,3,1 +5456,ortica,3,2 +5457,pit,3,1 +5458,fossa,3,2 +5459,pity,3,1 +5460,compatire,3,2 +5461,scoot over,3,1 +5462,fatti in la,3,2 +5463,scroll,3,1 +5464,pergamena,3,2 +5465,sieve,3,1 +5466,setaccio,3,2 +5467,spread,3,1 +5468,diffondersi,3,2 +5469,stage,3,1 +5470,palco,3,2 +5471,whenever,3,1 +5472,ogni volta,3,2 +5473,castaway,3,1 +5474,naufrago,3,2 +5475,chauffeur,3,1 +5476,autista,3,2 +5477,construe,3,1 +5478,interpretare,3,2 +5479,covetous,3,1 +5480,cupidigia,3,2 +5481,entangled,3,1 +5482,ingarbugliato,3,2 +5483,forefather,3,1 +5484,antenato,3,2 +5485,gasket,3,1 +5486,guarnizione,3,2 +5487,ignite,3,1 +5488,prendere fuoco,3,2 +5489,lean,3,1 +5490,appoggiarsi,3,2 +5491,malfeasance,3,1 +5492,illecito,3,2 +5493,misshapen,3,1 +5494,deforme,3,2 +5495,rapture,3,1 +5496,estasi,3,2 +5497,shake,3,1 +5498,agitare,3,2 +5499,shape,3,1 +5500,forma,3,2 +5501,stakes,3,1 +5502,posta in gioco,3,2 +5503,strict,3,1 +5504,rigoroso,3,2 +5505,switchback,3,1 +5506,tornante,3,2 +5507,teetotal,3,1 +5508,astemio,3,2 +5509,threadbare,3,1 +5510,liso,3,2 +5511,willing,3,1 +5512,disposto,3,2 +5513,abysmal,3,1 +5514,abissale,3,2 +5515,ant,3,1 +5516,formica,3,2 +5517,brawny,3,1 +5518,muscoloso,3,2 +5519,damping,3,1 +5520,smorzamento,3,2 +5521,den,3,1 +5522,covo,3,2 +5523,dote on,3,1 +5524,stravedere per,3,2 +5525,droves,3,1 +5526,frotta,3,2 +5527,each other,3,1 +5528,a vicenda,3,2 +5529,enlightenment,3,1 +5530,illuminazione,3,2 +5531,frost,3,1 +5532,brina,3,2 +5533,headwind,3,1 +5534,vento contrario,3,2 +5535,low blow,3,1 +5536,colpo basso,3,2 +5537,roughly,3,1 +5538,all'incirca,3,2 +5539,safecracker,3,1 +5540,scassinatore,3,2 +5541,simmer,3,1 +5542,sobbollire,3,2 +5543,snarky,3,1 +5544,irreverente,3,2 +5545,sobering,3,1 +5546,che fa riflettere,3,2 +5547,strenuous,3,1 +5548,faticoso,3,2 +5549,therefore,3,1 +5550,percio',3,2 +5551,unassailable,3,1 +5552,inattaccabile,3,2 +5555,accustomed,3,1 +5556,avvezzo,3,2 +5557,atone,3,1 +5558,espiare,3,2 +5559,bright,3,1 +5560,luminoso,3,2 +5561,clockwise,3,1 +5562,in senso orario,3,2 +5563,cognizant,3,1 +5564,essere al corrente,3,2 +5565,concierge,3,1 +5566,portinaio,3,2 +5567,copycat,3,1 +5568,copione,3,2 +5569,dilute,3,1 +5570,diluire,3,2 +5571,endure,3,1 +5572,sopportare,3,2 +5573,join,3,1 +5574,unire,3,2 +5575,matt,3,1 +5576,opaco,3,2 +5577,meantime,3,1 +5578,intanto,3,2 +5579,momentous,3,1 +5580,epocale,3,2 +5581,nest,3,1 +5582,nido,3,2 +5583,pamper,3,1 +5584,viziare,3,2 +5585,pastime,3,1 +5586,passatempo,3,2 +5587,split,3,1 +5588,dividere,3,2 +5589,vilify,3,1 +5590,diffamare,3,2 +5591,watershed,3,1 +5592,spartiacque,3,2 +5593,wound,3,1 +5594,ferita,3,2 +5595,aim,3,1 +5596,mirare,3,2 +5597,bend,3,1 +5598,piegare,3,2 +5599,bishop,3,1 +5600,vescovo,3,2 +5601,blossom,3,1 +5602,fiorire,3,2 +5603,cob,3,1 +5604,pannocchia,3,2 +5605,eager,3,1 +5606,desideroso di,3,2 +5607,fist,3,1 +5608,pugno,3,2 +5609,gnaw,3,1 +5610,rosicchiare,3,2 +5611,hoax,3,1 +5612,bufala,3,2 +5613,insight,3,1 +5614,intuizione,3,2 +5615,leek,3,1 +5616,porro,3,2 +5617,mink,3,1 +5618,visone,3,2 +5619,nape,3,1 +5620,nuca,3,2 +5621,overage,3,1 +5622,eccedenza,3,2 +5623,prig,3,1 +5624,saccente,3,2 +5625,pursue,3,1 +5626,inseguire,3,2 +5627,scoff,3,1 +5628,sbeffeggiare,3,2 +5629,sift,3,1 +5630,setacciare,3,2 +5631,stinger,3,1 +5632,pungiglione,3,2 +5633,unlikely,3,1 +5634,improbabile,3,2 +5635,auctioneer,3,1 +5636,banditore,3,2 +5637,bested,3,1 +5638,avere la meglio,3,2 +5639,bulwark,3,1 +5640,baluardo,3,2 +5641,daisy,3,1 +5642,margherita,3,2 +5643,defeat,3,1 +5644,sconfitta,3,2 +5645,disquiet,3,1 +5646,inquietudine,3,2 +5647,douse,3,1 +5648,gettare acqua su,3,2 +5649,ease,3,1 +5650,attenuare,3,2 +5651,figurehead,3,1 +5652,polena,3,2 +5653,flatter,3,1 +5654,lusingare,3,2 +5655,grasshopper,3,1 +5656,cavalletta,3,2 +5657,habit,3,1 +5658,abitudine,3,2 +5659,prowling,3,1 +5660,aggirarsi,3,2 +5661,roar,3,1 +5662,ruggito,3,2 +5663,rugged,3,1 +5664,accidentato,3,2 +5665,saffron,3,1 +5666,zafferano,3,2 +5667,scab,3,1 +5668,crosta,3,2 +5669,stench,3,1 +5670,tanfo,3,2 +5671,swan,3,1 +5672,cigno,3,2 +5673,yarn,3,1 +5674,filo,3,2 +5675,awl,3,1 +5676,punteruolo,3,2 +5677,basin,3,1 +5678,lavabo,3,2 +5679,blush,3,1 +5680,arrossire,3,2 +5681,braggart,3,1 +5682,sbruffone,3,2 +5683,bric a brac,3,1 +5684,cianfrusaglie,3,2 +5685,dye,3,1 +5686,tintura,3,2 +5687,eke out,3,1 +5688,razionare,3,2 +5689,fatuous,3,1 +5690,fatuo,3,2 +5691,fault,3,1 +5692,guasto,3,2 +5693,foundry,3,1 +5694,fonderia,3,2 +5695,frowning,3,1 +5696,accigliato,3,2 +5697,garland,3,1 +5698,ghirlanda,3,2 +5699,guess,3,1 +5700,indovinare,3,2 +5701,life size,3,1 +5702,grandezza naturale,3,2 +5703,merely,3,1 +5704,semplicemente,3,2 +5705,poaching,3,1 +5706,bracconaggio,3,2 +5707,preen,3,1 +5708,agghindarsi,3,2 +5709,scourge,3,1 +5710,flagellare,3,2 +5711,swallow,3,1 +5712,rondine,3,2 +5713,tilt,3,1 +5714,inclinare,3,2 +5715,bask,3,1 +5716,crogiolarsi,3,2 +5717,borrow,3,1 +5718,prendere in prestito,3,2 +5719,bump into,3,1 +5720,imbattersi,3,2 +5721,burly,3,1 +5722,corpulento,3,2 +5723,canvas,3,1 +5724,tela,3,2 +5725,challenging,3,1 +5726,impegnativo,3,2 +5727,contrive,3,1 +5728,escogitare,3,2 +5729,cringe,3,1 +5730,farsi piccolo,3,2 +5731,croon,3,1 +5732,canticchiare,3,2 +5733,cursory,3,1 +5734,frettoloso,3,2 +5735,dread,3,1 +5736,timore,3,2 +5737,exult,3,1 +5738,esultare,3,2 +5739,faint,3,1 +5740,tenue,3,2 +5741,flaky,3,1 +5742,friabile,3,2 +5743,get rid of,3,1 +5744,sbarazzarsi di,3,2 +5745,invoice,3,1 +5746,fattura,3,2 +5747,nicety,3,1 +5748,finezza,3,2 +5749,shawl,3,1 +5750,scialle,3,2 +5751,starve,3,1 +5752,morire di fame,3,2 +5753,vat,3,1 +5754,tinozza,3,2 +5755,bud,3,1 +5756,bocciolo,3,2 +5757,chaperone,3,1 +5758,accompagnatore,3,2 +5759,chop,3,1 +5760,spaccare,3,2 +5761,christening,3,1 +5762,battesimo,3,2 +5763,crestfallen,3,1 +5764,avvilito,3,2 +5765,exhaust,3,1 +5766,sfinire,3,2 +5767,footman,3,1 +5768,valletto,3,2 +5769,frentic,3,1 +5770,convulso,3,2 +5771,genuflect,3,1 +5772,genuflettersi,3,2 +5773,pantomime,3,1 +5774,pantomima,3,2 +5775,petitioner,3,1 +5776,richiedente,3,2 +5777,proper,3,1 +5778,corretto,3,2 +5779,rascal,3,1 +5780,birbantello,3,2 +5781,reimburse,3,1 +5782,rimborsare,3,2 +5783,scum,3,1 +5784,feccia,3,2 +5785,shingle,3,1 +5786,tegola,3,2 +5787,steeplechase,3,1 +5788,corsa a ostacoli,3,2 +5789,surreptitious,3,1 +5790,furtivo,3,2 +5791,tarry,3,1 +5792,indugiare,3,2 +5793,treacherous,3,1 +5794,sleale,3,2 +5795,afford,3,1 +5796,permettersi,3,2 +5797,allay,3,1 +5798,acquietare,3,2 +5799,bald,3,1 +5800,calvo,3,2 +5801,bumpkin,3,1 +5802,bifolco,3,2 +5803,carousel,3,1 +5804,giostra,3,2 +5805,dowdy,3,1 +5806,senza stile,3,2 +5807,elope,3,1 +5808,fuga d'amore,3,2 +5809,fawning,3,1 +5810,servile,3,2 +5811,flotsam,3,1 +5812,detriti,3,2 +5813,gild,3,1 +5814,dorare,3,2 +5815,guilt,3,1 +5816,colpa,3,2 +5817,hymn,3,1 +5818,inno,3,2 +5819,mantelpiece,3,1 +5820,mensola del camino,3,2 +5821,nowadays,3,1 +5822,al giorno d'oggi,3,2 +5823,ruckus,3,1 +5824,putiferio,3,2 +5825,shake hands,3,1 +5826,stringere la mano,3,2 +5827,snarl,3,1 +5828,ringhiare,3,2 +5829,tidy,3,1 +5830,ordinato,3,2 +5831,warble,3,1 +5832,gorgheggiare,3,2 +5833,wilt,3,1 +5834,perdere vigore,3,2 +5835,abbey,3,1 +5836,abbazia,3,2 +5837,adorned,3,1 +5838,ornato,3,2 +5839,afferent,3,1 +5840,afferente,3,2 +5841,awkward,3,1 +5842,scomodo,3,2 +5843,cobweb,3,1 +5844,ragnatela,3,2 +5845,commonplace,3,1 +5846,luogo comune,3,2 +5847,concur,3,1 +5848,concordare,3,2 +5849,disappointed,3,1 +5850,deluso,3,2 +5851,doleful,3,1 +5852,addolorato,3,2 +5853,flyer,3,1 +5854,volantino,3,2 +5855,glad,3,1 +5856,lieto,3,2 +5857,hit,3,1 +5858,colpire,3,2 +5859,inane,3,1 +5860,insensato,3,2 +5861,nab,3,1 +5862,acciuffare,3,2 +5863,ravine,3,1 +5864,burrone,3,2 +5865,rub,3,1 +5866,sfregare,3,2 +5867,scratch,3,1 +5868,graffio,3,2 +5869,tight,3,1 +5870,stretto,3,2 +5871,weep,3,1 +5872,pianto,3,2 +5873,wing,3,1 +5874,ala,3,2 +5875,amble,3,1 +5876,ambiare,3,2 +5877,amenable,3,1 +5878,ben disposto,3,2 +5879,beam,3,1 +5880,raggio,3,2 +5881,belong,3,1 +5882,appartenere,3,2 +5883,certitude,3,1 +5884,certezza,3,2 +5885,coil,3,1 +5886,bobina,3,2 +5887,dumb,3,1 +5888,muto,3,2 +5889,fancy,3,1 +5890,di lusso,3,2 +5891,gorgeous,3,1 +5892,splendida,3,2 +5893,greasy,3,1 +5894,unto,3,2 +5895,lack,3,1 +5896,mancanza,3,2 +5897,loyalty,3,1 +5898,lealta',3,2 +5899,relieve the pressure,3,1 +5900,ridurre la pressione,3,2 +5901,ringlet,3,1 +5902,boccolo,3,2 +5903,ruse,3,1 +5904,inganno,3,2 +5905,seer,3,1 +5906,veggente,3,2 +5907,smother,3,1 +5908,asfissiare,3,2 +5909,stance,3,1 +5910,presa di posizione,3,2 +5911,tremble,3,1 +5912,tremolio,3,2 +5913,vexatious,3,1 +5914,vessatorio,3,2 +5915,acknowledge,3,1 +5916,riconoscere,3,2 +5917,attitude,3,1 +5918,attitudine,3,2 +5919,bankruptcy,3,1 +5920,bancarotta,3,2 +5921,blank,3,1 +5922,in bianco,3,2 +5923,bleat,3,1 +5924,belare,3,2 +5925,expatriate,3,1 +5926,espatriato,3,2 +5927,exude,3,1 +5928,trasudare,3,2 +5929,fix,3,1 +5930,sistemare,3,2 +5931,former,3,1 +5932,il precedente,3,2 +5933,green room,3,1 +5934,camerino,3,2 +5935,greenhouse,3,1 +5936,serra,3,2 +5937,harebrained,3,1 +5938,strampalato,3,2 +5939,highlight,3,1 +5940,evidenziare,3,2 +5941,latter,3,1 +5942,quest'ultimo,3,2 +5943,pageant,3,1 +5944,sfilata,3,2 +5945,saunter,3,1 +5946,andatura rilassata,3,2 +5947,semiotics,3,1 +5948,semiotica,3,2 +5949,stuff,3,1 +5950,roba,3,2 +5951,thoroughbred,3,1 +5952,purosangue,3,2 +5953,wrapper,3,1 +5954,involucro,3,2 +5955,cage,3,1 +5956,gabbia,3,2 +5957,cod,3,1 +5958,merluzzo,3,2 +5959,courier,3,1 +5960,corriere,3,2 +5961,crumple,3,1 +5962,stropicciare,3,2 +5963,graft,3,1 +5964,innestare,3,2 +5965,gullet,3,1 +5966,esofago,3,2 +5967,humble,3,1 +5968,umile,3,2 +5969,lynch,3,1 +5970,linciare,3,2 +5971,misunderstand,3,1 +5972,frainteso,3,2 +5973,pane,3,1 +5974,riquadro,3,2 +5975,plate,3,1 +5976,piatto,3,2 +5977,refine,3,1 +5978,rifinire,3,2 +5979,slapdash,3,1 +5980,fatto alla buona,3,2 +5981,snug,3,1 +5982,aderente,3,2 +5983,surge,3,1 +5984,impennata,3,2 +5985,sweep,3,1 +5986,spazzare,3,2 +5987,swelter,3,1 +5988,caldo soffocante,3,2 +5989,thickset,3,1 +5990,tarchiato,3,2 +5991,tossed,3,1 +5992,sballottato,3,2 +5993,wince,3,1 +5994,trasalire,3,2 +5995,blockade,3,1 +5996,embargo,3,2 +5997,cheque,3,1 +5998,assegno,3,2 +5999,cue,3,1 +6000,spunto,3,2 +6001,employee,3,1 +6002,impiegato,3,2 +6003,flickering,3,1 +6004,tremolante,3,2 +6005,furrow,3,1 +6006,solco,3,2 +6007,imperil,3,1 +6008,mettere a rischio,3,2 +6009,muffler,3,1 +6010,silenziatore,3,2 +6011,relief,3,1 +6012,sollievo,3,2 +6013,rooster,3,1 +6014,gallo,3,2 +6015,rough,3,1 +6016,ruvido,3,2 +6017,rowdy,3,1 +6018,turbolento,3,2 +6019,sipping,3,1 +6020,sorseggiare,3,2 +6021,slumber,3,1 +6022,assopirsi,3,2 +6035,absent,3,1 +6036,assente,3,2 +6037,belief,3,1 +6038,credenza,3,2 +6039,cinnamon,3,1 +6040,cannella,3,2 +6041,enthral,3,1 +6042,incollato alla sedia,3,2 +6043,gizmo,3,1 +6044,aggeggio,3,2 +6045,hansom,3,1 +6046,carrozza,3,2 +6047,hawk,3,1 +6048,falco,3,2 +6049,lined,3,1 +6050,foderato,3,2 +6051,lubricate,3,1 +6052,lubrificare,3,2 +6053,mutiny,3,1 +6054,ammutinamento,3,2 +6055,platitude,3,1 +6056,frase fatta,3,2 +6057,rickety,3,1 +6058,pericolante,3,2 +6059,upbringing,3,1 +6060,educazione,3,2 +6061,witty,3,1 +6062,spiritoso,3,2 +6075,bigwig,3,1 +6076,pezzo grosso,3,2 +6077,blur,3,1 +6078,sfocato,3,2 +6079,bonkers,3,1 +6080,fuori di testa,3,2 +6081,erratic,3,1 +6082,erratico,3,2 +6083,flesh,3,1 +6084,carne,3,2 +6085,gloom,3,1 +6086,oscurita',3,2 +6087,hike,3,1 +6088,escursione,3,2 +6089,huge,3,1 +6090,immenso,3,2 +6091,interim,3,1 +6092,provvisorio,3,2 +6093,lampoon,3,1 +6094,satira,3,2 +6095,pursuant to,3,1 +6096,ai sensi di,3,2 +6097,swear,3,1 +6098,giurare,3,2 +6099,trample,3,1 +6100,pestare,3,2 +6101,whistle,3,1 +6102,fischio,3,2 +6115,breadcrumb,3,1 +6116,pangrattato,3,2 +6117,drowsy,3,1 +6118,assonnato,3,2 +6119,fair,3,1 +6120,giusto,3,2 +6121,gumption,3,1 +6122,intraprendenza,3,2 +6123,match,3,1 +6124,abbinato,3,2 +6125,matchstick,3,1 +6126,fiammifero,3,2 +6127,poppies,3,1 +6128,papaveri,3,2 +6129,sob,3,1 +6130,singhiozzare,3,2 +6131,soon,3,1 +6132,presto,3,2 +6133,stun,3,1 +6134,stordire,3,2 +6135,trade,3,1 +6136,commercio,3,2 +6137,turntable,3,1 +6138,giradischi,3,2 +6139,yank,3,1 +6140,strattonare,3,2 +6141,yardstick,3,1 +6142,criterio di paragone,3,2 +6143,brace,3,1 +6144,tutore,3,2 +6145,crease,3,1 +6146,grinza,3,2 +6147,deaden,3,1 +6148,attuire,3,2 +6149,deserve,3,1 +6150,meritare,3,2 +6151,dimly,3,1 +6152,vagamente,3,2 +6153,estrange,3,1 +6154,estraniare,3,2 +6155,gross,3,1 +6156,lordo,3,2 +6157,mackintosh,3,1 +6158,impermeabile,3,2 +6159,moose,3,1 +6160,alce,3,2 +6161,runner up,3,1 +6162,secondo classificato,3,2 +6163,snoop around,3,1 +6164,ficcare il naso,3,2 +6165,sodden,3,1 +6166,fradicio,3,2 +6167,twofer,3,1 +6168,due per uno,3,2 +6169,wide,3,1 +6170,ampio,3,2 +6171,block letters,3,1 +6172,stampatello,3,2 +6173,buttonhole,3,1 +6174,asola,3,2 +6175,coop,3,1 +6176,pollaio,3,2 +6177,gaunt,3,1 +6178,scarno,3,2 +6179,irretrievable,3,1 +6180,irrimediabile,3,2 +6181,knucklehead,3,1 +6182,testone,3,2 +6183,label,3,1 +6184,etichetta,3,2 +6185,lowbrow,3,1 +6186,poco colto,3,2 +6187,mushy,3,1 +6188,sdolcinato,3,2 +6189,scenery,3,1 +6190,panorama,3,2 +6191,smidgen,3,1 +6192,pizzico,3,2 +6193,trivial,3,1 +6194,irrilevante,3,2 +6195,vulture,3,1 +6196,avvoltoio,3,2 +6197,wharf,3,1 +6198,molo,3,2 +6199,anchovy,3,1 +6200,acciuga,3,2 +6201,buddy,3,1 +6202,compare,3,2 +6203,cagey,3,1 +6204,evasivo,3,2 +6205,counsel,3,1 +6206,consigliare,3,2 +6207,dashed,3,1 +6208,tratteggiato,3,2 +6209,enraged,3,1 +6210,infuriato,3,2 +6211,helping,3,1 +6212,porzione,3,2 +6213,histrionic,3,1 +6214,istrionico,3,2 +6215,pace,3,1 +6216,ritmo,3,2 +6217,play truant,3,1 +6218,bigiare,3,2 +6219,starry,3,1 +6220,stellato,3,2 +6221,tramp,3,1 +6222,barbone,3,2 +6223,unassuming,3,1 +6224,senza pretese,3,2 +6225,waylay,3,1 +6226,tendere un agguato,3,2 +6227,aide,3,1 +6228,assistente,3,2 +6229,bite,3,1 +6230,pungere,3,2 +6231,cackle,3,1 +6232,schiamazzo,3,2 +6233,despondent,3,1 +6234,abbattuto,3,2 +6235,dizzy,3,1 +6236,vertigine,3,2 +6237,earn,3,1 +6238,guadagnare,3,2 +6239,laughingstock,3,1 +6240,zimbello,3,2 +6241,peek,3,1 +6242,occhiata veloce,3,2 +6243,peerless,3,1 +6244,senza eguali,3,2 +6245,pilfer,3,1 +6246,sgraffignare,3,2 +6247,prank,3,1 +6248,burla,3,2 +6249,risible,3,1 +6250,risibile,3,2 +6251,sedition,3,1 +6252,sedizione,3,2 +6253,thrash,3,1 +6254,picchiare,3,2 +6255,bray,3,1 +6256,ragliare,3,2 +6257,cliff,3,1 +6258,scogliera,3,2 +6259,curvaceous,3,1 +6260,sinuosa,3,2 +6261,dalliance,3,1 +6262,breve rapporto,3,2 +6263,manly,3,1 +6264,virile,3,2 +6265,mosquito,3,1 +6266,zanzara,3,2 +6267,pipe,3,1 +6268,tubo,3,2 +6269,prissy,3,1 +6270,affettato,3,2 +6271,rag,3,1 +6272,straccio,3,2 +6273,rectitude,3,1 +6274,rettitudine,3,2 +6275,thunderstruck,3,1 +6276,scioccato,3,2 +6277,untie,3,1 +6278,slegare,3,2 +6279,voluptuous,3,1 +6280,voluttuoso,3,2 +6281,wink,3,1 +6282,occhiolino,3,2 +6283,acquit,3,1 +6284,assolvere,3,2 +6285,addendum,3,1 +6286,aggiunta,3,2 +6287,fodder,3,1 +6288,foraggio,3,2 +6289,gown,3,1 +6290,abito da sera,3,2 +6291,guild,3,1 +6292,corporazione,3,2 +6293,hedgehog,3,1 +6294,riccio,3,2 +6295,huckleberry,3,1 +6296,mirtillo,3,2 +6297,maggot,3,1 +6298,larva,3,2 +6299,overlay,3,1 +6300,copertura,3,2 +6301,overload,3,1 +6302,sovraccarico,3,2 +6303,panoply,3,1 +6304,panoplia,3,2 +6305,sticky,3,1 +6306,adesivo,3,2 +6307,thundering,3,1 +6308,fragoroso,3,2 +6309,wasteland,3,1 +6310,terra desolata,3,2 +6311,anoint,3,1 +6312,ungere,3,2 +6313,cough,3,1 +6314,tossire,3,2 +6315,drain,3,1 +6316,drenare,3,2 +6317,garlic,3,1 +6318,aglio,3,2 +6319,hint,3,1 +6320,suggerimento,3,2 +6321,hunker down,3,1 +6322,mettersi sotto,3,2 +6323,offal,3,1 +6324,frattaglie,3,2 +6325,ointment,3,1 +6326,unguento,3,2 +6327,perfunctory,3,1 +6328,sbrigativo,3,2 +6329,sheaf,3,1 +6330,covone,3,2 +6331,stripe,3,1 +6332,striscia,3,2 +6333,swirl,3,1 +6334,vorticare,3,2 +6335,whimsical,3,1 +6336,estroso,3,2 +6337,willow,3,1 +6338,salice,3,2 +6339,afterglow,3,1 +6340,riverbero,3,2 +6341,bait,3,1 +6342,esca,3,2 +6343,clearing,3,1 +6344,radura,3,2 +6345,crafty,3,1 +6346,sornione,3,2 +6347,frazzle,3,1 +6348,esaurimento,3,2 +6349,louse,3,1 +6350,pidocchio,3,2 +6351,misstatement,3,1 +6352,inesattezza,3,2 +6353,mottled,3,1 +6354,screziato,3,2 +6355,racket,3,1 +6356,chiasso,3,2 +6357,raring,3,1 +6358,impaziente,3,2 +6359,stilted,3,1 +6360,pomposo,3,2 +6361,stubble,3,1 +6362,barba corta,3,2 +6363,vial,3,1 +6364,fiala,3,2 +6365,vituperation,3,1 +6366,vituperio,3,2 +6367,abominable,3,1 +6368,abominevole,3,2 +6369,buck,3,1 +6370,dollaro,3,2 +6371,commend,3,1 +6372,elogiare,3,2 +6373,crowded,3,1 +6374,affollato,3,2 +6375,discreet,3,1 +6376,discreto,3,2 +6377,enjoin,3,1 +6378,ingiungere,3,2 +6379,freehand,3,1 +6380,a mano libera,3,2 +6381,limp,3,1 +6382,claudicare,3,2 +6383,out of the blue,3,1 +6384,di punto in bianco,3,2 +6385,pie,3,1 +6386,torta,3,2 +6387,row,3,1 +6388,fila,3,2 +6389,tar,3,1 +6390,catrame,3,2 +6391,tattered,3,1 +6392,sbrindellato,3,2 +6393,unheard,3,1 +6394,inaudito,3,2 +6395,awhile,3,1 +6396,per un po',3,2 +6397,bold,3,1 +6398,audace,3,2 +6399,cheeky,3,1 +6400,sbarazzino,3,2 +6401,cranky,3,1 +6402,irritabile,3,2 +6403,deserter,3,1 +6404,disertore,3,2 +6405,devilment,3,1 +6406,diavoleria,3,2 +6407,imbalance,3,1 +6408,squilibrio,3,2 +6409,masseur,3,1 +6410,massaggiatore,3,2 +6411,peak,3,1 +6412,cima,3,2 +6413,renegade,3,1 +6414,rinnegato,3,2 +6415,sketch,3,1 +6416,schizzo,3,2 +6417,sliver,3,1 +6418,frammento,3,2 +6419,upholster,3,1 +6420,tappezzare,3,2 +6421,width,3,1 +6422,larghezza,3,2 +6423,alluring,3,1 +6424,allettante,3,2 +6425,bead,3,1 +6426,perlina,3,2 +6427,briefcase,3,1 +6428,ventiquattrore,3,2 +6429,brisk,3,1 +6430,svelto,3,2 +6431,broach the subject,3,1 +6432,affrontare l'argomento,3,2 +6433,contemptuous,3,1 +6434,sprezzante,3,2 +6435,guarantor,3,1 +6436,garante,3,2 +6437,nexus,3,1 +6438,nesso,3,2 +6439,scar,3,1 +6440,cicatrice,3,2 +6441,seal,3,1 +6442,foca,3,2 +6443,spice,3,1 +6444,spezia,3,2 +6445,stringy,3,1 +6446,filante,3,2 +6447,unbeatable,3,1 +6448,imbattibile,3,2 +6449,uplifting,3,1 +6450,incoraggiante,3,2 +6451,baseless,3,1 +6452,infondato,3,2 +6453,bevel,3,1 +6454,smussare,3,2 +6455,cursing,3,1 +6456,imprecare,3,2 +6457,demur,3,1 +6458,obiettare,3,2 +6459,flyleaf,3,1 +6460,risguardo,3,2 +6461,gesturing,3,1 +6462,gesticolare,3,2 +6463,inherit,3,1 +6464,ereditare,3,2 +6465,quest,3,1 +6466,ricerca,3,2 +6467,rebuke,3,1 +6468,sgridare,3,2 +6469,sardonic,3,1 +6470,sardonico,3,2 +6471,suborn,3,1 +6472,subornare,3,2 +6473,sunbath,3,1 +6474,prendere il sole,3,2 +6475,sunbed,3,1 +6476,sdraio,3,2 +6477,upset,3,1 +6478,turbato,3,2 +6479,adroit,3,1 +6480,sagace,3,2 +6481,anteroom,3,1 +6482,anticamera,3,2 +6483,buttock,3,1 +6484,natica,3,2 +6485,canteen,3,1 +6486,mensa,3,2 +6487,escarpment,3,1 +6488,scarpata,3,2 +6489,gauze,3,1 +6490,garza,3,2 +6491,handlebar,3,1 +6492,manubrio,3,2 +6493,holy father,3,1 +6494,papa,3,2 +6495,jammed,3,1 +6496,inceppato,3,2 +6497,liver,3,1 +6498,fegato,3,2 +6499,obeisance,3,1 +6500,omaggio,3,2 +6501,pummel,3,1 +6502,prendere a pugni,3,2 +6503,towel,3,1 +6504,asciugamano,3,2 +6505,upright,3,1 +6506,eretto,3,2 +6507,caliper,3,1 +6508,calibro,3,2 +6509,crouch,3,1 +6510,accucciarsi,3,2 +6511,diaper,3,1 +6512,pannolino,3,2 +6513,gully,3,1 +6514,canale,3,2 +6515,lane,3,1 +6516,corsia,3,2 +6517,leniency,3,1 +6518,clemenza,3,2 +6519,oatmeal,3,1 +6520,farina d'avena,3,2 +6521,rack,3,1 +6522,rastrelliera,3,2 +6523,saucer,3,1 +6524,piattino,3,2 +6525,shoplift,3,1 +6526,taccheggiare,3,2 +6527,smudge,3,1 +6528,sbavatura,3,2 +6529,sock,3,1 +6530,calzino,3,2 +6531,warn,3,1 +6532,avvertire,3,2 +6533,wasp,3,1 +6534,vespa,3,2 +6535,afresh,3,1 +6536,da capo,3,2 +6537,blast,3,1 +6538,esplosione,3,2 +6539,bump,3,1 +6540,urto,3,2 +6541,carefree,3,1 +6542,sereno,3,2 +6543,counterfeit,3,1 +6544,contraffatto,3,2 +6545,grub up,3,1 +6546,estirpare,3,2 +6547,neck strap,3,1 +6548,tracolla,3,2 +6549,raisin,3,1 +6550,uvetta,3,2 +6551,smash,3,1 +6552,frantumarsi,3,2 +6553,spoon,3,1 +6554,cucchiaio,3,2 +6555,stocky,3,1 +6556,tozzo,3,2 +6557,trout,3,1 +6558,trota,3,2 +6559,wanly,3,1 +6560,debolmente,3,2 +6561,whilst,3,1 +6562,mentre,3,2 +6563,aboveboard,3,1 +6564,a carte scoperte,3,2 +6565,denouement,3,1 +6566,epilogo,3,2 +6567,disingenuous,3,1 +6568,in malafede,3,2 +6569,eminent,3,1 +6570,eminente,3,2 +6571,heal,3,1 +6572,guarire,3,2 +6573,hypocrite,3,1 +6574,ipocrita,3,2 +6575,incurious,3,1 +6576,privo di curiosita',3,2 +6577,infringement,3,1 +6578,infrazione,3,2 +6579,madhouse,3,1 +6580,manicomio,3,2 +6581,merge,3,1 +6582,fusione,3,2 +6583,plot,3,1 +6584,tema,3,2 +6585,underlie,3,1 +6586,stare alla base,3,2 +6587,underneath,3,1 +6588,al di sotto,3,2 +6589,underpin,3,1 +6590,sorreggere,3,2 +6591,blame,3,1 +6592,biasimare,3,2 +6593,finding,3,1 +6594,scoperta,3,2 +6595,fizzle out,3,1 +6596,affievolirsi,3,2 +6597,flute,3,1 +6598,flauto,3,2 +6599,forestall,3,1 +6600,prevenire,3,2 +6601,impassable,3,1 +6602,intransitabile,3,2 +6603,namely,3,1 +6604,vale a dire,3,2 +6605,newbie,3,1 +6606,principiante,3,2 +6607,puzzling,3,1 +6608,enigmatico,3,2 +6609,rampart,3,1 +6610,bastione,3,2 +6611,sentry,3,1 +6612,sentinella,3,2 +6613,underdog,3,1 +6614,sfavorito,3,2 +6615,unfold,3,1 +6616,svelare,3,2 +6617,urge,3,1 +6618,sollecitare,3,2 +6619,afterthought,3,1 +6620,ripensamento,3,2 +6621,condemn,3,1 +6622,condannare,3,2 +6623,gush,3,1 +6624,sgorgare,3,2 +6625,idiosyncrasy,3,1 +6626,idiosincrasia,3,2 +6627,knee brace,3,1 +6628,ginocchiera,3,2 +6629,overturn,3,1 +6630,ribaltare,3,2 +6631,package,3,1 +6632,pacco,3,2 +6633,profiteer,3,1 +6634,approfittatore,3,2 +6635,scorcher,3,1 +6636,giornata torrida,3,2 +6637,striking,3,1 +6638,impressionante,3,2 +6639,tackle,3,1 +6640,fronteggiare,3,2 +6641,tick,3,1 +6642,zecca,3,2 +6643,unappealing,3,1 +6644,poco invitante,3,2 +6645,uptight,3,1 +6646,nervoso,3,2 +6647,as well as,3,1 +6648,cosi' come,3,2 +6649,broad,3,1 +6650,vasto,3,2 +6651,clockwork,3,1 +6652,orologeria,3,2 +6653,defiant,3,1 +6654,provocatorio,3,2 +6655,featured,3,1 +6656,in evidenza,3,2 +6657,gill,3,1 +6658,branchia,3,2 +6659,hangnail,3,1 +6660,pellicina,3,2 +6661,nun,3,1 +6662,suora,3,2 +6663,skill,3,1 +6664,capacita',3,2 +6665,slurp,3,1 +6666,succhiare,3,2 +6667,stampede,3,1 +6668,fuga precipitosa,3,2 +6669,template,3,1 +6670,schema,3,2 +6671,turnstile,3,1 +6672,tornello,3,2 +6673,wager,3,1 +6674,puntare,3,2 +6675,available,3,1 +6676,disponibile,3,2 +6677,drivel,3,1 +6678,banalita',3,2 +6679,framework,3,1 +6680,struttura,3,2 +6681,goodwill,3,1 +6682,buona volonta',3,2 +6683,levity,3,1 +6684,levita',3,2 +6685,makeover,3,1 +6686,rifacimento,3,2 +6687,overlap,3,1 +6688,sovrapposizione,3,2 +6689,pitchfork,3,1 +6690,forcone,3,2 +6691,powder,3,1 +6692,polvere,3,2 +6693,priest,3,1 +6694,sacerdote,3,2 +6695,sanctimonious,3,1 +6696,bigotto,3,2 +6697,swift,3,1 +6698,rapido,3,2 +6699,untoward,3,1 +6700,spiacevole,3,2 +6701,whatsoever,3,1 +6702,sorta,3,2 +6703,befit,3,1 +6704,addire,3,2 +6705,buoy,3,1 +6706,boa,3,2 +6707,craze,3,1 +6708,moda del momento,3,2 +6709,cross,3,1 +6710,valicare,3,2 +6711,custard,3,1 +6712,crema pasticciera,3,2 +6713,foliage,3,1 +6714,fogliame,3,2 +6715,increase,3,1 +6716,aumentare,3,2 +6717,indulgent,3,1 +6718,indulgente,3,2 +6719,knot,3,1 +6720,nodo,3,2 +6721,phalanx,3,1 +6722,falange,3,2 +6723,shuttle,3,1 +6724,navetta,3,2 +6725,spark,3,1 +6726,scintilla,3,2 +6727,subtlety,3,1 +6728,sottigliezza,3,2 +6729,vapid,3,1 +6730,insulso,3,2 +6731,altercation,3,1 +6732,alterco,3,2 +6733,awash,3,1 +6734,inondato,3,2 +6735,caterpillar,3,1 +6736,bruco,3,2 +6737,chalice,3,1 +6738,calice,3,2 +6739,cuff,3,1 +6740,polsino,3,2 +6741,defiance,3,1 +6742,spregio,3,2 +6743,floodlight,3,1 +6744,riflettore,3,2 +6745,fuel,3,1 +6746,carburante,3,2 +6747,marksman,3,1 +6748,tiratore scelto,3,2 +6749,mezzanine,3,1 +6750,soppalco,3,2 +6751,pillar,3,1 +6752,pilastro,3,2 +6753,ratting,3,1 +6754,fare la spia,3,2 +6755,snicker,3,1 +6756,ridere sotto i baffi,3,2 +6757,whole,3,1 +6758,intero,3,2 +6759,as much as,3,1 +6760,tanto quanto,3,2 +6761,bake,3,1 +6762,infornare,3,2 +6763,encore,3,1 +6764,chiedere il bis,3,2 +6765,escapism,3,1 +6766,escapismo,3,2 +6767,further,3,1 +6768,ulteriore,3,2 +6769,impart,3,1 +6770,impartire,3,2 +6771,loophole,3,1 +6772,appiglio,3,2 +6773,mourning,3,1 +6774,lutto,3,2 +6775,parse,3,1 +6776,analizzare,3,2 +6777,pinch,3,1 +6778,pizzicotto,3,2 +6779,siblings,3,1 +6780,fratelli,3,2 +6781,sordid,3,1 +6782,sordido,3,2 +6783,thrilling,3,1 +6784,entusiasmante,3,2 +6785,wean,3,1 +6786,svezzare,3,2 +6787,ale,3,1 +6788,birra,3,2 +6789,bet,3,1 +6790,scommessa,3,2 +6791,boundary,3,1 +6792,confine,3,2 +6793,conviction,3,1 +6794,convinzione,3,2 +6795,defray,3,1 +6796,sostenere le spese,3,2 +6797,handsomely,3,1 +6798,profumatamente,3,2 +6799,marquee,3,1 +6800,tendone,3,2 +6801,nosedive,3,1 +6802,picchiata,3,2 +6803,outstrip,3,1 +6804,distanziare,3,2 +6805,overview,3,1 +6806,panoramica,3,2 +6807,pollinate,3,1 +6808,impollinare,3,2 +6809,subsidize,3,1 +6810,sovvenzionare,3,2 +6811,weird,3,1 +6812,bizzarro,3,2 +6813,whereas,3,1 +6814,laddove,3,2 +6815,accomplish,3,1 +6816,compiere,3,2 +6817,amplifier,3,1 +6818,amplificatore,3,2 +6819,arbitration,3,1 +6820,arbitrato,3,2 +6821,bit by bit,3,1 +6822,piano piano,3,2 +6823,decay,3,1 +6824,decadimento,3,2 +6825,ennoble,3,1 +6826,nobilitare,3,2 +6827,foothold,3,1 +6828,punto d'appoggio,3,2 +6829,income,3,1 +6830,reddito,3,2 +6831,paste,3,1 +6832,incollare,3,2 +6833,quilt,3,1 +6834,trapunta,3,2 +6835,retool,3,1 +6836,riattrezzare,3,2 +6837,rung,3,1 +6838,piolo,3,2 +6839,tongue in cheek,3,1 +6840,ironicamente,3,2 +6841,wrongdoing,3,1 +6842,misfatto,3,2 +6843,carnation,3,1 +6844,garofano,3,2 +6845,cobbler,3,1 +6846,calzolaio,3,2 +6847,cookbook,3,1 +6848,ricettario,3,2 +6849,cricket,3,1 +6850,grillo,3,2 +6851,dangle,3,1 +6852,penzolare,3,2 +6853,griddle,3,1 +6854,piastra,3,2 +6855,jamb,3,1 +6856,stipite,3,2 +6857,lighter,3,1 +6858,accendino,3,2 +6859,restorative,3,1 +6860,rigenerante,3,2 +6861,skirting,3,1 +6862,zoccolino,3,2 +6863,then again,3,1 +6864,d'altronde,3,2 +6865,topic,3,1 +6866,argomento,3,2 +6867,whetstone,3,1 +6868,cote,3,2 +6869,yet again,3,1 +6870,ancora una volta,3,2 +6871,behold,3,1 +6872,ammirare,3,2 +6873,fulfill,3,1 +6874,adempiere,3,2 +6875,handrail,3,1 +6876,corrimano,3,2 +6877,hatched,3,1 +6878,covato,3,2 +6879,insouciance,3,1 +6880,noncuranza,3,2 +6881,ladder,3,1 +6882,scala,3,2 +6883,lazybones,3,1 +6884,scansafatiche,3,2 +6885,morbid,3,1 +6886,morboso,3,2 +6887,preposterous,3,1 +6888,irragionevole,3,2 +6889,retinue,3,1 +6890,scorta,3,2 +6891,squatter,3,1 +6892,abusivo,3,2 +6893,straightforward,3,1 +6894,diretto,3,2 +6895,trustworthy,3,1 +6896,fidato,3,2 +6897,upturn,3,1 +6898,rialzo,3,2 +6899,adoption,3,1 +6900,adottare,3,2 +6901,at the latest,3,1 +6902,al piu' tardi,3,2 +6903,bounce,3,1 +6904,rimbalzo,3,2 +6905,brink,3,1 +6906,orlo,3,2 +6907,cooker hood,3,1 +6908,cappa,3,2 +6909,deal,3,1 +6910,affare,3,2 +6911,decoction,3,1 +6912,decotto,3,2 +6913,emaciate,3,1 +6914,emaciare,3,2 +6915,gorge yourself,3,1 +6916,ingozzarsi,3,2 +6917,indent,3,1 +6918,rientro,3,2 +6919,lampshade,3,1 +6920,paralume,3,2 +6921,ledge,3,1 +6922,sporgenza,3,2 +6923,on the other hand,3,1 +6924,d'altra parte,3,2 +6925,sputter,3,1 +6926,scoppiettare,3,2 +6927,accuracy,3,1 +6928,accuratezza,3,2 +6929,callow,3,1 +6930,inesperto,3,2 +6931,cove,3,1 +6932,baia,3,2 +6933,crampon,3,1 +6934,rampone,3,2 +6935,crayfish,3,1 +6936,gambero,3,2 +6937,detect,3,1 +6938,rilevare,3,2 +6939,downcast,3,1 +6940,scoraggiato,3,2 +6941,dungeon,3,1 +6942,segreta,3,2 +6943,fillet,3,1 +6944,filetto,3,2 +6945,gift,3,1 +6946,dono,3,2 +6947,gnarled,3,1 +6948,nodoso,3,2 +6949,reluctant,3,1 +6950,riluttante,3,2 +6951,rubbish,3,1 +6952,spazzatura,3,2 +6953,spike,3,1 +6954,spuntone,3,2 +6955,alight,3,1 +6956,in fiamme,3,2 +6957,commoner,3,1 +6958,popolano,3,2 +6959,congenial,3,1 +6960,congeniale,3,2 +6961,curdle,3,1 +6962,cagliare,3,2 +6963,decoy,3,1 +6964,diversivo,3,2 +6965,deliverance,3,1 +6966,liberazione,3,2 +6967,equip,3,1 +6968,equipaggiare,3,2 +6969,exceed,3,1 +6970,eccedere,3,2 +6971,flub,3,1 +6972,fare un pasticcio,3,2 +6973,menial,3,1 +6974,lavoro umile,3,2 +6975,oaf,3,1 +6976,babbeo,3,2 +6977,pile,3,1 +6978,cumulo,3,2 +6979,sustainable,3,1 +6980,sostenibile,3,2 +6981,tussle,3,1 +6982,azzuffarsi,3,2 +6983,amount,3,1 +6984,ammontare,3,2 +6985,anvil,3,1 +6986,incudine,3,2 +6987,bellow,3,1 +6988,muggire,3,2 +6989,chat,3,1 +6990,conversazione,3,2 +6991,crucible,3,1 +6992,crogiolo,3,2 +6993,daily,3,1 +6994,quotidiano,3,2 +6995,drawl,3,1 +6996,parlare strascicato,3,2 +6997,get along,3,1 +6998,andare d'accordo,3,2 +6999,heartfelt,3,1 +7000,di cuore,3,2 +7001,housemaid,3,1 +7002,governante,3,2 +7003,pincushion,3,1 +7004,puntaspilli,3,2 +7005,rafter,3,1 +7006,trave,3,2 +7007,reach,3,1 +7008,giungere,3,2 +7009,recall,3,1 +7010,rievocare,3,2 +7011,buckwheat,3,1 +7012,grano saraceno,3,2 +7013,buttress,3,1 +7014,contrafforte,3,2 +7015,contour,3,1 +7016,sagoma,3,2 +7017,corpse,3,1 +7018,cadavere,3,2 +7019,elder,3,1 +7020,sambuco,3,2 +7021,fanciful,3,1 +7022,fantasioso,3,2 +7023,millet,3,1 +7024,miglio,3,2 +7025,needlework,3,1 +7026,ricamo,3,2 +7027,ore,3,1 +7028,minerale,3,2 +7029,scarcely,3,1 +7030,a stento,3,2 +7031,scree,3,1 +7032,ghiaione,3,2 +7033,speck,3,1 +7034,granello,3,2 +7035,trouble,3,1 +7036,guaio,3,2 +7037,volition,3,1 +7038,volonta',3,2 +7039,airship,3,1 +7040,dirigibile,3,2 +7041,deploy,3,1 +7042,schierare,3,2 +7043,frolic,3,1 +7044,folleggiare,3,2 +7045,insulate,3,1 +7046,isolare,3,2 +7047,luscious,3,1 +7048,succulento,3,2 +7049,ovum,3,1 +7050,ovulo,3,2 +7051,pannier,3,1 +7052,gerla,3,2 +7053,penalty,3,1 +7054,sanzione,3,2 +7055,pushover,3,1 +7056,bersaglio facile,3,2 +7057,spire,3,1 +7058,guglia,3,2 +7059,streak,3,1 +7060,serie,3,2 +7061,supply,3,1 +7062,fornire,3,2 +7063,tenement,3,1 +7064,caseggiato,3,2 +7065,veracity,3,1 +7066,veridicita',3,2 +7067,bawdy,3,1 +7068,sconcio,3,2 +7069,bunk,3,1 +7070,letto a castello,3,2 +7071,buzzkill,3,1 +7072,guastafeste,3,2 +7073,cherry,3,1 +7074,ciliegia,3,2 +7075,closet,3,1 +7076,guardaroba,3,2 +7077,comparison,3,1 +7078,paragone,3,2 +7079,dishwasher,3,1 +7080,lavastoviglie,3,2 +7081,rest,3,1 +7082,riposo,3,2 +7083,ruler,3,1 +7084,righello,3,2 +7085,shell,3,1 +7086,conchiglia,3,2 +7087,tarpaulin,3,1 +7088,incerata,3,2 +7089,tasty,3,1 +7090,gustoso,3,2 +7091,wagon,3,1 +7092,carro,3,2 +7093,wastrel,3,1 +7094,perdigiorno,3,2 +7095,bore,3,1 +7096,noia,3,2 +7097,charred,3,1 +7098,carbonizzato,3,2 +7099,coworker,3,1 +7100,collega,3,2 +7101,disburse,3,1 +7102,sborsare,3,2 +7103,headmaster,3,1 +7104,preside,3,2 +7105,liquorice,3,1 +7106,liquirizia,3,2 +7107,nepotism,3,1 +7108,nepotismo,3,2 +7109,plenty,3,1 +7110,abbondanza,3,2 +7111,rejoin,3,1 +7112,riunire,3,2 +7113,schedule,3,1 +7114,programma,3,2 +7115,sect,3,1 +7116,setta,3,2 +7117,slush,3,1 +7118,fanghiglia,3,2 +7119,treat,3,1 +7120,trattare,3,2 +7121,unique,3,1 +7122,unico,3,2 +7123,abroad,3,1 +7124,all'estero,3,2 +7125,cart,3,1 +7126,carrello,3,2 +7127,crooked,3,1 +7128,storto,3,2 +7129,dairy,3,1 +7130,latticini,3,2 +7131,disinter,3,1 +7132,esumare,3,2 +7133,fastidious,3,1 +7134,meticoloso,3,2 +7135,hovel,3,1 +7136,tugurio,3,2 +7137,item,3,1 +7138,articolo,3,2 +7139,mate,3,1 +7140,partner,3,2 +7141,pick,3,1 +7142,scegliere,3,2 +7143,pungency,3,1 +7144,sapidita',3,2 +7145,purchase,3,1 +7146,acquisto,3,2 +7147,reticent,3,1 +7148,reticente,3,2 +7149,spry,3,1 +7150,arzillo,3,2 +7151,apex,3,1 +7152,apice,3,2 +7153,cask,3,1 +7154,botte,3,2 +7155,core,3,1 +7156,nucleo,3,2 +7157,keg,3,1 +7158,fusto,3,2 +7159,landmark,3,1 +7160,punto di riferimento,3,2 +7161,pallet,3,1 +7162,bancale,3,2 +7163,perjure,3,1 +7164,spergiurare,3,2 +7165,retail,3,1 +7166,al dettaglio,3,2 +7167,rob,3,1 +7168,rapinare,3,2 +7169,scare,3,1 +7170,spavento,3,2 +7171,secede,3,1 +7172,secedere,3,2 +7173,snifter,3,1 +7174,goccetto,3,2 +7175,tank,3,1 +7176,carro armato,3,2 +7177,watermelon,3,1 +7178,anguria,3,2 +7179,ambush,3,1 +7180,imboscata,3,2 +7181,downwind,3,1 +7182,sottovento,3,2 +7183,draught,3,1 +7184,spiffero,3,2 +7185,fin,3,1 +7186,pinna,3,2 +7187,hefty,3,1 +7188,pesante,3,2 +7189,itemize,3,1 +7190,elencare,3,2 +7191,juniper,3,1 +7192,ginepro,3,2 +7193,murder,3,1 +7194,omicidio,3,2 +7195,myth,3,1 +7196,mito,3,2 +7197,quay,3,1 +7198,banchina,3,2 +7199,reindeer,3,1 +7200,renna,3,2 +7201,sphere,3,1 +7202,sfera,3,2 +7203,upwind,3,1 +7204,controvento,3,2 +7205,wild berry,3,1 +7206,frutti di bosco,3,2 +7207,banner,3,1 +7208,striscione,3,2 +7209,coconut,3,1 +7210,noce di cocco,3,2 +7211,duress,3,1 +7212,costrizione,3,2 +7213,frizzy,3,1 +7214,crespo,3,2 +7215,hauteur,3,1 +7216,alterigia,3,2 +7217,inhabit,3,1 +7218,abitare,3,2 +7219,intruder,3,1 +7220,intruso,3,2 +7221,prepackaged,3,1 +7222,preconfezionato,3,2 +7223,rent,3,1 +7224,affitto,3,2 +7225,shield,3,1 +7226,scudo,3,2 +7227,smoulder,3,1 +7228,covare rabbia,3,2 +7229,undo,3,1 +7230,disfare,3,2 +7231,uninhabited,3,1 +7232,disabitato,3,2 +7233,wet,3,1 +7234,bagnato,3,2 +7235,apocryphal,3,1 +7236,apocrifo,3,2 +7237,bangle,3,1 +7238,bracciale,3,2 +7239,creepy,3,1 +7240,raccapricciante,3,2 +7241,dissemble,3,1 +7242,dissimulare,3,2 +7243,facilities,3,1 +7244,servizi,3,2 +7245,gravestone,3,1 +7246,lapide,3,2 +7247,hospice,3,1 +7248,ospizio,3,2 +7249,lassitude,3,1 +7250,fiacchezza,3,2 +7251,lone,3,1 +7252,solitario,3,2 +7253,rush,3,1 +7254,di corsa,3,2 +7255,sideline,3,1 +7256,bordocampo,3,2 +7257,soak,3,1 +7258,immergere,3,2 +7259,trick,3,1 +7260,trucco,3,2 +7261,tryst,3,1 +7262,tresca,3,2 +7263,boil,3,1 +7264,bollire,3,2 +7265,din,3,1 +7266,frastuono,3,2 +7267,downtown,3,1 +7268,centro citta',3,2 +7269,employer,3,1 +7270,datore di lavoro,3,2 +7271,flounder,3,1 +7272,annaspare,3,2 +7273,flow,3,1 +7274,flusso,3,2 +7275,foremost,3,1 +7276,principale,3,2 +7277,icicle,3,1 +7278,stalattite,3,2 +7279,parson,3,1 +7280,parroco,3,2 +7281,spades,3,1 +7282,picche,3,2 +7283,studded,3,1 +7284,costellato,3,2 +7285,truculent,3,1 +7286,truculento,3,2 +7287,undergoing,3,1 +7288,in corso,3,2 +7289,wherein,3,1 +7290,in cui,3,2 +7291,farce,3,1 +7292,farsa,3,2 +7293,fervour,3,1 +7294,fervore,3,2 +7295,girder,3,1 +7296,putrella,3,2 +7297,howl,3,1 +7298,ululare,3,2 +7299,in thrall to,3,1 +7300,alla merce' di,3,2 +7301,intervene,3,1 +7302,intervenire,3,2 +7303,pilgrim,3,1 +7304,pellegrino,3,2 +7305,resonance,3,1 +7306,risonanza,3,2 +7307,seem,3,1 +7308,sembrare,3,2 +7309,surety,3,1 +7310,fideiussore,3,2 +7311,time lapse,3,1 +7312,lasso di tempo,3,2 +7313,trainee,3,1 +7314,tirocinante,3,2 +7315,trough,3,1 +7316,trogolo,3,2 +7317,unerring,3,1 +7318,preciso,3,2 +7319,alloy,3,1 +7320,lega,3,2 +7321,assert,3,1 +7322,asserire,3,2 +7323,awestruck,3,1 +7324,sbalordito,3,2 +7325,baleful,3,1 +7326,malevolo,3,2 +7327,dip,3,1 +7328,intingere,3,2 +7329,drag on,3,1 +7330,andare per le lunghe,3,2 +7331,fired,3,1 +7332,licenziato,3,2 +7333,harpoon,3,1 +7334,arpione,3,2 +7335,mundane,3,1 +7336,mondano,3,2 +7337,polymath,3,1 +7338,eclettico,3,2 +7339,shatter,3,1 +7340,frantumare,3,2 +7341,shift,3,1 +7342,turno,3,2 +7343,spawn,3,1 +7344,dare origine a,3,2 +7345,vent,3,1 +7346,sfiato,3,2 +7347,altogether,3,1 +7348,del tutto,3,2 +7349,annoy,3,1 +7350,scocciare,3,2 +7351,blink,3,1 +7352,lampeggiare,3,2 +7353,croak,3,1 +7354,gracidare,3,2 +7355,forewarn,3,1 +7356,preavvertire,3,2 +7357,intermingle,3,1 +7358,legarsi,3,2 +7359,outcrop,3,1 +7360,affioramento,3,2 +7361,outlast,3,1 +7362,durare piu' a lungo,3,2 +7363,ponytail,3,1 +7364,coda di cavallo,3,2 +7365,portent,3,1 +7366,premonizione,3,2 +7367,puzzlement,3,1 +7368,perplessita',3,2 +7369,redolent,3,1 +7370,rievocativo,3,2 +7371,reef,3,1 +7372,barriera corallina,3,2 +7373,wreckage,3,1 +7374,relitto,3,2 +7375,demijohn,3,1 +7376,damigiana,3,2 +7377,disloyal,3,1 +7378,infedele,3,2 +7379,disrepair,3,1 +7380,pessimo stato,3,2 +7381,earthquake,3,1 +7382,terremoto,3,2 +7383,foal,3,1 +7384,puledro,3,2 +7385,forecast,3,1 +7386,previsione,3,2 +7387,guile,3,1 +7388,scaltrezza,3,2 +7389,indolent,3,1 +7390,indolente,3,2 +7391,obviously,3,1 +7392,senza dubbio,3,2 +7393,prescient,3,1 +7394,preveggente,3,2 +7395,rouse,3,1 +7396,risvegliare,3,2 +7397,scaly,3,1 +7398,squamoso,3,2 +7399,suave,3,1 +7400,soave,3,2 +7401,underline,3,1 +7402,sottolineare,3,2 +7403,ablution,3,1 +7404,abluzione,3,2 +7405,benighted,3,1 +7406,arretrato,3,2 +7407,bordering,3,1 +7408,confinante,3,2 +7409,cottage,3,1 +7410,casolare,3,2 +7411,fob,3,1 +7412,portachiavi,3,2 +7413,garrulous,3,1 +7414,garrulo,3,2 +7415,languid,3,1 +7416,languido,3,2 +7417,musk,3,1 +7418,muschio,3,2 +7419,peremptory,3,1 +7420,perentorio,3,2 +7421,reconnoiter,3,1 +7422,recognizione,3,2 +7423,reprisal,3,1 +7424,rappresaglia,3,2 +7425,secrete,3,1 +7426,secernere,3,2 +7427,stud,3,1 +7428,stallone,3,2 +7429,thrice,3,1 +7430,tre volte,3,2 +7431,catwalk,3,1 +7432,passerella,3,2 +7433,compliance,3,1 +7434,conformita',3,2 +7435,desist,3,1 +7436,desistere,3,2 +7437,gravitas,3,1 +7438,solennita',3,2 +7439,grok,3,1 +7440,groccare,3,2 +7441,headcount,3,1 +7442,conta dei presenti,3,2 +7443,heads up,3,1 +7444,dritta,3,2 +7445,midrange,3,1 +7446,di fascia media,3,2 +7447,nonsense,3,1 +7448,assurdita',3,2 +7449,notch,3,1 +7450,tacca,3,2 +7451,predate,3,1 +7452,precedere,3,2 +7453,ring,3,1 +7454,anello,3,2 +7455,scrounge,3,1 +7456,scroccare,3,2 +7457,waiver,3,1 +7458,rinuncia,3,2 +7459,air quotes,3,1 +7460,virgolette,3,2 +7461,baloney,3,1 +7462,fesseria,3,2 +7463,baton,3,1 +7464,bacchetta,3,2 +7465,deputy,3,1 +7466,deputato,3,2 +7467,expeditious,3,1 +7468,spedito,3,2 +7469,handoff,3,1 +7470,passaggio di consegne,3,2 +7471,harrowing,3,1 +7472,straziante,3,2 +7473,hick,3,1 +7474,campagnolo,3,2 +7475,inescapable,3,1 +7476,ineludibile,3,2 +7477,leave in the lurch,3,1 +7478,piantare in asso,3,2 +7479,on the brink,3,1 +7480,sul punto di,3,2 +7481,restate,3,1 +7482,ribadire,3,2 +7483,retrofit,3,1 +7484,ammodernare,3,2 +7485,scathing,3,1 +7486,critica feroce,3,2 +7487,above and beyond,3,1 +7488,ben oltre,3,2 +7489,as far as,3,1 +7490,per quanto,3,2 +7491,by means of,3,1 +7492,mediante,3,2 +7493,by the way,3,1 +7494,a proposito,3,2 +7495,crag,3,1 +7496,falesia,3,2 +7497,craggy,3,1 +7498,scosceso,3,2 +7499,in order to,3,1 +7500,al fine di,3,2 +7501,jerky,3,1 +7502,a scatti,3,2 +7503,linchpin,3,1 +7504,fulcro,3,2 +7505,over and above,3,1 +7506,in aggiunta a,3,2 +7507,undue,3,1 +7508,indebito,3,2 +7509,wallop,3,1 +7510,sberla,3,2 +7511,wattle,3,1 +7512,acacia,3,2 +7513,way out,3,1 +7514,via d'uscita,3,2 +7515,accede,3,1 +7516,acconsentire,3,2 +7517,acrid,3,1 +7518,acre,3,2 +7519,canopy,3,1 +7520,tettoia,3,2 +7521,cutoff,3,1 +7522,limite massimo,3,2 +7523,extricate,3,1 +7524,districare,3,2 +7525,lintel,3,1 +7526,architrave,3,2 +7527,maze,3,1 +7528,labirinto,3,2 +7529,melt,3,1 +7530,sciogliere,3,2 +7531,nosy,3,1 +7532,impiccione,3,2 +7533,pewter,3,1 +7534,peltro,3,2 +7535,pleasant,3,1 +7536,piacevole,3,2 +7537,raptor,3,1 +7538,rapace,3,2 +7539,verdant,3,1 +7540,verdeggiante,3,2 +7541,wile,3,1 +7542,sotterfugio,3,2 +7543,alacrity,3,1 +7544,alacrita',3,2 +7545,carpet,3,1 +7546,tappeto,3,2 +7547,checker,3,1 +7548,dama,3,2 +7549,club,3,1 +7550,mazza,3,2 +7551,condescend,3,1 +7552,condiscendere,3,2 +7553,divot,3,1 +7554,zolla,3,2 +7555,fiery,3,1 +7556,ardente,3,2 +7557,fitfully,3,1 +7558,intermittente,3,2 +7559,opulent,3,1 +7560,opulento,3,2 +7561,pennant,3,1 +7562,stendardo,3,2 +7563,pigpen,3,1 +7564,porcile,3,2 +7565,smattering,3,1 +7566,infarinatura,3,2 +7567,tread,3,1 +7568,percorrere,3,2 +7569,woozy,3,1 +7570,frastornato,3,2 +7571,afoul,3,1 +7572,in conflitto con,3,2 +7573,amorphous,3,1 +7574,amorfo,3,2 +7575,auburn,3,1 +7576,ramato,3,2 +7577,docker,3,1 +7578,scaricatore di porto,3,2 +7579,gain,3,1 +7580,guadagno,3,2 +7581,haft,3,1 +7582,manico,3,2 +7583,jerkin,3,1 +7584,farsetto,3,2 +7585,mooring,3,1 +7586,ormeggio,3,2 +7587,mound,3,1 +7588,ammasso,3,2 +7589,plank,3,1 +7590,asse,3,2 +7591,potency,3,1 +7592,efficacia,3,2 +7593,prong,3,1 +7594,rebbio,3,2 +7595,redemption,3,1 +7596,redenzione,3,2 +7597,sycophant,3,1 +7598,sicofante,3,2 +7599,ailing,3,1 +7600,in difficolta',3,2 +7601,barefoot,3,1 +7602,scalzo,3,2 +7603,bivouac,3,1 +7604,bivacco,3,2 +7605,conspicuous,3,1 +7606,cospicuo,3,2 +7607,contraption,3,1 +7608,marchingegno,3,2 +7609,egregious,3,1 +7610,vergognoso,3,2 +7611,outstanding,3,1 +7612,eccezionale,3,2 +7613,promenade,3,1 +7614,passeggiata lungomare,3,2 +7615,redouble,3,1 +7616,intensificare,3,2 +7617,simper,3,1 +7618,sorriso falso,3,2 +7619,spinster,3,1 +7620,zitella,3,2 +7621,string,3,1 +7622,spago,3,2 +7623,untimely,3,1 +7624,prematura,3,2 +7625,wrangler,3,1 +7626,mandriano,3,2 +7627,bulge,3,1 +7628,rigonfiamento,3,2 +7629,complexion,3,1 +7630,carnagione,3,2 +7631,consign,3,1 +7632,spedire,3,2 +7633,crew,3,1 +7634,equipaggio,3,2 +7635,excise,3,1 +7636,accisa,3,2 +7637,hark back,3,1 +7638,richiamare alla memoria,3,2 +7639,haunch,3,1 +7640,cosciotto,3,2 +7641,inkling,3,1 +7642,sospetto,3,2 +7643,pavilion,3,1 +7644,padiglione,3,2 +7645,purpose,3,1 +7646,scopo,3,2 +7647,serration,3,1 +7648,dentellatura,3,2 +7649,shanty,3,1 +7650,baracca,3,2 +7651,splint,3,1 +7652,stecca,3,2 +7653,walkway,3,1 +7654,passaggio,3,2 +7655,attire,3,1 +7656,modo di vestire,3,2 +7657,collarbone,3,1 +7658,clavicola,3,2 +7659,discord,3,1 +7660,discordia,3,2 +7661,gutter,3,1 +7662,grondaia,3,2 +7663,lectern,3,1 +7664,leggio,3,2 +7665,missive,3,1 +7666,missiva,3,2 +7667,neuter,3,1 +7668,neutro,3,2 +7669,pendant,3,1 +7670,pendente,3,2 +7671,rash,3,1 +7672,incauto,3,2 +7673,remark,3,1 +7674,osservazione,3,2 +7675,reprobate,3,1 +7676,reprobo,3,2 +7677,stepladder,3,1 +7678,scala a libretto,3,2 +7679,tannery,3,1 +7680,conceria,3,2 +7681,warmonger,3,1 +7682,guerrafondaio,3,2 +7683,adjunct,3,1 +7684,aggiunto,3,2 +7685,aircraft,3,1 +7686,velivolo,3,2 +7687,breastbone,3,1 +7688,sterno,3,2 +7689,halberd,3,1 +7690,alabarda,3,2 +7691,inquest,3,1 +7692,inchiesta,3,2 +7693,pariah,3,1 +7694,paria,3,2 +7695,parietal,3,1 +7696,parietale,3,2 +7697,prudish,3,1 +7698,pudico,3,2 +7699,spacecraft,3,1 +7700,astronave,3,2 +7701,spindly,3,1 +7702,allampanato,3,2 +7703,spittle,3,1 +7704,saliva,3,2 +7705,steed,3,1 +7706,destriero,3,2 +7707,tie,3,1 +7708,cravatta,3,2 +7709,vestibule,3,1 +7710,vestibolo,3,2 +7711,beleaguered,3,1 +7712,bersagliato,3,2 +7713,bespectacled,3,1 +7714,occhialuto,3,2 +7715,bumper,3,1 +7716,paraurti,3,2 +7717,hoodlum,3,1 +7718,delinquente,3,2 +7719,larch,3,1 +7720,larice,3,2 +7721,miscreant,3,1 +7722,furfante,3,2 +7723,parry,3,1 +7724,parare,3,2 +7725,prude,3,1 +7726,puritano,3,2 +7727,pull,3,1 +7728,tirare,3,2 +7729,push,3,1 +7730,premere,3,2 +7731,requisition,3,1 +7732,requisizione,3,2 +7733,righteous,3,1 +7734,virtuoso,3,2 +7735,rout,3,1 +7736,disfatta,3,2 +7737,sombre,3,1 +7738,fosco,3,2 +7739,agog,3,1 +7740,elettrizzato,3,2 +7741,archenemy,3,1 +7742,arcinemico,3,2 +7743,attrition,3,1 +7744,logoramento,3,2 +7745,bedrock,3,1 +7746,basamento,3,2 +7747,brainwash,3,1 +7748,indottrinare,3,2 +7749,chivalry,3,1 +7750,galanteria,3,2 +7751,downright,3,1 +7752,addirittura,3,2 +7753,fowl,3,1 +7754,pollame,3,2 +7755,friction,3,1 +7756,attrito,3,2 +7757,hound,3,1 +7758,segugio,3,2 +7759,instalment,3,1 +7760,rata,3,2 +7761,phoney,3,1 +7762,fasullo,3,2 +7763,sunscreen,3,1 +7764,crema solare,3,2 +7765,tributary,3,1 +7766,immissario,3,2 +7767,beacon,3,1 +7768,segnale luminoso,3,2 +7769,berm,3,1 +7770,banchina,3,2 +7771,bittersweet,3,1 +7772,agrodolce,3,2 +7773,cashew,3,1 +7774,anacardo,3,2 +7775,damsel,3,1 +7776,donzella,3,2 +7777,evildoer,3,1 +7778,malfattore,3,2 +7779,genial,3,1 +7780,cordiale,3,2 +7781,germane,3,1 +7782,attinente,3,2 +7783,lapdog,3,1 +7784,tirapiedi,3,2 +7785,misconstrue,3,1 +7786,fraintendere,3,2 +7787,recess,3,1 +7788,recesso,3,2 +7789,unquiet,3,1 +7790,inquieto,3,2 +7791,walnut,3,1 +7792,noce,3,2 +7793,willful,3,1 +7794,intenzionale,3,2 +7795,loam,3,1 +7796,terriccio,3,2 +7797,out of kilter,3,1 +7798,sbilanciato,3,2 +7799,peerage,3,1 +7800,nobilta',3,2 +7801,polarized,3,1 +7802,antitetico,3,2 +7803,pretext,3,1 +7804,pretesto,3,2 +7805,proctor,3,1 +7806,sorvegliante,3,2 +7807,relive,3,1 +7808,rivivere,3,2 +7809,sneer,3,1 +7810,ghigno,3,2 +7811,stately,3,1 +7812,signorile,3,2 +7813,zealotry,3,1 +7814,fanatismo,3,2 +7815,niche,3,1 +7816,nicchia,3,2 +7817,byway,3,1 +7818,strada secondaria,3,2 +7819,uncoil,3,1 +7820,srotolare,3,2 +7821,debacle,3,1 +7822,fiasco,3,2 +7823,forebode,3,1 +7824,pronosticare,3,2 +7825,tacky,3,1 +7826,di cattivo gusto,3,2 +7827,haunt,3,1 +7828,infestare,3,2 +7829,endearing,3,1 +7830,fa tenerezza,3,2 +7831,airtight,3,1 +7832,ermetico,3,2 +7833,landfall,3,1 +7834,approdo,3,2 +7835,pike,3,1 +7836,lancia,3,2 +7837,mage,3,1 +7838,mago,3,2 +7839,crossword,3,1 +7840,cruciverba,3,2 +7841,gorse,3,1 +7842,ginestra,3,2 +7843,shy away,3,1 +7844,restare in disparte,3,2 +7845,anathema,3,1 +7846,anatema,3,2 +7847,outlying,3,1 +7848,periferico,3,2 +7849,underground,3,1 +7850,sotterraneo,3,2 +7851,exodus,3,1 +7852,esodo,3,2 +7853,torque,3,1 +7854,torcere,3,2 +7855,toad,3,1 +7856,rospo,3,2 +7857,settle,3,1 +7858,risolvere,3,2 +7859,brake,3,1 +7860,freno,3,2 +7861,sort,3,1 +7862,smistare,3,2 +7863,kind of,3,1 +7864,in un certo senso,3,2 +7865,receipt,3,1 +7866,ricevuta,3,2 +7867,wriggle out,3,1 +7868,sfuggire a,3,2 +7869,detail,3,1 +7870,dettaglio,3,2 +7871,seat,3,1 +7872,posto a sedere,3,2 +7873,take a seat,3,1 +7874,si accomodi,3,2 +7875,toothbrush,3,1 +7876,spazzolino,3,2 +7877,madden,3,1 +7878,esasperare,3,2 +7879,tart,3,1 +7880,crostata,3,2 +7881,auspicious,3,1 +7882,propizio,3,2 +7883,stare,3,1 +7884,fissare,3,2 +7885,take care,3,1 +7886,prendere cura,3,2 +7887,grate,3,1 +7888,grattuggiare,3,2 +7889,flag,3,1 +7890,bandiera,3,2 +7891,shade,3,1 +7892,fare ombra,3,2 +7893,grateful,3,1 +7894,riconoscente,3,2 +7895,ruin,3,1 +7896,rovinare,3,2 +7897,load,3,1 +7898,carico,3,2 +7899,coward,3,1 +7900,codardo,3,2 +7901,versed in,3,1 +7902,esperto di,3,2 +7903,messy,3,1 +7904,disordinato,3,2 +7905,cruel,3,1 +7906,crudele,3,2 +7907,interrupt,3,1 +7908,interrompere,3,2 +7909,eggnog,3,1 +7910,zabaione,3,2 +7911,surround,3,1 +7912,circondare,3,2 +7913,fork,3,1 +7914,bivio,3,2 +7915,handle,3,1 +7916,gestire,3,2 +7917,hilarious,3,1 +7918,spassoso,3,2 +7919,blowout,3,1 +7920,vittoria schiacciante,3,2 +7921,heat,3,1 +7922,calore,3,2 +7923,mindless,3,1 +7924,ripetitivo,3,2 +7925,resonant,3,1 +7926,risonante,3,2 +7927,toothsome,3,1 +7928,appetitoso,3,2 +7929,common thread,3,1 +7930,filo conduttore,3,2 +7931,pollute,3,1 +7932,inquinare,3,2 +7933,scent,3,1 +7934,profumo,3,2 +7935,secondhand,3,1 +7936,di seconda mano,3,2 +7937,shellfish,3,1 +7938,mollusco,3,2 +7939,fine,3,1 +7940,bene,3,2 +7941,quaint,3,1 +7942,pittoresco,3,2 +7943,grip,3,1 +7944,tenere stretto,3,2 +7945,voracious,3,1 +7946,vorace,3,2 +7947,sealed,3,1 +7948,sigillato,3,2 +7949,encourage,3,1 +7950,incoraggiare,3,2 +7951,temper,3,1 +7952,carattere irascibile,3,2 +7953,resolute,3,1 +7954,risoluto,3,2 +7955,reminiscent,3,1 +7956,che ricorda,3,2 +7957,steel,3,1 +7958,acciaio,3,2 +7959,sheet,3,1 +7960,foglio,3,2 +7961,sudden,3,1 +7962,repentino,3,2 +7963,committee,3,1 +7964,comitato,3,2 +7965,foregoing,3,1 +7966,quanto precede,3,2 +7967,remarkable,3,1 +7968,notevole,3,2 +7969,somehow,3,1 +7970,in qualche modo,3,2 +7971,knuckle down,3,1 +7972,darsi da fare,3,2 +7973,knock down,3,1 +7974,abbattere,3,2 +7975,undress,3,1 +7976,spogliare,3,2 +7977,trail,3,1 +7978,sentiero,3,2 +7979,yell,3,1 +7980,urlare,3,2 +7981,belligerent,3,1 +7982,bellicoso,3,2 +7983,realize,3,1 +7984,rendersi conto,3,2 +7985,jog,3,1 +7986,corsetta,3,2 +7987,null and void,3,1 +7988,nullo,3,2 +7989,overcome,3,1 +7990,andare oltre,3,2 +7991,arise,3,1 +7992,sorgere,3,2 +7993,devote,3,1 +7994,dedicarsi a,3,2 +7995,attractive,3,1 +7996,attraente,3,2 +7997,holiday,3,1 +7998,vacanza,3,2 +7999,shame,3,1 +8000,vergogna,3,2 +8001,fold,3,1 +8002,ripiegare,3,2 +8003,admin,3,1 +8004,amministratore,3,2 +8005,wilderness,3,1 +8006,landa selvaggia,3,2 +8007,hole,3,1 +8008,buco,3,2 +8009,remind,3,1 +8010,ricordare,3,2 +8011,plug,3,1 +8012,spina elettrica,3,2 +8013,lock,3,1 +8014,bloccare,3,2 +8015,dispensable,3,1 +8016,non essenziale,3,2 +8017,juggle,3,1 +8018,destreggiare,3,2 +8019,nondescript,3,1 +8020,indistinto,3,2 +8021,shut,3,1 +8022,chiudere,3,2 +8023,doll,3,1 +8024,bambola,3,2 +8025,rescue,3,1 +8026,soccorso,3,2 +8027,edible,3,1 +8028,commestibile,3,2 +8029,blow,3,1 +8030,soffiare,3,2 +8031,seed,3,1 +8032,seme,3,2 +8033,worm,3,1 +8034,verme,3,2 +8035,overrate,3,1 +8036,sopravvalutare,3,2 +8037,stitch,3,1 +8038,sutura,3,2 +8039,thoughtless,3,1 +8040,privo di tatto,3,2 +8041,crown,3,1 +8042,corona,3,2 +8043,profuse,3,1 +8044,profuso,3,2 +8045,royal,3,1 +8046,regale,3,2 +8047,idiotic,3,1 +8048,demenziale,3,2 +8049,highfalutin,3,1 +8050,ampolloso,3,2 +8051,woeful,3,1 +8052,afflitto,3,2 +8053,lackadaisical,3,1 +8054,apatico,3,2 +8055,gig,3,1 +8056,ingaggio,3,2 +8057,brokerage,3,1 +8058,intermediazione,3,2 +8059,provision,3,1 +8060,fornitura,3,2 +8061,inconceivable,3,1 +8062,inconcepibile,3,2 +8063,lining,3,1 +8064,imbottitura,3,2 +8065,buzzword,3,1 +8066,parola di moda,3,2 +8067,newsstand,3,1 +8068,edicola,3,2 +8069,everlasting,3,1 +8070,eterno,3,2 +8071,flip,3,1 +8072,rivoltare,3,2 +8073,flip flop,3,1 +8074,infradito,3,2 +8075,life long,3,1 +8076,per tutta la vita,3,2 +8077,protractor,3,1 +8078,goniometro,3,2 +8079,lifeguard,3,1 +8080,bagnino,3,2 +8081,fruition,3,1 +8082,compimento,3,2 +8083,proclaim,3,1 +8084,proclamare,3,2 +8085,unworn,3,1 +8086,non indossato,3,2 +8087,prevaricate,3,1 +8088,tergiversare,3,2 +8089,speech,3,1 +8090,discorso,3,2 +8091,garbage,3,1 +8092,immondizia,3,2 +8093,establish,3,1 +8094,istituire,3,2 +8095,dealership,3,1 +8096,concessionaria,3,2 +8097,veal,3,1 +8098,carne di vitello,3,2 +8099,tribulation,3,1 +8100,tribolazione,3,2 +8101,made up,3,1 +8102,inventato,3,2 +8103,tenant,3,1 +8104,inquilino,3,2 +8105,canary,3,1 +8106,canarino,3,2 +8107,truism,3,1 +8108,ovvieta',3,2 +8109,disdain,3,1 +8110,disdegno,3,2 +8111,innkeeper,3,1 +8112,locandiere,3,2 +8113,hatred,3,1 +8114,odio,3,2 +8115,goner,3,1 +8116,spacciato,3,2 +8117,perpetrate,3,1 +8118,commettere,3,2 +8119,vehement,3,1 +8120,veemente,3,2 +8121,trousseau,3,1 +8122,corredo,3,2 +8123,dossier,3,1 +8124,pratica,3,2 +8125,chicory,3,1 +8126,cicoria,3,2 +8127,aimless,3,1 +8128,senza scopo,3,2 +8129,headset,3,1 +8130,cuffie,3,2 +8131,wrest,3,1 +8132,estorcere,3,2 +8133,cardboard,3,1 +8134,cartone,3,2 +8135,restraint,3,1 +8136,ritegno,3,2 +8137,fishbone,3,1 +8138,lisca di pesce,3,2 +8139,deadly,3,1 +8140,letale,3,2 +8141,reliant,3,1 +8142,dipendere da,3,2 +8143,starry eyed,3,1 +8144,sognatore,3,2 +8145,wastepaper,3,1 +8146,carta straccia,3,2 +8147,shorthand,3,1 +8148,abbreviazione,3,2 +8149,turndown,3,1 +8150,rifiuto,3,2 +8151,hamlet,3,1 +8152,frazione,3,2 +8153,act,3,1 +8154,recitare,3,2 +8155,all in all,3,1 +8156,tutto sommato,3,2 +8157,moron,3,1 +8158,imbecille,3,2 +8159,boost,3,1 +8160,promuovere,3,2 +8161,cross eyed,3,1 +8162,strabico,3,2 +8163,shakeup,3,1 +8164,riorganizzazione,3,2 +8165,bridesmaid,3,1 +8166,damigella,3,2 +8167,long time no see,3,1 +8168,da quanto tempo,3,2 +8169,frame,3,1 +8170,telaio,3,2 +8171,wanderlust,3,1 +8172,voglia di viaggiare,3,2 +8173,cliffhanger,3,1 +8174,finale in sospeso,3,2 +8177,razor,3,1 +8178,rasoio,3,2 +8179,rainstorm,3,1 +8180,temporale,3,2 +8181,footprint,3,1 +8182,impronta,3,2 +8183,bliss,3,1 +8184,beatitudine,3,2 +8185,railroad,3,1 +8186,ferrovia,3,2 +8187,racecourse,3,1 +8188,ippodromo,3,2 +8189,ubiquitous,3,1 +8190,onnipresente,3,2 +8191,pheasant,3,1 +8192,fagiano,3,2 +8193,cop,3,1 +8194,poliziotto,3,2 +8195,slam,3,1 +8196,sbattere,3,2 +8197,crackdown,3,1 +8198,giro di vite,3,2 +8199,bookmark,3,1 +8200,segnalibro,3,2 +8201,matchless,3,1 +8202,ineguagliabile,3,2 +8203,refuel,3,1 +8204,fare benzina,3,2 +8205,easygoing,3,1 +8206,accomodante,3,2 +8207,fundraiser,3,1 +8208,raccolta fondi,3,2 +8209,out of date,3,1 +8210,non aggiornato,3,2 +8211,unsheathe,3,1 +8212,sguainare,3,2 +8213,chimp,3,1 +8214,scimpanze',3,2 +8215,award,3,1 +8216,premio,3,2 +8217,undermine,3,1 +8218,minare,3,2 +8219,ineffectual,3,1 +8220,inefficace,3,2 +8221,currency,3,1 +8222,valuta,3,2 +8223,concurrent,3,1 +8224,concomitante,3,2 +8225,reasonable,3,1 +8226,ragionevole,3,2 +8227,trowel,3,1 +8228,spatola,3,2 +8229,bogeyman,3,1 +8230,spauracchio,3,2 +8231,backlit,3,1 +8232,retroilluminato,3,2 +8233,trap,3,1 +8234,trappola,3,2 +8235,jail,3,1 +8236,carcere,3,2 +8237,cutback,3,1 +8238,riduzione,3,2 +8239,broil,3,1 +8240,arrostire,3,2 +8241,task,3,1 +8242,compito,3,2 +8243,checkpoint,3,1 +8244,posto di blocco,3,2 +8245,moonbeam,3,1 +8246,raggio di luna,3,2 +8247,recapitulate,3,1 +8248,riepilogare,3,2 +8249,all hands,3,1 +8250,tutto l'equipaggio,3,2 +8251,all over,3,1 +8252,dappertutto,3,2 +8253,rocket,3,1 +8254,razzo,3,2 +8255,hokum,3,1 +8256,baggianate,3,2 +8257,uphill,3,1 +8258,in salita,3,2 +8259,gunpowder,3,1 +8260,polvere da sparo,3,2 +8261,evergreen,3,1 +8262,sempreverde,3,2 +8263,obliterate,3,1 +8264,annientare,3,2 +8265,transgress,3,1 +8266,trasgredire,3,2 +8267,sop,3,1 +8268,concessione,3,2 +8269,precept,3,1 +8270,precetto,3,2 +8271,quick,3,1 +8272,breve,3,2 +8273,sidekick,3,1 +8274,aiutante,3,2 +8275,fulfilling,3,1 +8276,appagante,3,2 +8277,servicewoman,3,1 +8278,soldatessa,3,2 +8279,unseat,3,1 +8280,scalzare,3,2 +8281,vestige,3,1 +8282,vestigio,3,2 +8283,sunroof,3,1 +8284,cappotta,3,2 +8285,ordain,3,1 +8286,decretare,3,2 +8287,portcullis,3,1 +8288,saracinesca,3,2 +8289,lengthwise,3,1 +8290,longitudinale,3,2 +8291,submissive,3,1 +8292,remissivo,3,2 +8293,loud,3,1 +8294,rumoroso,3,2 +8295,pounding,3,1 +8296,martellante,3,2 +8297,mesh,3,1 +8298,maglia della rete,3,2 +8299,disavow,3,1 +8300,sconfessare,3,2 +8301,debase,3,1 +8302,svalutare,3,2 +8303,tentative,3,1 +8304,preliminare,3,2 +8305,usurer,3,1 +8306,usuraio,3,2 +8307,watermark,3,1 +8308,filigrana,3,2 +8309,watercolor,3,1 +8310,acquerello,3,2 +8311,invariable,3,1 +8312,immutato,3,2 +8313,quit,3,1 +8314,smettere,3,2 +8315,damage,3,1 +8316,danneggiare,3,2 +8317,unbutton,3,1 +8318,sbottonare,3,2 +8319,droplet,3,1 +8320,gocciolina,3,2 +8321,drop,3,1 +8322,far cadere,3,2 +8323,ivory,3,1 +8324,avorio,3,2 +8325,mint,3,1 +8326,menta,3,2 +8327,pave,3,1 +8328,pavimentare,3,2 +8329,overtire,3,1 +8330,sovraffaticare,3,2 +8331,whale,3,1 +8332,balena,3,2 +8333,roster,3,1 +8334,elenco,3,2 +8335,curse,3,1 +8336,maledizione,3,2 +8337,even,3,1 +8338,uniforme,3,2 +8339,foreword,3,1 +8340,prefazione,3,2 +8341,breastplate,3,1 +8342,corazza,3,2 +8343,hyphen,3,1 +8344,trattino,3,2 +8345,semicolon,3,1 +8346,punto e virgola,3,2 +8347,optician,3,1 +8348,ottico,3,2 +8349,perjury,3,1 +8350,falsa testimonianza,3,2 +8351,race,3,1 +8352,gara,3,2 +8353,spank,3,1 +8354,sculacciare,3,2 +8355,spotless,3,1 +8356,senza macchia,3,2 +8357,westbound,3,1 +8358,diretto a ovest,3,2 +8359,minion,3,1 +8360,seguace,3,2 +8361,storehouse,3,1 +8362,magazzino,3,2 +8363,ping,3,1 +8364,segnale,3,2 +8365,halfway,3,1 +8366,a meta' strada,3,2 +8367,indigo,3,1 +8368,indaco,3,2 +8369,livelihood,3,1 +8370,sussistenza,3,2 +8371,despite,3,1 +8372,nonostante,3,2 +8373,attempt,3,1 +8374,tentativo,3,2 +8375,throw,3,1 +8376,lanciare,3,2 +8377,retrieve,3,1 +8378,reperire,3,2 +8379,waterworks,3,1 +8380,acquedotto,3,2 +8381,painkiller,3,1 +8382,antidolorifico,3,2 +8383,frontman,3,1 +8384,rappresentante,3,2 +8385,cover,3,1 +8386,copertina,3,2 +8387,resonate,3,1 +8388,risuonare,3,2 +8389,overstep,3,1 +8390,oltrepassare,3,2 +8391,allot,3,1 +8392,allocare,3,2 +8393,argue,3,1 +8394,dibattere,3,2 +8395,depict,3,1 +8396,raffigurare,3,2 +8397,forester,3,1 +8398,guardia forestale,3,2 +8399,insole,3,1 +8400,soletta,3,2 +8401,grocery,3,1 +8402,alimentari,3,2 +8403,overreact,3,1 +8404,reazione eccessiva,3,2 +8405,kerb,3,1 +8406,cordolo,3,2 +8407,vicarious,3,1 +8408,vicario,3,2 +8409,lick,3,1 +8410,leccare,3,2 +8411,citizen,3,1 +8412,cittadino,3,2 +8413,muffled,3,1 +8414,ovattato,3,2 +8415,stillness,3,1 +8416,quiete,3,2 +8417,regret,3,1 +8418,rimpianto,3,2 +8419,policy,3,1 +8420,norma,3,2 +8421,storefront,3,1 +8422,vetrina,3,2 +8423,out of the way,3,1 +8424,fuori mano,3,2 +8425,hillside,3,1 +8426,pendio,3,2 +8427,backdoor,3,1 +8428,porta sul retro,3,2 +8429,bullet,3,1 +8430,proiettile,3,2 +8431,addict,3,1 +8432,dipendenza,3,2 +8433,recover,3,1 +8434,riprendersi,3,2 +8435,sling,3,1 +8436,imbracatura,3,2 +8437,vouch,3,1 +8438,garantire per,3,2 +8439,nectar,3,1 +8440,nettare,3,2 +8441,cease,3,1 +8442,cessare,3,2 +8443,proofread,3,1 +8444,rileggere,3,2 +8445,baseline,3,1 +8446,linea guida,3,2 +8447,prophecy,3,1 +8448,profezia,3,2 +8449,deplore,3,1 +8450,deplorare,3,2 +8451,makeshift,3,1 +8452,di ripiego,3,2 +8453,squint,3,1 +8454,strizzare gli occhi,3,2 +8455,complain,3,1 +8456,lamentare,3,2 +8457,sprite,3,1 +8458,spiritello,3,2 +8459,blab,3,1 +8460,spifferare,3,2 +8461,mismatch,3,1 +8462,discrepanza,3,2 +8463,eraser,3,1 +8464,gomma da cancellare,3,2 +8465,misfire,3,1 +8466,fare cilecca,3,2 +8467,adhere,3,1 +8468,aderire,3,2 +8469,handmade,3,1 +8470,fatto a mano,3,2 +8471,wand,3,1 +8472,bacchetta,3,2 +8473,eve,3,1 +8474,vigilia,3,2 +8475,chew,3,1 +8476,masticare,3,2 +8477,instil,3,1 +8478,instillare,3,2 +8479,cutlet,3,1 +8480,cotoletta,3,2 +8481,tassel,3,1 +8482,nappa,3,2 +8483,falsehood,3,1 +8484,menzogna,3,2 +8485,atop,3,1 +8486,in cima,3,2 +8487,mouthwash,3,1 +8488,colluttorio,3,2 +8489,phrase,3,1 +8490,frase,3,2 +8491,shelter,3,1 +8492,rifugio,3,2 +8493,meant,3,1 +8494,destinato,3,2 +8495,hosting,3,1 +8496,accoglienza,3,2 +8497,twist,3,1 +8498,torcere,3,2 +8499,board,3,1 +8500,tavola,3,2 +8501,wire,3,1 +8502,fil di ferro,3,2 +8503,wire transfer,3,1 +8504,bonifico,3,2 +8505,bow,3,1 +8506,arco,3,2 +8507,pool,3,1 +8508,piscina,3,2 +8509,checkmate,3,1 +8510,scacco matto,3,2 +8511,turn,3,1 +8512,girare,3,2 +8513,attach,3,1 +8514,allegare,3,2 +8515,append,3,1 +8516,accodare,3,2 +8517,stem,3,1 +8518,stelo,3,2 +8519,develop,3,1 +8520,sviluppare,3,2 +8521,notice,3,1 +8522,preavviso,3,2 +8523,puff pastry,3,1 +8524,pasta sfoglia,3,2 +8525,byproduct,3,1 +8526,sottoprodotto,3,2 +8527,freewill,3,1 +8528,libero arbitrio,3,2 +8529,freewheel,3,1 +8530,a ruota libera,3,2 +8531,plugin,3,1 +8532,componente aggiuntivo,3,2 +8533,custom,3,1 +8534,consuetudine,3,2 +8535,source,3,1 +8536,origine,3,2 +8537,shorten,3,1 +8538,accorciare,3,2 +8539,outdoor,3,1 +8540,all'aperto,3,2 +8541,preference,3,1 +8542,preferenza,3,2 +8543,saw,3,1 +8544,segare,3,2 +8545,bigmouth,3,1 +8546,pettegolo,3,2 +8547,meager,3,1 +8548,esiguo,3,2 +8549,overblown,3,1 +8550,esagerato,3,2 +8551,stumble,3,1 +8552,inciampare,3,2 +8553,around,3,1 +8554,attorno a,3,2 +8555,loop,3,1 +8556,circuito,3,2 +8557,escape,3,1 +8558,sfuggire,3,2 +8559,faker,3,1 +8560,impostore,3,2 +8561,pitch dark,3,1 +8562,buio pesto,3,2 +8563,dark,3,1 +8564,oscuro,3,2 +8565,detract,3,1 +8566,detrarre,3,2 +8567,script,3,1 +8568,sceneggiatura,3,2 +8569,linesman,3,1 +8570,guardalinee,3,2 +8571,inmate,3,1 +8572,detenuto,3,2 +8573,walkthrough,3,1 +8574,passo per passo,3,2 +8575,startup,3,1 +8576,avvio,3,2 +8577,youth,3,1 +8578,giovinezza,3,2 +8579,overpay,3,1 +8580,strapagare,3,2 +8581,stew,3,1 +8582,zuppa,3,2 +8583,abolish,3,1 +8584,abolire,3,2 +8585,interview,3,1 +8586,intervista,3,2 +8587,footer,3,1 +8588,pie' di pagina,3,2 +8589,header,3,1 +8590,intestazione,3,2 +8591,breastfeed,3,1 +8592,allattare,3,2 +8593,lasting,3,1 +8594,duraturo,3,2 +8595,fairness,3,1 +8596,correttezza,3,2 +8597,birthmark,3,1 +8598,voglia,3,2 +8599,in depth,3,1 +8600,in dettaglio,3,2 +8601,incite,3,1 +8602,incitare,3,2 +8603,genre,3,1 +8604,genere,3,2 +8605,maintain,3,1 +8606,mantenere,3,2 +8607,childhood,3,1 +8608,infanzia,3,2 +8609,dishtowel,3,1 +8610,canovaccio,3,2 +8611,ugly,3,1 +8612,brutto,3,2 +8613,distrust,3,1 +8614,sfiducia,3,2 +8615,barbed wire,3,1 +8616,filo spinato,3,2 +8617,fumes,3,1 +8618,esalazioni,3,2 +8619,amnesty,3,1 +8620,amnistia,3,2 +8621,clear head,3,1 +8622,mente lucida,3,2 +8623,bummer,3,1 +8624,disdetta,3,2 +8625,paper clip,3,1 +8626,graffetta,3,2 +8627,vein,3,1 +8628,vena,3,2 +8629,shinbone,3,1 +8630,tibia,3,2 +8631,fibula,3,1 +8632,perone,3,2 +8633,playful,3,1 +8634,giocoso,3,2 +8635,turnover,3,1 +8636,giro di affari,3,2 +8637,concrete,3,1 +8638,cemento,3,2 +8639,paragliding,3,1 +8640,parapendio,3,2 +8641,affirm,3,1 +8642,affermare,3,2 +8643,elector,3,1 +8644,elettore,3,2 +8645,several,3,1 +8646,parecchi,3,2 +8647,bookshelf,3,1 +8648,libreria,3,2 +8649,bookstore,3,1 +8650,negozio di libri,3,2 +8651,at the crack,3,1 +8652,al sorgere,3,2 +8653,fend off,3,1 +8654,scacciare,3,2 +8655,handful,3,1 +8656,manciata,3,2 +8657,maple,3,1 +8658,acero,3,2 +8659,double bed,3,1 +8660,letto matrimoniale,3,2 +8661,clip,3,1 +8662,fermaglio,3,2 +8663,headrest,3,1 +8664,poggiatesta,3,2 +8665,flagrant,3,1 +8666,flagrante,3,2 +8667,prow,3,1 +8668,prua,3,2 +8669,outlive,3,1 +8670,vivere piu' a lungo,3,2 +8671,teaspoon,3,1 +8672,cucchiaino,3,2 +8673,wrap,3,1 +8674,incartare,3,2 +8675,accountable,3,1 +8676,tenuto a rispondere,3,2 +8677,italics,3,1 +8678,corsivo,3,2 +8679,cross out,3,1 +8680,barrare,3,2 +8681,defeatist,3,1 +8682,rinunciatario,3,2 +8683,bourgeois,3,1 +8684,borghese,3,2 +8685,hairdo,3,1 +8686,acconciatura,3,2 +8687,outsize,3,1 +8688,fuori misura,3,2 +8689,speechless,3,1 +8690,senza parole,3,2 +8691,unleash,3,1 +8692,sguinzagliare,3,2 +8693,tacked,3,1 +8694,imbastito,3,2 +8695,tweezer,3,1 +8696,pinzetta,3,2 +8697,guesswork,3,1 +8698,congettura,3,2 +8699,aftertaste,3,1 +8700,retrogusto,3,2 +8701,hairline,3,1 +8702,attaccatura dei capelli,3,2 +8703,braise,3,1 +8704,brasare,3,2 +8705,seaway,3,1 +8706,rotta,3,2 +8707,congeal,3,1 +8708,rapprendersi,3,2 +8709,heron,3,1 +8710,airone,3,2 +8711,split up,3,1 +8712,dividersi,3,2 +8713,acquire,3,1 +8714,acquisire,3,2 +8715,overheat,3,1 +8716,surriscaldarsi,3,2 \ No newline at end of file diff --git a/examples/file_read_stream/pubspec.yaml b/examples/file_read_stream/pubspec.yaml new file mode 100644 index 00000000..b9fa4aac --- /dev/null +++ b/examples/file_read_stream/pubspec.yaml @@ -0,0 +1,20 @@ +name: file_read_stream +description: > + Example of using fpdart to read an compute a large file using Stream. +version: 2.0.0 +homepage: https://www.sandromaglione.com/ +repository: https://github.com/SandroMaglione/fpdart +publish_to: "none" + +environment: + sdk: ">=3.3.0 <4.0.0" + +dependencies: + http: ^1.2.1 + equatable: ^2.0.5 + fpdart: + path: ../../packages/fpdart + +dev_dependencies: + lints: ^2.0.1 + test: ^1.23.1 diff --git a/examples/fpdart_http/lib/api.dart b/examples/fpdart_http/lib/api.dart new file mode 100644 index 00000000..a464fc06 --- /dev/null +++ b/examples/fpdart_http/lib/api.dart @@ -0,0 +1,30 @@ +import 'package:fpdart/fpdart.dart'; +import 'package:http/http.dart' as http; + +import 'http_error.dart'; + +/// 1️⃣ Define dependencies, errors, response +Effect get( + Uri url, { + Map? headers, +}) => + + /// 2️⃣ Use the Do notation with the `gen` constructor + Effect.gen(($) async { + /// 3️⃣ Extract the dependency using `env` (environment) + final client = $.sync(Effect.env()); + + /// 4️⃣ Perform a request, catch errors, extract the response + final response = await $.async(Effect.tryCatch( + execute: () => client.get(url, headers: headers), + onError: (_, __) => const RequestError(), + )); + + /// 5️⃣ Use plain dart code to check for valid status + if (response.statusCode != 200) { + return $.sync(Effect.fail(const ResponseError())); + } + + /// 6️⃣ Return extracted/valid response + return response; + }); diff --git a/examples/fpdart_http/lib/http_error.dart b/examples/fpdart_http/lib/http_error.dart new file mode 100644 index 00000000..c7f93915 --- /dev/null +++ b/examples/fpdart_http/lib/http_error.dart @@ -0,0 +1,11 @@ +sealed class HttpError { + const HttpError(); +} + +final class RequestError extends HttpError { + const RequestError(); +} + +final class ResponseError extends HttpError { + const ResponseError(); +} diff --git a/examples/fpdart_http/lib/main.dart b/examples/fpdart_http/lib/main.dart new file mode 100644 index 00000000..3e583569 --- /dev/null +++ b/examples/fpdart_http/lib/main.dart @@ -0,0 +1,20 @@ +import 'package:fpdart/fpdart.dart'; +import 'package:http/http.dart' as http; + +import 'api.dart'; + +void main() async { + await get( + Uri.https("pokeapi.co", "/api/v2/pokemon/10"), + ) + .timeout(Duration(milliseconds: 1300)) + .tap( + (response) => Effect.succeedLazy( + () => print(response.body), + ), + ) + .provideEnv( + http.Client(), + ) + .runFutureOrThrow(); +} diff --git a/examples/fpdart_http/pubspec.yaml b/examples/fpdart_http/pubspec.yaml new file mode 100644 index 00000000..38620153 --- /dev/null +++ b/examples/fpdart_http/pubspec.yaml @@ -0,0 +1,19 @@ +name: fpdart_http +description: > + Example of using fpdart with http. +version: 2.0.0 +homepage: https://www.sandromaglione.com/ +repository: https://github.com/SandroMaglione/fpdart +publish_to: "none" + +environment: + sdk: ">=3.3.0 <4.0.0" + +dependencies: + http: ^1.2.1 + fpdart: + path: ../../packages/fpdart + +dev_dependencies: + lints: ^2.0.1 + test: ^1.23.1 diff --git a/examples/hello_world/bin/fpdart_hello_world.dart b/examples/hello_world/bin/fpdart_hello_world.dart deleted file mode 100644 index c4ec52dd..00000000 --- a/examples/hello_world/bin/fpdart_hello_world.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -void helloWorld(String message) { - print("Hello World: $message"); -} - -/// 1️⃣ Pure function (Thunk) -void Function() helloWorld1(String message) => () { - print("Hello World: $message"); - }; - -/// A thunk with no error is called [IO] in `fpdart` -IO helloWorld1Fpdart(String message) => IO(() { - print("Hello World: $message"); - }); - -/// 2️⃣ Explicit error -/// Understand from the return type if and how the function may fail -Either Function() helloWorld2(String message) => () { - print("Hello World: $message"); - return Either.of(null); - }; - -/// A thunk with explicit error [Either] is called [IOEither] in `fpdart` -IOEither helloWorld2Fpdart1(String message) => IOEither(() { - print("Hello World: $message"); - return Either.of(null); - }); - -/// ...or using the `right` constructor -IOEither helloWorld2Fpdart2(String message) => IOEither.right(() { - print("Hello World: $message"); - }); - -/// 3️⃣ Explicit dependency -/// Provide the `print` method as a dependency instead of implicit global function - -abstract class Console { - void log(Object? object); -} - -class ConsoleImpl implements Console { - @override - void log(Object? object) { - print(object); - } -} - -Either Function() Function(Console) helloWorld3(String message) => - (console) => () { - console.log("Hello World: $message"); - return Either.of(null); - }; - -/// Thunk (async) + error + dependency is called [ReaderTaskEither] in `fpdart` -ReaderTaskEither helloWorld3Fpdart(String message) => - ReaderTaskEither((console) async { - console.log("Hello World: $message"); - return Either.of(null); - }); - -void main(List args) { - final definition = helloWorld3("Sandro"); - final thunk = definition(ConsoleImpl()); - thunk(); -} diff --git a/examples/hello_world/bin/hello_world.dart b/examples/hello_world/bin/hello_world.dart deleted file mode 100644 index 4dc74cea..00000000 --- a/examples/hello_world/bin/hello_world.dart +++ /dev/null @@ -1,7 +0,0 @@ -void helloWorld(String message) { - print("Hello World: $message"); -} - -void main(List args) { - helloWorld("Sandro"); -} diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml deleted file mode 100644 index 7a3a050e..00000000 --- a/examples/hello_world/pubspec.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: fpdart_hello_world -publish_to: none -version: 0.1.0 -homepage: https://www.sandromaglione.com/ -repository: https://github.com/SandroMaglione/fpdart -description: Example of Functional programming in Dart and Flutter using fpdart. Write a simple "Hello World" using fpdart. -author: Maglione Sandro - -environment: - sdk: ">=3.0.0 <4.0.0" - -dependencies: - fpdart: - path: ../../packages/fpdart - -dev_dependencies: - lint: ^2.1.2 - test: ^1.24.3 - mocktail: ^0.3.0 diff --git a/examples/hello_world/test/fpdart_hello_world_test.dart b/examples/hello_world/test/fpdart_hello_world_test.dart deleted file mode 100644 index 686c853e..00000000 --- a/examples/hello_world/test/fpdart_hello_world_test.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:mocktail/mocktail.dart'; -import 'package:test/test.dart'; - -import '../bin/fpdart_hello_world.dart'; - -class ConsoleTest extends Mock implements Console {} - -void main() { - group('helloWorld3Fpdart', () { - test( - 'should call "log" from the "Console" dependency with the correct input', - () async { - final console = ConsoleTest(); - const input = "test"; - - when(() => console.log(any)).thenReturn(null); - await helloWorld3Fpdart(input).run(console); - verify(() => console.log("Hello World: $input")).called(1); - }, - ); - }); -} diff --git a/examples/hello_world/test/hello_world_test.dart b/examples/hello_world/test/hello_world_test.dart deleted file mode 100644 index e0515e33..00000000 --- a/examples/hello_world/test/hello_world_test.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:test/test.dart'; - -void main() { - group('helloWorld', () { - /// `'should call "print" with the correct input'` - /// - /// This is difficult to test, since `print` is an implicit dependency 🙌 - /// - /// Furthermore, `print` will be executed at every test. Imagine having a - /// request to update a production database instead of `print` (both are side-effects), - /// you do not want to interact with a real database with tests ⚠️ - }); -} diff --git a/examples/json_serializable/.gitattributes b/examples/json_serializable/.gitattributes deleted file mode 100644 index 88694901..00000000 --- a/examples/json_serializable/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.g.dart linguist-generated=true diff --git a/examples/json_serializable/.gitignore b/examples/json_serializable/.gitignore deleted file mode 100644 index 570e1df8..00000000 --- a/examples/json_serializable/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.dart_tool/ -.packages -pubspec.lock - -# Generated files -**.g.dart -.idea/ \ No newline at end of file diff --git a/examples/json_serializable/lib/main.dart b/examples/json_serializable/lib/main.dart deleted file mode 100644 index ab73b3a2..00000000 --- a/examples/json_serializable/lib/main.dart +++ /dev/null @@ -1 +0,0 @@ -void main() {} diff --git a/examples/json_serializable/lib/user.dart b/examples/json_serializable/lib/user.dart deleted file mode 100644 index 0058064a..00000000 --- a/examples/json_serializable/lib/user.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'user.g.dart'; - -@JsonSerializable() -class User { - final Option id; - final Option birthDate; - final Option phone; - - const User({ - required this.id, - required this.birthDate, - required this.phone, - }); - - factory User.fromJson(Map json) => _$UserFromJson(json); - Map toJson() => _$UserToJson(this); -} diff --git a/examples/json_serializable/pubspec.yaml b/examples/json_serializable/pubspec.yaml deleted file mode 100644 index 2a1bfdb7..00000000 --- a/examples/json_serializable/pubspec.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: fpdart_json_serializable -publish_to: none -version: 0.1.0 -homepage: https://www.sandromaglione.com/ -repository: https://github.com/SandroMaglione/fpdart -description: Example of using json_serializable with fpdart types. -author: Maglione Sandro - -environment: - sdk: ">=2.13.0 <3.0.0" - -dependencies: - json_serializable: ^6.6.1 - fpdart: - path: ../../packages/fpdart - -dev_dependencies: - test: ^1.17.5 - lint: ^2.0.1 - json_annotation: ^4.1.0 - build_runner: ^2.0.6 diff --git a/examples/json_serializable/test/user_test.dart b/examples/json_serializable/test/user_test.dart deleted file mode 100644 index aba28619..00000000 --- a/examples/json_serializable/test/user_test.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:fpdart_json_serializable/user.dart'; -import 'package:test/test.dart'; - -void main() { - group('Option', () { - test('toJson (None)', () { - expect( - User( - id: none(), - birthDate: none(), - phone: none(), - ).toJson(), - { - "id": null, - "birthDate": null, - "phone": null, - }, - ); - }); - - test('toJson (Some)', () { - expect( - User( - id: some(1), - birthDate: some(DateTime(2020)), - phone: some('phone'), - ).toJson(), - { - "id": 1, - "birthDate": "2020-01-01T00:00:00.000", - "phone": "phone", - }, - ); - }); - - test('fromJson (None)', () { - final user = User.fromJson({ - "id": null, - "birthDate": null, - "phone": null, - }); - - expect(user.id, isA()); - expect(user.birthDate, isA()); - expect(user.phone, isA()); - }); - - test('fromJson (Some)', () { - final user = User.fromJson({ - "id": 1, - "birthDate": DateTime(2020), - "phone": "phone", - }); - - expect(user.id, isA>()); - expect(user.id.getOrElse(() => -1), 1); - expect(user.birthDate.getOrElse(() => DateTime(1990)), DateTime(2020)); - expect(user.phone.getOrElse(() => ''), 'phone'); - }); - }); -} diff --git a/examples/managing_imports/.gitignore b/examples/managing_imports/.gitignore deleted file mode 100644 index a2c86b7d..00000000 --- a/examples/managing_imports/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Files and directories created by pub. -.dart_tool/ -.packages -pubspec.lock - -# Conventional directory for build output. -build/ diff --git a/examples/managing_imports/README.md b/examples/managing_imports/README.md deleted file mode 100644 index 10b32c03..00000000 --- a/examples/managing_imports/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Managing Imports - -Naming things is hard. Sometimes, the same name gets used for different things. In Dart, naming conflicts can be mitigated through the use of [import prefixes](https://dart.dev/language/libraries#specifying-a-library-prefix), as well as [show and hide operations](https://dart.dev/language/libraries#importing-only-part-of-a-library). - -This is particularly important when using a package like `fpdart` that provides a lot of classes with common names. - -As an example, suppose you decide to use `fpdart` with your Flutter program. You'll quickly discover that `fpdart` uses `State` as a class name, which conflicts with the `State` class in Flutter. - -The solution is to create an import shim that solves both of these problems. We'll call it `functional.dart`. This shim will import `fpdart`, and re-export the classes we want to use. We can rename `fpdart`'s `State` to `FpState` to avoid the conflict. We can then import `functional.dart` instead of `fpdart`. - -`functional.dart` can also hold any other functional programming utilities we want to use. It can also be used to provide or import class extensions and mapping functions between our types and the functional types. - -A one-stop shop for functional programming in Dart! diff --git a/examples/managing_imports/analysis_options.yaml b/examples/managing_imports/analysis_options.yaml deleted file mode 100644 index e5e23e95..00000000 --- a/examples/managing_imports/analysis_options.yaml +++ /dev/null @@ -1,8 +0,0 @@ -include: package:very_good_analysis/analysis_options.yaml -analyzer: - exclude: - - lib/**/*.g.dart - -linter: - rules: - public_member_api_docs: false diff --git a/examples/managing_imports/bin/managing_imports.dart b/examples/managing_imports/bin/managing_imports.dart deleted file mode 100644 index 8405dd95..00000000 --- a/examples/managing_imports/bin/managing_imports.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:managing_imports/functional.dart'; -import 'package:test/test.dart'; - -void main() { - /// Borrow the `flatMap` test from `state_test.dart` - test('flatMap', () { - final state = FpState, int>((s) => (s.first, s.sublist(1))); - final ap = state.flatMap( - (a) => FpState( - (s) => (a / 2, s.sublist(1)), - ), - ); - final result = ap.run([1, 2, 3, 4, 5]); - expect(result.$1, 0.5); - expect(result.$2, [3, 4, 5]); - }); -} diff --git a/examples/managing_imports/lib/functional.dart b/examples/managing_imports/lib/functional.dart deleted file mode 100644 index c5ba2864..00000000 --- a/examples/managing_imports/lib/functional.dart +++ /dev/null @@ -1,13 +0,0 @@ -// ignore_for_file: dangling_library_doc_comments - -/// This file is used to export all the functional programming libraries used in -/// the project. It also exports the `FpState` type alias, which is used to -/// avoid conflicts with the `State` class from the Flutter SDK. - -import 'package:fpdart/fpdart.dart' as fpdart show State; - -// The `fpdart` library is used to create functional programming constructs. -export 'package:fpdart/fpdart.dart' hide State; - -/// A type alias for the `State` class from the `fpdart` library. -typedef FpState = fpdart.State; diff --git a/examples/managing_imports/pubspec.yaml b/examples/managing_imports/pubspec.yaml deleted file mode 100644 index ebbca2d5..00000000 --- a/examples/managing_imports/pubspec.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: managing_imports -description: Demonstration of managing imports -version: 1.0.0 -publish_to: none - -environment: - sdk: ">=3.0.0 <4.0.0" - -dependencies: - fpdart: - path: ../../packages/fpdart - test: - very_good_analysis: - -dev_dependencies: - lints: diff --git a/examples/open_meteo_api/.gitignore b/examples/open_meteo_api/.gitignore deleted file mode 100644 index 570e1df8..00000000 --- a/examples/open_meteo_api/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.dart_tool/ -.packages -pubspec.lock - -# Generated files -**.g.dart -.idea/ \ No newline at end of file diff --git a/examples/open_meteo_api/README.md b/examples/open_meteo_api/README.md deleted file mode 100644 index 18412255..00000000 --- a/examples/open_meteo_api/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Open Meteo API - `fpdart` -This is a re-implementation using `fpdart` and functional programming of the [Open Meteo API](https://github.com/felangel/bloc/tree/master/examples/flutter_weather/packages/open_meteo_api) from the [flutter_weather](https://bloclibrary.dev/#/flutterweathertutorial) app example in the [bloc](https://pub.dev/packages/bloc) package. - -The goal is to show a comparison between usual dart code and functional code written using `fpdart`. - -## Structure -The example is simple but comprehensive. - -The Open Meteo API implementation is only 1 file. The original source is [open_meteo_api_client.dart](./lib/src/open_meteo_api_client.dart) (copy of the [bloc package implementation](https://github.com/felangel/bloc/blob/master/examples/flutter_weather/packages/open_meteo_api/lib/src/open_meteo_api_client.dart)). - -Inside [lib/src/fpdart](./lib/src/fpdart/) you can then find the refactoring using functional programming and `fpdart`: -- [open_meteo_api_client_fpdart.dart](./lib/src/fpdart/open_meteo_api_client_fpdart.dart): implementation of the Open Meteo API with `fpdart` -- [location_failure.dart](./lib/src/fpdart/location_failure.dart): failure classes for the `locationSearch` request -- [weather_failure.dart](./lib/src/fpdart/weather_failure.dart): failure classes for the `getWeather` request - -### Test -Also the [test](./test/) has been rewritten based on the `fpdart` refactoring: -- [open_meteo_api_client_test.dart](./test/open_meteo_api_client_test.dart): Original Open Meteo API test implementation -- [open_meteo_api_client_test_fpdart.dart](./test/open_meteo_api_client_test_fpdart.dart): Testing for the new implementation using `fpdart` and functional programming - -## Types used from `fpdart` -- `TaskEither`: Used instead of `Future` to make async request that may fail -- `Either`: Used to validate the response from the API with either an error or a valid value -- `Option`: Used to get values that may be missing - - `lookup` in a `Map`: getting a value by key in a `Map` may return nothing if the key is not found - - `head` in a `List`: The list may be empty, so getting the first element (called _"head"_) may return nothing \ No newline at end of file diff --git a/examples/open_meteo_api/analysis_options.yaml b/examples/open_meteo_api/analysis_options.yaml deleted file mode 100644 index 1d5ab95c..00000000 --- a/examples/open_meteo_api/analysis_options.yaml +++ /dev/null @@ -1,8 +0,0 @@ -include: package:very_good_analysis/analysis_options.3.0.2.yaml -analyzer: - exclude: - - lib/**/*.g.dart - -linter: - rules: - public_member_api_docs: false diff --git a/examples/open_meteo_api/build.yaml b/examples/open_meteo_api/build.yaml deleted file mode 100644 index 917f4561..00000000 --- a/examples/open_meteo_api/build.yaml +++ /dev/null @@ -1,12 +0,0 @@ -targets: - $default: - builders: - source_gen|combining_builder: - options: - ignore_for_file: - - implicit_dynamic_parameter - json_serializable: - options: - field_rename: snake - create_to_json: false - checked: true diff --git a/examples/open_meteo_api/lib/open_meteo_api.dart b/examples/open_meteo_api/lib/open_meteo_api.dart deleted file mode 100644 index 90cc854d..00000000 --- a/examples/open_meteo_api/lib/open_meteo_api.dart +++ /dev/null @@ -1,5 +0,0 @@ -library open_meteo_api; - -export 'src/fpdart/open_meteo_api_client_fpdart.dart'; -export 'src/models/models.dart'; -export 'src/open_meteo_api_client.dart'; diff --git a/examples/open_meteo_api/lib/src/fpdart/location_failure.dart b/examples/open_meteo_api/lib/src/fpdart/location_failure.dart deleted file mode 100644 index 911d772b..00000000 --- a/examples/open_meteo_api/lib/src/fpdart/location_failure.dart +++ /dev/null @@ -1,65 +0,0 @@ -// ignore_for_file: comment_references - -import 'package:http/http.dart' as http; - -/// Abstract class which represents a failure in the `locationSearch` request. -abstract class OpenMeteoApiFpdartLocationFailure {} - -/// [OpenMeteoApiFpdartLocationFailure] when **http request** fails -class LocationHttpRequestFpdartFailure - implements OpenMeteoApiFpdartLocationFailure { - const LocationHttpRequestFpdartFailure(this.object, this.stackTrace); - final Object object; - final StackTrace stackTrace; -} - -/// [OpenMeteoApiFpdartLocationFailure] when request is not successful -/// (`status != 200`) -class LocationRequestFpdartFailure - implements OpenMeteoApiFpdartLocationFailure { - const LocationRequestFpdartFailure(this.response); - final http.Response response; -} - -/// [OpenMeteoApiFpdartLocationFailure] when location response -/// cannot be decoded from json. -class LocationInvalidJsonDecodeFpdartFailure - implements OpenMeteoApiFpdartLocationFailure { - const LocationInvalidJsonDecodeFpdartFailure(this.body); - final String body; -} - -/// [OpenMeteoApiFpdartLocationFailure] when location response is not a valid -/// [Map]. -class LocationInvalidMapFpdartFailure - implements OpenMeteoApiFpdartLocationFailure { - const LocationInvalidMapFpdartFailure(this.json); - final dynamic json; -} - -/// [OpenMeteoApiFpdartLocationFailure] when location information -/// is not found (missing expected key). -class LocationKeyNotFoundFpdartFailure - implements OpenMeteoApiFpdartLocationFailure {} - -/// [OpenMeteoApiFpdartLocationFailure] when location data is not a valid -/// [List]. -class LocationInvalidListFpdartFailure - implements OpenMeteoApiFpdartLocationFailure { - const LocationInvalidListFpdartFailure(this.value); - final dynamic value; -} - -/// [OpenMeteoApiFpdartLocationFailure] when location for provided location -/// is not found (missing data). -class LocationDataNotFoundFpdartFailure - implements OpenMeteoApiFpdartLocationFailure {} - -/// [OpenMeteoApiFpdartLocationFailure] when the response is not -/// a valid [Location] -class LocationFormattingFpdartFailure - implements OpenMeteoApiFpdartLocationFailure { - const LocationFormattingFpdartFailure(this.object, this.stackTrace); - final Object object; - final StackTrace stackTrace; -} diff --git a/examples/open_meteo_api/lib/src/fpdart/open_meteo_api_client_fpdart.dart b/examples/open_meteo_api/lib/src/fpdart/open_meteo_api_client_fpdart.dart deleted file mode 100644 index edc4b4a0..00000000 --- a/examples/open_meteo_api/lib/src/fpdart/open_meteo_api_client_fpdart.dart +++ /dev/null @@ -1,141 +0,0 @@ -import 'dart:convert'; - -import 'package:fpdart/fpdart.dart'; -import 'package:http/http.dart' as http; -import 'package:open_meteo_api/open_meteo_api.dart'; -import 'package:open_meteo_api/src/fpdart/location_failure.dart'; -import 'package:open_meteo_api/src/fpdart/weather_failure.dart'; - -class OpenMeteoApiClientFpdart { - OpenMeteoApiClientFpdart({http.Client? httpClient}) - : _httpClient = httpClient ?? http.Client(); - - static const _baseUrlWeather = 'api.open-meteo.com'; - static const _baseUrlGeocoding = 'geocoding-api.open-meteo.com'; - - final http.Client _httpClient; - - /// Finds a [Location] `/v1/search/?name=(query)`. - TaskEither locationSearch( - String query, - ) => - TaskEither.tryCatch( - () => _httpClient.get( - Uri.https( - _baseUrlGeocoding, - '/v1/search', - {'name': query, 'count': '1'}, - ), - ), - LocationHttpRequestFpdartFailure.new, - ).chainEither( - (response) => Either.Do((_) { - final body = _( - _validResponseBody(response, LocationRequestFpdartFailure.new), - ); - - final json = _( - Either.tryCatch( - () => jsonDecode(body), - (_, __) => LocationInvalidJsonDecodeFpdartFailure(body), - ), - ); - - final data = _( - Either>.safeCast( - json, - LocationInvalidMapFpdartFailure.new, - ), - ); - - final currentWeather = _( - data - .lookup('results') - .toEither(LocationKeyNotFoundFpdartFailure.new), - ); - - final results = _( - Either>.safeCast( - currentWeather, - LocationInvalidListFpdartFailure.new, - ), - ); - - final weather = _( - results.head.toEither(LocationDataNotFoundFpdartFailure.new), - ); - - return _( - Either.tryCatch( - () => Location.fromJson(weather as Map), - LocationFormattingFpdartFailure.new, - ), - ); - }), - ); - - /// Fetches [Weather] for a given [latitude] and [longitude]. - TaskEither getWeather({ - required double latitude, - required double longitude, - }) => - TaskEither.tryCatch( - () async => _httpClient.get( - Uri.https( - _baseUrlWeather, - 'v1/forecast', - { - 'latitude': '$latitude', - 'longitude': '$longitude', - 'current_weather': 'true' - }, - ), - ), - WeatherHttpRequestFpdartFailure.new, - ) - .chainEither( - (response) => - _validResponseBody(response, WeatherRequestFpdartFailure.new), - ) - .chainEither( - (body) => Either.safeCastStrict< - OpenMeteoApiFpdartWeatherFailure, - Map, - String>(body, WeatherInvalidMapFpdartFailure.new), - ) - .chainEither( - (body) => body - .lookup('current_weather') - .toEither(WeatherKeyNotFoundFpdartFailure.new), - ) - .chainEither( - (currentWeather) => Either>.safeCast( - currentWeather, - WeatherInvalidListFpdartFailure.new, - ), - ) - .chainEither( - (results) => - results.head.toEither(WeatherDataNotFoundFpdartFailure.new), - ) - .chainEither( - (weather) => Either.tryCatch( - () => Weather.fromJson(weather as Map), - WeatherFormattingFpdartFailure.new, - ), - ); - - /// Verify that the response status code is 200, - /// and extract the response's body. - Either _validResponseBody( - http.Response response, - E Function(http.Response) onError, - ) => - Either.fromPredicate( - response, - (r) => r.statusCode == 200, - onError, - ).map((r) => r.body); -} diff --git a/examples/open_meteo_api/lib/src/fpdart/weather_failure.dart b/examples/open_meteo_api/lib/src/fpdart/weather_failure.dart deleted file mode 100644 index 8d923bbc..00000000 --- a/examples/open_meteo_api/lib/src/fpdart/weather_failure.dart +++ /dev/null @@ -1,54 +0,0 @@ -// ignore_for_file: comment_references - -import 'package:http/http.dart' as http; - -/// Abstract class which represents a failure in the `getWeather` request. -abstract class OpenMeteoApiFpdartWeatherFailure {} - -/// [OpenMeteoApiFpdartWeatherFailure] when **http request** fails -class WeatherHttpRequestFpdartFailure - implements OpenMeteoApiFpdartWeatherFailure { - const WeatherHttpRequestFpdartFailure(this.object, this.stackTrace); - final Object object; - final StackTrace stackTrace; -} - -/// [OpenMeteoApiFpdartWeatherFailure] when getWeather fails -class WeatherRequestFpdartFailure implements OpenMeteoApiFpdartWeatherFailure { - const WeatherRequestFpdartFailure(this.response); - final http.Response response; -} - -/// [OpenMeteoApiFpdartWeatherFailure] when weather response is not a valid -/// [Map]. -class WeatherInvalidMapFpdartFailure - implements OpenMeteoApiFpdartWeatherFailure { - const WeatherInvalidMapFpdartFailure(this.body); - final String body; -} - -/// [OpenMeteoApiFpdartWeatherFailure] when weather information -/// is not found (missing expected key). -class WeatherKeyNotFoundFpdartFailure - implements OpenMeteoApiFpdartWeatherFailure {} - -/// [OpenMeteoApiFpdartWeatherFailure] when weather data is not a valid [List]. -class WeatherInvalidListFpdartFailure - implements OpenMeteoApiFpdartWeatherFailure { - const WeatherInvalidListFpdartFailure(this.value); - final dynamic value; -} - -/// [OpenMeteoApiFpdartWeatherFailure] when weather for provided location -/// is not found (missing data). -class WeatherDataNotFoundFpdartFailure - implements OpenMeteoApiFpdartWeatherFailure {} - -/// [OpenMeteoApiFpdartWeatherFailure] when the response is not a valid -/// [Weather]. -class WeatherFormattingFpdartFailure - implements OpenMeteoApiFpdartWeatherFailure { - const WeatherFormattingFpdartFailure(this.object, this.stackTrace); - final Object object; - final StackTrace stackTrace; -} diff --git a/examples/open_meteo_api/lib/src/models/location.dart b/examples/open_meteo_api/lib/src/models/location.dart deleted file mode 100644 index f11c46c0..00000000 --- a/examples/open_meteo_api/lib/src/models/location.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -part 'location.g.dart'; - -@JsonSerializable() -class Location { - const Location({ - required this.id, - required this.name, - required this.latitude, - required this.longitude, - }); - - factory Location.fromJson(Map json) => - _$LocationFromJson(json); - - final int id; - final String name; - final double latitude; - final double longitude; -} diff --git a/examples/open_meteo_api/lib/src/models/models.dart b/examples/open_meteo_api/lib/src/models/models.dart deleted file mode 100644 index 4f0d8637..00000000 --- a/examples/open_meteo_api/lib/src/models/models.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'location.dart'; -export 'weather.dart'; diff --git a/examples/open_meteo_api/lib/src/models/weather.dart b/examples/open_meteo_api/lib/src/models/weather.dart deleted file mode 100644 index bb2fc687..00000000 --- a/examples/open_meteo_api/lib/src/models/weather.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -part 'weather.g.dart'; - -@JsonSerializable() -class Weather { - const Weather({required this.temperature, required this.weatherCode}); - - factory Weather.fromJson(Map json) => - _$WeatherFromJson(json); - - final double temperature; - @JsonKey(name: 'weathercode') - final double weatherCode; -} diff --git a/examples/open_meteo_api/lib/src/open_meteo_api_client.dart b/examples/open_meteo_api/lib/src/open_meteo_api_client.dart deleted file mode 100644 index 103eb517..00000000 --- a/examples/open_meteo_api/lib/src/open_meteo_api_client.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:http/http.dart' as http; -import 'package:open_meteo_api/open_meteo_api.dart'; - -/// Exception thrown when locationSearch fails. -class LocationRequestFailure implements Exception {} - -/// Exception thrown when the provided location is not found. -class LocationNotFoundFailure implements Exception {} - -/// Exception thrown when getWeather fails. -class WeatherRequestFailure implements Exception {} - -/// Exception thrown when weather for provided location is not found. -class WeatherNotFoundFailure implements Exception {} - -/// {@template open_meteo_api_client} -/// Dart API Client which wraps the [Open Meteo API](https://open-meteo.com). -/// {@endtemplate} -class OpenMeteoApiClient { - /// {@macro open_meteo_api_client} - OpenMeteoApiClient({http.Client? httpClient}) - : _httpClient = httpClient ?? http.Client(); - - static const _baseUrlWeather = 'api.open-meteo.com'; - static const _baseUrlGeocoding = 'geocoding-api.open-meteo.com'; - - final http.Client _httpClient; - - /// Finds a [Location] `/v1/search/?name=(query)`. - Future locationSearch(String query) async { - final locationRequest = Uri.https( - _baseUrlGeocoding, - '/v1/search', - {'name': query, 'count': '1'}, - ); - - final locationResponse = await _httpClient.get(locationRequest); - - if (locationResponse.statusCode != 200) { - throw LocationRequestFailure(); - } - - final locationJson = jsonDecode(locationResponse.body) as Map; - - if (!locationJson.containsKey('results')) throw LocationNotFoundFailure(); - - final results = locationJson['results'] as List; - - if (results.isEmpty) throw LocationNotFoundFailure(); - - return Location.fromJson(results.first as Map); - } - - /// Fetches [Weather] for a given [latitude] and [longitude]. - Future getWeather({ - required double latitude, - required double longitude, - }) async { - final weatherRequest = Uri.https(_baseUrlWeather, 'v1/forecast', { - 'latitude': '$latitude', - 'longitude': '$longitude', - 'current_weather': 'true' - }); - - final weatherResponse = await _httpClient.get(weatherRequest); - - if (weatherResponse.statusCode != 200) { - throw WeatherRequestFailure(); - } - - final bodyJson = jsonDecode(weatherResponse.body) as Map; - - if (!bodyJson.containsKey('current_weather')) { - throw WeatherNotFoundFailure(); - } - - final weatherJson = bodyJson['current_weather'] as Map; - - return Weather.fromJson(weatherJson); - } -} diff --git a/examples/open_meteo_api/pubspec.yaml b/examples/open_meteo_api/pubspec.yaml deleted file mode 100644 index 0e976e85..00000000 --- a/examples/open_meteo_api/pubspec.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: open_meteo_api -description: A Dart API Client for the Open-Meteo API. -version: 1.0.0+1 -publish_to: "none" - -environment: - sdk: ">=2.18.0 <3.0.0" - -dependencies: - fpdart: - path: ../../packages/fpdart - - http: ^0.13.0 - json_annotation: ^4.6.0 - -dev_dependencies: - build_runner: ^2.0.0 - json_serializable: ^6.3.1 - mocktail: ^0.3.0 - test: ^1.16.4 - very_good_analysis: ^4.0.0+1 diff --git a/examples/open_meteo_api/test/open_meteo_api_client_test.dart b/examples/open_meteo_api/test/open_meteo_api_client_test.dart deleted file mode 100644 index 60a36aa6..00000000 --- a/examples/open_meteo_api/test/open_meteo_api_client_test.dart +++ /dev/null @@ -1,202 +0,0 @@ -// ignore_for_file: prefer_const_constructors -import 'package:http/http.dart' as http; -import 'package:mocktail/mocktail.dart'; -import 'package:open_meteo_api/open_meteo_api.dart'; -import 'package:test/test.dart'; - -class MockHttpClient extends Mock implements http.Client {} - -class MockResponse extends Mock implements http.Response {} - -class FakeUri extends Fake implements Uri {} - -void main() { - group('OpenMeteoApiClient', () { - late http.Client httpClient; - late OpenMeteoApiClient apiClient; - - setUpAll(() { - registerFallbackValue(FakeUri()); - }); - - setUp(() { - httpClient = MockHttpClient(); - apiClient = OpenMeteoApiClient(httpClient: httpClient); - }); - - group('constructor', () { - test('does not require an httpClient', () { - expect(OpenMeteoApiClient(), isNotNull); - }); - }); - - group('locationSearch', () { - const query = 'mock-query'; - test('makes correct http request', () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn('{}'); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - try { - await apiClient.locationSearch(query); - } catch (_) {} - verify( - () => httpClient.get( - Uri.https( - 'geocoding-api.open-meteo.com', - '/v1/search', - {'name': query, 'count': '1'}, - ), - ), - ).called(1); - }); - - test('throws LocationRequestFailure on non-200 response', () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(400); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - expect( - () async => apiClient.locationSearch(query), - throwsA(isA()), - ); - }); - - test('throws LocationNotFoundFailure on error response', () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn('{}'); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - await expectLater( - apiClient.locationSearch(query), - throwsA(isA()), - ); - }); - - test('throws LocationNotFoundFailure on empty response', () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn('{"results": []}'); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - await expectLater( - apiClient.locationSearch(query), - throwsA(isA()), - ); - }); - - test('returns Location on valid response', () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn( - ''' -{ - "results": [ - { - "id": 4887398, - "name": "Chicago", - "latitude": 41.85003, - "longitude": -87.65005 - } - ] -}''', - ); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - final actual = await apiClient.locationSearch(query); - expect( - actual, - isA() - .having((l) => l.name, 'name', 'Chicago') - .having((l) => l.id, 'id', 4887398) - .having((l) => l.latitude, 'latitude', 41.85003) - .having((l) => l.longitude, 'longitude', -87.65005), - ); - }); - }); - - group('getWeather', () { - const latitude = 41.85003; - const longitude = -87.6500; - - test('makes correct http request', () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn('{}'); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - try { - await apiClient.getWeather(latitude: latitude, longitude: longitude); - } catch (_) {} - verify( - () => httpClient.get( - Uri.https('api.open-meteo.com', 'v1/forecast', { - 'latitude': '$latitude', - 'longitude': '$longitude', - 'current_weather': 'true' - }), - ), - ).called(1); - }); - - test('throws WeatherRequestFailure on non-200 response', () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(400); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - expect( - () async => apiClient.getWeather( - latitude: latitude, - longitude: longitude, - ), - throwsA(isA()), - ); - }); - - test('throws WeatherNotFoundFailure on empty response', () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn('{}'); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - expect( - () async => apiClient.getWeather( - latitude: latitude, - longitude: longitude, - ), - throwsA(isA()), - ); - }); - - test('returns weather on valid response', () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn( - ''' -{ -"latitude": 43, -"longitude": -87.875, -"generationtime_ms": 0.2510547637939453, -"utc_offset_seconds": 0, -"timezone": "GMT", -"timezone_abbreviation": "GMT", -"elevation": 189, -"current_weather": { -"temperature": 15.3, -"windspeed": 25.8, -"winddirection": 310, -"weathercode": 63, -"time": "2022-09-12T01:00" -} -} - ''', - ); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - final actual = await apiClient.getWeather( - latitude: latitude, - longitude: longitude, - ); - expect( - actual, - isA() - .having((w) => w.temperature, 'temperature', 15.3) - .having((w) => w.weatherCode, 'weatherCode', 63.0), - ); - }); - }); - }); -} diff --git a/examples/open_meteo_api/test/open_meteo_api_client_test_fpdart.dart b/examples/open_meteo_api/test/open_meteo_api_client_test_fpdart.dart deleted file mode 100644 index 1cc346e4..00000000 --- a/examples/open_meteo_api/test/open_meteo_api_client_test_fpdart.dart +++ /dev/null @@ -1,249 +0,0 @@ -// ignore_for_file: prefer_const_constructors, lines_longer_than_80_chars -import 'package:fpdart/fpdart.dart'; -import 'package:http/http.dart' as http; -import 'package:mocktail/mocktail.dart'; -import 'package:open_meteo_api/open_meteo_api.dart'; -import 'package:open_meteo_api/src/fpdart/location_failure.dart'; -import 'package:test/test.dart'; - -class MockHttpClient extends Mock implements http.Client {} - -class MockResponse extends Mock implements http.Response {} - -class FakeUri extends Fake implements Uri {} - -void _isLeftOfType( - Either result, { - dynamic Function(TypeMatcher)? typeMatch, -}) { - expect(result, isA>()); - result.match( - (l) => expect(l, typeMatch != null ? typeMatch(isA()) : isA()), - (_) => fail('should not be right'), - ); -} - -void main() { - group('OpenMeteoApiClientFpdart', () { - late http.Client httpClient; - late OpenMeteoApiClientFpdart apiClient; - - setUpAll(() { - registerFallbackValue(FakeUri()); - }); - - setUp(() { - httpClient = MockHttpClient(); - apiClient = OpenMeteoApiClientFpdart(httpClient: httpClient); - }); - - group('constructor', () { - test('does not require an httpClient', () { - expect(OpenMeteoApiClientFpdart(), isNotNull); - }); - }); - - group('locationSearch', () { - const query = 'mock-query'; - test('makes correct http request', () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn('{}'); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - - /// No need of try/catch - await apiClient.locationSearch(query).run(); - - verify( - () => httpClient.get( - Uri.https( - 'geocoding-api.open-meteo.com', - '/v1/search', - {'name': query, 'count': '1'}, - ), - ), - ).called(1); - }); - - test('returns LocationHttpRequestFpdartFailure when http request fails', - () async { - when(() => httpClient.get(any())).thenThrow(Exception()); - - final result = await apiClient.locationSearch(query).run(); - - _isLeftOfType( - result, - typeMatch: (m) => m.having( - (failure) => failure.object, - 'Exception', - isA(), - ), - ); - }); - - test('returns LocationRequestFpdartFailure on non-200 response', - () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(400); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - - final result = await apiClient.locationSearch(query).run(); - - _isLeftOfType( - result, - typeMatch: (m) => m.having( - (failure) => failure.response, - 'MockResponse', - response, - ), - ); - }); - - test( - 'returns LocationInvalidJsonDecodeFpdartFailure when response is invalid', - () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn('_{}_'); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - - final result = await apiClient.locationSearch(query).run(); - - _isLeftOfType( - result, - typeMatch: (m) => m.having( - (failure) => failure.body, - 'body', - '_{}_', - ), - ); - }); - - test('returns LocationInvalidMapFpdartFailure when response is not a Map', - () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn('[]'); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - - final result = await apiClient.locationSearch(query).run(); - - _isLeftOfType( - result, - typeMatch: (m) => m.having( - (failure) => failure.json, - 'json', - [], - ), - ); - }); - - test( - 'returns LocationKeyNotFoundFpdartFailure when the response is missing the correct key', - () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn('{}'); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - - final result = await apiClient.locationSearch(query).run(); - - _isLeftOfType(result); - }); - - test( - 'returns LocationInvalidListFpdartFailure when Map key does not contain a valid List', - () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn('{"results": {}}'); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - - final result = await apiClient.locationSearch(query).run(); - - _isLeftOfType( - result, - typeMatch: (m) => m.having( - (failure) => failure.value, - 'value', - {}, - ), - ); - }); - - test('returns LocationDataNotFoundFpdartFailure on empty response', - () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn('{"results": []}'); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - - final result = await apiClient.locationSearch(query).run(); - - _isLeftOfType(result); - }); - - test( - 'returns LocationFormattingFpdartFailure when response is not a correct Location object', - () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn( - ''' -{ - "results": [ - { - "_id": 4887398, - "_name": "Chicago", - "_latitude": 41.85003, - "_longitude": -87.65005 - } - ] -}''', - ); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - - final result = await apiClient.locationSearch(query).run(); - - _isLeftOfType(result); - }); - - test('returns Location on valid response', () async { - final response = MockResponse(); - when(() => response.statusCode).thenReturn(200); - when(() => response.body).thenReturn( - ''' -{ - "results": [ - { - "id": 4887398, - "name": "Chicago", - "latitude": 41.85003, - "longitude": -87.65005 - } - ] -}''', - ); - when(() => httpClient.get(any())).thenAnswer((_) async => response); - - final result = await apiClient.locationSearch(query).run(); - expect( - result, - isA>() - .having((l) => l.value.name, 'name', 'Chicago') - .having((l) => l.value.id, 'id', 4887398) - .having((l) => l.value.latitude, 'latitude', 41.85003) - .having((l) => l.value.longitude, 'longitude', -87.65005), - ); - }); - }); - }); -} diff --git a/examples/poke_api/analysis_options.yaml b/examples/poke_api/analysis_options.yaml new file mode 100644 index 00000000..027c612f --- /dev/null +++ b/examples/poke_api/analysis_options.yaml @@ -0,0 +1,12 @@ +include: package:lints/recommended.yaml + +linter: + rules: + annotate_overrides: true + prefer_void_to_null: false + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true diff --git a/examples/pokeapi_functional/lib/constants/constants.dart b/examples/poke_api/lib/constants.dart similarity index 71% rename from examples/pokeapi_functional/lib/constants/constants.dart rename to examples/poke_api/lib/constants.dart index 84b301f6..2c794b29 100644 --- a/examples/pokeapi_functional/lib/constants/constants.dart +++ b/examples/poke_api/lib/constants.dart @@ -1,7 +1,7 @@ -/// App constants under 'Constants' namespace. -abstract class Constants { +abstract interface class Constants { static const int minimumPokemonId = 1; static const int maximumPokemonId = 898; + static String requestAPIUrl(int pokemonId) => 'https://pokeapi.co/api/v2/pokemon/$pokemonId'; } diff --git a/examples/poke_api/lib/main.dart b/examples/poke_api/lib/main.dart new file mode 100644 index 00000000..a8d513c5 --- /dev/null +++ b/examples/poke_api/lib/main.dart @@ -0,0 +1,78 @@ +import 'dart:convert'; + +import 'package:fpdart/fpdart.dart'; +import 'package:http/http.dart' as http; +import 'package:poke_api/constants.dart'; +import 'package:poke_api/pokemon.dart'; +import 'package:poke_api/pokemon_error.dart'; + +abstract interface class HttpClient { + Effect get(Uri uri); +} + +class Http implements HttpClient { + @override + Effect get(Uri uri) => Effect.gen( + ($) async { + final response = await $.async(Effect.tryCatch( + execute: () => http.get(uri), + onError: (error, stackTrace) => const GetPokemonRequestError(), + )); + + return response.body; + }, + ); +} + +typedef Env = (HttpClient, JsonCodec); + +Effect program( + String pokemonId, +) => + Effect.gen(($) async { + final (client, json) = $.sync(Effect.env()); + + final id = $.sync(Either.fromNullable( + int.tryParse(pokemonId), + PokemonIdNotInt.new, + )); + + if (id < Constants.minimumPokemonId || id > Constants.maximumPokemonId) { + return $.sync(Effect.fail(const InvalidPokemonIdRange())); + } + + final uri = Uri.parse(Constants.requestAPIUrl(id)); + final body = await $.async(client.get(uri).withEnv()); + + final bodyJson = $.sync( + Either.tryCatch( + execute: () => json.decode(body), + onError: (_, __) => const PokemonJsonDecodeError(), + ), + ); + + final bodyJsonMap = $.sync>( + Either.safeCastStrict, dynamic>( + bodyJson, + (value) => const PokemonJsonInvalidMap(), + ), + ); + + return $.sync(Effect.tryCatch( + execute: () => Pokemon.fromJson(bodyJsonMap), + onError: (_, __) => const PokemonInvalidJsonModel(), + )); + }); + +void main() async { + final exit = await program("9722") + .map((pokemon) => print(pokemon)) + .catchError( + (error) => Effect.succeedLazy( + () => print("No pokemon: $error"), + ), + ) + .provideEnv((Http(), JsonCodec())).runFutureExit(); + + print(exit); +} diff --git a/examples/poke_api/lib/pokemon.dart b/examples/poke_api/lib/pokemon.dart new file mode 100644 index 00000000..6008654a --- /dev/null +++ b/examples/poke_api/lib/pokemon.dart @@ -0,0 +1,25 @@ +class Pokemon { + final int id; + final String name; + final int height; + final int weight; + + const Pokemon({ + required this.id, + required this.name, + required this.height, + required this.weight, + }); + + factory Pokemon.fromJson(Map json) => Pokemon( + id: json['id'] as int, + name: json['name'] as String, + height: json['height'] as int, + weight: json['weight'] as int, + ); + + @override + String toString() { + return "Pokemon(id:$id, name:$name, height:$height, weight:$weight)"; + } +} diff --git a/examples/poke_api/lib/pokemon_error.dart b/examples/poke_api/lib/pokemon_error.dart new file mode 100644 index 00000000..92c65f80 --- /dev/null +++ b/examples/poke_api/lib/pokemon_error.dart @@ -0,0 +1,27 @@ +sealed class PokemonError { + const PokemonError(); +} + +class PokemonIdNotInt extends PokemonError { + const PokemonIdNotInt(); +} + +class InvalidPokemonIdRange extends PokemonError { + const InvalidPokemonIdRange(); +} + +class GetPokemonRequestError extends PokemonError { + const GetPokemonRequestError(); +} + +class PokemonJsonDecodeError extends PokemonError { + const PokemonJsonDecodeError(); +} + +class PokemonJsonInvalidMap extends PokemonError { + const PokemonJsonInvalidMap(); +} + +class PokemonInvalidJsonModel extends PokemonError { + const PokemonInvalidJsonModel(); +} diff --git a/examples/poke_api/pubspec.yaml b/examples/poke_api/pubspec.yaml new file mode 100644 index 00000000..19880480 --- /dev/null +++ b/examples/poke_api/pubspec.yaml @@ -0,0 +1,19 @@ +name: poke_api +description: > + Example of using fpdart to fetch pokemon from pokeapi with validation. +version: 2.0.0 +homepage: https://www.sandromaglione.com/ +repository: https://github.com/SandroMaglione/fpdart +publish_to: "none" + +environment: + sdk: ">=3.3.0 <4.0.0" + +dependencies: + http: ^1.2.1 + fpdart: + path: ../../packages/fpdart + +dev_dependencies: + lints: ^2.0.1 + test: ^1.23.1 diff --git a/examples/pokeapi_functional/.gitattributes b/examples/pokeapi_functional/.gitattributes deleted file mode 100644 index 243a7690..00000000 --- a/examples/pokeapi_functional/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -*.freezed.dart linguist-generated=true -*.g.dart linguist-generated=true diff --git a/examples/pokeapi_functional/.gitignore b/examples/pokeapi_functional/.gitignore deleted file mode 100644 index d207f7e1..00000000 --- a/examples/pokeapi_functional/.gitignore +++ /dev/null @@ -1,48 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.metadata -.pub-cache/ -.pub/ -/build/ -pubspec.lock - -# Web related -lib/generated_plugin_registrant.dart - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/examples/pokeapi_functional/README.md b/examples/pokeapi_functional/README.md deleted file mode 100644 index 415b5039..00000000 --- a/examples/pokeapi_functional/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# pokeapi_functional - -A new Flutter project. - -## Getting Started - -- `flutter pub get` -- `dart run build_runner build` -- `flutter run -d chrome` diff --git a/examples/pokeapi_functional/android/.gitignore b/examples/pokeapi_functional/android/.gitignore deleted file mode 100644 index 0a741cb4..00000000 --- a/examples/pokeapi_functional/android/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties diff --git a/examples/pokeapi_functional/android/app/build.gradle b/examples/pokeapi_functional/android/app/build.gradle deleted file mode 100644 index 099ad9d4..00000000 --- a/examples/pokeapi_functional/android/app/build.gradle +++ /dev/null @@ -1,59 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 30 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.sandromaglione.fpdart.pokeapi.pokeapi_functional" - minSdkVersion 16 - targetSdkVersion 30 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/examples/pokeapi_functional/android/app/src/debug/AndroidManifest.xml b/examples/pokeapi_functional/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 79a815e2..00000000 --- a/examples/pokeapi_functional/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/examples/pokeapi_functional/android/app/src/main/AndroidManifest.xml b/examples/pokeapi_functional/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index a9ac11d4..00000000 --- a/examples/pokeapi_functional/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/examples/pokeapi_functional/android/app/src/main/kotlin/com/sandromaglione/fpdart/pokeapi/pokeapi_functional/MainActivity.kt b/examples/pokeapi_functional/android/app/src/main/kotlin/com/sandromaglione/fpdart/pokeapi/pokeapi_functional/MainActivity.kt deleted file mode 100644 index e409e61d..00000000 --- a/examples/pokeapi_functional/android/app/src/main/kotlin/com/sandromaglione/fpdart/pokeapi/pokeapi_functional/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.sandromaglione.fpdart.pokeapi.pokeapi_functional - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/examples/pokeapi_functional/android/app/src/main/res/drawable-v21/launch_background.xml b/examples/pokeapi_functional/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f3..00000000 --- a/examples/pokeapi_functional/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/examples/pokeapi_functional/android/app/src/main/res/drawable/launch_background.xml b/examples/pokeapi_functional/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/examples/pokeapi_functional/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/examples/pokeapi_functional/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/pokeapi_functional/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b..00000000 Binary files a/examples/pokeapi_functional/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/examples/pokeapi_functional/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/pokeapi_functional/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79..00000000 Binary files a/examples/pokeapi_functional/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/examples/pokeapi_functional/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/examples/pokeapi_functional/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 09d43914..00000000 Binary files a/examples/pokeapi_functional/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/examples/pokeapi_functional/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/pokeapi_functional/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d3..00000000 Binary files a/examples/pokeapi_functional/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/examples/pokeapi_functional/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/examples/pokeapi_functional/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372ee..00000000 Binary files a/examples/pokeapi_functional/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/examples/pokeapi_functional/android/app/src/main/res/values-night/styles.xml b/examples/pokeapi_functional/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 449a9f93..00000000 --- a/examples/pokeapi_functional/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/examples/pokeapi_functional/android/app/src/main/res/values/styles.xml b/examples/pokeapi_functional/android/app/src/main/res/values/styles.xml deleted file mode 100644 index d74aa35c..00000000 --- a/examples/pokeapi_functional/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/examples/pokeapi_functional/android/app/src/profile/AndroidManifest.xml b/examples/pokeapi_functional/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 79a815e2..00000000 --- a/examples/pokeapi_functional/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/examples/pokeapi_functional/android/build.gradle b/examples/pokeapi_functional/android/build.gradle deleted file mode 100644 index 9b6ed06e..00000000 --- a/examples/pokeapi_functional/android/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/examples/pokeapi_functional/android/gradle.properties b/examples/pokeapi_functional/android/gradle.properties deleted file mode 100644 index 94adc3a3..00000000 --- a/examples/pokeapi_functional/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true diff --git a/examples/pokeapi_functional/android/gradle/wrapper/gradle-wrapper.properties b/examples/pokeapi_functional/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index bc6a58af..00000000 --- a/examples/pokeapi_functional/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/examples/pokeapi_functional/android/settings.gradle b/examples/pokeapi_functional/android/settings.gradle deleted file mode 100644 index 44e62bcf..00000000 --- a/examples/pokeapi_functional/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/examples/pokeapi_functional/ios/.gitignore b/examples/pokeapi_functional/ios/.gitignore deleted file mode 100644 index 151026b9..00000000 --- a/examples/pokeapi_functional/ios/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/examples/pokeapi_functional/ios/Flutter/AppFrameworkInfo.plist b/examples/pokeapi_functional/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 9367d483..00000000 --- a/examples/pokeapi_functional/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/examples/pokeapi_functional/ios/Flutter/Debug.xcconfig b/examples/pokeapi_functional/ios/Flutter/Debug.xcconfig deleted file mode 100644 index 592ceee8..00000000 --- a/examples/pokeapi_functional/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/examples/pokeapi_functional/ios/Flutter/Release.xcconfig b/examples/pokeapi_functional/ios/Flutter/Release.xcconfig deleted file mode 100644 index 592ceee8..00000000 --- a/examples/pokeapi_functional/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/examples/pokeapi_functional/ios/Runner.xcodeproj/project.pbxproj b/examples/pokeapi_functional/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 7e08de38..00000000 --- a/examples/pokeapi_functional/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,471 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.sandromaglione.fpdart.pokeapi.pokeapiFunctional; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.sandromaglione.fpdart.pokeapi.pokeapiFunctional; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.sandromaglione.fpdart.pokeapi.pokeapiFunctional; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/examples/pokeapi_functional/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/pokeapi_functional/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/examples/pokeapi_functional/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/examples/pokeapi_functional/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/examples/pokeapi_functional/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/examples/pokeapi_functional/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/examples/pokeapi_functional/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/examples/pokeapi_functional/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/examples/pokeapi_functional/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/examples/pokeapi_functional/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/examples/pokeapi_functional/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cf..00000000 --- a/examples/pokeapi_functional/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/pokeapi_functional/ios/Runner.xcworkspace/contents.xcworkspacedata b/examples/pokeapi_functional/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/examples/pokeapi_functional/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/examples/pokeapi_functional/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/examples/pokeapi_functional/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/examples/pokeapi_functional/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/examples/pokeapi_functional/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/examples/pokeapi_functional/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/examples/pokeapi_functional/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/examples/pokeapi_functional/ios/Runner/AppDelegate.swift b/examples/pokeapi_functional/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/examples/pokeapi_functional/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab..00000000 --- a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada47..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 28c6bf03..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 2ccbfd96..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cde1211..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index dcdc2306..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 2ccbfd96..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b860..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b860..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d3..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 6a84f41e..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index d0e1f585..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2f..00000000 --- a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/examples/pokeapi_functional/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/examples/pokeapi_functional/ios/Runner/Base.lproj/LaunchScreen.storyboard b/examples/pokeapi_functional/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/examples/pokeapi_functional/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/pokeapi_functional/ios/Runner/Base.lproj/Main.storyboard b/examples/pokeapi_functional/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/examples/pokeapi_functional/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/pokeapi_functional/ios/Runner/Info.plist b/examples/pokeapi_functional/ios/Runner/Info.plist deleted file mode 100644 index de2ddd88..00000000 --- a/examples/pokeapi_functional/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - pokeapi_functional - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/examples/pokeapi_functional/ios/Runner/Runner-Bridging-Header.h b/examples/pokeapi_functional/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a56..00000000 --- a/examples/pokeapi_functional/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/examples/pokeapi_functional/lib/api/fetch_pokemon.dart b/examples/pokeapi_functional/lib/api/fetch_pokemon.dart deleted file mode 100644 index 392878c1..00000000 --- a/examples/pokeapi_functional/lib/api/fetch_pokemon.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'dart:convert'; - -import 'package:fpdart/fpdart.dart'; -import 'package:http/http.dart' as http; -import 'package:pokeapi_functional/constants/constants.dart'; -import 'package:pokeapi_functional/models/pokemon.dart'; - -/// Parse [String] to [int] in a functional way using [IOEither]. -IOEither _parseStringToInt(String str) => IOEither.tryCatch( - () => int.parse(str), - (_, __) => - 'Cannot convert input to valid pokemon id (it must be a number)!', - ); - -/// Validate the pokemon id inserted by the user: -/// 1. Parse [String] from the user to [int] -/// 2. Check pokemon id in valid range -/// -/// Chain (1) and (2) using `flatMap`. -IOEither _validateUserPokemonId(String pokemonId) => - _parseStringToInt(pokemonId).flatMap( - (intPokemonId) => IOEither.fromPredicate( - intPokemonId, - (id) => - id >= Constants.minimumPokemonId && - id <= Constants.maximumPokemonId, - (id) => - 'Invalid pokemon id $id: the id must be between ${Constants.minimumPokemonId} and ${Constants.maximumPokemonId + 1}!', - ), - ); - -/// Make HTTP request to fetch pokemon information from the pokeAPI -/// using [TaskEither] to perform an async request in a composable way. -TaskEither fetchPokemon(int pokemonId) => TaskEither.tryCatch( - () async { - final url = Uri.parse(Constants.requestAPIUrl(pokemonId)); - final response = await http.get(url); - return Pokemon.fromJson( - jsonDecode(response.body) as Map, - ); - }, - (error, __) => 'Unknown error: $error', - ); - -/// Try to parse the user input from [String] to [int] using [IOEither]. -/// We use [IOEither] since the `parse` method is **synchronous** (no need of [Future]). -/// -/// Then check that the pokemon id is in the valid range. -/// -/// If the validation is successful, then fetch the pokemon information from the [int] id. -/// -/// All the functions are simply chained together following the principle of composability. -TaskEither fetchPokemonFromUserInput(String pokemonId) => - TaskEither.Do((_) async { - final validPokemonId = await _(_validateUserPokemonId( - pokemonId, - ).toTaskEither()); - return _(fetchPokemon(validPokemonId)); - }); - -TaskEither fetchRandomPokemon = TaskEither.Do((_) async { - final pokemonId = await _(randomInt( - Constants.minimumPokemonId, - Constants.maximumPokemonId + 1, - ).toTaskEither()); - return _(fetchPokemon(pokemonId)); -}); diff --git a/examples/pokeapi_functional/lib/controllers/pokemon_provider.dart b/examples/pokeapi_functional/lib/controllers/pokemon_provider.dart deleted file mode 100644 index cc65968d..00000000 --- a/examples/pokeapi_functional/lib/controllers/pokemon_provider.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -import '../api/fetch_pokemon.dart'; -import '../models/pokemon.dart'; - -part 'pokemon_provider.g.dart'; - -@riverpod -class PokemonState extends _$PokemonState { - @override - FutureOr build() async => - fetchRandomPokemon.getOrElse((l) => throw Exception(l)).run(); - - /// User request, try to convert user input to [int] and then - /// request the pokemon if successful. - Future fetch(String pokemonId) async => _pokemonRequest( - () => fetchPokemonFromUserInput(pokemonId), - ); - - /// Generic private method to perform request and update the state. - Future _pokemonRequest( - TaskEither Function() request, - ) async { - state = AsyncLoading(); - final pokemon = request(); - state = (await pokemon.run()).match( - (error) => AsyncError(error, StackTrace.current), - (pokemon) => AsyncData(pokemon), - ); - return unit; - } -} diff --git a/examples/pokeapi_functional/lib/main.dart b/examples/pokeapi_functional/lib/main.dart deleted file mode 100644 index bc921f26..00000000 --- a/examples/pokeapi_functional/lib/main.dart +++ /dev/null @@ -1,75 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart' show useTextEditingController; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:pokeapi_functional/controllers/pokemon_provider.dart'; - -void main() { - /// [ProviderScope] required for riverpod state management - runApp(ProviderScope(child: MyApp())); -} - -class MyApp extends HookConsumerWidget { - @override - Widget build(BuildContext context, WidgetRef ref) { - /// [TextEditingController] using hooks - final controller = useTextEditingController(); - final requestStatus = ref.watch(pokemonStateProvider); - final pokemonNotifier = ref.watch(pokemonStateProvider.notifier); - - return MaterialApp( - title: 'Fpdart PokeAPI', - home: Scaffold( - body: Column( - children: [ - /// [TextField] and [ElevatedButton] to input pokemon id to fetch - TextField( - textInputAction: TextInputAction.next, - textAlign: TextAlign.center, - controller: controller, - decoration: InputDecoration( - hintText: 'Insert pokemon id number', - ), - ), - ElevatedButton( - onPressed: () => pokemonNotifier.fetch(controller.text), - child: Text('Get my pokemon!'), - ), - - /// Map each [AsyncValue] to a different UI - requestStatus.when( - loading: () => Center(child: CircularProgressIndicator()), - - /// When either is [Left], display error message 💥 - error: (error, stackTrace) => Text(error.toString()), - - /// When either is [Right], display pokemon 🤩 - data: (pokemon) => Card( - child: Column( - children: [ - Image.network( - pokemon.sprites.frontDefault, - width: 200, - height: 200, - ), - Padding( - padding: const EdgeInsets.only( - bottom: 24, - ), - child: Text( - pokemon.name, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 24, - ), - ), - ), - ], - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/examples/pokeapi_functional/lib/models/pokemon.dart b/examples/pokeapi_functional/lib/models/pokemon.dart deleted file mode 100644 index b3644c83..00000000 --- a/examples/pokeapi_functional/lib/models/pokemon.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:pokeapi_functional/models/sprite.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'pokemon.freezed.dart'; -part 'pokemon.g.dart'; - -/// Pokemon information, with method to deserialize json -@freezed -class Pokemon with _$Pokemon { - const factory Pokemon({ - required int id, - required String name, - required int height, - required int weight, - required Sprite sprites, - }) = _Pokemon; - - factory Pokemon.fromJson(Map json) => - _$PokemonFromJson(json); -} diff --git a/examples/pokeapi_functional/lib/models/pokemon.freezed.dart b/examples/pokeapi_functional/lib/models/pokemon.freezed.dart deleted file mode 100644 index d7ab0516..00000000 --- a/examples/pokeapi_functional/lib/models/pokemon.freezed.dart +++ /dev/null @@ -1,234 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'pokemon.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); - -Pokemon _$PokemonFromJson(Map json) { - return _Pokemon.fromJson(json); -} - -/// @nodoc -mixin _$Pokemon { - int get id => throw _privateConstructorUsedError; - String get name => throw _privateConstructorUsedError; - int get height => throw _privateConstructorUsedError; - int get weight => throw _privateConstructorUsedError; - Sprite get sprites => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $PokemonCopyWith get copyWith => throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $PokemonCopyWith<$Res> { - factory $PokemonCopyWith(Pokemon value, $Res Function(Pokemon) then) = - _$PokemonCopyWithImpl<$Res, Pokemon>; - @useResult - $Res call({int id, String name, int height, int weight, Sprite sprites}); - - $SpriteCopyWith<$Res> get sprites; -} - -/// @nodoc -class _$PokemonCopyWithImpl<$Res, $Val extends Pokemon> - implements $PokemonCopyWith<$Res> { - _$PokemonCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? name = null, - Object? height = null, - Object? weight = null, - Object? sprites = null, - }) { - return _then(_value.copyWith( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as int, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - height: null == height - ? _value.height - : height // ignore: cast_nullable_to_non_nullable - as int, - weight: null == weight - ? _value.weight - : weight // ignore: cast_nullable_to_non_nullable - as int, - sprites: null == sprites - ? _value.sprites - : sprites // ignore: cast_nullable_to_non_nullable - as Sprite, - ) as $Val); - } - - @override - @pragma('vm:prefer-inline') - $SpriteCopyWith<$Res> get sprites { - return $SpriteCopyWith<$Res>(_value.sprites, (value) { - return _then(_value.copyWith(sprites: value) as $Val); - }); - } -} - -/// @nodoc -abstract class _$$_PokemonCopyWith<$Res> implements $PokemonCopyWith<$Res> { - factory _$$_PokemonCopyWith( - _$_Pokemon value, $Res Function(_$_Pokemon) then) = - __$$_PokemonCopyWithImpl<$Res>; - @override - @useResult - $Res call({int id, String name, int height, int weight, Sprite sprites}); - - @override - $SpriteCopyWith<$Res> get sprites; -} - -/// @nodoc -class __$$_PokemonCopyWithImpl<$Res> - extends _$PokemonCopyWithImpl<$Res, _$_Pokemon> - implements _$$_PokemonCopyWith<$Res> { - __$$_PokemonCopyWithImpl(_$_Pokemon _value, $Res Function(_$_Pokemon) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? name = null, - Object? height = null, - Object? weight = null, - Object? sprites = null, - }) { - return _then(_$_Pokemon( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as int, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - height: null == height - ? _value.height - : height // ignore: cast_nullable_to_non_nullable - as int, - weight: null == weight - ? _value.weight - : weight // ignore: cast_nullable_to_non_nullable - as int, - sprites: null == sprites - ? _value.sprites - : sprites // ignore: cast_nullable_to_non_nullable - as Sprite, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$_Pokemon implements _Pokemon { - const _$_Pokemon( - {required this.id, - required this.name, - required this.height, - required this.weight, - required this.sprites}); - - factory _$_Pokemon.fromJson(Map json) => - _$$_PokemonFromJson(json); - - @override - final int id; - @override - final String name; - @override - final int height; - @override - final int weight; - @override - final Sprite sprites; - - @override - String toString() { - return 'Pokemon(id: $id, name: $name, height: $height, weight: $weight, sprites: $sprites)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$_Pokemon && - (identical(other.id, id) || other.id == id) && - (identical(other.name, name) || other.name == name) && - (identical(other.height, height) || other.height == height) && - (identical(other.weight, weight) || other.weight == weight) && - (identical(other.sprites, sprites) || other.sprites == sprites)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => - Object.hash(runtimeType, id, name, height, weight, sprites); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$_PokemonCopyWith<_$_Pokemon> get copyWith => - __$$_PokemonCopyWithImpl<_$_Pokemon>(this, _$identity); - - @override - Map toJson() { - return _$$_PokemonToJson( - this, - ); - } -} - -abstract class _Pokemon implements Pokemon { - const factory _Pokemon( - {required final int id, - required final String name, - required final int height, - required final int weight, - required final Sprite sprites}) = _$_Pokemon; - - factory _Pokemon.fromJson(Map json) = _$_Pokemon.fromJson; - - @override - int get id; - @override - String get name; - @override - int get height; - @override - int get weight; - @override - Sprite get sprites; - @override - @JsonKey(ignore: true) - _$$_PokemonCopyWith<_$_Pokemon> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/examples/pokeapi_functional/lib/models/sprite.dart b/examples/pokeapi_functional/lib/models/sprite.dart deleted file mode 100644 index 684e1599..00000000 --- a/examples/pokeapi_functional/lib/models/sprite.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'sprite.freezed.dart'; -part 'sprite.g.dart'; - -/// Pokemon sprite image, with method to deserialize json -@freezed -class Sprite with _$Sprite { - const factory Sprite({ - @JsonKey(name: 'front_default') required String frontDefault, - }) = _Sprite; - - factory Sprite.fromJson(Map json) => _$SpriteFromJson(json); -} diff --git a/examples/pokeapi_functional/lib/models/sprite.freezed.dart b/examples/pokeapi_functional/lib/models/sprite.freezed.dart deleted file mode 100644 index 11103b42..00000000 --- a/examples/pokeapi_functional/lib/models/sprite.freezed.dart +++ /dev/null @@ -1,151 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'sprite.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); - -Sprite _$SpriteFromJson(Map json) { - return _Sprite.fromJson(json); -} - -/// @nodoc -mixin _$Sprite { - @JsonKey(name: 'front_default') - String get frontDefault => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $SpriteCopyWith get copyWith => throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $SpriteCopyWith<$Res> { - factory $SpriteCopyWith(Sprite value, $Res Function(Sprite) then) = - _$SpriteCopyWithImpl<$Res, Sprite>; - @useResult - $Res call({@JsonKey(name: 'front_default') String frontDefault}); -} - -/// @nodoc -class _$SpriteCopyWithImpl<$Res, $Val extends Sprite> - implements $SpriteCopyWith<$Res> { - _$SpriteCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? frontDefault = null, - }) { - return _then(_value.copyWith( - frontDefault: null == frontDefault - ? _value.frontDefault - : frontDefault // ignore: cast_nullable_to_non_nullable - as String, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$_SpriteCopyWith<$Res> implements $SpriteCopyWith<$Res> { - factory _$$_SpriteCopyWith(_$_Sprite value, $Res Function(_$_Sprite) then) = - __$$_SpriteCopyWithImpl<$Res>; - @override - @useResult - $Res call({@JsonKey(name: 'front_default') String frontDefault}); -} - -/// @nodoc -class __$$_SpriteCopyWithImpl<$Res> - extends _$SpriteCopyWithImpl<$Res, _$_Sprite> - implements _$$_SpriteCopyWith<$Res> { - __$$_SpriteCopyWithImpl(_$_Sprite _value, $Res Function(_$_Sprite) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? frontDefault = null, - }) { - return _then(_$_Sprite( - frontDefault: null == frontDefault - ? _value.frontDefault - : frontDefault // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$_Sprite implements _Sprite { - const _$_Sprite({@JsonKey(name: 'front_default') required this.frontDefault}); - - factory _$_Sprite.fromJson(Map json) => - _$$_SpriteFromJson(json); - - @override - @JsonKey(name: 'front_default') - final String frontDefault; - - @override - String toString() { - return 'Sprite(frontDefault: $frontDefault)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$_Sprite && - (identical(other.frontDefault, frontDefault) || - other.frontDefault == frontDefault)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash(runtimeType, frontDefault); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$_SpriteCopyWith<_$_Sprite> get copyWith => - __$$_SpriteCopyWithImpl<_$_Sprite>(this, _$identity); - - @override - Map toJson() { - return _$$_SpriteToJson( - this, - ); - } -} - -abstract class _Sprite implements Sprite { - const factory _Sprite( - {@JsonKey(name: 'front_default') - required final String frontDefault}) = _$_Sprite; - - factory _Sprite.fromJson(Map json) = _$_Sprite.fromJson; - - @override - @JsonKey(name: 'front_default') - String get frontDefault; - @override - @JsonKey(ignore: true) - _$$_SpriteCopyWith<_$_Sprite> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/examples/pokeapi_functional/pubspec.yaml b/examples/pokeapi_functional/pubspec.yaml deleted file mode 100644 index 7423846f..00000000 --- a/examples/pokeapi_functional/pubspec.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: pokeapi_functional -description: Functional Programming using fpdart. Fetch and display pokemon from pokeApi. -publish_to: "none" - -version: 1.0.0+1 - -environment: - sdk: ">=2.19.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - - http: ^0.13.5 - hooks_riverpod: ^2.3.6 - flutter_hooks: ^0.18.6 - freezed: ^2.3.2 - fpdart: - path: ../../packages/fpdart - json_annotation: ^4.8.0 - riverpod_annotation: ^2.1.1 - -dev_dependencies: - flutter_test: - sdk: flutter - freezed_annotation: ^2.2.0 - build_runner: ^2.4.1 - json_serializable: ^6.6.1 - riverpod_generator: ^2.2.1 - -flutter: - uses-material-design: true diff --git a/examples/pokeapi_functional/web/favicon.png b/examples/pokeapi_functional/web/favicon.png deleted file mode 100644 index 8aaa46ac..00000000 Binary files a/examples/pokeapi_functional/web/favicon.png and /dev/null differ diff --git a/examples/pokeapi_functional/web/icons/Icon-192.png b/examples/pokeapi_functional/web/icons/Icon-192.png deleted file mode 100644 index b749bfef..00000000 Binary files a/examples/pokeapi_functional/web/icons/Icon-192.png and /dev/null differ diff --git a/examples/pokeapi_functional/web/icons/Icon-512.png b/examples/pokeapi_functional/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48d..00000000 Binary files a/examples/pokeapi_functional/web/icons/Icon-512.png and /dev/null differ diff --git a/examples/pokeapi_functional/web/index.html b/examples/pokeapi_functional/web/index.html deleted file mode 100644 index 1734d474..00000000 --- a/examples/pokeapi_functional/web/index.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - pokeapi_functional - - - - - - - diff --git a/examples/pokeapi_functional/web/manifest.json b/examples/pokeapi_functional/web/manifest.json deleted file mode 100644 index 98773063..00000000 --- a/examples/pokeapi_functional/web/manifest.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "pokeapi_functional", - "short_name": "pokeapi_functional", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - } - ] -} diff --git a/examples/read_write_file/.gitignore b/examples/read_write_file/.gitignore deleted file mode 100644 index 570e1df8..00000000 --- a/examples/read_write_file/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.dart_tool/ -.packages -pubspec.lock - -# Generated files -**.g.dart -.idea/ \ No newline at end of file diff --git a/examples/read_write_file/assets/source_eng.txt b/examples/read_write_file/assets/source_eng.txt deleted file mode 100644 index 05fecd25..00000000 --- a/examples/read_write_file/assets/source_eng.txt +++ /dev/null @@ -1,8 +0,0 @@ -This page collects information about Giulianova Calcio in the official competitions of the 1982-1983 season. -A fossil group of galaxies consists of a gigantic elliptical galaxy resulting from the fusion of the galaxies that originally formed the group. -Born and designed for distribution in cinemas, it enhances the artistic and dramaturgical aspect, often with particular virtuosity in both photography and especially in the screenplay, editing and critical and authoritative analysis of content. -This position is represented and uniquely identified by a series of alphanumeric symbols, a code called ‘location marking’ and identified in precise ways. -The capital of the state itself bears the name Bihar. -In the 97-98 season the first Czech division changed its name from 1. -On 21 December 1944, a "National Council" was formed in Debrecen with the approval of the Soviet Union and the participation of some members of the Hungarian Communist Party, such as Ernő Gerő, László Rajk and later Mátyás Rákosi. -It was given as a wife in 1447 to Duke John II of Bourbon. \ No newline at end of file diff --git a/examples/read_write_file/assets/source_ita.txt b/examples/read_write_file/assets/source_ita.txt deleted file mode 100644 index d8c53cbb..00000000 --- a/examples/read_write_file/assets/source_ita.txt +++ /dev/null @@ -1,8 +0,0 @@ -Questa pagina raccoglie le informazioni riguardanti il Giulianova Calcio nelle competizioni ufficiali della stagione 1982-1983. -Un gruppo fossile di galassie è costituito da una gigantesca galassia ellittica risultato della fusione delle galassie che originariamente formavano il gruppo. -Nato e pensato per la distribuzione nei cinema, esalta l'aspetto artistico e drammaturgico, spesso con particolare virtuosismo sia nella fotografia che soprattutto nella sceneggiatura, nel montaggio e nell'analisi critica e autoriale dei contenuti. -Tale posizione è rappresentata e individuata, in modo univoco, da una serie di simboli alfanumerici, un codice chiamato «segnatura di collocazione» e individuato secondo precise modalità. -La stessa capitale dello stato porta il nome di Bihar. -Nella stagione 97-98 la prima divisione ceca cambia nome da 1. -Il 21 dicembre 1944, un "Consiglio nazionale" si costituì a Debrecen con l'approvazione dell'Unione Sovietica e la partecipazione di alcuni membri del Partito Comunista Ungherese, come Ernő Gerő, László Rajk e più tardi Mátyás Rákosi. -Venne data in moglie nel 1447 al duca Giovanni II di Borbone. \ No newline at end of file diff --git a/examples/read_write_file/main.dart b/examples/read_write_file/main.dart deleted file mode 100644 index a1d364ff..00000000 --- a/examples/read_write_file/main.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'dart:io'; - -import 'package:fpdart/fpdart.dart'; - -/** - * Read lines from a `.txt` file using [TaskEither] of fpdart. - * - * This application reads from two files containing english and italian sentences. - * It then uses `zip` to join the two resulting lists together in a `List<(String, String)>`. - * - * Finally, it uses `flatMap` and `foldLeft` to iterate over the sentences and search words from a predefined list (`searchWords`). - * At the end, we have a list of [FoundWord] containing all the sentences and words matched. - */ - -/// Store words and sentence in [FoundWord] class -class FoundWord { - final int index; - final String word; - final int wordIndex; - final String english; - final String italian; - const FoundWord( - this.index, - this.word, - this.wordIndex, - this.english, - this.italian, - ); -} - -/// Word to search in each sentence -const searchWords = ['that', 'and', 'for']; - -Iterable collectFoundWords( - Iterable<(String, String)> iterable, -) => - iterable.flatMapWithIndex( - (tuple, index) => searchWords.foldLeftWithIndex>( - [], - (acc, word, wordIndex) => - tuple.$2.toLowerCase().split(' ').contains(word) - ? [ - ...acc, - FoundWord( - index, - word, - wordIndex, - tuple.$2.replaceAll(word, '<\$>'), - tuple.$1, - ), - ] - : acc, - ), - ); - -void main() async { - final collectDoNotation = TaskEither>.Do( - (_) async { - final linesIta = await _(readFileAsync('./assets/source_ita.txt')); - final linesEng = await _(readFileAsync('./assets/source_eng.txt')); - final linesZip = linesIta.zip(linesEng); - return collectFoundWords(linesZip); - }, - ); - - final collectFlatMap = readFileAsync('./assets/source_ita.txt') - .flatMap( - (linesIta) => readFileAsync('./assets/source_eng.txt').map( - (linesEng) => linesIta.zip(linesEng), - ), - ) - .map(collectFoundWords); - - /// Read file async using [TaskEither] - /// - /// Since we are using [TaskEither], until we call the `run` method, - /// no actual reading is performed. - final task = collectDoNotation.match( - (l) => print(l), - (list) { - /// Print all the found [FoundWord] - list.forEach( - (e) => print( - '${e.index}, ${e.word}(${e.wordIndex}): ${e.english}_${e.italian}\n'), - ); - }, - ); - - /// Run the reading process - await task.run(); -} - -/// Read file content in `source` directory using [TaskEither] -/// -/// Since the operation may fail, initialize [TaskEither] using `tryCatch` -TaskEither> readFileAsync(String source) => - TaskEither.tryCatch( - () async => File(source).readAsLines(), - (error, stackTrace) => 'Error opening file $source: $error', - ); diff --git a/examples/read_write_file/pubspec.yaml b/examples/read_write_file/pubspec.yaml deleted file mode 100644 index 80ea3f86..00000000 --- a/examples/read_write_file/pubspec.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: fpdart_read_write_file -publish_to: none -version: 0.1.0 -homepage: https://www.sandromaglione.com/ -repository: https://github.com/SandroMaglione/fpdart -description: Example of Functional programming in Dart and Flutter using fpdart. Read and write local text file. -author: Maglione Sandro - -environment: - sdk: ">=3.0.0 <4.0.0" - -dependencies: - fpdart: - path: ../../packages/fpdart - -dev_dependencies: - lint: ^1.5.3 diff --git a/packages/fpdart/CHANGELOG.md b/packages/fpdart/CHANGELOG.md index 73c07b15..0d975ce1 100644 --- a/packages/fpdart/CHANGELOG.md +++ b/packages/fpdart/CHANGELOG.md @@ -1,3 +1,20 @@ +## v2.0.0-dev.3 - 4 April 2024 +- Added `Scope` +- `const` constructor for `None` + +## v2.0.0-dev.2 - 29 March 2024 +- Complete `Option` and `Either` API +- Execute `Effect` using `provide` (with `Null` as dependency) +- Fixed implementation of running `Effect` and catching `Cause` +- Added interruption (`Cause.Interrupted`) + - `Deferred` + - `Context` + - New methods (`raceAll`, `race`, `delay`, `sleep`, `timeout`) + +## v2.0.0-dev.1 - 23 March 2024 +- Initial preview release of `fpdart` v2 + - Refactoring to use `Effect` class + ## v1.1.0 - 13 August 2023 - Improved performance of some iterable based functions in `Iterable` and `Map` extension (thanks to [lrhn](https://github.com/lrhn) 🎉) diff --git a/packages/fpdart/README.md b/packages/fpdart/README.md index 7ed80a98..17cbcd04 100644 --- a/packages/fpdart/README.md +++ b/packages/fpdart/README.md @@ -6,11 +6,11 @@

-Functional programming in Dart and Flutter +Functional Effect System in Dart and Flutter (v2)

-All the main functional programming types and patterns fully documented, tested, and with examples +Functional Effect System fully documented, tested, and with examples, to write complex type-safe dart applications

@@ -35,11 +35,13 @@ All the main functional programming types and patterns fully documented<

+> 🏗️ Pre-release version of `fpdart v2` + ## Introduction -> **fpdart is fully documented. You do not need to have any previous experience with functional programming to start using `fpdart`. Give it a try!** +> **fpdart is fully documented. You do not need to have any previous experience with functional effect systems to start using `fpdart`. Give it a try!** -fpdart is inspired by [fp-ts](https://gcanti.github.io/fp-ts/), [cats](https://typelevel.org/cats/typeclasses.html#type-classes-in-cats), and [dartz](https://github.com/spebbe/dartz). +fpdart is inspired by [effect](https://www.effect.website/) and [dartz](https://github.com/spebbe/dartz). > Follow my [**Twitter**](https://twitter.com/SandroMaglione) for updates, or [subscribe to the newsletter](https://www.sandromaglione.com/newsletter) @@ -120,10 +122,8 @@ Interested in what `fpdart` is and how it came to be? ## 💻 Installation -```yaml -# pubspec.yaml -dependencies: - fpdart: ^1.1.0 +```shell +dart pub add fpdart:'v2.0.0-dev.3' ``` ## ✨ Examples @@ -499,6 +499,11 @@ In general, **any contribution or feedback is welcome** (and encouraged!). ## 📃 Versioning +- v2.0.0-dev.2 - 29 March 2024 +- v2.0.0-dev.1 - 23 March 2024 + +*** + - v1.1.0 - 13 August 2023 - **v1.0.0** - 26 July 2023 diff --git a/packages/fpdart/analysis_options.yaml b/packages/fpdart/analysis_options.yaml index 4701dcd9..d9d369f6 100644 --- a/packages/fpdart/analysis_options.yaml +++ b/packages/fpdart/analysis_options.yaml @@ -3,6 +3,7 @@ include: package:lints/recommended.yaml linter: rules: annotate_overrides: true + prefer_const_constructors: true analyzer: language: diff --git a/packages/fpdart/example/api_requests/try_catch_validation.dart b/packages/fpdart/example/api_requests/try_catch_validation.dart deleted file mode 100644 index 5cf6593d..00000000 --- a/packages/fpdart/example/api_requests/try_catch_validation.dart +++ /dev/null @@ -1,107 +0,0 @@ -import 'dart:convert'; - -import 'package:fpdart/fpdart.dart'; - -/// Example of API request with `fpdart` with validation -/// Source: https://github.com/SandroMaglione/fpdart/issues/50#issue-1372504529 - -/// Mock [Response] implementation -class Response { - final String body; - Response(this.body); -} - -/// Mock for `post` API request -Response post( - Uri uri, { - Map? headers, -}) => - Response(''); - -TaskEither request() => TaskEither.tryCatch( - () async { - final Response getPrice = await post( - Uri.parse("URL"), - headers: { - 'Content-Type': 'application/json; charset=UTF-8', - }, - ); - - final Map json = - jsonDecode(getPrice.body) as Map; - - if (!json.containsKey("pricing")) { - throw Exception("I don't have price"); - } - - return json["pricing"].toString(); - }, - (error, stackTrace) { - return error.toString(); - }, - ); - -/// Instead of placing all the request + validation inside `tryCatch` -/// we want to chain different [TaskEither] methods. -/// -/// This allows to create a pipeline where each step is responsible -/// for a specific purpose (request, extract parameters, validation). -/// -/// It's also important to implement a solid error reporting system, -/// ideally by adding our own [Error] class. -/// -/// Finally, in order for the request to be a **pure function** we want to -/// pass all the parameters as inputs to the function -typedef Pricing = String; - -abstract class RequestError { - String get message; -} - -class ApiRequestError implements RequestError { - final Object error; - final StackTrace stackTrace; - - ApiRequestError(this.error, this.stackTrace); - - @override - String get message => "Error in the API request"; -} - -class MissingPricingRequestError implements RequestError { - @override - String get message => "Missing pricing in API response"; -} - -TaskEither makeRequest(String url) => - TaskEither.tryCatch( - () async => post( - Uri.parse(url), - headers: { - 'Content-Type': 'application/json; charset=UTF-8', - }, - ), - (error, stackTrace) => ApiRequestError(error, stackTrace), - ); - -Map mapToJson(Response response) => - jsonDecode(response.body) as Map; - -TaskEither> mappingRequest(String url) => - makeRequest(url).map(mapToJson); - -TaskEither validationRequest(Map json) => - !json.containsKey("pricing") - ? TaskEither.left(MissingPricingRequestError()) - : TaskEither.of(json["pricing"].toString()); - -TaskEither requestTE(String url) => - makeRequest(url).map(mapToJson).flatMap(validationRequest); - -/// **Note**: Ideally we should not access `post`, `Uri.parse`, and `jsonDecode` inside the function. -/// -/// We should instead pass them as inputs to the function. This will allow to make the function -/// completely pure, without hidden dependencies (i.e. accessing variables in the global scope). -/// -/// Furthermore, doing this will help with testing, since we can provide our own mock -/// implementation of those function for testing purposes. diff --git a/packages/fpdart/example/do_notation/main.dart b/packages/fpdart/example/do_notation/main.dart deleted file mode 100644 index adec7179..00000000 --- a/packages/fpdart/example/do_notation/main.dart +++ /dev/null @@ -1,83 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -TaskEither getUsernameFromId(int id) => TaskEither.of('sandro'); -TaskEither getProfilePicture(String username) => - TaskEither.of('image'); -int getPictureWidth(String image) => 10; -TaskEither updatePictureWidth(int width) => TaskEither.of(true); - -Future getUsernameFromIdLinear(int id) async => 'sandro'; -Future getProfilePictureLinear(String username) async => 'image'; -int getPictureWidthLinear(String image) => 10; -Future updatePictureWidthLinear(int width) async => true; - -/// Linear (no fpdart) -Future changePictureSizeFromIdLinear(int id) async { - final username = await getUsernameFromIdLinear(id); - final image = await getProfilePictureLinear(username); - final width = getPictureWidthLinear(image); - return updatePictureWidthLinear(width); -} - -/// Chaining -TaskEither changePictureSizeFromId(int id) => - getUsernameFromId(id) - .flatMap((username) => getProfilePicture(username)) - .map((image) => getPictureWidth(image)) - .flatMap((width) => updatePictureWidth(width)); - -/// Do notation -TaskEither changePictureSizeFromIdDo(int id) => - TaskEither.Do( - (_) async { - final username = await _(getUsernameFromId(id)); - final image = await _(getProfilePicture(username)); - final width = getPictureWidth(image); - return _(updatePictureWidth(width)); - }, - ); - -/// [map]: Update value inside [Option] -Option map() => Option.of(10) - .map( - (a) => a + 1, - ) - .map( - (b) => b * 3, - ) - .map( - (c) => c - 4, - ); - -Option mapDo() => Option.Do((_) { - final a = _(Option.of(10)); - final b = a + 1; - final c = b * 3; - return c - 4; - }); - -/// [flatMap]: Chain [Option] -Option flatMap() => Option.of(10) - .flatMap( - (a) => Option.of(a + 1), - ) - .flatMap( - (b) => Option.of(b * 3), - ) - .flatMap( - (c) => Option.of(c - 4), - ); - -Option flatMapDo() => Option.Do((_) { - final a = _(Option.of(10)); - final b = _(Option.of(a + 1)); - final c = _(Option.of(b * 3)); - return _(Option.of(c - 4)); - }); - -/// [andThen]: Chain [Option] without storing its value -Option andThen() => Option.of(10).andThen(() => Option.of(20)); -Option andThenDo() => Option.Do((_) { - _(Option.of(10)); // Chain Option, but do not store the result - return 20; - }); diff --git a/packages/fpdart/example/logger/logger.dart b/packages/fpdart/example/logger/logger.dart deleted file mode 100644 index 9b195ab5..00000000 --- a/packages/fpdart/example/logger/logger.dart +++ /dev/null @@ -1,78 +0,0 @@ -enum Level { - verbose, - debug, - info, - warning, - error, - wtf, - nothing, -} - -class LogEvent { - final Level level; - final dynamic message; - final dynamic error; - final StackTrace? stackTrace; - - LogEvent(this.level, this.message, this.error, this.stackTrace); -} - -class OutputEvent { - final Level level; - final List lines; - - OutputEvent(this.level, this.lines); -} - -abstract class LogFilter { - bool shouldLog(LogEvent logEvent); -} - -abstract class LogPrinter { - List log(LogEvent logEvent); -} - -abstract class LogOutput { - void output(OutputEvent outputEvent); -} - -class Logger { - static Level level = Level.verbose; - final bool _active = true; - final LogFilter _filter; - final LogPrinter _printer; - final LogOutput _output; - - Logger(this._filter, this._printer, this._output); - - /// Log a message with [level]. - void log( - Level level, - dynamic message, [ - dynamic error, - StackTrace? stackTrace, - ]) { - if (!_active) { - throw ArgumentError('Logger has already been closed.'); - } else if (error != null && error is StackTrace) { - throw ArgumentError('Error parameter cannot take a StackTrace!'); - } else if (level == Level.nothing) { - throw ArgumentError('Log events cannot have Level.nothing'); - } - var logEvent = LogEvent(level, message, error, stackTrace); - - if (_filter.shouldLog(logEvent)) { - var output = _printer.log(logEvent); - - if (output.isNotEmpty) { - var outputEvent = OutputEvent(level, output); - try { - _output.output(outputEvent); - } catch (e, s) { - print(e); - print(s); - } - } - } - } -} diff --git a/packages/fpdart/example/logger/main.dart b/packages/fpdart/example/logger/main.dart deleted file mode 100644 index a6d1fec5..00000000 --- a/packages/fpdart/example/logger/main.dart +++ /dev/null @@ -1,121 +0,0 @@ -/// Convert `log` function from `logger` package -/// from Imperative to Functional code using `fpdart` -/// -/// Repository: https://github.com/leisim/logger -import 'package:fpdart/fpdart.dart'; - -import 'logger.dart'; - -class Logger { - static Level level = Level.verbose; - bool _active = true; - final LogFilter _filter; - final LogPrinter _printer; - final LogOutput _output; - Logger(this._filter, this._printer, this._output); - - /// Imperative (not-functional) code - /// - /// From https://github.com/leisim/logger/blob/6832ee0f5c430321f6a74dce99338b242861161d/lib/src/logger.dart#L104 - void log( - Level level, - dynamic message, [ - dynamic error, - StackTrace? stackTrace, - ]) { - if (!_active) { - throw ArgumentError('Logger has already been closed.'); - } else if (error != null && error is StackTrace) { - throw ArgumentError('Error parameter cannot take a StackTrace!'); - } else if (level == Level.nothing) { - throw ArgumentError('Log events cannot have Level.nothing'); - } - var logEvent = LogEvent(level, message, error, stackTrace); - - if (_filter.shouldLog(logEvent)) { - var output = _printer.log(logEvent); - - if (output.isNotEmpty) { - var outputEvent = OutputEvent(level, output); - try { - _output.output(outputEvent); - } catch (e, s) { - print(e); - print(s); - } - } - } - } -} - -/// Functional approach 💪 -/// ---------------------------------------------------------------- -/// Use [IOEither] to handle errors and avoid throwing exceptions 🔨 -/// -/// Use [Unit] instead of `void` to represent a function that returns nothing 🎭 -IOEither logFunctional({ - required Level level, - required dynamic message, - required dynamic error, - StackTrace? stackTrace, - - /// Add all external dependencies as input to make the function pure 🥼 - required bool active, - required LogFilter filter, - required LogPrinter printer, - required LogOutput output, -}) { - /// Handle errors using [Either] instead of throwing errors 💥 - if (!active) { - return IOEither.left('Logger has already been closed.'); - } else if (error != null && error is StackTrace) { - return IOEither.left('Error parameter cannot take a StackTrace!'); - } else if (level == Level.nothing) { - return IOEither.left('Log events cannot have Level.nothing'); - } - - /// Declare all the variables as `const` or `final` 🧱 - final logEvent = LogEvent(level, message, error, stackTrace); - - /// Make sure to handle all the cases using [Option] 🎉 - /// - /// Use the `identity` function to return the input parameter as it is - final shouldLogOption = Option.fromPredicate( - filter.shouldLog(logEvent), - identity, - ); - - /// Using [Option], you must specify both `true` and `false` cases 🌎 - return shouldLogOption.match( - /// Simply return a [Unit] in the else case 🎁 - () => IOEither.of(unit), - - /// Use another [Option] to evaluate `printer.log` - (_) => Option>.fromPredicate( - printer.log(logEvent), - (v) => v.isNotEmpty, - ).match( - /// Simply return a [Unit] in the else case 🎁 - () => IOEither.of(unit), - - (lines) { - /// All variables are `final` 🧱 - final outputEvent = OutputEvent(level, lines); - return IOEither.tryCatch( - () { - output.output(outputEvent); - - /// Return [Unit] 🎁 - return unit; - }, - (e, s) { - /// Return an error message 🔨 - /// - /// Do not `print`, it would make the function impure! 🤯 - return 'An error occurred: $e'; - }, - ); - }, - ), - ); -} diff --git a/packages/fpdart/example/main.dart b/packages/fpdart/example/main.dart index b046fff2..c93f5f84 100644 --- a/packages/fpdart/example/main.dart +++ b/packages/fpdart/example/main.dart @@ -1,124 +1,16 @@ import 'package:fpdart/fpdart.dart'; -void main() {} - -void overview() { - /// [Option] - const int? a = null; - final Option b = none(); - - /// You must manually handle missing values - int resultI = 0; - if (a != null) { - resultI = a * 2; - } - - /// No need to check for `null` - final resultF = b.getOrElse(() => 0) * 2; -} - -void imperativeVSfunctional() { - /// Sum elements of a list - const List list = [1, 2, 3, 4]; - - /// Imperative solution - int sumI = 0; - for (int i = 0; i < list.length; ++i) { - sumI = sumI + list[i]; - } - - /// Functional solution - final sumF = list.fold(0, (p, c) => p + c); - - /// Composability - /// Sum all elements of a list that are greater than 2 - /// Imperative solution - int sum2I = 0; - for (int i = 0; i < list.length; ++i) { - final value = list[i]; - if (value > 2) { - sum2I = sum2I + value; - } - } - - /// Functional solution - final sum2F = list.where((e) => e > 2).fold(0, (p, c) => p + c); - - /// Extreme example - /// - /// How can you achieve the same result with Imperative code? - /// Is it even possible? 🤷‍♂️ - final result = list - .where((e) => e > 2) - .concat([1, 2, 3]) - .drop(2) - .intersect([1, 2, 3]) - .map((e) => e * 2) - .take(3) - .first; -} - -void option() { - /// Create an instance of [Some] - final option = Option.of(10); - - /// Create an instance of [None] - final none = Option.none(); - - /// Map [int] to [String] - final map = option.map((a) => '$a'); - - /// Extract the value from [Option] - final value = option.getOrElse(() => -1); - - /// Pattern matching - final match = option.match( - () => print('None'), - (a) => print('Some($a)'), - ); - - /// Convert to [Either] - final either = option.toEither(() => 'missing'); - - /// Chain computations - final flatMap = option.flatMap((a) => Option.of(a + 10)); - - /// Return [None] if the function throws an error - final tryCatch = Option.tryCatch(() => int.parse('invalid')); -} - -void either() { - /// Create an instance of [Right] - final right = Either.of(10); - - /// Create an instance of [Left] - final left = Either.left('none'); - - /// Map the right value to a [String] - final mapRight = right.map((a) => '$a'); - - /// Map the left value to a [int] - final mapLeft = right.mapLeft((a) => a.length); - - /// Return [Left] if the function throws an error. - /// Otherwise return [Right]. - final tryCatch = Either.tryCatch( - () => int.parse('invalid'), - (e, s) => 'Error: $e', - ); - - /// Extract the value from [Either] - final value = right.getOrElse((l) => -1); - - /// Chain computations - final flatMap = right.flatMap((a) => Either.of(a + 10)); - - /// Pattern matching - final match = right.match( - (l) => print('Left($l)'), - (r) => print('Right($r)'), - ); - - /// Convert to [Option] - final option = right.toOption(); -} +typedef Env = ({String url, int seed}); +typedef Error = String; +typedef Success = int; + +final either = Right(10); +final option = Some(10); + +final effect = Effect.gen(($) async { + final eitherValue = $.sync(either); + final optionValue = $.sync(option); + final deferred = $.sync(Deferred.make().withEnv()); + final value = await $.async(deferred.wait()); + return eitherValue + optionValue; +}); diff --git a/packages/fpdart/example/screenshot_fpdart.png b/packages/fpdart/example/screenshot_fpdart.png index 4d120e5b..3ce61447 100644 Binary files a/packages/fpdart/example/screenshot_fpdart.png and b/packages/fpdart/example/screenshot_fpdart.png differ diff --git a/packages/fpdart/example/src/either/cast.dart b/packages/fpdart/example/src/either/cast.dart deleted file mode 100644 index f6dc0aca..00000000 --- a/packages/fpdart/example/src/either/cast.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -void main() { - int intValue = 10; - - /// Unhandled exception: type 'int' is not a subtype of type 'List' in type cast - final waitWhat = intValue as List; - final first = waitWhat.first; - print(first); - - /// Safe 🎯 - final wellYeah = Either>.safeCast( - intValue, - (dynamic value) => 'Not an List!', - ); - final firstEither = wellYeah.map((list) => list.first); - print(firstEither); - - /// Verify using `is` - dynamic locationJson = 0; - - if (locationJson is List) { - final first = locationJson.first; - print(first); - } -} diff --git a/packages/fpdart/example/src/either/chain_either.dart b/packages/fpdart/example/src/either/chain_either.dart deleted file mode 100644 index 0dca6499..00000000 --- a/packages/fpdart/example/src/either/chain_either.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -class Cart { - const Cart(); -} - -class User { - String get uid => ''; -} - -class Order { - const Order(); - factory Order.fromCart({required String userId, required Cart cart}) { - return Order(); - } -} - -class AuthRepository { - User? get currentUser { - return null; - } -} - -class CartRepository { - Cart fetchCart(String uid) => Cart(); - Future setCart(String uid, Cart cart) { - return Future.value(); - } -} - -class OrdersRepository { - Future addOrder(String uid, Order order) { - return Future.value(); - } -} - -final cartRepository = CartRepository(); -final authRepository = AuthRepository(); -final ordersRepository = OrdersRepository(); - -Future placeOrder() async { - /// Imperative try-catch code - /// Source: https://codewithandrea.com/articles/flutter-exception-handling-try-catch-result-type/#when-the-result-type-doesnt-work-well - try { - final uid = authRepository.currentUser!.uid; - // first await call - final cart = await cartRepository.fetchCart(uid); - final order = Order.fromCart(userId: uid, cart: cart); - // second await call - await ordersRepository.addOrder(uid, order); - // third await call - await cartRepository.setCart(uid, const Cart()); - } catch (e) { - // TODO: Handle exceptions from any of the methods above - } - - /// Same code using fpart and Functional programming - Either.fromNullable( - authRepository.currentUser?.uid, - () => 'Missing uid', - ).toTaskEither().flatMap( - (uid) => TaskEither.tryCatch( - () async => cartRepository.fetchCart(uid), - (_, __) => 'Error while fetching cart', - ) - .flatMap( - (cart) => TaskEither.tryCatch( - () async => ordersRepository.addOrder( - uid, - Order.fromCart( - userId: uid, - cart: cart, - ), - ), - (_, __) => 'Error while adding order', - ), - ) - .flatMap( - (_) => TaskEither.tryCatch( - () async => cartRepository.setCart( - uid, - const Cart(), - ), - (_, __) => 'Error while setting cart', - ), - ), - ); -} diff --git a/packages/fpdart/example/src/either/either1.dart b/packages/fpdart/example/src/either/either1.dart deleted file mode 100644 index 50d76458..00000000 --- a/packages/fpdart/example/src/either/either1.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -int? getNoEither(int index, List list) { - if (index < 0 || index >= list.length) { - return null; - } - - return list[index]; -} - -Either getEither(int index, List list) { - if (index < 0 || index >= list.length) { - return Either.left('index not valid'); - } - - return Either.of(list[index]); -} - -int multiply(int value) => value * 2; - -void main() { - const list = [1, 2, 3]; - - /// Without [Either], you must check that the value is not null. - /// You must also remember to handle the case in which the value is null, - /// what would happen then? - final noEither = getNoEither(-1, list); - if (noEither != null) { - print(multiply(noEither)); - } - - /// With [Either], you are required to handle all cases. You will never run - /// in unspecified edge cases. - final withEither = getEither(-1, list); - withEither.match((l) => print(l), (r) => print(multiply(r))); -} diff --git a/packages/fpdart/example/src/either/overview.dart b/packages/fpdart/example/src/either/overview.dart deleted file mode 100644 index f22dd7ad..00000000 --- a/packages/fpdart/example/src/either/overview.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -/// Don't do that! ⚠ -int divideI(int x, int y) => x ~/ y; // this will throw if y == 0 - -/// Error handling without exceptions using [Either] 🎉 -Either divideF(int x, int y) { - if (y == 0) { - return left('Cannot divide by 0'); - } - return right(x ~/ y); -} - -/// Error handling with exceptions using [Either] 🎉 -Either divide2F(int x, int y) { - /// Easy way with caveat: first param type 'object' due to dart limitation - return Either.tryCatch(() => x ~/ y, (o, s) => o.toString()); -} - -void main() { - /// Create an instance of [Right] - final right = Either.of(10); - - /// Create an instance of [Left] - final left = Either.left('none'); - - /// Map the right value to a [String] - final mapRight = right.map((a) => '$a'); - - /// Map the left value to a [int] - final mapLeft = right.mapLeft((a) => a.length); - - /// Return [Left] if the function throws an error. - /// Otherwise return [Right]. - final tryCatch = Either.tryCatch( - () => int.parse('invalid'), - (e, s) => 'Error: $e', - ); - - /// Extract the value from [Either] - final value = right.getOrElse((l) => -1); - - /// Chain computations - final flatMap = right.flatMap((a) => Either.of(a + 10)); - - /// Pattern matching - final match = right.match( - (l) => print('Left($l)'), - (r) => print('Right($r)'), - ); - - /// or use Dart's pattern matching as well 🤝 - final dartMatch = switch (right) { - Left(value: final l) => 'Left($l)', - Right(value: final r) => 'Right($r)', - }; - - /// Convert to [Option] - final option = right.toOption(); -} diff --git a/packages/fpdart/example/src/either/shopping/functional.dart b/packages/fpdart/example/src/either/shopping/functional.dart deleted file mode 100644 index 75a519e0..00000000 --- a/packages/fpdart/example/src/either/shopping/functional.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -class Market { - const Market(); - - // I want to buy a Banana, an Apple, and a Pear. If either one - // of these is missing, I will not but anything 😒 - Either buyBanana() => getRandomEither('🍌', "We got no 🍌"); - Either buyApple() => getRandomEither('🍎', "We got no 🍎"); - Either buyPear() => getRandomEither('🍐', "We got no 🍐"); - - Either buyAmount() => - getRandomEither(randomInt(1, 10).run(), "Empty 💁🏼‍♂️"); -} - -Either getRandomEither(R right, L left) => randomBool - .map>( - (isValid) => isValid ? Either.of(right) : Either.left(left), - ) - .run(); - -// I go shopping in the Shopping Center. If it is closed, then -// I will go to the Local Market (which is always open 🥇). -Either goToShoppingCenter() => - getRandomEither(const Market(), "Shopping center closed ☝️"); -Either goToLocalMarket() => Either.of(const Market()); - -// Combine all the instructions and go shopping! 🛒 -String goShopping() => goToShoppingCenter() - .alt(goToLocalMarket) - .flatMap( - (market) => market.buyBanana().flatMap( - (banana) => market.buyApple().flatMap( - (apple) => market.buyPear().flatMap( - (pear) => Either.of('Shopping: $banana, $apple, $pear'), - ), - ), - ), - ) - .getOrElse(identity); - -// Combine all the instructions and go shopping! 🛒 -String goShoppingDo() => Either.Do( - (_) { - final market = _(goToShoppingCenter().alt(goToLocalMarket)); - final amount = _(market.buyAmount()); - - final banana = _(market.buyBanana()); - final apple = _(market.buyApple()); - final pear = _(market.buyPear()); - - return 'Shopping: $banana, $apple, $pear'; - }, - ).getOrElse(identity); - -// Combine all the instructions and go shopping! 🛒 -String goShoppingDoFlatMap() => goToShoppingCenter() - .alt(goToLocalMarket) - .flatMap( - /// Not required types here, since [Left] inferred from chain, - /// and [Right] from the return type of `Do` - (market) => Either.Do((_) { - final banana = _(market.buyBanana()); - final apple = _(market.buyApple()); - final pear = _(market.buyPear()); - return 'Shopping: $banana, $apple, $pear'; - }), - ) - .getOrElse(identity); - -void main() { - for (int i = 0; i < 100; i++) { - final shopping = goShopping(); - print(shopping); - } - - for (int i = 0; i < 100; i++) { - final shopping = goShoppingDo(); - print('[Do]: $shopping'); - } -} diff --git a/packages/fpdart/example/src/function/const_f.dart b/packages/fpdart/example/src/function/const_f.dart deleted file mode 100644 index 3bdc3816..00000000 --- a/packages/fpdart/example/src/function/const_f.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -void main() { - final c = constF(10); - print(c('none')); // -> 10 - print(c('any')); // -> 10 - print(c(112.12)); // -> 10 -} diff --git a/packages/fpdart/example/src/function/curry.dart b/packages/fpdart/example/src/function/curry.dart deleted file mode 100644 index c0dd7655..00000000 --- a/packages/fpdart/example/src/function/curry.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -int sum(int param1, int param2) => param1 + param2; - -double sumMultiplyDivide(int param1, int param2, int param3, int param4) => - (param1 + param2) * param3 / param4; - -void main() { - /// Convert a function with 2 parameters to a function that - /// takes the first parameter and returns a function that takes - /// the seconds parameter. - final sumCurry = sum.curry; - final sumBy2 = sumCurry(2); - final sumBy10 = sumCurry(10); - print(sumBy2(10)); - print(sumBy10(2)); - - /// Same as above but with 4 parameters. - final sumMultiplyDivideCurry = sumMultiplyDivide.curryAll; - final sumBy5 = sumMultiplyDivideCurry(5); - final multiplyBy2 = sumBy5(2); - final divideBy3 = multiplyBy2(3); - print(divideBy3(10)); - print(sumMultiplyDivideCurry(5)(2)(3)(10)); - - /// Using the extension - final sumBy2Extension = sum.curry(2); - final sumBy10Extension = sum.curry(10); - print(sumBy2Extension(10)); - print(sumBy10Extension(2)); - - final fourParamsCurry = sumMultiplyDivide.curryAll; - final fourParamsUncurry = fourParamsCurry.uncurry; -} diff --git a/packages/fpdart/example/src/function/identity.dart b/packages/fpdart/example/src/function/identity.dart deleted file mode 100644 index c8e44c26..00000000 --- a/packages/fpdart/example/src/function/identity.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -Future main() async { - final either = Either.of(10); - - /// Without using `identity`, you must write a function to return - /// the input parameter `(l) => l`. - final noId = either.match((l) => l, (r) => '$r'); - - /// Using `identity`/`id`, the function just returns its input parameter. - final withIdentity = either.match(identity, (r) => '$r'); - - /// Using `identityFuture`/`idFuture`, the function just returns its input - /// parameter, wrapped in `Future.value`. - final withIdentityFuture = await either.match( - identityFuture, - (r) async => '$r', - ); -} diff --git a/packages/fpdart/example/src/io/overview.dart b/packages/fpdart/example/src/io/overview.dart deleted file mode 100644 index 070911dd..00000000 --- a/packages/fpdart/example/src/io/overview.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -Future main() async { - /// Create instance of [IO] from a value - final IO io = IO.of(10); - - /// Create instance of [IO] from a sync function - final ioRun = IO(() => 10); - - /// Map [int] to [String] - final IO map = io.map((a) => '$a'); - - /// Extract the value inside [IO] by running its function - final int value = io.run(); - - /// Chain another [IO] based on the value of the current [IO] - final flatMap = io.flatMap((a) => IO.of(a + 10)); -} diff --git a/packages/fpdart/example/src/list/fold.dart b/packages/fpdart/example/src/list/fold.dart deleted file mode 100644 index e53af715..00000000 --- a/packages/fpdart/example/src/list/fold.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -void main() { - const list = [1, 2, 3]; - - print('--- Visualize fold left'); - final fl = list.foldLeft(0, (b, t) { - print("([$b] - [$t])"); - return b - t; - }); - print('== $fl'); - - print('--- Visualize fold right'); - final fr = list.foldRight(0, (b, t) { - print("([$b] - [$t])"); - return b - t; - }); - print('== $fr'); - - print('--- Visualize fold left with index'); - final fli = list.foldLeftWithIndex(0, (b, t, i) { - print("([$b] - [$t] - [$i])"); - return b - t - i; - }); - print('== $fli'); - - print('--- Visualize fold right with index'); - final fri = list.foldRightWithIndex(0, (b, t, i) { - print("([$b] - [$t] - [$i])"); - return b - t - i; - }); - print('== $fri'); -} diff --git a/packages/fpdart/example/src/list/overview.dart b/packages/fpdart/example/src/list/overview.dart deleted file mode 100644 index 3d811213..00000000 --- a/packages/fpdart/example/src/list/overview.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -void main() { - /// Dart: `1` - [1, 2, 3, 4].first; - - /// fpdart: `Some(1)` - [1, 2, 3, 4].head; - - /// Dart: Throws a [StateError] ⚠️ - [].first; - - /// fpdart: `None()` - [].head; -} diff --git a/packages/fpdart/example/src/list/zip.dart b/packages/fpdart/example/src/list/zip.dart deleted file mode 100644 index 71031c77..00000000 --- a/packages/fpdart/example/src/list/zip.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -void main() { - final list1 = ['a', 'b']; - final list2 = [1, 2]; - final zipList = list1.zip(list2); - print(zipList); // -> [(a, 1), (b, 2)] -} diff --git a/packages/fpdart/example/src/map/overview.dart b/packages/fpdart/example/src/map/overview.dart deleted file mode 100644 index 05e21e88..00000000 --- a/packages/fpdart/example/src/map/overview.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -void main() { - final d1 = DateTime(2001, 1, 1); - final d2 = DateTime(2001, 1, 2); - - /// Use `eq` based on the `DateTime` year to upsert in the map. - /// - /// The first date `d1` will be overwritten by the second date `d2`, - /// since the year is the same. - final map = {} - .upsertAt( - Eq.dateEqYear, - d1, - 1, - ) - .upsertAt( - Eq.dateEqYear, - d2, - 2, - ); - - print(map); // {2001-01-02 00:00:00.000: 2} -} diff --git a/packages/fpdart/example/src/option/cheat_sheet.md b/packages/fpdart/example/src/option/cheat_sheet.md deleted file mode 100644 index b208bb60..00000000 --- a/packages/fpdart/example/src/option/cheat_sheet.md +++ /dev/null @@ -1,120 +0,0 @@ -# `Option` Cheat Sheet 👀 - -```dart -[_] -> None -[🍌] -> Some(🍌) - -🤷‍♂️ -> null -💥 -> Exception -``` - -## Constructors - -```dart -some(🍌) -> [🍌] -none() -> [_] - - 👆 same as 👇 - -Option.of(🍌) -> [🍌] -Option.none() -> [_] -``` - -```dart -optionOf(🤷‍♂️) -> [_] -optionOf(🍌) -> [🍌] - - 👆 same as 👇 - -Option.fromNullable(🤷‍♂️) -> [_] -Option.fromNullable(🍌) -> [🍌] -``` - -```dart -option(🍌, (b) => b == 🍌) -> [🍌] -option(🍌, (b) => b == 🍎) -> [_] - - 👆 same as 👇 - -Option.fromPredicate(🍌, (b) => b == 🍌) -> [🍌] -Option.fromPredicate(🍌, (b) => b == 🍎) -> [_] -``` - -```dart -Option.tryCatch(() => 🍌) -> [🍌] -Option.tryCatch(() => 💥) -> [_] -``` - -```dart -Option.flatten([ [🍌] ]) -> [🍌] -``` - -## Methods - -### `match` - -```dart -[🍌].match((🍌) => 🍌 * 2, () => 🍎) -> 🍌🍌 - -[_].match((🍌) => 🍌 * 2, () => 🍎) -> 🍎 -``` - -### `getOrElse` - -```dart -[🍌].getOrElse(() => 🍎) -> 🍌 - -[_].getOrElse(() => 🍎) -> 🍎 - - 👆 same as 👇 - -[🍌].match((🍌) => 🍌, () => 🍎) -``` - -### `map` - -```dart -[🥚].map((🥚) => 👨‍🍳(🥚)) -> [🍳] - -[_].map((🥚) => 👨‍🍳(🥚)) -> [_] -``` - -### `alt` - -```dart -[🍌].alt(() => [🍎]) -> [🍌] - -[_].alt(() => [🍎]) -> [🍎] -``` - -### `andThen` - -```dart -[🍌].andThen(() => [🍎]) -> [🍎] - -[_].andThen(() => [🍎]) -> [_] -``` - -### `flatMap` - -```dart -[😀].flatMap( - (😀) => [👻(😀)] - ) -> [😱] - -[😀].flatMap( - (😀) => [👻(😀)] - ).flatMap( - (😱) => [👨‍⚕️(😱)] - ) -> [🤕] - -[😀].flatMap( - (😀) => [_] - ).flatMap( - (_) => [👨‍⚕️(_)] - ) -> [_] - -[_].flatMap( - (😀) => [👻(😀)] - ) -> [_] -``` diff --git a/packages/fpdart/example/src/option/get-price/functional.dart b/packages/fpdart/example/src/option/get-price/functional.dart deleted file mode 100644 index 8932094f..00000000 --- a/packages/fpdart/example/src/option/get-price/functional.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -Option getPrice(String productName) { - if (productName.length > 6) { - return none(); - } - - return some(productName.length); -} - -void main() { - final price = getPrice('my product name'); - price.match( - () { - print('Sorry, no product found!'); - }, - (a) { - print('Total price is: $price'); - }, - ); -} diff --git a/packages/fpdart/example/src/option/get-price/non_functional.dart b/packages/fpdart/example/src/option/get-price/non_functional.dart deleted file mode 100644 index 1d1834e9..00000000 --- a/packages/fpdart/example/src/option/get-price/non_functional.dart +++ /dev/null @@ -1,16 +0,0 @@ -int? getPrice(String productName) { - if (productName.length > 6) { - return null; - } - - return productName.length; -} - -void main() { - final price = getPrice('my product name'); - if (price == null) { - print('Sorry, no product found!'); - } else { - print('Total price is: $price'); - } -} diff --git a/packages/fpdart/example/src/option/nullable/option_nullable.dart b/packages/fpdart/example/src/option/nullable/option_nullable.dart deleted file mode 100644 index fef3765b..00000000 --- a/packages/fpdart/example/src/option/nullable/option_nullable.dart +++ /dev/null @@ -1,64 +0,0 @@ -// ignore_for_file: unchecked_use_of_nullable_value, undefined_getter, unnecessary_null_comparison -import 'package:fpdart/fpdart.dart'; -import 'package:glados/glados.dart'; - -int doSomething(String str) => str.length + 10 * 2; -int doSomethingElse(int number) => number + 10 * 2; - -void main(List args) { - int? nullableInt = 10; - if (nullableInt == null) { - print("Missing ‼️"); - } else { - print("Found $nullableInt 🎯"); - } - - /// 👆 Exactly the same as 👇 - - Option optionInt = Option.of(10); - optionInt.match(() { - print("Missing ‼️"); - }, (t) { - print("Found $nullableInt 🎯"); - }); - - /// Null safety and `Option` save you from `null` 🚀 - String? str = Random().nextBool() ? "string" : null; - Option optionStr = Random().nextBool() ? some("string") : none(); - - /// ⛔️ The property 'toLowerCase' can't be unconditionally accessed because the receiver can be 'null'. - str.toLowerCase; - - /// ⛔️ The getter 'toLowerCase' isn't defined for the type 'Option'. - optionStr.toLowerCase; - - /// Option has methods that makes it more powerful (chain methods) ⛓ - String? strNullable = Random().nextBool() ? "string" : null; - Option optionNullable = some("string"); - - /// Declarative API: more readable and composable 🎉 - Option optionIntNullable = optionNullable - .map(doSomething) - .alt(() => some(20)) - .map(doSomethingElse) - .flatMap((t) => some(t / 2)); - - /// Not really clear what is going on here 🤔 - double? intNullable = (strNullable != null - ? doSomethingElse(doSomething(strNullable)) - : doSomethingElse(20)) / - 2; - - if (optionNullable.isSome()) { - /// Still type `Option`, not `Some` 😐 - optionIntNullable; - } - - if (strNullable != null) { - /// This is now `String` 🤝 - strNullable; - } - - List? list = Random().nextBool() ? [1, 2, 3, 4] : null; - list.map((e) => /** What type is `e`? 😐 */ null); -} diff --git a/packages/fpdart/example/src/option/nullable/overview.dart b/packages/fpdart/example/src/option/nullable/overview.dart deleted file mode 100644 index 102d7c2d..00000000 --- a/packages/fpdart/example/src/option/nullable/overview.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:math'; - -import 'package:fpdart/fpdart.dart'; - -int? nullable() => Random().nextBool() ? 10 : null; - -String takesNullable(int? nullInt) => "$nullInt"; - -void main(List args) { - int noNull = 10; - int? canBeNull = nullable(); - - /// `bool` - final noNullIsEven = noNull.isEven; - - /// final canBeNullIsEven = canBeNull.isEven; ⛔️ - - /// `bool?` - final canBeNullIsEven = canBeNull?.isEven; - - /// ☑️ - takesNullable(canBeNull); - - /// ☑️ - takesNullable(noNull); - - /// ☑️ - noNull.abs(); - - /// ☑️ - canBeNull?.abs(); - - Option optionInt = Option.of(10); - int? nullInt = nullable(); - - nullInt?.abs(); - optionInt.map((t) => t.abs()); - - nullInt?.isEven; - optionInt.map((t) => t.isEven); - - takesNullable(nullInt); - - /// takesNullable(optionInt); ⛔️ - takesNullable(optionInt.toNullable()); -} diff --git a/packages/fpdart/example/src/option/option1.dart b/packages/fpdart/example/src/option/option1.dart deleted file mode 100644 index 65cc871e..00000000 --- a/packages/fpdart/example/src/option/option1.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -void printString(String str) { - print(str); -} - -void main() { - final String? str = 'name'; - - /// Error: The argument type 'String?' can't be assigned to the parameter type 'String' - // printString(str); - - /// With dart null-safety, you must check that the value is not null - /// before calling the function - /// - /// What will happen if the value is `null` instead? - /// You are not required to handle such case, which can lead to errors! - if (str != null) { - printString(str); - } - - final Option mStr = Option.of('name'); - - /// Using [Option] you are required to specify every possible case. - /// The type system helps you to find and define edge-cases and avoid errors. - mStr.match( - () => print('I have no string to print 🤷‍♀️'), - printString, - ); -} diff --git a/packages/fpdart/example/src/option/option2.dart b/packages/fpdart/example/src/option/option2.dart deleted file mode 100644 index a4f6d818..00000000 --- a/packages/fpdart/example/src/option/option2.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -double sumToDouble(int a, int b) => (a + b).toDouble(); - -void main() { - final a = Option.of(10); - final b = Option.of(20); - - /// `map` takes one parameter [int] and returns `sumToDouble`. - /// We therefore have a function inside a [Option] that we want to - /// apply to another value! - final Option map = a.map( - (a) => (int b) => sumToDouble(a, b), - ); - - /// Using `ap`, we get the final `Option` that we want 🚀 - final result = b.ap(map); -} diff --git a/packages/fpdart/example/src/option/option3.dart b/packages/fpdart/example/src/option/option3.dart deleted file mode 100644 index 5e1637e9..00000000 --- a/packages/fpdart/example/src/option/option3.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -int? stringToIntNull(String a) { - if (a.isNotEmpty) { - return a.length; - } else { - return null; - } -} - -double? intToDoubleNull(int a) { - if (a != 0) { - return a / 2; - } else { - return null; - } -} - -Option stringToInt(String a) => Option.fromPredicateMap( - a, - (str) => str.isNotEmpty, - (str) => str.length, - ); - -Option intToDouble(int a) => - Option.fromPredicateMap(a, (v) => v != 0, (v) => v / 2); - -void main() { - /// Using `null`, you are required to check that the value is not - /// `null` every time you call a function. - /// - /// Furthermore, you left unspecified what will happen when one of the - /// values is a `null` 🤦‍♂️ - const aNull = 'name'; - final intNull = stringToIntNull(aNull); - if (intNull != null) { - final doubleNull = intToDoubleNull(intNull); - } - - /// Using `flatMap`, you can forget that the value may be missing and just - /// use it as if it was there. - /// - /// In case one of the values is actually missing, you will get a [None] - /// at the end of the chain ⛓ - final a = Option.of('name'); - final Option result = a.flatMap( - (s) => stringToInt(s).flatMap( - (i) => intToDouble(i), - ), - ); -} diff --git a/packages/fpdart/example/src/option/overview.dart b/packages/fpdart/example/src/option/overview.dart deleted file mode 100644 index c1e103ff..00000000 --- a/packages/fpdart/example/src/option/overview.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -/// Don't do that! ⚠ -int divideI(int x, int y) => x ~/ y; // this will throw if y == 0 - -/// Error handling without exceptions using [Option] 🎉 -Option divideF(int x, int y) { - if (y == 0) { - return none(); - } - return some(x ~/ y); -} - -/// Error handling with exceptions using [Option] 🎉 -Option divide2F(int x, int y) => Option.tryCatch(() => x ~/ y); - -void main() { - // --- Initialize an Option 👇 --- // - const someInit = Some(10); - const noneInit = None(); - - final someInit2 = some(10); - final noneInit2 = none(); - - /// Create an instance of [Some] - final option = Option.of(10); - - /// Create an instance of [None] - final noneInit3 = Option.none(); - - /// If the predicate is `true`, then [Some], otherwise [None] - final predicate = Option.fromPredicate(10, (a) => a > 5); - - /// If no exception, then [Some], otherwise [None] - final tryCatchInit = Option.tryCatch(() => int.parse('10')); - - /// When the value is not `null`, then [Some], otherwise [None] - final nullable = Option.fromNullable(10); - - /// Map [int] to [String] - final map = option.map((a) => '$a'); - - /// Extract the value from [Option] - final value = option.getOrElse(() => -1); - - /// Pattern matching - final match = option.match( - () => print('None'), - (a) => print('Some($a)'), - ); - - /// or use Dart's pattern matching as well 🤝 - final dartMatch = switch (option) { - None() => 'None', - Some(value: final a) => 'Some($a)', - }; - - /// Convert to [Either] - final either = option.toEither(() => 'missing'); - - /// Chain computations - final flatMap = option.flatMap((a) => Option.of(a + 10)); - - /// Return [None] if the function throws an error - final tryCatch = Option.tryCatch(() => int.parse('invalid')); -} diff --git a/packages/fpdart/example/src/option/shopping/functional.dart b/packages/fpdart/example/src/option/shopping/functional.dart deleted file mode 100644 index d6d10293..00000000 --- a/packages/fpdart/example/src/option/shopping/functional.dart +++ /dev/null @@ -1,83 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -class Market { - const Market(); - - // I want to buy a Banana, an Apple, and a Pear. If either one - // of these is missing, I will not but anything 😒 - Option buyBanana() => getRandomOption('🍌'); - Option buyApple() => getRandomOption('🍎'); - Option buyPear() => getRandomOption('🍐'); - - Option buyAmount() => getRandomOption(randomInt(1, 10).run()); -} - -Option getRandomOption(T value) => randomBool - .map( - (isValid) => isValid ? some(value) : none(), - ) - .run(); - -// I go shopping in the Shopping Center. If it is closed, then -// I will go to the Local Market (which is always open 🥇). -Option goToShoppingCenter() => getRandomOption(const Market()); -Option goToLocalMarket() => some(const Market()); - -// Combine all the instructions and go shopping! 🛒 -String goShopping() => goToShoppingCenter() - .alt(goToLocalMarket) - .flatMap( - (market) => market.buyBanana().flatMap( - (banana) => market.buyApple().flatMap( - (apple) => market.buyPear().flatMap( - (pear) => Option.of('Shopping: $banana, $apple, $pear'), - ), - ), - ), - ) - .getOrElse( - () => 'I did not find 🍌 or 🍎 or 🍐, so I did not buy anything 🤷‍♂️', - ); - -// Combine all the instructions and go shopping! 🛒 -String goShoppingDo() => Option.Do( - (_) { - final market = _(goToShoppingCenter().alt(goToLocalMarket)); - final amount = _(market.buyAmount()); - - final banana = _(market.buyBanana()); - final apple = _(market.buyApple()); - final pear = _(market.buyPear()); - - return 'Shopping: $banana, $apple, $pear'; - }, - ).getOrElse( - () => 'I did not find 🍌 or 🍎 or 🍐, so I did not buy anything 🤷‍♂️', - ); - -// Combine all the instructions and go shopping! 🛒 -String goShoppingDoFlatMap() => goToShoppingCenter() - .alt(goToLocalMarket) - .flatMap( - (market) => Option.Do((_) { - final banana = _(market.buyBanana()); - final apple = _(market.buyApple()); - final pear = _(market.buyPear()); - return 'Shopping: $banana, $apple, $pear'; - }), - ) - .getOrElse( - () => 'I did not find 🍌 or 🍎 or 🍐, so I did not buy anything 🤷‍♂️', - ); - -void main() { - for (int i = 0; i < 100; i++) { - final shopping = goShopping(); - print(shopping); - } - - for (int i = 0; i < 100; i++) { - final shopping = goShoppingDo(); - print('[Do]: $shopping'); - } -} diff --git a/packages/fpdart/example/src/predicate/overview.dart b/packages/fpdart/example/src/predicate/overview.dart deleted file mode 100644 index af75530b..00000000 --- a/packages/fpdart/example/src/predicate/overview.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -bool isEven(int n) => n % 2 == 0; -bool isDivisibleBy3(int n) => n % 3 == 0; - -final isOdd = isEven.negate; -final isEvenAndDivisibleBy3 = isEven.and(isDivisibleBy3); -final isEvenOrDivisibleBy3 = isEven.or(isDivisibleBy3); -final isStringWithEvenLength = isEven.contramap((n) => n.length); diff --git a/packages/fpdart/example/src/pure_function.dart b/packages/fpdart/example/src/pure_function.dart deleted file mode 100644 index 7ba7c820..00000000 --- a/packages/fpdart/example/src/pure_function.dart +++ /dev/null @@ -1,41 +0,0 @@ -/// `Impure function` -/// -/// Modify input parameter -List modifyInput(List list) { - list.add(10); // <- Do not change input parameter 🙅‍♂️ - return list; -} - -var global = 10; - -/// `Impure function` -/// -/// Modify variable outside the scope of the function -int modifyGlobal(int a) { - global = global + a; // <- Do not change variable outside the function 🙅‍♂️ - return global; -} - -/// `Impure function` -/// -/// Side effects (Database, IO, API request) -int sideEffect(int a) { - print("Side effect"); // <- Do not introduce side effects 🙅‍♂️ - return global; -} - -/// `Impure function` -/// -/// Return `void`: Either the function does nothing, or a -/// side effect is guaranteed to be executed -void voidReturn(String str) { - print(str); // <- Either side effect, or nothing 🙅‍♂️ - return; -} - -/// `Impure function` -/// -/// Throw [Exception] (use [Option] or [Either] instead) -int throwException(int a) { - throw Exception(); // <- Do not throw 🙅‍♂️ -} diff --git a/packages/fpdart/example/src/reader/reader1.dart b/packages/fpdart/example/src/reader/reader1.dart deleted file mode 100644 index 6bb26e3c..00000000 --- a/packages/fpdart/example/src/reader/reader1.dart +++ /dev/null @@ -1,51 +0,0 @@ -/// Source: https://gist.github.com/ruizb/554c17afb9cd3dedc76706862a9fa035 -import 'package:fpdart/src/reader.dart'; - -/// Dependency -abstract class Printer { - String write(String message); -} - -class BoldPrinter implements Printer { - @override - String write(String message) => '$message'; -} - -class ItalicPrinter implements Printer { - @override - String write(String message) => '$message'; -} - -/// Try 1: Supply the dependency every time you call the function -String printing1(String name, Printer printer) => printer.write(name); - -/// Try 2: Hide the dependency by curring -String Function(Printer) printing2(String name) => - (Printer printer) => printer.write(name); - -/// Try 3: Using the [Reader] monad to hide the dependency completely -Reader printing3(String name) => Reader((r) => r.write(name)); - -void main() { - /// Required to pass [Printer] dependency, when all you would want is to - /// pass the `name` and get the result. - final String result1 = printing1('name', BoldPrinter()); - print(result1); // -> name - - /// Dependency on [Printer] hidden, but it is not possible to change - /// the result from `render2` after `printing2` has been called (for example using `map`). - final String Function(Printer) render2 = printing2('name'); - final String result2 = render2(BoldPrinter()); - print(result2); // -> name - - /// Dependency on [Printer] required only in the final call of `run`. - /// Before that you can change the value without bothering about the [Printer]. - final Reader render3 = printing3('name'); - final Reader map = render3.map((a) => a.length); - - /// Reader allows dependency injection - final String result3a = render3.run(BoldPrinter()); - final int result3b = map.run(ItalicPrinter()); - print(result3a); // -> name - print(result3b); // -> 11 -} diff --git a/packages/fpdart/example/src/reader/reader2.dart b/packages/fpdart/example/src/reader/reader2.dart deleted file mode 100644 index 90d97942..00000000 --- a/packages/fpdart/example/src/reader/reader2.dart +++ /dev/null @@ -1,49 +0,0 @@ -/// Source: https://gist.github.com/ruizb/554c17afb9cd3dedc76706862a9fa035 -import 'package:fpdart/src/reader.dart'; - -abstract class Dependency { - void logger(String message); - String get environment; -} - -class PrintLog implements Dependency { - @override - String get environment => 'Production'; - - @override - void logger(String message) { - print(message); - } -} - -/// Example 1: Without [Reader] -/// -/// We are required to pass [Dependency] between all the intermediate functions -/// (`b` and `a`), even if these functions do not use [Dependency]. Then just pass the -/// value to `c`. -int c(Dependency dependency) { - dependency.logger('Current environment: ${dependency.environment}'); - return 1; -} - -int b(Dependency dependency) => c(dependency) * 2; -int a(Dependency dependency) => b(dependency) + 1; - -/// Example 2: Using [Reader] -/// -/// Both `a` and `b` do not know about [Dependency]. The dependency is hidden -/// being the [Reader]. `a` and `b` just care about the value [int]. -Reader cReader() => Reader((dependency) { - dependency.logger('Current environment: ${dependency.environment}'); - return 1; - }); -Reader bReader() => cReader().map((a) => a * 2); -Reader aReader() => bReader().map((a) => a + 1); - -void main() { - final resultNoReader = a(PrintLog()); - print(resultNoReader); - - final resultWithReader = aReader().run(PrintLog()); - print(resultWithReader); -} diff --git a/packages/fpdart/example/src/reader_task_either/overview.dart b/packages/fpdart/example/src/reader_task_either/overview.dart deleted file mode 100644 index 1169079f..00000000 --- a/packages/fpdart/example/src/reader_task_either/overview.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -typedef Env = (int, String); -typedef Error = String; -typedef Success = String; - -void main(List args) async { - final rte = ReaderTaskEither.Do((_) async { - final a = 10; - final val = await _(ReaderTaskEither.fromReader( - Reader( - (env) => env.$1 + env.$2.length, - ), - )); - final env = await _(ReaderTaskEither.ask()); - final env2 = await _(ReaderTaskEither.asks((dep) => dep.$2)); - - return "$a and $val and $env and $env2"; - }); - - final result = await rte.run((30, "abc")); - print(result); -} diff --git a/packages/fpdart/example/src/state/state1.dart b/packages/fpdart/example/src/state/state1.dart deleted file mode 100644 index a007eafa..00000000 --- a/packages/fpdart/example/src/state/state1.dart +++ /dev/null @@ -1,57 +0,0 @@ -/// Source: http://www.learnyouahaskell.com/for-a-few-monads-more -import 'package:fpdart/src/state.dart'; -import 'package:fpdart/src/unit.dart'; - -/// [Stack] is an alias for [List]. -typedef Stack = List; - -const Stack stack = ['a', 'b', 'c']; - -/// Example Without State Monad -/// -/// We need to explicitly pass the state [Stack] every time we call `pop` or `push`. - -(String, Stack) pop(Stack s) => (s.last, s.sublist(0, s.length - 1)); - -(Unit, Stack) push(String value, Stack s) => (unit, [...s, value]); - -/// Example Using State Monad -/// -/// The global variable [Stack] is hidden using [State]. - -State popState() => State( - (s) => (s.last, s.sublist(0, s.length - 1)), - ); - -State pushState(String value) => State( - (s) => (unit, [...s, value]), - ); - -void main() { - // Without State Monad - final pop1NoState = pop(stack); - final push1NoState = push('d', pop1NoState.$2); - final pop2NoState = pop(push1NoState.$2); - print('No State'); - print(stack); - print('Pop'); - print(pop1NoState.$2); - print(pop1NoState.$1); - print("Push 'd'"); - print(push1NoState.$2); - print('Pop'); - print(pop2NoState.$2); - print(pop2NoState.$1); - - // Using State Monad - print('---'); - print('Using State'); - final withState = popState().execute( - pushState('d').execute( - popState().run(stack).$2, - ), - ); - final withState2 = popState()(pushState('d'))(popState()).run(stack); - print(withState); - print(withState2); -} diff --git a/packages/fpdart/example/src/state_async/state_async1.dart b/packages/fpdart/example/src/state_async/state_async1.dart deleted file mode 100644 index a44043c6..00000000 --- a/packages/fpdart/example/src/state_async/state_async1.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -Future add10(int previous) async => previous + 10; - -Future main() async { - final stateAsync = StateAsync( - (state) async => (unit, await add10(state)), - ); - - final result = await stateAsync.execute(10); - print(result); -} diff --git a/packages/fpdart/example/src/task/overview.dart b/packages/fpdart/example/src/task/overview.dart deleted file mode 100644 index 682885a9..00000000 --- a/packages/fpdart/example/src/task/overview.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -/// You must run one [Future] after the other, no way around this... -Future asyncI() { - return Future.value(10).then((value) => value * 10); -} - -/// No need of `async`, you decide when to run the [Future] ⚡ -Task asyncF() { - return Task(() async => 10).map((a) => a * 10); -} - -Future main() async { - /// Create instance of [Task] from a value - final Task task = Task.of(10); - - /// Create instance of [Task] from an async function - final taskRun1 = Task(() async => 10); - final taskRun2 = Task(() => Future.value(10)); - - /// Map [int] to [String] - final Task map = task.map((a) => '$a'); - - /// Extract the value inside [Task] by running its async function - final int value = await task.run(); - - /// Chain another [Task] based on the value of the current [Task] - final flatMap = task.flatMap((a) => Task.of(a + 10)); -} diff --git a/packages/fpdart/example/src/task/task_and_future.dart b/packages/fpdart/example/src/task/task_and_future.dart deleted file mode 100644 index 1678ced8..00000000 --- a/packages/fpdart/example/src/task/task_and_future.dart +++ /dev/null @@ -1,92 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -/// Helper functions ⚙️ (sync) -String addNamePrefix(String name) => "Mr. $name"; -String addEmailPrefix(String email) => "mailto:$email"; -String decodeName(int code) => "$code"; - -/// API functions 🔌 (async) -Future getUsername() => Future.value("Sandro"); -Future getEncodedName() => Future.value(10); - -Future getEmail() => Future.value("@"); - -Future sendInformation(String usernameOrName, String email) => - Future.value(true); - -Future withFuture() async { - late String usernameOrName; - late String email; - - try { - usernameOrName = await getUsername(); - } catch (e) { - try { - usernameOrName = decodeName(await getEncodedName()); - } catch (e) { - throw Exception("Missing both username and name"); - } - } - - try { - email = await getEmail(); - } catch (e) { - throw Exception("Missing email"); - } - - try { - final usernameOrNamePrefix = addNamePrefix(usernameOrName); - final emailPrefix = addEmailPrefix(email); - return await sendInformation(usernameOrNamePrefix, emailPrefix); - } catch (e) { - throw Exception("Error when sending information"); - } -} - -TaskEither withTask() => TaskEither.tryCatch( - getUsername, - (_, __) => "Missing username", - ) - .alt( - () => TaskEither.tryCatch( - getEncodedName, - (_, __) => "Missing name", - ).map( - decodeName, - ), - ) - .map( - addNamePrefix, - ) - .flatMap( - (usernameOrNamePrefix) => TaskEither.tryCatch( - getEmail, - (_, __) => "Missing email", - ) - .map( - addEmailPrefix, - ) - .flatMap( - (emailPrefix) => TaskEither.tryCatch( - () => sendInformation(usernameOrNamePrefix, emailPrefix), - (_, __) => "Error when sending information", - ), - ), - ); - -Task getTask() => Task(() async { - print("I am running [Task]..."); - return 10; - }); - -Future getFuture() async { - print("I am running [Future]..."); - return 10; -} - -void main() { - Task taskInt = getTask(); - Future futureInt = getFuture(); - - // Future taskRun = taskInt.run(); -} diff --git a/packages/fpdart/example/src/task_either/async_flat_map/data.dart b/packages/fpdart/example/src/task_either/async_flat_map/data.dart deleted file mode 100644 index 8cb51152..00000000 --- a/packages/fpdart/example/src/task_either/async_flat_map/data.dart +++ /dev/null @@ -1,9 +0,0 @@ -class Student { - final String name; - Student(this.name); -} - -class Course { - final String name; - Course(this.name); -} diff --git a/packages/fpdart/example/src/task_either/async_flat_map/failure.dart b/packages/fpdart/example/src/task_either/async_flat_map/failure.dart deleted file mode 100644 index 402a7456..00000000 --- a/packages/fpdart/example/src/task_either/async_flat_map/failure.dart +++ /dev/null @@ -1,5 +0,0 @@ -abstract class ApiFailure {} - -class StudentFailure implements ApiFailure {} - -class CourseFailure implements ApiFailure {} diff --git a/packages/fpdart/example/src/task_either/async_flat_map/main.dart b/packages/fpdart/example/src/task_either/async_flat_map/main.dart deleted file mode 100644 index c92fc1ee..00000000 --- a/packages/fpdart/example/src/task_either/async_flat_map/main.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import 'data.dart'; -import 'failure.dart'; -import 'student_repo.dart'; - -TaskEither> getStudents = TaskEither.tryCatch( - () => StudentRepo.getAllStudents(), - (_, __) => StudentFailure(), -); - -TaskEither> getCoursesOfStudents( - List studentList, -) => - TaskEither.tryCatch( - () => StudentRepo.getAllCourses(studentList), - (_, __) => CourseFailure(), - ); - -String logFailure(ApiFailure apiFailure) { - if (apiFailure is StudentFailure) { - return 'Error while fetching list of students'; - } else if (apiFailure is CourseFailure) { - return 'Error while fetching list of courses'; - } else { - throw UnimplementedError(); - } -} - -void main() async { - /// How to call `getCoursesOfStudents` only if students is `Right`? - /// - /// Type: `TaskEither>` - final taskEitherRequest = getStudents.flatMap(getCoursesOfStudents); - - /// In case of error map `ApiFailure` to `String` using `logFailure` - /// - /// Type: `TaskEither>` - final taskRequest = taskEitherRequest.mapLeft(logFailure); - - /// Run everything at the end! - /// - /// Type: `Either>` - final result = await taskRequest.run(); -} diff --git a/packages/fpdart/example/src/task_either/async_flat_map/student_repo.dart b/packages/fpdart/example/src/task_either/async_flat_map/student_repo.dart deleted file mode 100644 index 4de97f98..00000000 --- a/packages/fpdart/example/src/task_either/async_flat_map/student_repo.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'data.dart'; - -// ignore: avoid_classes_with_only_static_members -class StudentRepo { - static Future> getAllStudents() async => [ - Student("Juan"), - Student("Maria"), - ]; - - static Future> getAllCourses(List studentList) async => - [ - Course("Math"), - Course("Physics"), - ]; -} diff --git a/packages/fpdart/example/src/task_either/chain.dart b/packages/fpdart/example/src/task_either/chain.dart deleted file mode 100644 index 7bc71991..00000000 --- a/packages/fpdart/example/src/task_either/chain.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -typedef MessageResponse = String; -typedef AnalyticsResponse = int; - -TaskEither resendVerificationEmail = - TaskEither.of("done"); - -TaskEither registerAnalytics = TaskEither.of(1); - -Future main() async { - /** - * This will execute `resendVerificationEmail` - * - * If `resendVerificationEmail` is successful, then it will chain a call to `registerAnalytics` - * while still returning the result from `resendVerificationEmail` - */ - final taskEither = resendVerificationEmail.chainFirst( - (_) => registerAnalytics, - ); - - final result = await taskEither.run(); - print(result); // Right("done") -} diff --git a/packages/fpdart/example/src/task_either/finally.dart b/packages/fpdart/example/src/task_either/finally.dart deleted file mode 100644 index d1d92ce1..00000000 --- a/packages/fpdart/example/src/task_either/finally.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -Future apiRequestMock() => Future.value(10); - -/// Imperative code -/// -/// `try` - `catch` - `finally` -Future imperative() async { - try { - final response = await apiRequestMock(); - print(response); - } catch (e) { - print("Error: $e"); - } finally { - print("Complete!"); - } -} - -/// Functional code -/// -/// `tryCatch` -Future functional() async { - final task = TaskEither.tryCatch( - apiRequestMock, - (e, _) => "Error: $e", - ).match( - (l) { - print(l); - return unit; - }, - (r) { - print(r); - return unit; - }, - ).chainFirst( - (a) => Task( - () async { - print("Complete!"); - return unit; - }, - ), - ); - - task.run(); -} - -void main() { - imperative(); - functional(); -} diff --git a/packages/fpdart/example/src/task_either/overview.dart b/packages/fpdart/example/src/task_either/overview.dart deleted file mode 100644 index 5a7128dd..00000000 --- a/packages/fpdart/example/src/task_either/overview.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -/// From [Future] to [TaskEither] -Future imperative(String str) async { - try { - return int.parse(str); - } catch (e) { - return -1; // What does -1 means? 🤨 - } -} - -TaskEither functional(String str) { - return TaskEither.tryCatch( - () async => int.parse(str), - // Clear error 🪄 - (error, stackTrace) => "Parsing error: $error", - ); -} - -/// What error is that? What is [dynamic]? -Future asyncI() { - return Future.error('Some error!') - .then((value) => value * 10) - .catchError( - (dynamic error) { - print(error); - return 0; - }, - ); -} - -/// Handle all the errors easily ✨ -TaskEither asyncF() { - return TaskEither( - () async => left('Some error'), - ).map((r) => r * 10); -} - -// Methods 👇 - -TaskEither mapLeftExample(TaskEither taskEither) => - taskEither.mapLeft( - (string) => string.length, - ); - -TaskEither bimapExample(TaskEither taskEither) => - taskEither.bimap( - (string) => string.length, - (number) => number / 2, - ); - -TaskEither toTaskEitherExample(Either taskEither) => - taskEither.toTaskEither(); - -/// Chain [Either] to [TaskEither] -TaskEither binding = - TaskEither.of("String").bindEither(Either.of(20)); diff --git a/packages/fpdart/example/src/task_either/sync_to_async.dart b/packages/fpdart/example/src/task_either/sync_to_async.dart deleted file mode 100644 index 15bee753..00000000 --- a/packages/fpdart/example/src/task_either/sync_to_async.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -Future everythingIsFine(int a) async => a + 42; - -Future sendComplainRequest(String a) async => - '$a - What data is that!!!'; - -Either validate() => Either.of(10); - -void main() { - /// You have an [Either]. Now, suddenly a [Future] appears! - /// What do you do? - /// - /// You need to change the context, moving from a sync [Either] - /// to an async [TaskEither]! Simply use `toTaskEither`. - final eitherToTaskEither = validate() - .toTaskEither() - .flatMap( - (r) => TaskEither( - () async => Either.of( - await everythingIsFine(r), - ), - ), - ) - .orElse( - (l) => TaskEither( - () async => Either.left( - await sendComplainRequest(l), - ), - ), - ); -} diff --git a/packages/fpdart/example/src/task_option/future_task_option.dart b/packages/fpdart/example/src/task_option/future_task_option.dart deleted file mode 100644 index 62c87326..00000000 --- a/packages/fpdart/example/src/task_option/future_task_option.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -late Future?> example; - -final taskOp = TaskOption.flatten( - (TaskOption.fromTask( - Task?>( - () => example, - ).map( - (ex) => Option.fromNullable(ex).toTaskOption(), - ), - )), -); - -/// Using `Option.fromNullable`, the [Future] cannot fail -final taskOpNoFail = TaskOption>( - () async => Option.fromNullable(await example), -); - -/// Using `Option.fromNullable` when the [Future] can fail -final taskOpFail = TaskOption?>.tryCatch( - () => example, -).flatMap>( - (r) => Option.fromNullable(r).toTaskOption(), -); diff --git a/packages/fpdart/example/src/task_option/overview.dart b/packages/fpdart/example/src/task_option/overview.dart deleted file mode 100644 index 26f9ebda..00000000 --- a/packages/fpdart/example/src/task_option/overview.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -// Methods 👇 - -TaskOption toTaskOptionExample(Option taskOption) => - taskOption.toTaskOption(); - -void main() {} diff --git a/packages/fpdart/example/src/traverse/option.dart b/packages/fpdart/example/src/traverse/option.dart deleted file mode 100644 index c3ed45ce..00000000 --- a/packages/fpdart/example/src/traverse/option.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -void main() { - /// "a40" is invalid 💥 - final inputValues = ["10", "20", "30", "a40"]; - - /// Verify that all the values can be converted to [int] 🔐 - /// - /// If **any** of them is invalid, then the result is [None] 🙅‍♂️ - final traverseOption = inputValues.traverseOption( - (a) => Option.tryCatch( - /// If `a` does not contain a valid integer literal a [FormatException] is thrown - () => int.parse(a), - ), - ); - - print(traverseOption); -} diff --git a/packages/fpdart/example/src/traverse/sequnce_traverse.dart b/packages/fpdart/example/src/traverse/sequnce_traverse.dart deleted file mode 100644 index d063a8c6..00000000 --- a/packages/fpdart/example/src/traverse/sequnce_traverse.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -void main() { - final inputValues = ["10", "20", "30", "40"]; - - /// Using `traverse` = `map` + `sequence` 🪄 - final traverseOption = inputValues.traverseOption( - (a) => Option.tryCatch(() => int.parse(a)), - ); - - /// Using `sequence`, same as the above with `traverse` 🪄 - final sequenceOption = inputValues - .map((a) => Option.tryCatch(() => int.parse(a))) - .sequenceOption(); - - /// `Some([10, 20, 30, 40])` - Same ☑️ - print(traverseOption); - - /// `Some([10, 20, 30, 40])` - Same ☑️ - print(sequenceOption); -} diff --git a/packages/fpdart/example/src/typeclass/eq/eq1.dart b/packages/fpdart/example/src/typeclass/eq/eq1.dart deleted file mode 100644 index d2488f2a..00000000 --- a/packages/fpdart/example/src/typeclass/eq/eq1.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -class Parent { - final int value1; - final double value2; - const Parent(this.value1, this.value2); -} - -void main() { - /// Equality for values of type [Parent] based on their `value1` ([int]). - final eqParentInt = Eq.eqInt.contramap( - (p) => p.value1, - ); - - /// Equality for of type [Parent] based on their `value2` ([double]). - final eqParentDouble = Eq.eqDouble.contramap( - (p) => p.value2, - ); -} diff --git a/packages/fpdart/example/src/typeclass/order/order1.dart b/packages/fpdart/example/src/typeclass/order/order1.dart deleted file mode 100644 index a4b6e445..00000000 --- a/packages/fpdart/example/src/typeclass/order/order1.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -enum GreekLetter { alpha, beta, gama, delta } - -class _GreekLetterOrder extends Order { - const _GreekLetterOrder(); - - @override - int compare(GreekLetter a, GreekLetter b) => - _internalValue[a]! - _internalValue[b]!; - - static const _internalValue = { - GreekLetter.alpha: 1, - GreekLetter.beta: 2, - GreekLetter.gama: 3, - GreekLetter.delta: 4, - }; -} - -const greekLetterOrder = _GreekLetterOrder(); - -void main() { - const letter1 = GreekLetter.alpha; - const letter2 = GreekLetter.beta; - - final compare1 = greekLetterOrder.compare(letter1, letter2); - print(compare1); // -> -1 (alpha < beta) - - final compare2 = greekLetterOrder.compare(letter1, letter1); - print(compare2); // -> 0 (alpha == alpha) - - final compare3 = greekLetterOrder.compare(letter2, letter1); - print(compare3); // -> 1 (beta > alpha) -} diff --git a/packages/fpdart/example/src/typeclass/order/order2.dart b/packages/fpdart/example/src/typeclass/order/order2.dart deleted file mode 100644 index d05a9c4d..00000000 --- a/packages/fpdart/example/src/typeclass/order/order2.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -class Parent { - final int value1; - final double value2; - const Parent(this.value1, this.value2); -} - -void main() { - /// Order values of type [Parent] based on their `value1` ([int]). - final orderParentInt = Order.orderInt.contramap( - (p) => p.value1, - ); - - /// Order values of type [Parent] based on their `value2` ([double]). - final orderParentDouble = Order.orderDouble.contramap( - (p) => p.value2, - ); -} diff --git a/packages/fpdart/lib/fpdart.dart b/packages/fpdart/lib/fpdart.dart index a3d852b7..e6cec5e4 100644 --- a/packages/fpdart/lib/fpdart.dart +++ b/packages/fpdart/lib/fpdart.dart @@ -1,21 +1,8 @@ -export 'src/date.dart'; -export 'src/either.dart'; -export 'src/extension/extension.export.dart'; +export 'src/effect.dart'; +export 'src/exit.dart'; +export 'src/extension/curry_extension.dart'; +export 'src/extension/iterable_extension.dart'; +export 'src/extension/list_extension.dart'; +export 'src/extension/map_extension.dart'; export 'src/function.dart'; -export 'src/io.dart'; -export 'src/io_either.dart'; -export 'src/io_option.dart'; -export 'src/io_ref.dart'; -export 'src/option.dart'; -export 'src/random.dart'; -export 'src/reader.dart'; -export 'src/reader_task.dart'; -export 'src/reader_task_either.dart'; -export 'src/state.dart'; -export 'src/state_async.dart'; -export 'src/task.dart'; -export 'src/task_either.dart'; -export 'src/task_option.dart'; -export 'src/typeclass/typeclass.export.dart'; -export 'src/typedef.dart'; export 'src/unit.dart'; diff --git a/packages/fpdart/lib/src/async_context.dart b/packages/fpdart/lib/src/async_context.dart new file mode 100644 index 00000000..dd306ca0 --- /dev/null +++ b/packages/fpdart/lib/src/async_context.dart @@ -0,0 +1,12 @@ +part of "effect.dart"; + +class AsyncContext { + final _deferred = Deferred.unsafeMake(); + + void succeed(R value) => _deferred.unsafeCompleteExit(Right(value)); + void fail(L error) => _deferred.unsafeCompleteExit(Left(Failure(error))); + void failCause(Cause cause) => _deferred.unsafeCompleteExit(Left(cause)); + void die(dynamic defect) => _deferred.unsafeCompleteExit(Left( + Die(defect, StackTrace.current), + )); +} diff --git a/packages/fpdart/lib/src/context.dart b/packages/fpdart/lib/src/context.dart new file mode 100644 index 00000000..93e543a6 --- /dev/null +++ b/packages/fpdart/lib/src/context.dart @@ -0,0 +1,32 @@ +part of "effect.dart"; + +final class Context { + final E env; + final Deferred signal; + + const Context._({required this.env, required this.signal}); + + factory Context({ + required E env, + required Deferred signal, + }) => + Context._(env: env, signal: signal); + + factory Context.env(E env) => + Context._(env: env, signal: Deferred.unsafeMake()); + + Context withEnv(C env) => Context._(env: env, signal: signal); + + Context get withoutSignal => withSignal(Deferred.unsafeMake()); + Context withSignal(Deferred signal) => + copyWith(signal: signal); + + Context copyWith({ + E? env, + Deferred? signal, + }) => + Context._( + env: env ?? this.env, + signal: signal ?? this.signal, + ); +} diff --git a/packages/fpdart/lib/src/date.dart b/packages/fpdart/lib/src/date.dart deleted file mode 100644 index 5d6ce63c..00000000 --- a/packages/fpdart/lib/src/date.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'io.dart'; - -/// Constructs a [DateTime] instance with current date and time in the local time zone. -/// -/// [IO] wrapper around dart `DateTime.now()`. -IO get dateNow => IO(() => DateTime.now()); - -/// The number of milliseconds since the "Unix epoch" 1970-01-01T00:00:00Z (UTC). -/// -/// This value is independent of the time zone. -/// -/// [IO] wrapper around dart `DateTime.now().millisecondsSinceEpoch`. -IO get now => dateNow.map((date) => date.millisecondsSinceEpoch); diff --git a/packages/fpdart/lib/src/deferred.dart b/packages/fpdart/lib/src/deferred.dart new file mode 100644 index 00000000..a1af7cdc --- /dev/null +++ b/packages/fpdart/lib/src/deferred.dart @@ -0,0 +1,49 @@ +part of 'effect.dart'; + +final class Deferred { + Option> _state = const None(); + Completer>? __completer; + + Deferred._(); + Deferred.unsafeMake(); + + static Effect> make() => + Effect.succeed(Deferred._()); + + Deferred.completed(R value) : _state = Some(Right(value)); + Deferred.failedCause(Cause cause) : _state = Some(Left(cause)); + Deferred.failed(L error) : _state = Some(Left(Failure(error))); + + Completer> get _completer => + __completer ??= Completer>.sync(); + + bool get unsafeCompleted => _state is Some>; + + Effect wait() => Effect.from( + (ctx) async => switch (_state) { + None() => await _completer.future, + Some(value: final value) => value, + }, + ); + + void unsafeCompleteExit(Exit exit) { + if (_state is Some>) return; + + _state = Some(exit); + __completer?.complete(exit); + } + + Effect completeExit(Exit exit) => + Effect.succeedLazy(() { + switch (_state) { + case None(): + unsafeCompleteExit(exit); + return unit; + case Some(): + return unit; + } + }); + + Effect failCause(Cause cause) => + completeExit(Left(cause)); +} diff --git a/packages/fpdart/lib/src/effect.dart b/packages/fpdart/lib/src/effect.dart new file mode 100644 index 00000000..2d33fd42 --- /dev/null +++ b/packages/fpdart/lib/src/effect.dart @@ -0,0 +1,843 @@ +import 'dart:async'; + +import 'package:fpdart/fpdart.dart'; + +import './extension/future_or_extension.dart'; +import 'unit.dart' as fpdart_unit; + +part 'async_context.dart'; +part 'context.dart'; +part 'deferred.dart'; +part 'either.dart'; +part 'option.dart'; +part 'scope.dart'; + +typedef EffectGen = ({ + FutureOr Function(IEffect) async, + A Function(IEffect) sync, +}); + +final class _EffectThrow implements Exception { + final Cause cause; + const _EffectThrow(this.cause); + + @override + String toString() { + return "Effect.gen error: $cause"; + } +} + +EffectGen _effectGen(Context context) => ( + async: (effect) => Future.sync( + () => effect.asEffect._unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => throw _EffectThrow(cause), + Right(value: final value) => value, + }, + ), + ), + sync: (effect) { + final run = effect.asEffect._unsafeRun(context); + if (run is Future) { + throw _EffectThrow( + Die.current( + Exception("gen.sync cannot execute async Effect"), + ), + ); + } + + return switch (run) { + Left(value: final cause) => throw _EffectThrow(cause), + Right(value: final value) => value, + }; + }, + ); + +typedef DoFunctionEffect = FutureOr Function( + EffectGen $, +); + +abstract class IEffect { + const IEffect(); + Effect get asEffect; +} + +final class Effect extends IEffect { + final FutureOr> Function(Context context) _unsafeRun; + const Effect._(this._unsafeRun); + + @override + Effect get asEffect => this; + + @override + String toString() { + return "Effect(${_unsafeRun.runtimeType})"; + } + + /// {@category constructors} + factory Effect.from(FutureOr> Function(Context context) run) => + Effect._((context) { + try { + if (context.signal.unsafeCompleted) { + return const Left(Interrupted()); + } + + return run(context).then((exit) { + if (context.signal.unsafeCompleted) { + return const Left(Interrupted()); + } + + return exit; + }); + } on Cause catch (cause) { + return Left(cause); + } catch (error, stackTrace) { + return Left(Die(error, stackTrace)); + } + }); + + /// {@category constructors} + factory Effect.gen(DoFunctionEffect f) => Effect._( + (env) { + try { + return f(_effectGen(env)).then( + Right.new, + onError: (error, stackTrace) { + if (error is _EffectThrow) { + return Left, R>(error.cause); + } + + return Left, R>(Die(error, stackTrace)); + }, + ); + } on _EffectThrow catch (genError) { + return Left(genError.cause); + } + }, + ); + + /// {@category constructors} + factory Effect.tryCatch({ + required FutureOr Function() execute, + required L Function(Object error, StackTrace stackTrace) onError, + }) => + Effect.from( + (env) { + try { + return execute().then( + Right.new, + onError: (error, stackTrace) => Left( + Failure(onError(error, stackTrace), stackTrace), + ), + ); + } catch (err, stack) { + return Left(Failure(onError(err, stack), stack)); + } + }, + ); + + /// {@category constructors} + factory Effect.fromNullable(R? value, {required L Function() onNull}) => + Effect.from( + (_) => value == null ? Left(Failure(onNull())) : Right(value), + ); + + /// {@category constructors} + factory Effect.failLazy(FutureOr> Function() f) => Effect.from( + (_) => f().then(Left.new), + ); + + /// {@category constructors} + factory Effect.succeedLazy(FutureOr Function() f) => Effect.from( + (_) => f().then(Right.new), + ); + + /// {@category constructors} + factory Effect.fail(L value) => Effect.from((_) => Left(Failure(value))); + + /// {@category constructors} + factory Effect.failCause(Cause cause) => Effect.from((_) => Left(cause)); + + /// {@category constructors} + factory Effect.succeed(R value) => Effect.from((_) => Right(value)); + + /// {@category constructors} + factory Effect.lazy(Effect Function() effect) => + Effect.from((context) => effect()._unsafeRun(context)); + + /// {@category constructors} + factory Effect.async(void Function(AsyncContext resume) callback) => + Effect.from( + (context) { + final asyncContext = AsyncContext(); + callback(asyncContext); + return asyncContext._deferred.wait()._unsafeRun(context); + }, + ); + + /// {@category constructors} + factory Effect.asyncInterrupt( + Effect Function(AsyncContext resume) callback, + ) => + Effect.from((context) { + final asyncContext = AsyncContext(); + + final finalizer = callback(asyncContext); + if (asyncContext._deferred.unsafeCompleted) { + return asyncContext._deferred.wait()._unsafeRun(context); + } + + final interruption = context.signal.wait().alwaysIgnore( + finalizer.withEnv(), + ); + + return asyncContext._deferred + .wait() + .race(interruption) + ._unsafeRun(context.withoutSignal); + }); + + /// {@category constructors} + static Effect sleep(Duration duration) => + Effect.asyncInterrupt( + (resume) { + final timer = Timer(duration, () { + resume.succeed(null); + }); + + return Effect.succeedLazy(() { + timer.cancel(); + return fpdart_unit.unit; + }); + }, + ); + + /// {@category constructors} + factory Effect.raceAll(Iterable> iterable) => + Effect.from((context) { + final signal = Deferred.unsafeMake(); + final deferred = Deferred.unsafeMake(); + + for (final effect in iterable) { + effect + ._unsafeRun(context.withSignal(signal)) + .then(deferred.unsafeCompleteExit); + + if (deferred.unsafeCompleted) { + break; + } + } + + return deferred.wait()._unsafeRun(context).then( + (exit) => signal + .failCause(const Interrupted()) + ._unsafeRun(context.withoutSignal) + .then((_) => exit), + ); + }); + + /// {@category constructors} + static Effect die(dynamic defect) => Effect.from( + (_) => Left(Die.current(defect)), + ); + + /// {@category constructors} + static Effect functionDie(dynamic Function() run) => + Effect.from( + (_) => Left(Die.current(run())), + ); + + /// {@category constructors} + static Effect unit() => Effect.from( + (_) => const Right(fpdart_unit.unit), + ); + + /// {@category collecting} + static Effect> forEach( + Iterable iterable, + Effect Function(A a, int index) f, + ) => + Effect.from( + (context) { + if (iterable.isEmpty) { + return const Right([]); + } + + return iterable + .mapWithIndex(f) + .fold>>( + Effect.succeed(const Iterable.empty()), + (acc, effect) => acc.zipWith( + effect, + (list, r) => list.append(r), + ), + ) + ._unsafeRun(context); + }, + ); + + /// {@category collecting} + static Effect> all( + Iterable> iterable, + ) => + Effect.forEach( + iterable, + (effect, _) => effect, + ); + + /// {@category zipping} + Effect zipWith( + Effect effect, + C Function(R r, B b) f, + ) => + flatMap( + (r) => effect.map( + (b) => f(r, b), + ), + ); + + /// {@category zipping} + Effect zipLeft( + Effect effect, + ) => + flatMap( + (r) => effect.map( + (_) => r, + ), + ); + + /// {@category zipping} + Effect zipRight( + Effect effect, + ) => + flatMap((_) => effect); + + /// {@category context} + Effect mapContext(Context Function(Context context) f) => + Effect.from( + (context) => _unsafeRun(f(context)), + ); + + /// {@category context} + Effect mapEnv(E Function(V env) f) => Effect.from( + (context) => _unsafeRun( + Context(env: f(context.env), signal: context.signal), + ), + ); + + Effect _provideEnvCloseScope(E env) => + env is ScopeMixin && !env.scopeClosable + ? Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final value) => Left(value), + Right(value: final value) => + env.closeScope()._unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final value) => Left(value), + Right() => Right(value), + }, + ), + }, + ), + ) + : this; + + /// {@category context} + Effect provide(Context context) => Effect.from( + (_) => _provideEnvCloseScope(context.env)._unsafeRun(context), + ); + + /// {@category context} + Effect provideEnv(E env) => Effect.from( + (_) => _provideEnvCloseScope(env)._unsafeRun(Context.env(env)), + ); + + /// {@category context} + Effect provideEffect(Effect effect) => Effect.from( + (context) => effect._unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => Left(cause), + Right(value: final value) => _unsafeRun(context.withEnv(value)), + }, + ), + ); + + /// {@category context} + static Effect env() => Effect.from( + (context) => Right(context.env), + ); + + /// {@category combining} + Effect ap( + Effect f, + ) => + f.flatMap( + (f) => flatMap( + (v) => Effect.succeed(f(v)), + ), + ); + + /// {@category conversions} + Effect> either() => Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => switch (cause) { + Failure(error: final error) => Right(Left(error)), + Die() => Left(cause), + Interrupted() => Left(cause), + }, + Right(value: final value) => Right(Right(value)), + }, + ), + ); + + /// {@category conversions} + Effect> option() => Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => switch (cause) { + Failure() => Right, Option>(const None()), + Die() => Left(cause), + Interrupted() => Left(cause), + }, + Right(value: final value) => Right(Some(value)), + }, + ), + ); + + /// {@category conversions} + Effect> exit() => Effect.from( + (context) => _unsafeRun(context).then( + (exit) => Right(exit), + ), + ); + + /// {@category folding} + Effect match({ + required C Function(L l) onFailure, + required C Function(R r) onSuccess, + }) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => switch (cause) { + Failure(error: final error) => Right(onFailure(error)), + Die() => Left(cause), + Interrupted() => Left(cause), + }, + Right(value: final value) => Right(onSuccess(value)), + }, + ), + ); + + /// {@category folding} + Effect matchCause({ + required C Function(Cause l) onFailure, + required C Function(R r) onSuccess, + }) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => Right(onFailure(cause)), + Right(value: final value) => Right(onSuccess(value)), + }, + ), + ); + + /// {@category folding} + Effect matchEffect({ + required Effect Function(L l) onFailure, + required Effect Function(R r) onSuccess, + }) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => switch (cause) { + Failure(error: final error) => + onFailure(error)._unsafeRun(context), + Die() => Left(cause), + Interrupted() => Left(cause), + }, + Right(value: final value) => onSuccess(value)._unsafeRun(context), + }, + ), + ); + + /// {@category folding} + Effect matchCauseEffect({ + required Effect Function(Cause l) onFailure, + required Effect Function(R r) onSuccess, + }) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => onFailure(cause)._unsafeRun(context), + Right(value: final value) => onSuccess(value)._unsafeRun(context), + }, + ), + ); + + /// {@category mapping} + Effect flip() => Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => switch (cause) { + Failure(error: final error) => Right(error), + Die() => Left(cause), + Interrupted() => Left(cause), + }, + Right(value: final value) => Left(Failure(value)), + }, + ), + ); + + /// {@category mapping} + Effect map(V Function(R r) f) => ap(Effect.succeed(f)); + + /// {@category mapping} + Effect mapError(C Function(L l) f) => Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => switch (cause) { + Failure(error: final error) => Left(Failure(f(error))), + Die() => Left(cause), + Interrupted() => Left(cause), + }, + Right(value: final value) => Right(value), + }, + ), + ); + + /// {@category mapping} + Effect mapErrorCause(C Function(Cause l) f) => Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => Left(Failure(f(cause))), + Right(value: final value) => Right(value), + }, + ), + ); + + /// {@category mapping} + Effect mapBoth(C Function(L l) fl, D Function(R r) fr) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => switch (cause) { + Failure(error: final error) => Left(Failure(fl(error))), + Die() => Left(cause), + Interrupted() => Left(cause), + }, + Right(value: final value) => Right(fr(value)), + }, + ), + ); + + /// {@category sequencing} + Effect race(Effect effect) => + Effect.raceAll([this, effect]); + + /// {@category sequencing} + Effect alwaysIgnore(Effect effect) => Effect.from( + (context) => race(context.signal.wait())._unsafeRun(context).then( + (exit) => effect._unsafeRun(context.withoutSignal).then( + (_) => exit, + ), + ), + ); + + /// {@category sequencing} + Effect flatMap(Effect Function(R r) f) => Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => Left(cause), + Right(value: final value) => f(value)._unsafeRun(context), + }, + ), + ); + + /// {@category sequencing} + Effect flatMapEnv(Effect Function(R r, E env) f) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => Left(cause), + Right(value: final value) => + f(value, context.env)._unsafeRun(context), + }, + ), + ); + + /// {@category sequencing} + Effect tap(Effect Function(R r) f) => + flatMap((r) => f(r).map((_) => r)); + + /// {@category sequencing} + Effect tapEnv( + Effect Function(R r, E env) f, + ) => + flatMapEnv( + (r, env) => f(r, env).map((_) => r), + ); + + /// {@category sequencing} + Effect tapError(Effect Function(L l) f) => Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => switch (cause) { + Failure(error: final error) => + f(error)._unsafeRun(context).then( + (_) => Left(Failure(error)), + ), + Die() => Left(cause), + Interrupted() => Left(cause), + }, + Right(value: final value) => Right(value), + }, + ), + ); + + /// {@category alternatives} + Effect orElse( + Effect Function(L l) orElse, + ) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => switch (cause) { + Failure(error: final error) => + orElse(error)._unsafeRun(context), + Die() => Left(cause), + Interrupted() => Left(cause), + }, + Right(value: final value) => + Effect.succeed(value)._unsafeRun(context), + }, + ), + ); + + /// {@category alternatives} + Effect get orDie => Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => Left(Die.current(cause)), + Right(value: final value) => + Effect.succeed(value)._unsafeRun(context), + }, + ), + ); + + /// {@category alternatives} + Effect orDieWith(T Function(L l) onError) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => switch (cause) { + Failure(error: final error) => + Left(Die.current(onError(error))), + Die() => Left(cause), + Interrupted() => Left(cause), + }, + Right(value: final value) => + Effect.succeed(value)._unsafeRun(context), + }, + ), + ); + + /// {@category error_handling} + Effect catchError( + Effect Function(L error) f, + ) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => switch (cause) { + Failure(error: final error) => f(error)._unsafeRun(context), + Die() => Left(cause), + Interrupted() => Left(cause), + }, + Right(value: final value) => + Effect.succeed(value)._unsafeRun(context), + }, + ), + ); + + /// {@category error_handling} + Effect catchCause( + Effect Function(Cause cause) f, + ) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => f(cause), + Right(value: final value) => Effect.succeed(value), + } + ._unsafeRun(context), + ), + ); + + /// {@category filtering} + Effect filterOrDie({ + required bool Function(R r) predicate, + required C Function(R r) orDieWith, + }) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => Left(cause), + Right(value: final value) => predicate(value) + ? Right(value) + : Left(Die.current(orDieWith(value))), + }, + ), + ); + + /// {@category filtering} + Effect filterOrElse({ + required bool Function(R r) predicate, + required Effect Function(R r) orElse, + }) => + Effect.from( + (context) => _unsafeRun(context).then( + (exit) => switch (exit) { + Left(value: final cause) => Left(cause), + Right(value: final value) => predicate(value) + ? Right(value) + : orElse(value)._unsafeRun(context), + }, + ), + ); + + /// {@category delay} + Effect delay(Duration duration) => + Effect.sleep(duration).zipRight(this); + + /// {@category delay} + Effect timeout(Duration duration) => + race(Effect.failCause(const Interrupted()).delay(duration)); + + /// {@category interruption} + Effect interrupt() => Effect.failCause(const Interrupted()); +} + +extension EffectWithScopeFinalizer + on Effect { + /// {@category scoping} + Effect addFinalizer(Effect release) => + tapEnv((_, env) => env.addScopeFinalizer(release)); + + /// {@category scoping} + Effect acquireRelease( + Effect Function(R r) release, + ) => + tap((r) => addFinalizer(release(r))); +} + +extension EffectNoScopeFinalizer on Effect { + /// {@category scoping} + Effect, L, R> addFinalizer(Effect release) => + Effect, L, R>.from( + (context) => _unsafeRun(context.withEnv(context.env.env)), + ).tapEnv( + (_, env) => env.addScopeFinalizer(release), + ); + + /// {@category scoping} + Effect, L, R> acquireRelease( + Effect Function(R r) release, + ) => + Effect, L, R>.from( + (context) => _unsafeRun(context.withEnv(context.env.env)), + ).tapEnv( + (r, env) => env.addScopeFinalizer( + release(r), + ), + ); +} + +extension EffectWithScope on Effect, L, R> { + /// {@category context} + Effect get provideScope => Effect.from((context) { + final scope = Scope.withEnv(context.env); + return _provideEnvCloseScope(scope)._unsafeRun(context.withEnv(scope)); + }); +} + +extension ProvideNull on Effect { + /// {@category context} + Effect withEnv() => Effect.from( + (context) => _unsafeRun(Context.env(null)), + ); + + /// {@category execution} + R runSyncOrThrow() { + try { + final result = _unsafeRun(Context.env(null)); + if (result is Future) { + throw Die.current( + Exception("runSync cannot execute async Effect"), + ); + } + + return switch (result) { + Left(value: final cause) => throw cause, + Right(value: final value) => value, + }; + } on Cause { + rethrow; + } catch (error, stackTrace) { + throw Die(error, stackTrace); + } + } + + /// {@category execution} + Exit runSyncExit() { + try { + final result = _unsafeRun(Context.env(null)); + if (result is Future) { + return Left(Die.current( + Exception("runSyncExit cannot execute async Effect"), + )); + } + return result; + } on Cause catch (cause) { + return Left(cause); + } catch (error, stackTrace) { + return Left(Die(error, stackTrace)); + } + } + + /// {@category execution} + Future runFutureOrThrow() async { + try { + final result = _unsafeRun(Context.env(null)); + if (result is! Future) { + return switch (result) { + Left(value: final cause) => throw cause, + Right(value: final value) => value, + }; + } + + return switch (await result) { + Left(value: final cause) => throw cause, + Right(value: final value) => value, + }; + } on Cause { + rethrow; + } catch (error, stackTrace) { + throw Die(error, stackTrace); + } + } + + /// {@category execution} + Future> runFutureExit() async { + try { + return _unsafeRun(Context.env(null)); + } on Cause catch (cause) { + return Left(cause); + } catch (error, stackTrace) { + return Left(Die(error, stackTrace)); + } + } +} diff --git a/packages/fpdart/lib/src/either.dart b/packages/fpdart/lib/src/either.dart index c3140e20..b54a4170 100644 --- a/packages/fpdart/lib/src/either.dart +++ b/packages/fpdart/lib/src/either.dart @@ -1,675 +1,214 @@ -import 'function.dart'; -import 'io_either.dart'; -import 'option.dart'; -import 'task_either.dart'; -import 'typeclass/typeclass.export.dart'; -import 'typedef.dart'; - -/// Return a `Right(r)`. -/// -/// Shortcut for `Either.of(r)`. -Either right(R r) => Right(r); - -/// Return a `Left(l)`. -/// -/// Shortcut for `Either.left(l)`. -Either left(L l) => Left(l); - -final class _EitherThrow { - final L value; - const _EitherThrow(this.value); -} +part of "effect.dart"; -typedef DoAdapterEither = R Function(Either); -DoAdapterEither _doAdapter() => - (Either either) => either.getOrElse( - (l) => throw _EitherThrow(l), - ); - -typedef DoFunctionEither = R Function(DoAdapterEither $); - -/// Tag the [HKT2] interface for the actual [Either]. -abstract final class _EitherHKT {} - -/// Represents a value of one of two possible types, [Left] or [Right]. -/// -/// [Either] is commonly used to **handle errors**. Instead of returning placeholder -/// values when a computation may fail (such as `-1`, `null`, etc.), we return an instance -/// of [Right] containing the correct result when a computation is successful, otherwise we return -/// an instance of [Left] containing information about the kind of error that occurred. -sealed class Either extends HKT2<_EitherHKT, L, R> - with - Functor2<_EitherHKT, L, R>, - Applicative2<_EitherHKT, L, R>, - Monad2<_EitherHKT, L, R>, - Foldable2<_EitherHKT, L, R>, - Alt2<_EitherHKT, L, R>, - Extend2<_EitherHKT, L, R> { +sealed class Either extends IEffect { const Either(); - /// Initialize a **Do Notation** chain. - // ignore: non_constant_identifier_names - factory Either.Do(DoFunctionEither f) { - try { - return Either.of(f(_doAdapter())); - } on _EitherThrow catch (e) { - return Either.left(e.value); - } - } - - /// Return the result of `f` called with `b` and the value of [Right]. - /// If this [Either] is [Left], return `b`. - @override - C foldRight(C b, C Function(C acc, R b) f); - - /// Return the result of `f` called with `b` and the value of [Right]. - /// If this [Either] is [Left], return `b`. - @override - C foldLeft(C b, C Function(C acc, R b) f) => - foldMap>(dualEndoMonoid(), (b) => (C c) => f(c, b))(b); - - /// Use `monoid` to combine the value of [Right] applied to `f`. - @override - C foldMap(Monoid monoid, C Function(R b) f) => - foldRight(monoid.empty, (c, b) => monoid.combine(f(b), c)); - - /// Return the result of `f` called with `b` and the value of [Right]. - /// If this [Either] is [Left], return `b`. - @override - C foldRightWithIndex(C c, C Function(int i, C acc, R b) f) => - foldRight<(C, int)>( - (c, length() - 1), - (t, b) => (f(t.$2, t.$1, b), t.$2 - 1), - ).$1; - - /// Return the result of `f` called with `b` and the value of [Right]. - /// If this [Either] is [Left], return `b`. - @override - C foldLeftWithIndex(C c, C Function(int i, C acc, R b) f) => - foldLeft<(C, int)>( - (c, 0), - (t, b) => (f(t.$2, t.$1, b), t.$2 + 1), - ).$1; - - /// Returns `1` when [Either] is [Right], `0` otherwise. - @override - int length() => foldLeft(0, (b, _) => b + 1); - - /// Return the result of `predicate` applied to the value of [Right]. - /// If the [Either] is [Left], returns `false`. - @override - bool any(bool Function(R a) predicate) => foldMap(boolOrMonoid(), predicate); - - /// Return the result of `predicate` applied to the value of [Right]. - /// If the [Either] is [Left], returns `true`. - @override - bool all(bool Function(R a) predicate) => foldMap(boolAndMonoid(), predicate); - - /// Use `monoid` to combine the value of [Right]. - @override - R concatenate(Monoid monoid) => foldMap(monoid, identity); - - /// If the [Either] is [Right], then change its value from type `R` to - /// type `C` using function `f`. - @override - Either map(C Function(R a) f); - - /// Define two functions to change both the [Left] and [Right] value of the - /// [Either]. - /// - /// {@template fpdart_bimap_either} - /// Same as `map`+`mapLeft` but for both [Left] and [Right] - /// (`map` is only to change [Right], while `mapLeft` is only to change [Left]). - /// {@endtemplate} - Either bimap(C Function(L l) mLeft, D Function(R b) mRight) => - mapLeft(mLeft).map(mRight); - - /// Return a [Right] containing the value `c`. - @override - Either pure(C c) => Right(c); - - /// Apply the function contained inside `a` to change the value on the [Right] from - /// type `R` to a value of type `C`. - @override - Either ap(covariant Either a) => - a.flatMap((f) => map(f)); - - /// If this [Either] is a [Right], then return the result of calling `then`. - /// Otherwise return [Left]. - @override - Either andThen(covariant Either Function() then) => - flatMap((_) => then()); - - /// Return the current [Either] if it is a [Right], otherwise return the result of `orElse`. - /// - /// Used to provide an **alt**ernative [Either] in case the current one is [Left]. - @override - Either alt(covariant Either Function() orElse); - - /// Change type of this [Either] based on its value of type `R` and the - /// value of type `C` of another [Either]. - @override - Either map2(covariant Either m1, D Function(R b, C c) f) => - flatMap((b) => m1.map((c) => f(b, c))); - - /// Change type of this [Either] based on its value of type `R`, the - /// value of type `C` of a second [Either], and the value of type `D` - /// of a third [Either]. - @override - Either map3(covariant Either m1, - covariant Either m2, E Function(R b, C c, D d) f) => - flatMap((b) => m1.flatMap((c) => m2.map((d) => f(b, c, d)))); - - /// Change the value of [Either] from type `R` to type `Z` based on the - /// value of `Either` using function `f`. - @override - Either extend(Z Function(Either t) f); - - /// Wrap this [Either] inside another [Either]. - @override - Either> duplicate() => extend(identity); - - /// Chain multiple functions having the same left type `L`. - @override - Either call(covariant Either chain) => flatMap((_) => chain); - - /// {@template fpdart_flat_map_either} - /// Used to chain multiple functions that return a [Either]. - /// - /// You can extract the value of every [Right] in the chain without - /// handling all possible missing cases. - /// If any of the functions in the chain returns [Left], the result is [Left]. - /// {@endtemplate} - /// - /// Same as `bind`. - @override - Either flatMap(covariant Either Function(R a) f); - - /// {@macro fpdart_flat_map_either} - /// - /// Same as `flatMap`. - Either bind(Either Function(R r) f) => flatMap(f); - - /// If `f` applied on this [Either] as [Right] returns `true`, then return this [Either]. - /// If it returns `false`, return the result of `onFalse` in a [Left]. - Either filterOrElse(bool Function(R r) f, L Function(R r) onFalse) => - flatMap((r) => f(r) ? Either.of(r) : Either.left(onFalse(r))); - - /// Chain a request that returns another [Either], execute it, ignore - /// the result, and return the same value as the current [Either]. - @override - Either chainFirst( - covariant Either Function(R b) chain, - ) => - flatMap((b) => chain(b).map((c) => b).orElse((l) => right(b))); - - /// Used to chain multiple functions that return a `Future`. - /// - /// When this value is [Right], it returns a [TaskEither] that will resolve to - /// the result of calling `f`. - /// Otherwise, if this value is [Left], it returns `TaskEither.left()`. - TaskEither bindFuture(Future> Function(R r) f); - - /// If the [Either] is [Left], then change its value from type `L` to - /// type `C` using function `f`. - Either mapLeft(C Function(L a) f); - - /// Convert this [Either] to a [Option]: - /// - If the [Either] is [Left], throw away its value and just return [None] - /// - If the [Either] is [Right], return a [Some] containing the value inside [Right] - Option toOption(); - - /// Convert this [Either] to a [IOEither]. - IOEither toIOEither(); - - /// Convert this [Either] to a [TaskEither]. - /// - /// Used to convert a sync context ([Either]) to an async context ([TaskEither]). - /// You should convert [Either] to [TaskEither] every time you need to - /// call an async ([Future]) function based on the value in [Either]. - TaskEither toTaskEither(); - - /// Convert [Either] to nullable `R?`. - /// - /// **Note**: this loses information about a possible [Left] value, - /// converting it to simply `null`. - R? toNullable(); - - /// Return `true` when this [Either] is [Left]. - bool isLeft(); - - /// Return `true` when this [Either] is [Right]. - bool isRight(); - - /// Extract the value from [Left] in a [Option]. - /// - /// If the [Either] is [Right], return [None]. - Option getLeft(); - - /// Extract the value from [Right] in a [Option]. - /// - /// If the [Either] is [Left], return [None]. - /// - /// Same as `toOption`. - Option getRight() => toOption(); - - /// Swap the values contained inside the [Left] and [Right] of this [Either]. - Either swap(); - - /// If this [Either] is [Left], return the result of `onLeft`. - /// - /// Used to recover from errors, so that when this value is [Left] you - /// try another function that returns an [Either]. - Either orElse(Either Function(L l) onLeft); - - /// Return the value inside this [Either] if it is a [Right]. - /// Otherwise return result of `onElse`. - R getOrElse(R Function(L l) orElse); - - /// Execute `onLeft` when value is [Left], otherwise execute `onRight`. - /// - /// Same as `fold`. - C match(C Function(L l) onLeft, C Function(R r) onRight); - - /// Execute `onLeft` when value is [Left], otherwise execute `onRight`. - /// - /// Same as `match`. - C fold(C Function(L l) onLeft, C Function(R r) onRight) => - match(onLeft, onRight); - - /// Return `true` when value of `r` is equal to the value inside this [Either]. - /// If this [Either] is [Left], then return `false`. - bool elem(R r, Eq eq); - - /// Return the result of calliing `predicate` with the value of [Either] if it is a [Right]. - /// Otherwise return `false`. - bool exists(bool Function(R r) predicate); - - /// {@template fpdart_traverse_list_either} - /// Map each element in the list to an [Either] using the function `f`, - /// and collect the result in an `Either>`. - /// - /// If any mapped element of the list is [Left], then the final result - /// will be [Left]. - /// {@endtemplate} - /// - /// Same as `Either.traverseList` but passing `index` in the map function. - static Either> traverseListWithIndex( - List list, - Either Function(A a, int i) f, - ) { - final resultList = []; - for (var i = 0; i < list.length; i++) { - final e = f(list[i], i); - if (e is Left) { - return left(e._value); - } else if (e is Right) { - resultList.add(e._value); - } else { - throw Exception( - "[fpdart]: Error when mapping Either, it should be either Left or Right.", - ); - } - } - - return right(resultList); - } - - /// {@macro fpdart_traverse_list_either} - /// - /// Same as `Either.traverseListWithIndex` but without `index` in the map function. - static Either> traverseList( - List list, - Either Function(A a) f, - ) => - traverseListWithIndex(list, (a, _) => f(a)); - - /// {@template fpdart_sequence_list_either} - /// Convert a `List>` to a single `Either>`. - /// - /// If any of the [Either] in the [List] is [Left], then the result is [Left]. - /// {@endtemplate} - static Either> sequenceList( - List> list, - ) => - traverseList(list, identity); - - /// {@template fpdart_rights_either} - /// Extract all the [Right] values from a `List>`. - /// {@endtemplate} - static List rights(List> list) { - final resultList = []; - for (var i = 0; i < list.length; i++) { - final e = list[i]; - if (e is Right) { - resultList.add(e._value); - } - } - - return resultList; - } - - /// {@template fpdart_lefts_either} - /// Extract all the [Left] values from a `List>`. - /// {@endtemplate} - static List lefts(List> list) { - final resultList = []; - for (var i = 0; i < list.length; i++) { - final e = list[i]; - if (e is Left) { - resultList.add(e._value); - } - } - - return resultList; - } - - /// {@template fpdart_partition_eithers_either} - /// Extract all the [Left] and [Right] values from a `List>` and - /// return them in two partitioned [List] inside a record. - /// {@endtemplate} - static (List, List) partitionEithers(List> list) { - final resultListLefts = []; - final resultListRights = []; - for (var i = 0; i < list.length; i++) { - final e = list[i]; - if (e is Left) { - resultListLefts.add(e._value); - } else if (e is Right) { - resultListRights.add(e._value); - } else { - throw Exception( - "[fpdart]: Error when mapping Either, it should be either Left or Right.", - ); - } - } - - return (resultListLefts, resultListRights); - } - - /// Flat a [Either] contained inside another [Either] to be a single [Either]. - factory Either.flatten(Either> e) => e.flatMap(identity); - - /// Return a `Right(r)`. - /// - /// Same as `Either.right(r)`. - factory Either.of(R r) => Right(r); - - /// Return a `Right(r)`. - /// - /// Same as `Either.of(r)`. - factory Either.right(R r) => Right(r); - - /// Return a `Left(l)`. - factory Either.left(L l) => Left(l); - - /// Return an [Either] from a [Option]: - /// - If [Option] is [Some], then return [Right] containing its value - /// - If [Option] is [None], then return [Left] containing the result of `onNone` - factory Either.fromOption(Option m, L Function() onNone) => m.match( - () => Either.left(onNone()), - (r) => Either.of(r), - ); - /// If calling `predicate` with `r` returns `true`, then return `Right(r)`. /// Otherwise return [Left] containing the result of `onFalse`. factory Either.fromPredicate( - R r, bool Function(R r) predicate, L Function(R r) onFalse) => - predicate(r) ? Either.of(r) : Either.left(onFalse(r)); + R r, + bool Function(R r) predicate, + L Function(R r) onFalse, + ) => + predicate(r) ? Right(r) : Left(onFalse(r)); - /// If `r` is `null`, then return the result of `onNull` in [Left]. - /// Otherwise return `Right(r)`. factory Either.fromNullable(R? r, L Function() onNull) => - r != null ? Either.of(r) : Either.left(onNull()); + r != null ? Right(r) : Left(onNull()); - /// Try to execute `run`. If no error occurs, then return [Right]. - /// Otherwise return [Left] containing the result of `onError`. - factory Either.tryCatch( - R Function() run, L Function(Object o, StackTrace s) onError) { + factory Either.tryCatch({ + required R Function() execute, + required L Function(Object o, StackTrace s) onError, + }) { try { - return Either.of(run()); + return Right(execute()); } catch (e, s) { - return Either.left(onError(e, s)); + return Left(onError(e, s)); } } - /// {@template fpdart_safe_cast_either} - /// Safely cast a value to type `R`. - /// - /// If `value` is not of type `R`, then return a [Left] - /// containing the result of `onError`. - /// {@endtemplate} - /// - /// Less strict version of `Either.safeCastStrict`, since `safeCast` - /// assumes the value to be `dynamic`. - /// - /// **Note**: Make sure to specify the types of [Either] (`Either.safeCast` - /// instead of `Either.safeCast`), otherwise this will always return [Right]! factory Either.safeCast( dynamic value, L Function(dynamic value) onError, ) => Either.safeCastStrict(value, onError); - /// {@macro fpdart_safe_cast_either} - /// - /// More strict version of `Either.safeCast`, in which also the **input value - /// type** must be specified (while in `Either.safeCast` the type is `dynamic`). static Either safeCastStrict( V value, L Function(V value) onError, ) => - value is R ? Either.of(value) : Either.left(onError(value)); - - /// Try to execute `run`. If no error occurs, then return [Right]. - /// Otherwise return [Left] containing the result of `onError`. - /// - /// `run` has one argument, which allows for easier chaining with - /// `Either.flatMap`. - static Either Function(T) tryCatchK( - R Function(T) run, L Function(Object o, StackTrace s) onError) => - (a) => Either.tryCatch( - () => run(a), - onError, - ); - - /// Build an `Eq` by comparing the values inside two [Either]. - /// - /// Return `true` when the two [Either] are equal or when both are [Left] or - /// [Right] and comparing using `eqL` or `eqR` returns `true`. - static Eq> getEq(Eq eqL, Eq eqR) => - Eq.instance((e1, e2) => - e1 == e2 || - (e1.match((l1) => e2.match((l2) => eqL.eqv(l1, l2), (_) => false), - (r1) => e2.match((_) => false, (r2) => eqR.eqv(r1, r2))))); - - /// Build a `Semigroup` from a [Semigroup]. - /// - /// If both are [Right], then return [Right] containing the result of `combine` from - /// `semigroup`. Otherwise return [Right] if any of the two [Either] is [Right]. - /// - /// When both are [Left], return the first [Either]. - static Semigroup> getSemigroup(Semigroup semigroup) => - Semigroup.instance((e1, e2) => e2.match( - (_) => e1, - (r2) => e1.match( - (_) => e2, (r1) => Either.of(semigroup.combine(r1, r2))))); -} - -class Right extends Either { - final R _value; - const Right(this._value); + value is R ? Right(value) : Left(onError(value)); - /// Extract the value of type `R` inside the [Right]. - R get value => _value; - - @override - Either map2(covariant Either m1, D Function(R b, C c) f) => - flatMap((b) => m1.map((c) => f(b, c))); - - @override - Either map3(covariant Either m1, - covariant Either m2, E Function(R b, C c, D d) f) => - flatMap((b) => m1.flatMap((c) => m2.map((d) => f(b, c, d)))); - - @override - Either map(C Function(R a) f) => Right(f(_value)); + static Iterable getRights(Iterable> iterable) sync* { + for (var either in iterable) { + if (either is Right) { + yield either.value; + } + } + } - @override - Either mapLeft(C Function(L a) f) => Right(_value); + static Iterable getLefts(Iterable> iterable) sync* { + for (var either in iterable) { + if (either is Left) { + yield either.value; + } + } + } - @override - C foldRight(C b, C Function(C acc, R a) f) => f(b, _value); + R? getOrNull(); + Either flatMap(Either Function(R r) f); + Either mapLeft(C Function(L l) f); + Effect provide(); + Either mapBoth({ + required D Function(L l) onLeft, + required C Function(R r) onRight, + }); + Either flip(); + R getOrElse(R Function(L l) orElse); + Either andThen(C Function(R r) f); + Either orElse(Either Function(L l) orElse); + Either tap(Either Function(R r) f); + Either filterOrLeft({ + required bool Function(R r) predicate, + required L Function(R r) orLeftWith, + }); + Option getLeft(); + Option getRight(); - @override - C match(C Function(L l) onLeft, C Function(R r) onRight) => - onRight(_value); + Either ap( + Either f, + ) => + f.flatMap( + (f) => flatMap( + (v) => Right(f(v)), + ), + ); - @override - Either flatMap(covariant Either Function(R a) f) => f(_value); + Either map(V Function(R r) f) => ap(Right(f)); +} - @override - Option toOption() => Some(_value); +final class Right extends Either { + final R value; + const Right(this.value); @override - bool isLeft() => false; + Effect get asEffect => Effect._((_) => Right(value)); @override - bool isRight() => true; + Either andThen(C Function(R value) f) => Right(f(value)); @override - Either swap() => Left(_value); + Either orElse(Either Function(L l) orElse) => Right(value); @override - Either alt(covariant Either Function() orElse) => this; + R getOrElse(R Function(L l) orElse) => value; @override - Option getLeft() => Option.none(); + Either flip() => Left(value); @override - Either extend(Z Function(Either t) f) => Either.of(f(this)); + Either mapBoth( + {required D Function(L l) onLeft, + required C Function(R r) onRight}) => + Right(onRight(value)); @override - Either orElse(Either Function(L l) onLeft) => - Either.of(_value); + Either mapLeft(C Function(L l) f) => Right(value); @override - R getOrElse(R Function(L l) orElse) => _value; + Either flatMap(Either Function(R r) f) => f(value); @override - bool elem(R r, Eq eq) => eq.eqv(r, _value); + Effect provide() => Effect.succeed(value); @override - bool exists(bool Function(R r) predicate) => predicate(_value); + R getOrNull() => value; @override - bool operator ==(Object other) => (other is Right) && other._value == _value; + Option getRight() => Some(value); @override - int get hashCode => _value.hashCode; + bool operator ==(Object other) => (other is Right) && other.value == value; @override - String toString() => 'Right($_value)'; + int get hashCode => value.hashCode; @override - TaskEither bindFuture(Future> Function(R r) f) => - TaskEither(() async => f(_value)); + String toString() => 'Right($value)'; @override - TaskEither toTaskEither() => TaskEither.of(_value); + Either filterOrLeft({ + required bool Function(R r) predicate, + required L Function(R r) orLeftWith, + }) => + predicate(value) ? Right(value) : Left(orLeftWith(value)); @override - IOEither toIOEither() => IOEither.of(_value); + Option getLeft() => const None(); @override - R? toNullable() => _value; + Either tap(Either Function(R r) f) => + f(value).map((_) => value); } -class Left extends Either { - final L _value; - const Left(this._value); - - /// Extract the value of type `L` inside the [Left]. - L get value => _value; - - @override - Either map2(covariant Either m1, D Function(R b, C c) f) => - flatMap((b) => m1.map((c) => f(b, c))); - - @override - Either map3(covariant Either m1, - covariant Either m2, E Function(R b, C c, D d) f) => - flatMap((b) => m1.flatMap((c) => m2.map((d) => f(b, c, d)))); - - @override - Either map(C Function(R a) f) => Left(_value); - - @override - Either mapLeft(C Function(L a) f) => Left(f(_value)); - - @override - C foldRight(C b, C Function(C acc, R a) f) => b; - - @override - C match(C Function(L l) onLeft, C Function(R r) onRight) => onLeft(_value); - - @override - Either flatMap(covariant Either Function(R a) f) => - Left(_value); - - @override - Option toOption() => Option.none(); +final class Left extends Either { + final L value; + const Left(this.value); @override - bool isLeft() => true; + Effect get asEffect => Effect._((_) => Left(Failure(value))); @override - bool isRight() => false; + Either andThen(C Function(R value) f) => Left(value); @override - Either swap() => Right(_value); + Either orElse(Either Function(L l) orElse) => orElse(value); @override - Either alt(covariant Either Function() orElse) => orElse(); + R getOrElse(R Function(L l) orElse) => orElse(value); @override - Option getLeft() => Some(_value); + Either flip() => Right(value); @override - Either extend(Z Function(Either t) f) => Either.left(_value); + Either mapBoth( + {required D Function(L l) onLeft, + required C Function(R r) onRight}) => + Left(onLeft(value)); @override - Either orElse(Either Function(L l) onLeft) => - onLeft(_value); + Either mapLeft(C Function(L l) f) => Left(f(value)); @override - R getOrElse(R Function(L l) orElse) => orElse(_value); + Either flatMap(Either Function(R r) f) => Left(value); @override - bool elem(R r, Eq eq) => false; + Effect provide() => Effect.fail(value); @override - bool exists(bool Function(R r) predicate) => false; + R? getOrNull() => null; @override - bool operator ==(Object other) => (other is Left) && other._value == _value; + Option getRight() => const None(); @override - int get hashCode => _value.hashCode; + bool operator ==(Object other) => (other is Left) && other.value == value; @override - String toString() => 'Left($_value)'; + int get hashCode => value.hashCode; @override - TaskEither bindFuture(Future> Function(R r) f) => - TaskEither.left(_value); + String toString() => 'Left($value)'; @override - TaskEither toTaskEither() => TaskEither.left(_value); + Either filterOrLeft({ + required bool Function(R r) predicate, + required L Function(R r) orLeftWith, + }) => + Left(value); @override - IOEither toIOEither() => IOEither.left(_value); + Option getLeft() => Some(value); @override - R? toNullable() => null; + Either tap(Either Function(R r) f) => Left(value); } diff --git a/packages/fpdart/lib/src/exit.dart b/packages/fpdart/lib/src/exit.dart new file mode 100644 index 00000000..6e6eb103 --- /dev/null +++ b/packages/fpdart/lib/src/exit.dart @@ -0,0 +1,71 @@ +import 'effect.dart'; + +typedef Exit = Either, R>; + +sealed class Cause implements Error { + const Cause(); +} + +/// Failed as a result of a defect (unexpected error) +final class Die extends Cause { + final dynamic error; + final StackTrace defectStackTrace; + + @override + final StackTrace? stackTrace; + + const Die(this.error, this.defectStackTrace, [this.stackTrace]); + + factory Die.current(dynamic error, [StackTrace? stackTrace]) => + Die(error, StackTrace.current, stackTrace); + + @override + bool operator ==(Object other) => (other is Failure) && other.error == error; + + @override + int get hashCode => error.hashCode; + + @override + String toString() { + return "Cause.Die($error)"; + } +} + +/// Failed with an expected error +final class Failure extends Cause { + final L error; + + @override + final StackTrace? stackTrace; + + const Failure(this.error, [this.stackTrace]); + + @override + bool operator ==(Object other) => (other is Failure) && other.error == error; + + @override + int get hashCode => error.hashCode; + + @override + String toString() { + return "Cause.Fail($error)"; + } +} + +final class Interrupted extends Cause { + @override + final StackTrace? stackTrace; + + const Interrupted([this.stackTrace]); + + @override + bool operator ==(Object other) => (other is Interrupted); + + @override + int get hashCode => 0; + + @override + String toString() { + return "Cause.Interrupted()"; + } +} diff --git a/packages/fpdart/lib/src/extension/curry_extension.dart b/packages/fpdart/lib/src/extension/curry_extension.dart index 2b1ca4ee..8bb1a961 100644 --- a/packages/fpdart/lib/src/extension/curry_extension.dart +++ b/packages/fpdart/lib/src/extension/curry_extension.dart @@ -1,10 +1,10 @@ -/// {@template fpdart_curry_extension} -/// Extract first parameter from this function to allow curring. -/// {@endtemplate} -/// -/// {@template fpdart_curry_last_extension} -/// Extract **last** parameter from this function to allow curring. -/// {@endtemplate} +// {@template fpdart_curry_extension} +// Extract first parameter from this function to allow curring. +// {@endtemplate} + +// {@template fpdart_curry_last_extension} +// Extract **last** parameter from this function to allow curring. +// {@endtemplate} extension CurryExtension2 on Output Function( Input1, Input2) { diff --git a/packages/fpdart/lib/src/extension/date_time_extension.dart b/packages/fpdart/lib/src/extension/date_time_extension.dart deleted file mode 100644 index fa431676..00000000 --- a/packages/fpdart/lib/src/extension/date_time_extension.dart +++ /dev/null @@ -1,17 +0,0 @@ -import '../typeclass/eq.dart'; - -/// `fpdart` extension methods on [DateTime] -extension FpdartOnDateTime on DateTime { - /// Return `true` when this [DateTime] and `other` have the same **year**. - bool eqvYear(DateTime other) => Eq.dateEqYear.eqv(this, other); - - /// Return `true` when this [DateTime] and `other` have the same **month**. - bool eqvMonth(DateTime other) => Eq.dateEqMonth.eqv(this, other); - - /// Return `true` when this [DateTime] and `other` have the same **day**. - bool eqvDay(DateTime other) => Eq.dateEqDay.eqv(this, other); - - /// Return `true` when this [DateTime] and `other` have the same **year, month, and day**. - bool eqvYearMonthDay(DateTime other) => - Eq.dateEqYearMonthDay.eqv(this, other); -} diff --git a/packages/fpdart/lib/src/extension/extension.export.dart b/packages/fpdart/lib/src/extension/extension.export.dart deleted file mode 100644 index 1a247e4a..00000000 --- a/packages/fpdart/lib/src/extension/extension.export.dart +++ /dev/null @@ -1,8 +0,0 @@ -export 'curry_extension.dart'; -export 'date_time_extension.dart'; -export 'iterable_extension.dart'; -export 'list_extension.dart'; -export 'map_extension.dart'; -export 'option_extension.dart'; -export 'predicate_extension.dart'; -export 'string_extension.dart'; diff --git a/packages/fpdart/lib/src/extension/future_or_extension.dart b/packages/fpdart/lib/src/extension/future_or_extension.dart new file mode 100644 index 00000000..67d3cf84 --- /dev/null +++ b/packages/fpdart/lib/src/extension/future_or_extension.dart @@ -0,0 +1,25 @@ +import 'dart:async'; + +extension FutureOrThenExtension on FutureOr { + FutureOr then( + FutureOr Function(A a) f, { + B Function(Object error, StackTrace stackTrace)? onError, + }) { + switch (this) { + case Future self: + return self.then(f).catchError( + (Object error, StackTrace stackTrace) { + if (onError != null) onError(error, stackTrace); + throw error; + }, + ); + case A self: + try { + return f(self); + } catch (error, stackTrace) { + if (onError != null) return onError(error, stackTrace); + rethrow; + } + } + } +} diff --git a/packages/fpdart/lib/src/extension/iterable_extension.dart b/packages/fpdart/lib/src/extension/iterable_extension.dart index 8ebba6b2..240ae25c 100644 --- a/packages/fpdart/lib/src/extension/iterable_extension.dart +++ b/packages/fpdart/lib/src/extension/iterable_extension.dart @@ -1,24 +1,23 @@ import 'dart:collection'; +import 'package:fpdart/src/ordering.dart'; + +import '../effect.dart'; import '../function.dart'; -import '../option.dart'; -import '../typeclass/eq.dart'; -import '../typeclass/order.dart'; -import 'predicate_extension.dart'; +import '../order.dart'; /// {@template fpdart_iterable_extension_head} /// Get the first element of the [Iterable]. /// If the [Iterable] is empty, return [None]. /// {@endtemplate} -/// Functional programming functions on a mutable dart [Iterable] using `fpdart`. extension FpdartOnIterable on Iterable { /// {@macro fpdart_iterable_extension_head} /// /// Same as `firstOption`. Option get head { var it = iterator; - if (it.moveNext()) return some(it.current); + if (it.moveNext()) return Some(it.current); return const None(); } @@ -32,7 +31,10 @@ extension FpdartOnIterable on Iterable { /// /// **Note**: Because accessing the last element of an [Iterable] requires /// stepping through all the other elements, `lastOption` **can be slow**. - Option get lastOption => isEmpty ? const None() : some(last); + Option get lastOption { + if (isEmpty) return const None(); + return Some(last); + } /// Return all the elements of a [Iterable] except the first one. /// If the [Iterable] is empty, return [None]. @@ -43,7 +45,10 @@ extension FpdartOnIterable on Iterable { /// iterable is iterated. If this original iterable has become empty /// at that point, the returned iterable will also be empty, same /// as if this iterable has only one element. - Option> get tail => isEmpty ? const None() : some(skip(1)); + Option> get tail { + if (isEmpty) return const None(); + return Some(skip(1)); + } /// Return all the elements of a [Iterable] except the last one. /// If the [Iterable] is empty, return [None]. @@ -56,7 +61,7 @@ extension FpdartOnIterable on Iterable { /// as if this iterable has only one element. Option> get init { if (isEmpty) return const None(); - return some(this.dropRight(1)); + return Some(this.dropRight(1)); } /// Drops the last [count] element of this iterable. @@ -131,17 +136,6 @@ extension FpdartOnIterable on Iterable { (Iterable, Iterable) span(bool Function(T t) test) => (takeWhile(test), skipWhile(test)); - /// Return a record where first element is longest prefix (possibly empty) of this [Iterable] - /// with elements that **do not satisfy** `test` and second element is the remainder of the [Iterable]. - (Iterable, Iterable) breakI(bool Function(T t) test) => - (takeWhile(test.negate), skipWhile(test.negate)); - - /// Return a record containing the values of this [Iterable] - /// for which `test` is `false` in the first element, - /// and the values for which it is `true` in the second element. - (Iterable, Iterable) partition(bool Function(T t) test) => - (where(test.negate), where(test)); - /// Return a record where first element is an [Iterable] with the first `n` elements of this [Iterable], /// and the second element contains the rest of the [Iterable]. (Iterable, Iterable) splitAt(int n) => (take(n), skip(n)); @@ -184,16 +178,6 @@ extension FpdartOnIterable on Iterable { /// Check if `element` is **not** contained inside this [Iterable]. bool notElem(T element) => !elem(element); - /// Get first element equal to [element] in this [Iterable]. - /// - /// Returns `None` if no such element. - Option lookupEq(Eq eq, T element) { - for (var e in this) { - if (eq.eqv(e, element)) return some(e); - } - return const None(); - } - /// Fold this [Iterable] into a single value by aggregating each element of the list /// **from the first to the last**. /// @@ -257,7 +241,7 @@ extension FpdartOnIterable on Iterable { Iterable insertBy(Order order, T element) sync* { var it = iterator; while (it.moveNext()) { - if (order.compare(it.current, element) < 0) { + if (order.compare(it.current, element) == Ordering.equal) { yield it.current; continue; } @@ -286,7 +270,7 @@ extension FpdartOnIterable on Iterable { var it = iterator; var elementValue = extract(element); while (it.moveNext()) { - if (order.compare(extract(it.current), elementValue) < 0) { + if (order.compare(extract(it.current), elementValue).isLessThan) { yield it.current; continue; } @@ -341,11 +325,11 @@ extension FpdartOnIterable on Iterable { if (it.moveNext()) { T min = it.current; while (it.moveNext()) { - if (order.compare(it.current, min) > 0) { + if (order.compare(it.current, min).isGreaterThan) { min = it.current; } } - return some(min); + return Some(min); } return const None(); } @@ -358,11 +342,11 @@ extension FpdartOnIterable on Iterable { if (it.moveNext()) { T min = it.current; while (it.moveNext()) { - if (order.compare(it.current, min) < 0) { + if (order.compare(it.current, min).isLessThan) { min = it.current; } } - return some(min); + return Some(min); } return const None(); } @@ -386,9 +370,9 @@ extension FpdartOnIterable on Iterable { /// Return an [Iterable] containing the values of this [Iterable] not included /// in `other` based on `eq`. - Iterable difference(Eq eq, Iterable other) sync* { + Iterable difference(Iterable other) sync* { for (var element in this) { - if (!other.any((e) => eq.eqv(e, element))) { + if (!other.any((e) => e == element)) { yield element; } } @@ -406,21 +390,36 @@ extension FpdartOnIterable on Iterable { } /// Sort this [List] based on `order` ([Order]). - List sortBy(Order order) => [...this]..sort(order.compare); + List sortBy(Order order) => + [...this]..sort((a, b) => order.compare(a, b).order); /// Sort this [Iterable] based on `order` of an object of type `A` extracted from `T` using `extract`. - List sortWith(A Function(T t) extract, Order order) => - [...this]..sort((e1, e2) => order.compare(extract(e1), extract(e2))); + List sortWith(A Function(T t) extract, Order order) => [...this] + ..sort((e1, e2) => order.compare(extract(e1), extract(e2)).order); /// Sort this [Iterable] based on [DateTime] extracted from type `T` using `getDate`. /// /// Sorting [DateTime] in **ascending** order (older dates first). - List sortWithDate(DateTime Function(T instance) getDate) => - sortWith(getDate, Order.orderDate); + List sortWithDate(DateTime Function(T instance) getDate) => sortWith( + getDate, + Order.comparable(), + ); } -/// Functional programming functions on `Iterable>` using `fpdart`. extension FpdartOnIterableOfIterable on Iterable> { /// From a `Iterable>` return a `Iterable` of their concatenation. Iterable get flatten => expand(identity); } + +extension IterableEffect on Iterable> { + Effect> get all => Effect.all(this); +} + +extension FpdartSequenceIterableOption on Iterable> { + Iterable get getSomes => Option.getSomes(this); +} + +extension FpdartSequenceIterableEither on Iterable> { + Iterable get getRights => Either.getRights(this); + Iterable get getLefts => Either.getLefts(this); +} diff --git a/packages/fpdart/lib/src/extension/list_extension.dart b/packages/fpdart/lib/src/extension/list_extension.dart index 8b4b0ba6..fbcfeca6 100644 --- a/packages/fpdart/lib/src/extension/list_extension.dart +++ b/packages/fpdart/lib/src/extension/list_extension.dart @@ -1,13 +1,3 @@ -import '../either.dart'; -import '../io.dart'; -import '../io_either.dart'; -import '../io_option.dart'; -import '../option.dart'; -import '../state.dart'; -import '../task.dart'; -import '../task_either.dart'; -import '../task_option.dart'; - /// Functional programming functions on a mutable dart [Iterable] using `fpdart`. extension FpdartOnList on List { /// Fold this [List] into a single value by aggregating each element of the list @@ -46,216 +36,3 @@ extension FpdartOnList on List { Iterable dropWhileRight(bool Function(T t) test) => reversed.skipWhile(test); } - -extension FpdartTraversableIterable on Iterable { - /// {@macro fpdart_traverse_list_option} - Option> traverseOptionWithIndex( - Option Function(T a, int i) f, - ) => - Option.traverseListWithIndex(toList(), f); - - /// {@macro fpdart_traverse_list_option} - Option> traverseOption( - Option Function(T a) f, - ) => - Option.traverseList(toList(), f); - - /// {@macro fpdart_traverse_list_io_option} - IOOption> traverseIOOptionWithIndex( - IOOption Function(T a, int i) f, - ) => - IOOption.traverseListWithIndex(toList(), f); - - /// {@macro fpdart_traverse_list_io_option} - IOOption> traverseIOOption( - IOOption Function(T a) f, - ) => - IOOption.traverseList(toList(), f); - - /// {@macro fpdart_traverse_list_task_option} - TaskOption> traverseTaskOptionWithIndex( - TaskOption Function(T a, int i) f, - ) => - TaskOption.traverseListWithIndex(toList(), f); - - /// {@macro fpdart_traverse_list_task_option} - TaskOption> traverseTaskOption( - TaskOption Function(T a) f, - ) => - TaskOption.traverseList(toList(), f); - - /// {@macro fpdart_traverse_list_seq_task_option} - TaskOption> traverseTaskOptionWithIndexSeq( - TaskOption Function(T a, int i) f, - ) => - TaskOption.traverseListWithIndexSeq(toList(), f); - - /// {@macro fpdart_traverse_list_seq_task_option} - TaskOption> traverseTaskOptionSeq( - TaskOption Function(T a) f, - ) => - TaskOption.traverseListSeq(toList(), f); - - /// {@macro fpdart_traverse_list_io} - IO> traverseIOWithIndex( - IO Function(T a, int i) f, - ) => - IO.traverseListWithIndex(toList(), f); - - /// {@macro fpdart_traverse_list_io} - IO> traverseIO( - IO Function(T a) f, - ) => - IO.traverseList(toList(), f); - - /// {@macro fpdart_traverse_list_task} - Task> traverseTaskWithIndex( - Task Function(T a, int i) f, - ) => - Task.traverseListWithIndex(toList(), f); - - /// {@macro fpdart_traverse_list_task} - Task> traverseTask( - Task Function(T a) f, - ) => - Task.traverseList(toList(), f); - - /// {@macro fpdart_traverse_list_seq_task} - Task> traverseTaskWithIndexSeq( - Task Function(T a, int i) f, - ) => - Task.traverseListWithIndexSeq(toList(), f); - - /// {@macro fpdart_traverse_list_seq_task} - Task> traverseTaskSeq( - Task Function(T a) f, - ) => - Task.traverseListSeq(toList(), f); - - /// {@macro fpdart_traverse_list_either} - Either> traverseEitherWithIndex( - Either Function(T a, int i) f, - ) => - Either.traverseListWithIndex(toList(), f); - - /// {@macro fpdart_traverse_list_either} - Either> traverseEither( - Either Function(T a) f, - ) => - Either.traverseList(toList(), f); - - /// {@macro fpdart_traverse_list_task_either} - TaskEither> traverseTaskEitherWithIndex( - TaskEither Function(T a, int i) f, - ) => - TaskEither.traverseListWithIndex(toList(), f); - - /// {@macro fpdart_traverse_list_task_either} - TaskEither> traverseTaskEither( - TaskEither Function(T a) f, - ) => - TaskEither.traverseList(toList(), f); - - /// {@macro fpdart_traverse_list_seq_task_either} - TaskEither> traverseTaskEitherWithIndexSeq( - TaskEither Function(T a, int i) f, - ) => - TaskEither.traverseListWithIndexSeq(toList(), f); - - /// {@macro fpdart_traverse_list_seq_task_either} - TaskEither> traverseTaskEitherSeq( - TaskEither Function(T a) f, - ) => - TaskEither.traverseListSeq(toList(), f); - - /// {@macro fpdart_traverse_list_io_either} - IOEither> traverseIOEitherWithIndex( - IOEither Function(T a, int i) f, - ) => - IOEither.traverseListWithIndex(toList(), f); - - /// {@macro fpdart_traverse_list_io_either} - IOEither> traverseIOEither( - IOEither Function(T a) f, - ) => - IOEither.traverseList(toList(), f); - - /// {@macro fpdart_traverse_list_state} - State> traverseStateWithIndex( - State Function(T a, int i) f, - ) => - State.traverseListWithIndex(toList(), f); - - /// {@macro fpdart_traverse_list_state} - State> traverseState( - State Function(T a) f, - ) => - State.traverseList(toList(), f); -} - -extension FpdartSequenceIterableOption on Iterable> { - /// {@macro fpdart_sequence_list_option} - Option> sequenceOption() => Option.sequenceList(toList()); -} - -extension FpdartSequenceIterableIOOption on Iterable> { - /// {@macro fpdart_sequence_list_io_option} - IOOption> sequenceIOOption() => IOOption.sequenceList(toList()); -} - -extension FpdartSequenceIterableTaskOption on Iterable> { - /// {@macro fpdart_sequence_list_task_option} - TaskOption> sequenceTaskOption() => TaskOption.sequenceList(toList()); - - /// {@macro fpdart_sequence_list_seq_task_option} - TaskOption> sequenceTaskOptionSeq() => - TaskOption.sequenceListSeq(toList()); -} - -extension FpdartSequenceIterableIO on Iterable> { - /// {@macro fpdart_sequence_list_io} - IO> sequenceIO() => IO.sequenceList(toList()); -} - -extension FpdartSequenceIterableTask on Iterable> { - /// {@macro fpdart_sequence_list_task} - Task> sequenceTask() => Task.sequenceList(toList()); - - /// {@macro fpdart_sequence_list_seq_task} - Task> sequenceTaskSeq() => Task.sequenceListSeq(toList()); -} - -extension FpdartSequenceIterableEither on Iterable> { - /// {@macro fpdart_sequence_list_either} - Either> sequenceEither() => Either.sequenceList(toList()); - - /// {@macro fpdart_rights_either} - List rightsEither() => Either.rights(toList()); - - /// {@macro fpdart_lefts_either} - List leftsEither() => Either.lefts(toList()); - - /// {@macro fpdart_partition_eithers_either} - (List, List) partitionEithersEither() => - Either.partitionEithers(toList()); -} - -extension FpdartSequenceIterableTaskEither on Iterable> { - /// {@macro fpdart_sequence_list_task_either} - TaskEither> sequenceTaskEither() => - TaskEither.sequenceList(toList()); - - /// {@macro fpdart_sequence_list_seq_task_either} - TaskEither> sequenceTaskEitherSeq() => - TaskEither.sequenceListSeq(toList()); -} - -extension FpdartSequenceIterableIOEither on Iterable> { - /// {@macro fpdart_sequence_list_io_either} - IOEither> sequenceIOEither() => IOEither.sequenceList(toList()); -} - -/// {@macro fpdart_sequence_list_state} -extension FpdartSequenceIterableState on Iterable> { - State> sequenceState() => State.sequenceList(toList()); -} diff --git a/packages/fpdart/lib/src/extension/map_extension.dart b/packages/fpdart/lib/src/extension/map_extension.dart index 9065e7f9..a5bf0f77 100644 --- a/packages/fpdart/lib/src/extension/map_extension.dart +++ b/packages/fpdart/lib/src/extension/map_extension.dart @@ -1,8 +1,6 @@ -import '../option.dart'; -import '../typeclass/eq.dart'; -import '../typeclass/order.dart'; +import '../effect.dart'; +import '../order.dart'; import 'iterable_extension.dart'; -import 'option_extension.dart'; /// Functional programming functions on a mutable dart [Map] using `fpdart`. extension FpdartOnMap on Map { @@ -55,35 +53,16 @@ extension FpdartOnMap on Map { /// Get the value at given `key` if present, otherwise return [None]. Option lookup(K key) { var value = this[key]; - if (value != null) return some(value); - if (containsKey(key)) return some(value as V); + if (value != null) return Some(value); + if (containsKey(key)) return Some(value as V); return const None(); } - /// Get the key equal to `key` if present, otherwise return [None]. - Option lookupKeyEq(Eq eq, K key) => keys.lookupEq(eq, key); - /// Get the value and key at given `key` if present, otherwise return [None]. Option<(K, V)> lookupWithKey(K key) { final value = this[key]; - if (value != null) return some((key, value)); - if (containsKey(key)) return some((key, value as V)); - return const None(); - } - - /// Get the value at given `key` if present using `eq`, otherwise return [None]. - Option lookupEq(Eq eq, K key) { - for (var entry in entries) { - if (eq.eqv(entry.key, key)) return some(entry.value); - } - return const None(); - } - - /// Get the value and key at given `key` if present using `eq`, otherwise return [None]. - Option<(K, V)> lookupWithKeyEq(Eq eq, K key) { - for (var entry in entries) { - if (eq.eqv(entry.key, key)) return some((entry.key, entry.value)); - } + if (value != null) return Some((key, value)); + if (containsKey(key)) return Some((key, value as V)); return const None(); } @@ -98,7 +77,8 @@ extension FpdartOnMap on Map { /// ``` Option extract(K key) { final value = this[key]; - return value is T ? some(value) : const None(); + if (value is T) return Some(value); + return const None(); } /// Return an [Option] that conditionally accesses map keys if they contain a value @@ -112,78 +92,10 @@ extension FpdartOnMap on Map { /// ``` Option> extractMap(K key) => extract>(key); - /// If the given `key` is present in the [Map], then modify its value - /// using `update` and return the [Map]. - /// - /// If multiple keys equal to [key] exist in the map, all of them are updated. - /// - /// Otherwise, return [None]. - Option> modifyAt( - Eq eq, - V Function(V value) update, - K key, - ) { - for (var entryKey in keys) { - if (eq.eqv(entryKey, key)) { - // At least one equal key exists in map. - return some({ - for (var entry in entries) - entry.key: - eq.eqv(entry.key, key) ? update(entry.value) : entry.value - }); - } - } - return const None(); - } - - /// If the given `key` is present in the [Map], then modify its value - /// using `update` and return a the new [Map]. - /// - /// Otherwise, return a copy of the original unmodified [Map]. - Map modifyAtIfPresent( - Eq eq, - V Function(V value) update, - K key, - ) => - modifyAt(eq, update, key).getOrElse(() => {...this}); - - /// If the given `key` is present in the [Map], then update its value to `value`. - /// - /// Otherwise, return [None]. - Option> updateAt(Eq eq, K key, V value) => - modifyAt(eq, (_) => value, key); - - /// If the given `key` is present in the [Map], then update its value to `value`. - /// Otherwise, return a copy of the original unmodified [Map]. - Map updateAtIfPresent( - Eq eq, - K key, - V value, - ) => - updateAt(eq, key, value).getOrElse( - () => {...this}, - ); - /// Delete entry at given `key` if present in the [Map] and return updated [Map]. /// /// See also `pop`. - Map deleteAt(Eq eq, K key) => - filterWithKey((k, v) => !eq.eqv(k, key)); - - /// Insert or replace a key/value pair in a [Map]. - Map upsertAt(Eq eq, K key, V value) => - modifyAt(eq, (_) => value, key).getOrElse( - () => {...this, key: value}, - ); - - /// Delete a `key` and value from a this [Map], returning the deleted value as well as the updated [Map]. - /// - /// If `key` is not present, then return [None]. - /// - /// See also `deleteAt`. - Option<(V, Map)> pop(Eq eq, K key) => lookupEq(eq, key).map( - (v) => (v, deleteAt(eq, key)), - ); + Map deleteAt(K key) => filterWithKey((k, v) => k != key); /// Apply `compose` to all the values of this [Map] sorted based on `order` on their key, /// and return the result of combining all the intermediate values. @@ -313,58 +225,13 @@ extension FpdartOnMap on Map { return result; } - /// Combine the key/value of this [Map] and `map` using `combine` where the key is the same. - Map union( - Eq eq, - V Function(V x, V y) combine, - Map map, - ) { - var result = {...this}; - for (var entry in map.entries) { - if (lookupKeyEq(eq, entry.key) case Some(value: var key)) { - result.update(key, (v) => combine(entry.value, v)); - } else { - result[entry.key] = entry.value; - } - } - return result; - } - - /// Intersect the key/value of two [Map] using `combine` where the key is the same. - Map intersection( - Eq eq, - V Function(V x, V y) combine, - Map map, - ) => - { - for (var entry in map.entries) - if (lookupEq(eq, entry.key) case Some(:var value)) - entry.key: combine(value, entry.value) - }; - /// Remove from this [Map] all the elements that have **key** contained in the given `map`. - Map difference(Eq eq, Map map) => filterWithKey( + Map difference(Map map) => filterWithKey( (key, value) => !map.keys.any( - (element) => eq.eqv(element, key), + (element) => element == key, ), ); - /// Test whether or not the given `map` contains all of the keys and values contained in this [Map]. - bool isSubmap( - Eq eqK, - Eq eqV, - Map map, - ) => - foldLeftWithKey( - Order.allEqual(), - true, - (b, k, v) => - b && - map.entries.any( - (e) => eqK.eqv(e.key, k) && eqV.eqv(e.value, v), - ), - ); - /// Collect all the entries in this [Map] into an [Iterable] using `compose`, /// with the values ordered using `order`. /// diff --git a/packages/fpdart/lib/src/extension/option_extension.dart b/packages/fpdart/lib/src/extension/option_extension.dart deleted file mode 100644 index 869f0827..00000000 --- a/packages/fpdart/lib/src/extension/option_extension.dart +++ /dev/null @@ -1,30 +0,0 @@ -import '../function.dart'; -import '../option.dart'; -import '../typeclass/eq.dart'; - -extension FpdartOnOption on Option { - /// Return the current [Option] if it is a [Some], otherwise return the result of `orElse`. - /// - /// Used to provide an **alt**ernative [Option] in case the current one is [None]. - /// ```dart - /// [🍌].alt(() => [🍎]) -> [🍌] - /// [_].alt(() => [🍎]) -> [🍎] - /// ``` - Option alt(Option Function() orElse) => - this is Some ? this : orElse(); - - /// Return `true` when value of `a` is equal to the value inside the [Option]. - bool elem(T t, Eq eq) => match(() => false, (value) => eq.eqv(value, t)); - - /// If this [Option] is a [Some] then return the value inside the [Option]. - /// Otherwise return the result of `orElse`. - /// ```dart - /// [🍌].getOrElse(() => 🍎) -> 🍌 - /// [_].getOrElse(() => 🍎) -> 🍎 - /// - /// 👆 same as 👇 - /// - /// [🍌].match(() => 🍎, (🍌) => 🍌) - /// ``` - T getOrElse(T Function() orElse) => match(orElse, identity); -} diff --git a/packages/fpdart/lib/src/extension/predicate_extension.dart b/packages/fpdart/lib/src/extension/predicate_extension.dart deleted file mode 100644 index fc9c8d72..00000000 --- a/packages/fpdart/lib/src/extension/predicate_extension.dart +++ /dev/null @@ -1,51 +0,0 @@ -extension FpdartOnPredicate on bool Function() { - /// Negate the return value of this function. - /// ```dart - /// bool alwaysTrue() => true; - /// final alwaysFalse = alwaysTrue.negate; - /// ``` - bool get negate => !this(); - - /// Compose using `&&` this function with `predicate`. - bool Function() and(bool Function() predicate) => () => this() && predicate(); - - /// Compose using `||` this function with `predicate`. - bool Function() or(bool Function() predicate) => () => this() || predicate(); - - /// Compose **xor** this function with `predicate`. - bool Function() xor(bool Function() predicate) => () { - final thisPredicate = this(); - final otherPredicate = predicate(); - return thisPredicate ? !otherPredicate : otherPredicate; - }; -} - -extension FpdartOnPredicate1

on bool Function(P) { - /// Negate the return value of this function. - /// ```dart - /// bool isEven(int n) => n % 2 == 0; - /// final isOdd = isEven.negate; - /// ``` - bool Function(P) get negate => (p) => !this(p); - - /// Compose using `&&` this function with `predicate`. - bool Function(P) and(bool Function(P p) predicate) => - (p) => this(p) && predicate(p); - - /// Compose using `||` this function with `predicate`. - bool Function(P) or(bool Function(P) predicate) => - (p) => this(p) || predicate(p); - - /// Compose **xor** this function with `predicate`. - bool Function(P) xor(bool Function(P) predicate) => - (p) => this(p) ^ predicate(p); - - /// Apply `map` to the value of the parameter `P` and return a new `bool Function(A)`. - /// - /// Similar to `map` for functions that return `bool`. - /// ```dart - /// bool even(int n) => n % 2 == 0; - /// final evenLength = even.contramap((a) => a.length); - /// ``` - bool Function(A) contramap(P Function(A a) map) => (a) => this(map(a)); -} diff --git a/packages/fpdart/lib/src/extension/string_extension.dart b/packages/fpdart/lib/src/extension/string_extension.dart deleted file mode 100644 index 19cb14ad..00000000 --- a/packages/fpdart/lib/src/extension/string_extension.dart +++ /dev/null @@ -1,34 +0,0 @@ -import '../either.dart'; -import '../option.dart'; - -/// Functional programming functions on dart [String] using `fpdart`. -extension FpdartOnString on String { - /// {@macro fpdart_string_extension_to_num_option} - Option get toNumOption => Option.fromNullable(num.tryParse(this)); - - /// {@macro fpdart_string_extension_to_int_option} - Option get toIntOption => Option.fromNullable(int.tryParse(this)); - - /// {@macro fpdart_string_extension_to_double_option} - Option get toDoubleOption => - Option.fromNullable(double.tryParse(this)); - - /// {@macro fpdart_string_extension_to_bool_option} - Option get toBoolOption => Option.fromNullable(bool.tryParse(this)); - - /// {@macro fpdart_string_extension_to_num_either} - Either toNumEither(L Function() onLeft) => - Either.fromNullable(num.tryParse(this), onLeft); - - /// {@macro fpdart_string_extension_to_int_either} - Either toIntEither(L Function() onLeft) => - Either.fromNullable(int.tryParse(this), onLeft); - - /// {@macro fpdart_string_extension_to_double_either} - Either toDoubleEither(L Function() onLeft) => - Either.fromNullable(double.tryParse(this), onLeft); - - /// {@macro fpdart_string_extension_to_bool_either} - Either toBoolEither(L Function() onLeft) => - Either.fromNullable(bool.tryParse(this), onLeft); -} diff --git a/packages/fpdart/lib/src/function.dart b/packages/fpdart/lib/src/function.dart index e7963fdd..ad769609 100644 --- a/packages/fpdart/lib/src/function.dart +++ b/packages/fpdart/lib/src/function.dart @@ -1,7 +1,3 @@ -import 'either.dart'; -import 'extension/string_extension.dart'; -import 'option.dart'; - /// Returns the given `a`. /// /// Shortcut function to return the input parameter: @@ -42,47 +38,3 @@ Future identityFuture(T a) => Future.value(a); /// print(c(112.12)); // -> 10 /// ``` A Function(dynamic b) constF(A a) => (B b) => a; - -/// {@template fpdart_string_extension_to_num_option} -/// Convert this [String] to [num], returns [None] for invalid inputs. -/// {@endtemplate} -Option toNumOption(String str) => str.toNumOption; - -/// {@template fpdart_string_extension_to_int_option} -/// Convert this [String] to [int], returns [None] for invalid inputs. -/// {@endtemplate} -Option toIntOption(String str) => str.toIntOption; - -/// {@template fpdart_string_extension_to_double_option} -/// Convert this [String] to [double], returns [None] for invalid inputs. -/// {@endtemplate} -Option toDoubleOption(String str) => str.toDoubleOption; - -/// {@template fpdart_string_extension_to_bool_option} -/// Convert this [String] to [bool], returns [None] for invalid inputs. -/// {@endtemplate} -Option toBoolOption(String str) => str.toBoolOption; - -/// {@template fpdart_string_extension_to_num_either} -/// Convert this [String] to [num], returns the result of `onLeft` for invalid inputs. -/// {@endtemplate} -Either Function(String) toNumEither(L Function() onLeft) => - (str) => str.toNumEither(onLeft); - -/// {@template fpdart_string_extension_to_int_either} -/// Convert this [String] to [int], returns the result of `onLeft` for invalid inputs. -/// {@endtemplate} -Either Function(String) toIntEither(L Function() onLeft) => - (str) => str.toIntEither(onLeft); - -/// {@template fpdart_string_extension_to_double_either} -/// Convert this [String] to [double], returns the result of `onLeft` for invalid inputs. -/// {@endtemplate} -Either Function(String) toDoubleEither(L Function() onLeft) => - (str) => str.toDoubleEither(onLeft); - -/// {@template fpdart_string_extension_to_bool_either} -/// Convert this [String] to [bool], returns the result of `onLeft` for invalid inputs. -/// {@endtemplate} -Either toBoolEither(String str, L Function() onLeft) => - str.toBoolEither(onLeft); diff --git a/packages/fpdart/lib/src/io.dart b/packages/fpdart/lib/src/io.dart deleted file mode 100644 index 91c7bd0d..00000000 --- a/packages/fpdart/lib/src/io.dart +++ /dev/null @@ -1,150 +0,0 @@ -import 'either.dart'; -import 'function.dart'; -import 'io_either.dart'; -import 'io_option.dart'; -import 'option.dart'; -import 'task.dart'; -import 'task_either.dart'; -import 'task_option.dart'; -import 'typeclass/applicative.dart'; -import 'typeclass/functor.dart'; -import 'typeclass/hkt.dart'; -import 'typeclass/monad.dart'; - -typedef DoAdapterIO = A Function(IO); -A _doAdapter(IO io) => io.run(); - -typedef DoFunctionIO = A Function(DoAdapterIO $); - -/// Tag the [HKT] interface for the actual [Option]. -abstract final class _IOHKT {} - -/// `IO` represents a **non-deterministic synchronous** computation that -/// can **cause side effects**, yields a value of type `A` and **never fails**. -/// -/// If you want to represent a synchronous computation that may fail, see [IOEither]. -final class IO extends HKT<_IOHKT, A> - with Functor<_IOHKT, A>, Applicative<_IOHKT, A>, Monad<_IOHKT, A> { - final A Function() _run; - - /// Build an instance of [IO] from `A Function()`. - const IO(this._run); - - /// Initialize a **Do Notation** chain. - // ignore: non_constant_identifier_names - factory IO.Do(DoFunctionIO f) => IO(() => f(_doAdapter)); - - /// Flat a [IO] contained inside another [IO] to be a single [IO]. - factory IO.flatten(IO> io) => io.flatMap(identity); - - /// Build a [IO] that returns `a`. - factory IO.of(A a) => IO(() => a); - - /// Used to chain multiple functions that return a [IO]. - @override - IO flatMap(covariant IO Function(A a) f) => IO(() => f(run()).run()); - - /// Chain a [Task] with an [IO]. - /// - /// Allows to chain a function that returns a `R` ([IO]) to - /// a function that returns a `Future` ([Task]). - Task flatMapTask(Task Function(A a) f) => f(run()); - - /// Convert this [IO] to a [IOEither]. - IOEither toIOEither() => IOEither(() => Either.of(run())); - - /// Lift this [IO] to a [Task]. - /// - /// Return a `Future` ([Task]) instead of a `R` ([IO]). - Task toTask() => Task(() async => run()); - - /// Convert this [IO] to a [TaskEither]. - TaskEither toTaskEither() => - TaskEither(() async => Either.of(run())); - - /// Convert this [IO] to a [TaskOption]. - TaskOption toTaskOption() => TaskOption(() async => Option.of(run())); - - /// Convert this [IO] to a [IOOption]. - IOOption toIOOption() => IOOption(() => Option.of(run())); - - /// Return an [IO] that returns the value `b`. - @override - IO pure(B b) => IO(() => b); - - /// Change the value of type `A` to a value of type `B` using function `f`. - @override - IO map(B Function(A a) f) => ap(pure(f)); - - /// Apply the function contained inside `a` to change the value of type `A` to - /// a value of type `B`. - @override - IO ap(covariant IO a) => - a.flatMap((f) => flatMap((v) => pure(f(v)))); - - /// Change type of this [IO] based on its value of type `A` and the - /// value of type `C` of another [IO]. - @override - IO map2(covariant IO mc, D Function(A a, C c) f) => - flatMap((a) => mc.map((c) => f(a, c))); - - /// Change type of this [IO] based on its value of type `A`, the - /// value of type `C` of a second [IO], and the value of type `D` - /// of a third [IO]. - @override - IO map3(covariant IO mc, covariant IO md, - E Function(A a, C c, D d) f) => - flatMap((a) => mc.flatMap((c) => md.map((d) => f(a, c, d)))); - - /// Chain multiple [IO] functions. - @override - IO call(covariant IO chain) => flatMap((_) => chain); - - /// Chain the result of `then` to this [IO]. - @override - IO andThen(covariant IO Function() then) => flatMap((_) => then()); - - /// Execute the IO function. - A run() => _run(); - - /// {@template fpdart_traverse_list_io} - /// Map each element in the list to an [IO] using the function `f`, - /// and collect the result in an `IO>`. - /// {@endtemplate} - /// - /// Same as `IO.traverseList` but passing `index` in the map function. - static IO> traverseListWithIndex( - List list, - IO Function(A a, int i) f, - ) => - IO>(() { - final resultList = []; - for (var i = 0; i < list.length; i++) { - resultList.add(f(list[i], i).run()); - } - return resultList; - }); - - /// {@macro fpdart_traverse_list_io} - /// - /// Same as `IO.traverseListWithIndex` but without `index` in the map function. - static IO> traverseList( - List list, - IO Function(A a) f, - ) => - traverseListWithIndex(list, (a, _) => f(a)); - - /// {@template fpdart_sequence_list_io} - /// Convert a `List>` to a single `IO>`. - /// {@endtemplate} - static IO> sequenceList( - List> list, - ) => - traverseList(list, identity); - - @override - bool operator ==(Object other) => (other is IO) && other._run == _run; - - @override - int get hashCode => _run.hashCode; -} diff --git a/packages/fpdart/lib/src/io_either.dart b/packages/fpdart/lib/src/io_either.dart deleted file mode 100644 index 06bcba14..00000000 --- a/packages/fpdart/lib/src/io_either.dart +++ /dev/null @@ -1,287 +0,0 @@ -import 'either.dart'; -import 'function.dart'; -import 'io.dart'; -import 'option.dart'; -import 'task_either.dart'; -import 'typeclass/alt.dart'; -import 'typeclass/applicative.dart'; -import 'typeclass/functor.dart'; -import 'typeclass/hkt.dart'; -import 'typeclass/monad.dart'; - -final class _IOEitherThrow { - final L value; - const _IOEitherThrow(this.value); -} - -typedef DoAdapterIOEither = A Function(IOEither); -DoAdapterIOEither _doAdapter() => - (ioEither) => ioEither.run().getOrElse((l) => throw _IOEitherThrow(l)); - -typedef DoFunctionIOEither = A Function(DoAdapterIOEither $); - -/// Tag the [HKT2] interface for the actual [IOEither]. -abstract final class _IOEitherHKT {} - -/// `IOEither` represents a **non-deterministic synchronous** computation that -/// can **cause side effects**, yields a value of type `R` or **can fail** by returning -/// a value of type `L`. -/// -/// If you want to represent a synchronous computation that may never fail, see [IO]. -final class IOEither extends HKT2<_IOEitherHKT, L, R> - with - Functor2<_IOEitherHKT, L, R>, - Applicative2<_IOEitherHKT, L, R>, - Monad2<_IOEitherHKT, L, R>, - Alt2<_IOEitherHKT, L, R> { - final Either Function() _run; - - /// Build an instance of [IOEither] from `Either Function()`. - const IOEither(this._run); - - /// Initialize a **Do Notation** chain. - // ignore: non_constant_identifier_names - factory IOEither.Do(DoFunctionIOEither f) => IOEither(() { - try { - return Either.of(f(_doAdapter())); - } on _IOEitherThrow catch (e) { - return Either.left(e.value); - } - }); - - /// Used to chain multiple functions that return a [IOEither]. - /// - /// You can extract the value of every [Right] in the chain without - /// handling all possible missing cases. - /// If running any of the IOs in the chain returns [Left], the result is [Left]. - @override - IOEither flatMap(covariant IOEither Function(R r) f) => - IOEither( - () => run().match( - (l) => Either.left(l), - (r) => f(r).run(), - ), - ); - - /// Chain a [TaskEither] with an [IOEither]. - /// - /// Allows to chain a function that returns a `Either` ([IOEither]) to - /// a function that returns a `Future>` ([TaskEither]). - TaskEither flatMapTask(TaskEither Function(R r) f) => - TaskEither( - () async => run().match( - (l) => Either.left(l), - (r) => f(r).run(), - ), - ); - - /// Convert this [IOEither] to [TaskEither]. - TaskEither toTaskEither() => TaskEither(() async => run()); - - /// Returns a [IOEither] that returns a `Right(a)`. - @override - IOEither pure(C a) => IOEither(() => Right(a)); - - /// Change the return type of this [IOEither] based on its value of type `R` and the - /// value of type `C` of another [IOEither]. - @override - IOEither map2( - covariant IOEither m1, D Function(R b, C c) f) => - flatMap((b) => m1.map((c) => f(b, c))); - - /// Change the return type of this [IOEither] based on its value of type `R`, the - /// value of type `C` of a second [IOEither], and the value of type `D` - /// of a third [IOEither]. - @override - IOEither map3(covariant IOEither m1, - covariant IOEither m2, E Function(R b, C c, D d) f) => - flatMap((b) => m1.flatMap((c) => m2.map((d) => f(b, c, d)))); - - /// If running this [IOEither] returns [Right], then return the result of calling `then`. - /// Otherwise return [Left]. - @override - IOEither andThen(covariant IOEither Function() then) => - flatMap((_) => then()); - - /// If running this [IOEither] returns [Right], then change its value from type `R` to - /// type `C` using function `f`. - @override - IOEither map(C Function(R r) f) => ap(pure(f)); - - /// Change the value in the [Left] of [IOEither]. - IOEither mapLeft(C Function(L l) f) => IOEither( - () => (run()).match((l) => Either.left(f(l)), Either.of), - ); - - /// Define two functions to change both the [Left] and [Right] value of the - /// [IOEither]. - /// - /// {@macro fpdart_bimap_either} - IOEither bimap(C Function(L a) mLeft, D Function(R b) mRight) => - mapLeft(mLeft).map(mRight); - - /// Apply the function contained inside `a` to change the value on the [Right] from - /// type `R` to a value of type `C`. - @override - IOEither ap(covariant IOEither a) => - a.flatMap((f) => flatMap((v) => pure(f(v)))); - - /// Change this [IOEither] from `IOEither` to `IOEither`. - IOEither swap() => - IOEither(() => run().match((l) => Right(l), (r) => Left(r))); - - /// When this [IOEither] returns [Right], then return the current [IOEither]. - /// Otherwise return the result of `orElse`. - /// - /// Used to provide an **alt**ernative [IOEither] in case the current one returns [Left]. - @override - IOEither alt(covariant IOEither Function() orElse) => - IOEither(() => run().match((_) => orElse().run(), right)); - - /// Chain multiple functions having the same left type `L`. - @override - IOEither call(covariant IOEither chain) => - flatMap((_) => chain); - - /// If `f` applied on this [IOEither] as [Right] returns `true`, then return this [IOEither]. - /// If it returns `false`, return the result of `onFalse` in a [Left]. - IOEither filterOrElse(bool Function(R r) f, L Function(R r) onFalse) => - flatMap((r) => f(r) ? IOEither.of(r) : IOEither.left(onFalse(r))); - - /// When this [IOEither] returns a [Left] then return the result of `orElse`. - /// Otherwise return this [IOEither]. - IOEither orElse(IOEither Function(L l) orElse) => - IOEither(() => run().match( - (l) => orElse(l).run(), (r) => IOEither.right(r).run())); - - /// Convert this [IOEither] to a [IO]. - /// - /// The IO returns a [Right] when [IOEither] returns [Right]. - /// Otherwise map the type `L` of [IOEither] to type `R` by calling `orElse`. - IO getOrElse(R Function(L l) orElse) => - IO(() => run().match(orElse, identity)); - - /// Pattern matching to convert a [IOEither] to a [IO]. - /// - /// Execute `onLeft` when running this [IOEither] returns a [Left]. - /// Otherwise execute `onRight`. - IO match(A Function(L l) onLeft, A Function(R r) onRight) => - IO(() => run().match(onLeft, onRight)); - - /// Chain a request that returns another [IOEither], execute it, ignore - /// the result, and return the same value as the current [IOEither]. - @override - IOEither chainFirst( - covariant IOEither Function(R b) chain, - ) => - flatMap((b) => chain(b).map((c) => b).orElse((l) => IOEither.right(b))); - - /// Run the IO and return a `Either`. - Either run() => _run(); - - /// Build a [IOEither] that returns a `Right(r)`. - /// - /// Same of `IOEither.right`. - factory IOEither.of(R r) => IOEither(() => Either.of(r)); - - /// Flat a [IOEither] contained inside another [IOEither] to be a single [IOEither]. - factory IOEither.flatten(IOEither> ioEither) => - ioEither.flatMap(identity); - - /// Build a [IOEither] that returns a `Right(right)`. - /// - /// Same of `IOEither.of`. - factory IOEither.right(R right) => IOEither(() => Either.of(right)); - - /// Build a [IOEither] that returns a `Left(left)`. - factory IOEither.left(L left) => IOEither(() => Left(left)); - - /// Build a [IOEither] that returns a [Left] containing the result of running `io`. - factory IOEither.leftIO(IO io) => IOEither(() => Either.left(io.run())); - - /// Build a [IOEither] that returns a [Right] containing the result of running `io`. - /// - /// Same of `IOEither.fromIO` - factory IOEither.rightIO(IO io) => IOEither(() => Right(io.run())); - - /// Build a [IOEither] from the result of running `io`. - /// - /// Same of `IOEither.rightIO` - factory IOEither.fromIO(IO io) => IOEither(() => Right(io.run())); - - /// When calling `predicate` with `value` returns `true`, then running [IOEither] returns `Right(value)`. - /// Otherwise return `onFalse`. - factory IOEither.fromPredicate( - R value, bool Function(R a) predicate, L Function(R a) onFalse) => - IOEither(() => predicate(value) ? Right(value) : Left(onFalse(value))); - - /// Build a [IOEither] from `option`. - /// - /// When `option` is [Some], then return [Right] when - /// running [IOEither]. Otherwise return `onNone`. - factory IOEither.fromOption(Option option, L Function() onNone) => - IOEither(() => option.match( - () => Left(onNone()), - Right.new, - )); - - /// Build a [IOEither] that returns `either`. - factory IOEither.fromEither(Either either) => IOEither(() => either); - - /// If `r` is `null`, then return the result of `onNull` in [Left]. - /// Otherwise return `Right(r)`. - factory IOEither.fromNullable(R? r, L Function() onNull) => - Either.fromNullable(r, onNull).toIOEither(); - - /// Converts a [Function] that may throw to a [Function] that never throws - /// but returns a [Either] instead. - /// - /// Used to handle asynchronous computations that may throw using [Either]. - factory IOEither.tryCatch(R Function() run, - L Function(Object error, StackTrace stackTrace) onError) => - IOEither(() { - try { - return Right(run()); - } catch (error, stack) { - return Left(onError(error, stack)); - } - }); - - /// {@template fpdart_traverse_list_io_either} - /// Map each element in the list to a [IOEither] using the function `f`, - /// and collect the result in an `IOEither>`. - /// {@endtemplate} - /// - /// Same as `IOEither.traverseList` but passing `index` in the map function. - static IOEither> traverseListWithIndex( - List list, - IOEither Function(A a, int i) f, - ) => - IOEither>( - () => Either.sequenceList( - IO - .traverseListWithIndex>( - list, - (a, i) => IO(() => f(a, i).run()), - ) - .run(), - ), - ); - - /// {@macro fpdart_traverse_list_io_either} - /// - /// Same as `IOEither.traverseListWithIndex` but without `index` in the map function. - static IOEither> traverseList( - List list, - IOEither Function(A a) f, - ) => - traverseListWithIndex(list, (a, _) => f(a)); - - /// {@template fpdart_sequence_list_io_either} - /// Convert a `List>` to a single `IOEither>`. - /// {@endtemplate} - static IOEither> sequenceList( - List> list, - ) => - traverseList(list, identity); -} diff --git a/packages/fpdart/lib/src/io_option.dart b/packages/fpdart/lib/src/io_option.dart deleted file mode 100644 index 385a2141..00000000 --- a/packages/fpdart/lib/src/io_option.dart +++ /dev/null @@ -1,258 +0,0 @@ -import 'either.dart'; -import 'extension/option_extension.dart'; -import 'function.dart'; -import 'io.dart'; -import 'io_either.dart'; -import 'option.dart'; -import 'task_either.dart'; -import 'task_option.dart'; -import 'typeclass/alt.dart'; -import 'typeclass/applicative.dart'; -import 'typeclass/functor.dart'; -import 'typeclass/hkt.dart'; -import 'typeclass/monad.dart'; - -final class _IOOptionThrow { - const _IOOptionThrow(); -} - -typedef DoAdapterIOOption = A Function(IOOption); -A _doAdapter(IOOption iOOption) => iOOption.run().getOrElse( - () => throw const _IOOptionThrow(), - ); - -typedef DoFunctionIOOption = A Function(DoAdapterIOOption $); - -/// Tag the [HKT] interface for the actual [IOOption]. -abstract final class _IOOptionHKT {} - -/// `IOOption` represents an **synchronous** computation that -/// may fails yielding a [None] or returns a `Some(R)` when successful. -/// -/// If you want to represent an synchronous computation that never fails, see [IO]. -/// -/// If you want to represent an synchronous computation that returns an object when it fails, -/// see [IOEither]. -final class IOOption extends HKT<_IOOptionHKT, R> - with - Functor<_IOOptionHKT, R>, - Applicative<_IOOptionHKT, R>, - Monad<_IOOptionHKT, R>, - Alt<_IOOptionHKT, R> { - final Option Function() _run; - - /// Build a [IOOption] from a function returning a `Option`. - const IOOption(this._run); - - /// Initialize a **Do Notation** chain. - // ignore: non_constant_identifier_names - factory IOOption.Do(DoFunctionIOOption f) => IOOption(() { - try { - return Option.of(f(_doAdapter)); - } on _IOOptionThrow catch (_) { - return const Option.none(); - } - }); - - /// Used to chain multiple functions that return a [IOOption]. - /// - /// You can extract the value of every [Some] in the chain without - /// handling all possible missing cases. - /// If running any of the functions in the chain returns [None], the result is [None]. - @override - IOOption flatMap(covariant IOOption Function(R r) f) => - IOOption(() => run().match( - Option.none, - (r) => f(r).run(), - )); - - /// Returns a [IOOption] that returns `Some(c)`. - @override - IOOption pure(C c) => IOOption(() => Option.of(c)); - - /// Change the return type of this [IOOption] based on its value of type `R` and the - /// value of type `C` of another [IOOption]. - @override - IOOption map2(covariant IOOption m1, D Function(R b, C c) f) => - flatMap((b) => m1.map((c) => f(b, c))); - - /// Change the return type of this [IOOption] based on its value of type `R`, the - /// value of type `C` of a second [IOOption], and the value of type `D` - /// of a third [IOOption]. - @override - IOOption map3(covariant IOOption m1, covariant IOOption m2, - E Function(R b, C c, D d) f) => - flatMap((b) => m1.flatMap((c) => m2.map((d) => f(b, c, d)))); - - /// If running this [IOOption] returns [Some], then return the result of calling `then`. - /// Otherwise return [None]. - @override - IOOption andThen(covariant IOOption Function() then) => - flatMap((_) => then()); - - /// Chain multiple [IOOption] functions. - @override - IOOption call(covariant IOOption chain) => flatMap((_) => chain); - - /// If running this [IOOption] returns [Some], then change its value from type `R` to - /// type `C` using function `f`. - @override - IOOption map(C Function(R r) f) => ap(pure(f)); - - /// Apply the function contained inside `a` to change the value on the [Some] from - /// type `R` to a value of type `C`. - @override - IOOption ap(covariant IOOption a) => - a.flatMap((f) => flatMap((v) => pure(f(v)))); - - /// When this [IOOption] returns [Some], then return the current [IOOption]. - /// Otherwise return the result of `orElse`. - /// - /// Used to provide an **alt**ernative [IOOption] in case the current one returns [None]. - @override - IOOption alt(covariant IOOption Function() orElse) => - IOOption(() => run().match( - () => orElse().run(), - some, - )); - - /// When this [IOOption] returns a [None] then return the result of `orElse`. - /// Otherwise return this [IOOption]. - IOOption orElse(IOOption Function() orElse) => - IOOption(() => run().match( - () => orElse().run(), - (r) => IOOption.some(r).run(), - )); - - /// Extract the result of this [IOOption] into a [IO]. - /// - /// The IO returns a [Some] when [IOOption] returns [Some]. - /// Otherwise map the type `L` of [IOOption] to type `R` by calling `orElse`. - IO getOrElse(R Function() orElse) => IO(() => run().match( - orElse, - identity, - )); - - /// Pattern matching to convert a [IOOption] to a [IO]. - /// - /// Execute `onNone` when running this [IOOption] returns a [None]. - /// Otherwise execute `onSome`. - IO match(A Function() onNone, A Function(R r) onSome) => - IO(() => run().match( - onNone, - onSome, - )); - - /// Run the IO and return a `Option`. - Option run() => _run(); - - /// Convert this [IOOption] to [IOEither]. - /// - /// If the value inside [IOOption] is [None], then use `onNone` to convert it - /// to a value of type `L`. - IOEither toIOEither(L Function() onNone) => - IOEither(() => Either.fromOption(run(), onNone)); - - /// Convert this [IOOption] to [TaskOption]. - TaskOption toTaskOption() => TaskOption(() async => run()); - - /// Convert this [IOOption] to [TaskEither]. - /// - /// If the value inside [IOOption] is [None], then use `onNone` to convert it - /// to a value of type `L`. - TaskEither toTaskEither(L Function() onNone) => - TaskEither(() async => Either.fromOption(run(), onNone)); - - /// Build a [IOOption] that returns a `Some(r)`. - /// - /// Same of `IOOption.some`. - factory IOOption.of(R r) => IOOption(() => Option.of(r)); - - /// Flat a [IOOption] contained inside another [IOOption] to be a single [IOOption]. - factory IOOption.flatten(IOOption> ioOption) => - ioOption.flatMap(identity); - - /// Build a [IOOption] that returns a `Some(r)`. - /// - /// Same of `IOOption.of`. - factory IOOption.some(R r) => IOOption(() => Option.of(r)); - - /// Build a [IOOption] that returns a [None]. - factory IOOption.none() => IOOption(() => const Option.none()); - - /// If `r` is `null`, then return [None]. - /// Otherwise return `Right(r)`. - factory IOOption.fromNullable(R? r) => Option.fromNullable(r).toIOOption(); - - /// When calling `predicate` with `value` returns `true`, then running [IOOption] returns `Some(value)`. - /// Otherwise return [None]. - factory IOOption.fromPredicate(R value, bool Function(R a) predicate) => - IOOption( - () => predicate(value) ? Option.of(value) : const Option.none(), - ); - - /// Converts a function that may throw to a function that never throws - /// but returns a [Option] instead. - /// - /// Used to handle synchronous computations that may throw using [Option]. - factory IOOption.tryCatch(R Function() run) => IOOption(() { - try { - return Option.of(run()); - } catch (_) { - return const Option.none(); - } - }); - - /// {@template fpdart_traverse_list_io_option} - /// Map each element in the list to a [IOOption] using the function `f`, - /// and collect the result in an `IOOption>`. - /// {@endtemplate} - /// - /// Same as `IOOption.traverseList` but passing `index` in the map function. - static IOOption> traverseListWithIndex( - List list, - IOOption Function(A a, int i) f, - ) => - IOOption>( - () => Option.sequenceList( - IO - .traverseListWithIndex>( - list, - (a, i) => IO(() => f(a, i).run()), - ) - .run(), - ), - ); - - /// {@macro fpdart_traverse_list_io_option} - /// - /// Same as `IOOption.traverseListWithIndex` but without `index` in the map function. - static IOOption> traverseList( - List list, - IOOption Function(A a) f, - ) => - traverseListWithIndex(list, (a, _) => f(a)); - - /// {@template fpdart_sequence_list_io_option} - /// Convert a `List>` to a single `IOOption>`. - /// {@endtemplate} - static IOOption> sequenceList( - List> list, - ) => - traverseList(list, identity); - - /// Build a [IOOption] from `either` that returns [None] when - /// `either` is [Left], otherwise it returns [Some]. - static IOOption fromEither(Either either) => - IOOption(() => either.match((_) => const Option.none(), some)); - - /// Converts a function that may throw to a function that never throws - /// but returns a [Option] instead. - /// - /// Used to handle synchronous computations that may throw using [Option]. - /// - /// It wraps the `IOOption.tryCatch` factory to make chaining with `flatMap` - /// easier. - static IOOption Function(A a) tryCatchK(R Function(A a) run) => - (a) => IOOption.tryCatch(() => run(a)); -} diff --git a/packages/fpdart/lib/src/io_ref.dart b/packages/fpdart/lib/src/io_ref.dart deleted file mode 100644 index 60103024..00000000 --- a/packages/fpdart/lib/src/io_ref.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'io.dart'; -import 'typeclass/eq.dart'; -import 'typedef.dart'; -import 'unit.dart'; - -/// Mutable reference in the [IO] monad. -/// -/// Allows having a reference that can be read and mutated inside the [IO] -/// monad. Can be used in conjunction with a closure to preserve a state across -/// multiple [IO] function calls, or in any other case where code is run -/// inside an IO monad. -/// -/// In most cases, the [State] monad should be used, and [IORef] must be -/// viewed as a last resort, as it holds a mutable field inside itself that can -/// be modified inside of the [IO] monad. -final class IORef { - T _value; - - IORef._(this._value); - - /// {@template create_io_ref} - /// Creates a new IORef inside an [IO] monad with a given initial value. - /// {@endtemplate} - static IO> create(T initial) => IO(() => IORef._(initial)); - - /// {@template read_io_ref} - /// Extracts a current value of the [IORef] and returns it inside the - /// [IO] monad. - /// {@endtemplate} - IO read() => IO.of(_value); - - /// {@template write_io_ref} - /// Writes the given value to the [IORef] and returns a [Unit] inside the - /// [IO] monad. - /// {@endtemplate} - IO write(T value) => IO(() => _value = value).map((_) => unit); - - /// {@template modify_io_ref} - /// Works almost identical to the [write] method, but instead of taking - /// a value that needs to be written, takes an [Endo] function, applies the - /// [IORef]'s current value to it and writes the result to the [IORef]. - /// {@endtemplate} - IO modify(Endo update) => read().map(update).flatMap(write); -} - -/// [Eq] instance to compare [IORef]s using pointer equality -final ioRefEq = Eq.instance>((a, b) => identical(a, b)); - -/// {@macro create_io_ref} -IO> newIORef(T initial) => IORef.create(initial); - -/// {@macro read_io_ref} -IO readIORef(IORef ref) => ref.read(); - -/// {@macro write_io_ref} -IO writeIORef(T value, IORef ref) => ref.write(value); - -/// {@template io_ref_curried_version} -/// A curried version of the -/// {@endtemplate} -/// [writeIORef] -IO Function(IORef ref) writeIORefC(T value) => - (ref) => ref.write(value); - -/// {@macro modify_io_ref} -IO modifyIORef(Endo update, IORef ref) => ref.modify(update); - -/// {@macro io_ref_curried_version} -/// [modifyIORef] -IO Function(IORef ref) modifyIORefC(Endo update) => - (ref) => ref.modify(update); diff --git a/packages/fpdart/lib/src/option.dart b/packages/fpdart/lib/src/option.dart index 139e3beb..9e883dcf 100644 --- a/packages/fpdart/lib/src/option.dart +++ b/packages/fpdart/lib/src/option.dart @@ -1,617 +1,159 @@ -import 'either.dart'; -import 'extension/option_extension.dart'; -import 'function.dart'; -import 'io_option.dart'; -import 'task_option.dart'; -import 'typeclass/applicative.dart'; -import 'typeclass/eq.dart'; -import 'typeclass/extend.dart'; -import 'typeclass/filterable.dart'; -import 'typeclass/functor.dart'; -import 'typeclass/hkt.dart'; -import 'typeclass/monad.dart'; -import 'typeclass/monoid.dart'; -import 'typeclass/order.dart'; -import 'typeclass/semigroup.dart'; - -/// Return a `Some(t)`. -/// -/// Shortcut for `Option.of(r)`. -Option some(T t) => Some(t); - -/// Return a [None]. -/// -/// Shortcut for `Option.none()`. -Option none() => const Option.none(); - -/// Return [None] if `t` is `null`, [Some] otherwise. -/// -/// Same as initializing `Option.fromNullable(t)`. -Option optionOf(T? t) => Option.fromNullable(t); - -/// Return [Some] of `value` when `predicate` applied to `value` returns `true`, -/// [None] otherwise. -/// -/// Same as initializing `Option.fromPredicate(value, predicate)`. -Option option(T value, bool Function(T) predicate) => - Option.fromPredicate(value, predicate); - -final class _OptionThrow { - const _OptionThrow(); -} +part of "effect.dart"; -typedef DoAdapterOption = A Function(Option); -A _doAdapter(Option option) => - option.getOrElse(() => throw const _OptionThrow()); - -typedef DoFunctionOption = A Function(DoAdapterOption $); - -/// Tag the [HKT] interface for the actual [Option]. -abstract final class _OptionHKT {} - -// `Option implements Functor` expresses correctly the -// return type of the `map` function as `HKT`. -// This tells us that the actual type parameter changed from `T` to `B`, -// according to the types `T` and `B` of the callable we actually passed as a parameter of `map`. -// -// Moreover, it informs us that we are still considering an higher kinded type -// with respect to the `OptionHKT` tag - -/// A type that can contain a value of type `T` in a [Some] or no value with [None]. -/// -/// Used to represent type-safe missing values. Instead of using `null`, you define the type -/// to be [Option]. In this way, you are required by the type system to handle the case in which -/// the value is missing. -/// ```dart -/// final Option mStr = Option.of('name'); -/// -/// /// Using [Option] you are required to specify every possible case. -/// /// The type system helps you to find and define edge-cases and avoid errors. -/// mStr.match( -/// () => print('I have no string to print 🤷‍♀️'), -/// printString, -/// ); -/// ``` -sealed class Option extends HKT<_OptionHKT, T> - with - Functor<_OptionHKT, T>, - Applicative<_OptionHKT, T>, - Monad<_OptionHKT, T>, - Extend<_OptionHKT, T>, - Filterable<_OptionHKT, T> { +sealed class Option extends IEffect { const Option(); - /// Initialize a **Do Notation** chain. - // ignore: non_constant_identifier_names - factory Option.Do(DoFunctionOption f) { - try { - return Option.of(f(_doAdapter)); - } on _OptionThrow catch (_) { - return const Option.none(); - } - } - - /// Change the value of type `T` to a value of type `B` using function `f`. - /// ```dart - /// /// Change type `String` (`T`) to type `int` (`B`) - /// final Option mStr = Option.of('name'); - /// final Option mInt = mStr.map((a) => a.length); - /// ``` - /// 👇 - /// ```dart - /// [🥚].map((🥚) => 👨‍🍳(🥚)) -> [🍳] - /// [_].map((🥚) => 👨‍🍳(🥚)) -> [_] - /// ``` - @override - Option map(B Function(T t) f); - - /// Apply the function contained inside `a` to change the value of type `T` to - /// a value of type `B`. - /// - /// If `a` is [None], return [None]. - /// ```dart - /// final a = Option.of(10); - /// final b = Option.of(20); - /// - /// /// `map` takes one parameter [int] and returns `sumToDouble`. - /// /// We therefore have a function inside a [Option] that we want to - /// /// apply to another value! - /// final Option map = a.map( - /// (a) => (int b) => sumToDouble(a, b), - /// ); - /// - /// /// Using `ap`, we get the final `Option` that we want 🚀 - /// final result = b.ap(map); - /// ``` - @override - Option ap(covariant Option a) => a.match( - () => Option.none(), - (f) => map(f), - ); - - /// Return a [Some] containing the value `b`. - @override - Option pure(B b) => Some(b); - - /// Used to chain multiple functions that return a [Option]. - /// - /// You can extract the value of every [Option] in the chain without - /// handling all possible missing cases. - /// If any of the functions in the chain returns [None], the result is [None]. - /// ```dart - /// /// Using `flatMap`, you can forget that the value may be missing and just - /// /// use it as if it was there. - /// /// - /// /// In case one of the values is actually missing, you will get a [None] - /// /// at the end of the chain ⛓ - /// final a = Option.of('name'); - /// final Option result = a.flatMap( - /// (s) => stringToInt(s).flatMap( - /// (i) => intToDouble(i), - /// ), - /// ); - /// ``` - /// 👇 - /// ```dart - /// [😀].flatMap( - /// (😀) => [👻(😀)] - /// ) -> [😱] - /// - /// [😀].flatMap( - /// (😀) => [👻(😀)] - /// ).flatMap( - /// (😱) => [👨‍⚕️(😱)] - /// ) -> [🤕] - /// - /// [😀].flatMap( - /// (😀) => [_] - /// ).flatMap( - /// (_) => [👨‍⚕️(_)] - /// ) -> [_] - /// - /// [_].flatMap( - /// (😀) => [👻(😀)] - /// ) -> [_] - /// ``` - @override - Option flatMap(covariant Option Function(T t) f); - - /// Return a new [Option] that calls [Option.fromNullable] on the result of of the given function [f]. - /// - /// ```dart - /// expect( - /// Option.of(123).flatMapNullable((_) => null), - /// Option.none(), - /// ); - /// - /// expect( - /// Option.of(123).flatMapNullable((_) => 456), - /// Option.of(456), - /// ); - /// ``` - Option flatMapNullable(B? Function(T t) f) => - flatMap((t) => Option.fromNullable(f(t))); - - /// Return a new [Option] that calls [Option.tryCatch] with the given function [f]. - /// - /// ```dart - /// expect( - /// Option.of(123).flatMapThrowable((_) => throw Exception()), - /// Option.of(123).flatMapThrowable((_) => 456), - /// Option.of(456), - /// ); - /// ``` - Option flatMapThrowable(B Function(T t) f) => - flatMap((t) => Option.tryCatch(() => f(t))); - - /// Change the value of [Option] from type `T` to type `Z` based on the - /// value of `Option` using function `f`. - @override - Option extend(Z Function(Option t) f); - - /// Wrap this [Option] inside another [Option]. - @override - Option> duplicate() => extend(identity); - - /// If this [Option] is a [Some] and calling `f` returns `true`, then return this [Some]. - /// Otherwise return [None]. - @override - Option filter(bool Function(T t) f) => - flatMap((t) => f(t) ? this : const Option.none()); - - /// If this [Option] is a [Some] and calling `f` returns [Some], then return this [Some]. - /// Otherwise return [None]. - @override - Option filterMap(Option Function(T t) f); - - /// Return a record. If this [Option] is a [Some]: - /// - if `f` applied to its value returns `true`, then the tuple contains this [Option] as second value - /// - if `f` applied to its value returns `false`, then the tuple contains this [Option] as first value - /// Otherwise the tuple contains both [None]. - @override - (Option, Option) partition(bool Function(T t) f) => - (filter((a) => !f(a)), filter(f)); - - /// Return a record that contains as first value a [Some] when `f` returns [Left], - /// otherwise the [Some] will be the second value of the tuple. - @override - (Option, Option) partitionMap(Either Function(T t) f) => - Option.separate(map(f)); - - /// If this [Option] is a [Some], then return the result of calling `then`. - /// Otherwise return [None]. - /// ```dart - /// [🍌].andThen(() => [🍎]) -> [🍎] - /// [_].andThen(() => [🍎]) -> [_] - /// ``` - @override - Option andThen(covariant Option Function() then) => - flatMap((_) => then()); - - /// Chain multiple [Option]s. - @override - Option call(covariant Option chain) => flatMap((_) => chain); - - /// Change type of this [Option] based on its value of type `T` and the - /// value of type `C` of another [Option]. - @override - Option map2(covariant Option mc, D Function(T t, C c) f) => - flatMap((a) => mc.map((c) => f(a, c))); + factory Option.safeCast(dynamic value) => + Option.safeCastStrict(value); - /// Change type of this [Option] based on its value of type `T`, the - /// value of type `C` of a second [Option], and the value of type `D` - /// of a third [Option]. - @override - Option map3(covariant Option mc, covariant Option md, - E Function(T t, C c, D d) f) => - flatMap((a) => mc.flatMap((c) => md.map((d) => f(a, c, d)))); - - /// {@template fpdart_option_match} - /// Execute `onSome` when value is [Some], otherwise execute `onNone`. - /// {@endtemplate} - /// ```dart - /// [🍌].match(() => 🍎, (🍌) => 🍌 * 2) -> 🍌🍌 - /// [_].match(() => 🍎, (🍌) => 🍌 * 2) -> 🍎 - /// ``` - /// - /// Same as `fold`. - B match(B Function() onNone, B Function(T t) onSome); - - /// {@macro fpdart_option_match} - /// ```dart - /// [🍌].fold(() => 🍎, (🍌) => 🍌 * 2) -> 🍌🍌 - /// [_].fold(() => 🍎, (🍌) => 🍌 * 2) -> 🍎 - /// ``` - /// - /// Same as `match`. - B fold(B Function() onNone, B Function(T t) onSome) => - match(onNone, onSome); - - /// Return `true` when value is [Some]. - bool isSome(); - - /// Return `true` when value is [None]. - bool isNone(); - - /// Return value of type `T` when this [Option] is a [Some], `null` otherwise. - T? toNullable(); - - /// Build an [Either] from [Option]. - /// - /// Return [Right] when [Option] is [Some], otherwise [Left] containing - /// the result of calling `onLeft`. - Either toEither(L Function() onLeft) => match( - () => Left(onLeft()), - Right.new, - ); + static Option safeCastStrict(V value) { + if (value is R) return Some(value); + return const None(); + } - /// Convert this [Option] to a [IOOption]. - IOOption toIOOption() => IOOption(() => this); - - /// Convert this [Option] to a [TaskOption]. - /// - /// Used to convert a sync context ([Option]) to an async context ([TaskOption]). - /// You should convert [Option] to [TaskOption] every time you need to - /// call an async ([Future]) function based on the value in [Option]. - TaskOption toTaskOption() => TaskOption(() => Future.value(this)); - - /// {@template fpdart_traverse_list_option} - /// Map each element in the list to an [Option] using the function `f`, - /// and collect the result in an `Option>`. - /// - /// If any mapped element of the list is [None], then the final result - /// will be [None]. - /// {@endtemplate} - /// - /// Same as `Option.traverseList` but passing `index` in the map function. - static Option> traverseListWithIndex( - List list, - Option Function(A a, int i) f, - ) { - final resultList = []; - for (var i = 0; i < list.length; i++) { - final o = f(list[i], i); - final r = o.match(() => null, identity); - if (r == null) return none(); - resultList.add(r); - } + factory Option.fromPredicate(R value, bool Function(R r) predicate) { + if (predicate(value)) return Some(value); + return const None(); + } - return some(resultList); + factory Option.fromNullable(R? value) { + if (value != null) return Some(value); + return const None(); } - /// {@macro fpdart_traverse_list_option} - /// - /// Same as `Option.traverseListWithIndex` but without `index` in the map function. - static Option> traverseList( - List list, - Option Function(A a) f, - ) => - traverseListWithIndex(list, (a, _) => f(a)); - - /// {@template fpdart_sequence_list_option} - /// Convert a `List>` to a single `Option>`. - /// - /// If any of the [Option] in the [List] is [None], then the result is [None]. - /// {@endtemplate} - static Option> sequenceList( - List> list, - ) => - traverseList(list, identity); - - /// Build a [Option] from a [Either] by returning [Some] when `either` is [Right], - /// [None] otherwise. - static Option fromEither(Either either) => - either.match((_) => const Option.none(), (r) => Some(r)); - - /// {@template fpdart_safe_cast_option} - /// Safely cast a value to type `T`. - /// - /// If `value` is not of type `T`, then return a [None]. - /// {@endtemplate} - /// - /// Less strict version of `Option.safeCastStrict`, since `safeCast` - /// assumes the value to be `dynamic`. - /// - /// **Note**: Make sure to specify the type of [Option] (`Option.safeCast` - /// instead of `Option.safeCast`), otherwise this will always return [Some]! - factory Option.safeCast(dynamic value) => - Option.safeCastStrict(value); - - /// {@macro fpdart_safe_cast_option} - /// - /// More strict version of `Option.safeCast`, in which also the **input value - /// type** must be specified (while in `Option.safeCast` the type is `dynamic`). - static Option safeCastStrict(V value) => - value is T ? Option.of(value) : Option.none(); - - /// Return [Some] of `value` when `predicate` applied to `value` returns `true`, - /// [None] otherwise. - factory Option.fromPredicate(T value, bool Function(T t) predicate) => - predicate(value) ? Some(value) : Option.none(); - - /// Return [Some] of type `B` by calling `f` with `value` when `predicate` applied to `value` is `true`, - /// `None` otherwise. - /// ```dart - /// /// If the value of `str` is not empty, then return a [Some] containing - /// /// the `length` of `str`, otherwise [None]. - /// Option.fromPredicateMap( - /// str, - /// (str) => str.isNotEmpty, - /// (str) => str.length, - /// ); - /// ``` - static Option fromPredicateMap( - A value, bool Function(A a) predicate, B Function(A a) f) => - predicate(value) ? Some(f(value)) : Option.none(); - - /// Return a [None]. - const factory Option.none() = None; - - /// Return a `Some(a)`. - const factory Option.of(T t) = Some; - - /// Flat a [Option] contained inside another [Option] to be a single [Option]. - factory Option.flatten(Option> m) => m.flatMap(identity); - - /// Return [None] if `a` is `null`, [Some] otherwise. - factory Option.fromNullable(T? t) => t == null ? Option.none() : Some(t); - - /// Try to run `f` and return `Some(a)` when no error are thrown, otherwise return `None`. - factory Option.tryCatch(T Function() f) { + factory Option.tryCatch(R Function() f) { try { return Some(f()); } catch (_) { - return const Option.none(); + return const None(); } } - /// Return a record of [Option] from a `Option>`. - /// - /// The value on the left of the [Either] will be the first value of the tuple, - /// while the right value of the [Either] will be the second of the tuple. - static (Option, Option) separate(Option> m) => - m.match( - () => (const Option.none(), const Option.none()), - (either) => (either.getLeft(), either.getRight()), - ); - - /// Build an `Eq mapInput(T Function(A) map) => Order( + (a1, a2) => compare(map(a1), map(a2)), + ); + + /// Return an [Order] reversed. + Order get reverse => Order((x, y) => compare(y, x)); + + bool equal(T x, T y) => compare(x, y) == Ordering.equal; + + bool lessThan(T x, T y) => compare(x, y) == Ordering.lessThan; + + bool greaterThan(T x, T y) => compare(x, y) == Ordering.greaterThan; + + bool lessOrEqual(T x, T y) { + if (compare(x, y) case Ordering.lessThan || Ordering.equal) return true; + return false; + } + + bool greaterOrEqual(T x, T y) { + if (compare(x, y) case Ordering.equal || Ordering.greaterThan) return true; + return false; + } + + /// Convert `Order` to an `Order` using `f` + static Order by(B Function(A a) f, Order ord) => + Order((x, y) => ord.compare(f(x), f(y))); + + /// Order using `first` and if two elements are equal falls back to `second` + static Order whenEqual(Order first, Order second) => Order( + (x, y) { + final ord = first.compare(x, y); + return ord == Ordering.equal ? second.compare(x, y) : ord; + }, + ); + + /// An `Order` instance that considers all instances to be equal + static Order allEqual() => Order((x, y) => Ordering.equal); +} diff --git a/packages/fpdart/lib/src/ordering.dart b/packages/fpdart/lib/src/ordering.dart new file mode 100644 index 00000000..e996c865 --- /dev/null +++ b/packages/fpdart/lib/src/ordering.dart @@ -0,0 +1,21 @@ +enum Ordering { + lessThan(-1), + equal(0), + greaterThan(1); + + const Ordering(this.order); + factory Ordering.fromOrder(int order) => switch (order) { + (< 0) => Ordering.lessThan, + (> 0) => Ordering.greaterThan, + _ => Ordering.equal + }; + + final int order; + + @override + String toString() => '$name($order)'; + + bool get isLessThan => this == Ordering.lessThan; + bool get isGreaterThan => this == Ordering.greaterThan; + bool get isEqual => this == Ordering.equal; +} diff --git a/packages/fpdart/lib/src/random.dart b/packages/fpdart/lib/src/random.dart deleted file mode 100644 index ccebc799..00000000 --- a/packages/fpdart/lib/src/random.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'dart:math'; - -import 'io.dart'; - -/// Generates a non-negative random floating point -/// value uniformly distributed in the range from 0.0, **inclusive**, to 1.0, **exclusive**. -/// -/// [IO] wrapper around dart `Random().nextDouble()`. -IO get random => IO(() => Random().nextDouble()); - -/// Generates a random boolean value. -/// -/// [IO] wrapper around dart `Random().nextBool()`. -IO get randomBool => IO(() => Random().nextBool()); - -/// Generates a non-negative random integer uniformly distributed -/// in the range from `min`, **inclusive**, to `max`, **exclusive**. -IO randomInt(int min, int max) => - IO(() => Random().nextInt(max - min) + min); diff --git a/packages/fpdart/lib/src/reader.dart b/packages/fpdart/lib/src/reader.dart deleted file mode 100644 index 047a4ac7..00000000 --- a/packages/fpdart/lib/src/reader.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'function.dart'; -import 'typeclass/applicative.dart'; -import 'typeclass/functor.dart'; -import 'typeclass/hkt.dart'; -import 'typeclass/monad.dart'; - -/// Tag the [HKT2] interface for the actual [Reader]. -abstract final class ReaderHKT {} - -/// `Reader` allows to read values `A` from a dependency/context `R` -/// without explicitly passing the dependency between multiple nested -/// function calls. -final class Reader extends HKT2 - with - Functor2, - Applicative2, - Monad2 { - final A Function(R r) _read; - - /// Build a [Reader] given `A Function(R)`. - const Reader(this._read); - - /// Flat a [Reader] contained inside another [Reader] to be a single [Reader]. - factory Reader.flatten(Reader> reader) => - reader.flatMap(identity); - - /// Apply the function contained inside `a` to change the value of type `A` to - /// a value of type `B`. - @override - Reader ap(covariant Reader a) => - Reader((r) => a.run(r)(run(r))); - - /// Used to chain multiple functions that return a [Reader]. - @override - Reader flatMap(covariant Reader Function(A a) f) => - Reader((r) => f(run(r)).run(r)); - - /// Return a [Reader] containing the value `c`. - @override - Reader pure(C c) => Reader((_) => c); - - /// Change the value of type `A` to a value of type `C` using function `f`. - @override - Reader map(C Function(A a) f) => ap(pure(f)); - - /// Change type of this [Reader] based on its value of type `A` and the - /// value of type `C` of another [Reader]. - @override - Reader map2(covariant Reader m1, D Function(A a, C c) f) => - flatMap((a) => m1.map((c) => f(a, c))); - - /// Change type of this [Reader] based on its value of type `A`, the - /// value of type `C` of a second [Reader], and the value of type `D` - /// of a third [Reader]. - @override - Reader map3(covariant Reader m1, - covariant Reader m2, E Function(A a, C c, D d) f) => - flatMap((a) => m1.flatMap((c) => m2.map((d) => f(a, c, d)))); - - /// Chain the result of `then` to this [Reader]. - @override - Reader andThen(covariant Reader Function() then) => - flatMap((_) => then()); - - /// Chain multiple functions having the reader `R`. - @override - Reader call(covariant Reader chain) => flatMap((_) => chain); - - /// Compose the dependency `R` of this [Reader] to `reader`. - Reader compose(Reader reader) => Reader((r) => reader.run(r)); - - /// Change dependency type of `Reader` from `R` to `R1` after calling `run`. - Reader local(R Function(R1 context) f) => Reader((r) => run(f(r))); - - /// Read the current dependency `R`. - Reader ask() => Reader(identity); - - /// Change reading function to `f` given context/dependency `R`. - Reader asks(A Function(R r) f) => Reader(f); - - /// Chain a request that returns another [Reader], execute it, ignore - /// the result, and return the same value as the current [Reader]. - @override - Reader chainFirst( - covariant Reader Function(A a) chain, - ) => - flatMap((a) => chain(a).map((c) => a)); - - /// Provide the value `R` (dependency) and extract result `A`. - A run(R r) => _read(r); - - @override - bool operator ==(Object other) => (other is Reader) && other._read == _read; - - @override - int get hashCode => _read.hashCode; -} diff --git a/packages/fpdart/lib/src/reader_task.dart b/packages/fpdart/lib/src/reader_task.dart deleted file mode 100644 index edd85cc3..00000000 --- a/packages/fpdart/lib/src/reader_task.dart +++ /dev/null @@ -1,145 +0,0 @@ -import 'either.dart'; -import 'function.dart'; -import 'reader_task_either.dart'; -import 'typeclass/applicative.dart'; -import 'typeclass/functor.dart'; -import 'typeclass/hkt.dart'; -import 'typeclass/monad.dart'; - -typedef DoAdapterReaderTask = Future Function(ReaderTask); -DoAdapterReaderTask _doAdapter(E env) => - (ReaderTask task) => task.run(env); - -typedef DoFunctionReaderTask = Future Function( - DoAdapterReaderTask $); - -/// Tag the [HKT] interface for the actual [ReaderTask]. -abstract final class _ReaderTaskHKT {} - -/// [ReaderTask] represents an asynchronous computation that yields a value of type `A` -/// from a context of type `E` and **never fails**. -/// -/// If you want to represent an asynchronous computation that may fail, see [ReaderTaskEither]. -final class ReaderTask extends HKT2<_ReaderTaskHKT, E, A> - with - Functor2<_ReaderTaskHKT, E, A>, - Applicative2<_ReaderTaskHKT, E, A>, - Monad2<_ReaderTaskHKT, E, A> { - final Future Function(E env) _run; - - /// Build a [ReaderTask] from a function returning a [Future] given `E`. - const ReaderTask(this._run); - - /// Initialize a **Do Notation** chain. - // ignore: non_constant_identifier_names - factory ReaderTask.Do(DoFunctionReaderTask f) => - ReaderTask((env) => f(_doAdapter(env))); - - /// Build a [ReaderTask] that returns `a`. - factory ReaderTask.of(A a) => ReaderTask((_) async => a); - - /// Flat a [ReaderTask] contained inside another [ReaderTask] to be a single [ReaderTask]. - factory ReaderTask.flatten(ReaderTask> task) => - task.flatMap(identity); - - /// Apply the function contained inside `a` to change the value of type `A` to - /// a value of type `B`. - @override - ReaderTask ap(covariant ReaderTask a) => - ReaderTask( - (env) => a.run(env).then( - (f) => run(env).then( - (v) => f(v), - ), - ), - ); - - /// Used to chain multiple functions that return a [ReaderTask]. - /// - /// You can extract the value inside the [ReaderTask] without actually running it. - @override - ReaderTask flatMap(covariant ReaderTask Function(A a) f) => - ReaderTask( - (env) => run(env).then( - (v) => f(v).run(env), - ), - ); - - /// Return a [ReaderTask] returning the value `b`. - @override - ReaderTask pure(B a) => ReaderTask((_) async => a); - - /// Change the returning value of the [ReaderTask] from type - /// `A` to type `B` using `f`. - @override - ReaderTask map(B Function(A a) f) => ap(pure(f)); - - /// Change type of this [ReaderTask] based on its value of type `A` and the - /// value of type `C` of another [ReaderTask]. - @override - ReaderTask map2( - covariant ReaderTask mc, D Function(A a, C c) f) => - flatMap( - (a) => mc.map( - (c) => f(a, c), - ), - ); - - /// Change type of this [ReaderTask] based on its value of type `A`, the - /// value of type `C` of a second [ReaderTask], and the value of type `D` - /// of a third [ReaderTask]. - @override - ReaderTask map3( - covariant ReaderTask mc, - covariant ReaderTask md, - F Function(A a, C c, D d) f, - ) => - flatMap( - (a) => mc.flatMap( - (c) => md.map( - (d) => f(a, c, d), - ), - ), - ); - - /// Run this [ReaderTask] and right after the [ReaderTask] returned from `then`. - @override - ReaderTask andThen(covariant ReaderTask Function() then) => - flatMap( - (_) => then(), - ); - - @override - ReaderTask chainFirst( - covariant ReaderTask Function(A a) chain, - ) => - flatMap( - (a) => chain(a).map((b) => a), - ); - - /// Chain multiple [ReaderTask] functions. - @override - ReaderTask call(covariant ReaderTask chain) => flatMap( - (_) => chain, - ); - - /// Run the task and return a [Future]. - Future run(E env) => _run(env); - - /// Convert this [ReaderTask] to [ReaderTaskEither]. - ReaderTaskEither toReaderTaskEither() => ReaderTaskEither( - (env) async => Either.of( - await run(env), - ), - ); - - /// Extract a value `A` given the current dependency `E`. - factory ReaderTask.asks(A Function(E) f) => ReaderTask( - (env) async => f(env), - ); - - /// Read the current dependency `E`. - static ReaderTask ask() => ReaderTask( - (env) async => env, - ); -} diff --git a/packages/fpdart/lib/src/reader_task_either.dart b/packages/fpdart/lib/src/reader_task_either.dart deleted file mode 100644 index ab4fe51e..00000000 --- a/packages/fpdart/lib/src/reader_task_either.dart +++ /dev/null @@ -1,371 +0,0 @@ -import 'either.dart'; -import 'function.dart'; -import 'io.dart'; -import 'io_either.dart'; -import 'io_option.dart'; -import 'option.dart'; -import 'reader.dart'; -import 'reader_task.dart'; -import 'task.dart'; -import 'task_either.dart'; -import 'task_option.dart'; -import 'typeclass/alt.dart'; -import 'typeclass/applicative.dart'; -import 'typeclass/functor.dart'; -import 'typeclass/hkt.dart'; -import 'typeclass/monad.dart'; - -final class _ReaderTaskEitherThrow { - final L value; - const _ReaderTaskEitherThrow(this.value); -} - -typedef DoAdapterReaderTaskEither = Future Function( - ReaderTaskEither); - -DoAdapterReaderTaskEither _doAdapter(E env) => - (readerTaskEither) => readerTaskEither.run(env).then( - (either) => either.getOrElse((l) => throw _ReaderTaskEitherThrow(l)), - ); - -typedef DoFunctionReaderTaskEither = Future Function( - DoAdapterReaderTaskEither $); - -/// Tag the [HKT3] interface for the actual [ReaderTaskEither]. -abstract final class _ReaderTaskEitherHKT {} - -/// `ReaderTaskEither` represents an asynchronous computation (`Task`) that -/// either yields a value of type `R` or fails yielding an error of type `L` (`Either`), -/// that allows to read values from a dependency/context `E` (`Reader`). -/// -/// [ReaderTaskEither] models a complete program using `Reader` for dependency injection, -/// `Task` to perform asynchronous computation, and `Either` to handle errors. -final class ReaderTaskEither - extends HKT3<_ReaderTaskEitherHKT, E, L, R> - with - Functor3<_ReaderTaskEitherHKT, E, L, R>, - Applicative3<_ReaderTaskEitherHKT, E, L, R>, - Monad3<_ReaderTaskEitherHKT, E, L, R>, - Alt3<_ReaderTaskEitherHKT, E, L, R> { - final Future> Function(E env) _run; - - /// Build a [ReaderTaskEither] from a function returning a `Future>`. - const ReaderTaskEither(this._run); - - /// Initialize a **Do Notation** chain. - // ignore: non_constant_identifier_names - factory ReaderTaskEither.Do(DoFunctionReaderTaskEither f) => - ReaderTaskEither((env) async { - try { - return Either.of(await f(_doAdapter(env))); - } on _ReaderTaskEitherThrow catch (e) { - return Either.left(e.value); - } - }); - - /// Run the task given `E` and return a `Future>`. - Future> run(E env) => _run(env); - - /// Returns a [ReaderTaskEither] that returns a `Right(a)`. - @override - ReaderTaskEither pure(C a) => ReaderTaskEither( - (_) async => Right(a), - ); - - /// Used to chain multiple functions that return a [ReaderTaskEither]. - /// - /// You can extract the value of every [Right] in the chain without - /// handling all possible missing cases. - /// - /// If running any of the tasks in the chain returns [Left], the result is [Left]. - @override - ReaderTaskEither flatMap( - covariant ReaderTaskEither Function(R r) f, - ) => - ReaderTaskEither((env) => run(env).then( - (either) async => either.match( - left, - (r) => f(r).run(env), - ), - )); - - /// Chain a function that takes the current value `R` inside this [TaskEither] - /// and returns [Either]. - /// - /// Similar to `flatMap`, but `f` returns [Either] instead of [TaskEither]. - ReaderTaskEither flatMapTaskEither( - TaskEither Function(R r) f, - ) => - ReaderTaskEither((env) => run(env).then( - (either) async => either.match( - left, - (r) => f(r).run(), - ), - )); - - /// If running this [ReaderTaskEither] returns [Right], then return the result of calling `then`. - /// Otherwise return [Left]. - @override - ReaderTaskEither andThen( - covariant ReaderTaskEither Function() then, - ) => - flatMap((_) => then()); - - /// If running this [ReaderTaskEither] returns [Right], then change its value from type `R` to - /// type `C` using function `f`. - @override - ReaderTaskEither map(C Function(R r) f) => ap(pure(f)); - - @override - ReaderTaskEither map2( - covariant ReaderTaskEither m1, - N2 Function(R p1, N1 p2) f, - ) => - flatMap((b) => m1.map((c) => f(b, c))); - - @override - ReaderTaskEither map3( - covariant ReaderTaskEither m1, - covariant ReaderTaskEither m2, - N3 Function(R p1, N1 p2, N2 p3) f, - ) => - flatMap( - (b) => m1.flatMap((c) => m2.map((d) => f(b, c, d))), - ); - - /// Change the value in the [Left] of [ReaderTaskEither]. - ReaderTaskEither mapLeft(C Function(L l) f) => ReaderTaskEither( - (env) async => (await run(env)).match( - (l) => Either.left(f(l)), - Either.of, - ), - ); - - /// Define two functions to change both the [Left] and [Right] value of the - /// [ReaderTaskEither]. - ReaderTaskEither bimap( - C Function(L l) mLeft, - D Function(R r) mRight, - ) => - mapLeft(mLeft).map(mRight); - - /// Apply the function contained inside `a` to change the value on the [Right] from - /// type `R` to a value of type `C`. - @override - ReaderTaskEither ap( - covariant ReaderTaskEither a, - ) => - a.flatMap( - (f) => flatMap( - (v) => pure(f(v)), - ), - ); - - @override - ReaderTaskEither chainFirst( - covariant ReaderTaskEither Function(R p1) chain, - ) => - flatMap((b) => chain(b).map((c) => b)); - - /// Chain multiple functions having the same left type `L`. - @override - ReaderTaskEither call( - covariant ReaderTaskEither chain, - ) => - flatMap((_) => chain); - - /// Change this [ReaderTaskEither] from `ReaderTaskEither` to `ReaderTaskEither`. - ReaderTaskEither swap() => ReaderTaskEither( - (env) async => (await run(env)).match(right, left), - ); - - /// When this [ReaderTaskEither] returns [Right], then return the current [ReaderTaskEither]. - /// Otherwise return the result of `orElse`. - /// - /// Used to provide an **alt**ernative [ReaderTaskEither] in case the current one returns [Left]. - @override - ReaderTaskEither alt( - covariant ReaderTaskEither Function() orElse, - ) => - ReaderTaskEither( - (env) async => (await run(env)).match( - (_) => orElse().run(env), - right, - ), - ); - - /// If `f` applied on this [ReaderTaskEither] as [Right] returns `true`, then return this [ReaderTaskEither]. - /// If it returns `false`, return the result of `onFalse` in a [Left]. - ReaderTaskEither filterOrElse( - bool Function(R r) f, - L Function(R r) onFalse, - ) => - flatMap( - (r) => - f(r) ? ReaderTaskEither.of(r) : ReaderTaskEither.left(onFalse(r)), - ); - - /// When this [ReaderTaskEither] returns a [Left] then return the result of `orElse`. - /// Otherwise return this [ReaderTaskEither]. - ReaderTaskEither orElse( - ReaderTaskEither Function(L l) orElse, - ) => - ReaderTaskEither((env) async => (await run(env)).match( - (l) => orElse(l).run(env), - (r) => ReaderTaskEither.of(r).run(env), - )); - - /// Convert this [ReaderTaskEither] to a [ReaderTask]. - /// - /// The task returns a [Right] when [ReaderTaskEither] returns [Right]. - /// Otherwise map the type `L` of [ReaderTaskEither] to type `R` by calling `orElse`. - ReaderTask getOrElse(R Function(L left) orElse) => ReaderTask( - (env) async => (await run(env)).match( - orElse, - identity, - ), - ); - - /// Pattern matching to convert a [ReaderTaskEither] to a [ReaderTask]. - /// - /// Execute `onLeft` when running this [ReaderTaskEither] returns a [Left]. - /// Otherwise execute `onRight`. - ReaderTask match( - B Function(L left) onLeft, - B Function(R right) onRight, - ) => - ReaderTask( - (env) async => (await run(env)).match( - onLeft, - onRight, - ), - ); - - /// Flat a [ReaderTaskEither] contained inside another [ReaderTaskEither] to be a single [ReaderTaskEither]. - factory ReaderTaskEither.flatten( - ReaderTaskEither> readerTaskEither, - ) => - readerTaskEither.flatMap(identity); - - /// Build a [ReaderTaskEither] that returns a [Right] containing the result of running `reader`. - factory ReaderTaskEither.fromReader(Reader reader) => ReaderTaskEither( - (env) async => Right(reader.run(env)), - ); - - /// Build a [ReaderTaskEither] from a `Reader`. - factory ReaderTaskEither.leftReader(Reader reader) => ReaderTaskEither( - (env) async => Left(reader.run(env)), - ); - - /// Build a [ReaderTaskEither] that returns a `Left(left)`. - factory ReaderTaskEither.left(L left) => ReaderTaskEither( - (_) async => Left(left), - ); - - /// Build a [ReaderTaskEither] that returns a [Left] containing the result of running `task`. - factory ReaderTaskEither.leftTask(Task task) => ReaderTaskEither( - (_) => task.run().then(left), - ); - - /// Build a [ReaderTaskEither] that returns a [Right] containing the result of running `task`. - factory ReaderTaskEither.fromTask(Task task) => ReaderTaskEither( - (_) async => Right(await task.run()), - ); - - /// Build a [ReaderTaskEither] that returns a [Right] containing the result of running `task`, - /// or the result of `onNone` if `task` is [Left]. - factory ReaderTaskEither.fromTaskOption( - TaskOption task, - L Function() onNone, - ) => - ReaderTaskEither( - (_) async => Either.fromOption(await task.run(), onNone), - ); - - /// Build a [ReaderTaskEither] that returns a [Right] containing the result of running `task`. - factory ReaderTaskEither.fromTaskEither(TaskEither task) => - ReaderTaskEither( - (_) async => task.run(), - ); - - /// Build a [ReaderTaskEither] that returns a [Right] containing the result of running `io`. - factory ReaderTaskEither.fromIO(IO io) => ReaderTaskEither( - (_) async => Right(io.run()), - ); - - /// Build a [ReaderTaskEither] that returns a [Right] containing the result of running `io`, - /// or the result of `onNone` if `io` is [Left]. - factory ReaderTaskEither.fromIOOption( - IOOption io, - L Function() onNone, - ) => - ReaderTaskEither( - (_) async => Either.fromOption(io.run(), onNone), - ); - - /// Build a [ReaderTaskEither] that returns a [Right] containing the result of running `io`. - factory ReaderTaskEither.fromIOEither(IOEither io) => ReaderTaskEither( - (_) async => io.run(), - ); - - /// {@template fpdart_from_nullable_reader_task_either} - /// If `r` is `null`, then return the result of `onNull` in [Left]. - /// Otherwise return `Right(r)`. - /// {@endtemplate} - factory ReaderTaskEither.fromNullable(R? r, L Function() onNull) => - ReaderTaskEither( - (_) async => Either.fromNullable(r, onNull), - ); - - /// {@macro fpdart_from_nullable_reader_task_either} - factory ReaderTaskEither.fromNullableAsync(R? r, Task onNull) => - ReaderTaskEither( - (_) async => r != null ? Either.of(r) : Either.left(await onNull.run()), - ); - - /// Build a [ReaderTaskEither] from `option`. - /// - /// When `option` is [Some], then return [Right] when - /// running [ReaderTaskEither]. Otherwise return `onNone`. - factory ReaderTaskEither.fromOption(Option option, L Function() onNone) => - ReaderTaskEither((_) async => option.match( - () => Left(onNone()), - Right.new, - )); - - /// Build a [ReaderTaskEither] that returns `either`. - factory ReaderTaskEither.fromEither(Either either) => - ReaderTaskEither((_) async => either); - - /// Build a [ReaderTaskEither] that returns a `Right(r)`. - factory ReaderTaskEither.of(R r) => ReaderTaskEither( - (_) async => Either.of(r), - ); - - /// Execute an async function ([Future]) and convert the result to [Either]: - /// - If the execution is successful, returns a [Right] - /// - If the execution fails (`throw`), then return a [Left] based on `onError` - /// - /// Used to work with [Future] and exceptions using [Either] instead of `try`/`catch`. - factory ReaderTaskEither.tryCatch( - Future Function(E) run, - L Function(Object error, StackTrace stackTrace) onError, - ) => - ReaderTaskEither((env) async { - try { - return Right(await run(env)); - } catch (error, stack) { - return Left(onError(error, stack)); - } - }); - - /// Extract a value `A` given the current dependency `E`. - factory ReaderTaskEither.asks(R Function(E) f) => ReaderTaskEither( - (env) async => right(f(env)), - ); - - /// Read the current dependency `E`. - static ReaderTaskEither ask() => ReaderTaskEither( - (env) async => right(env), - ); -} diff --git a/packages/fpdart/lib/src/scope.dart b/packages/fpdart/lib/src/scope.dart new file mode 100644 index 00000000..9b30ad8d --- /dev/null +++ b/packages/fpdart/lib/src/scope.dart @@ -0,0 +1,44 @@ +part of "effect.dart"; + +mixin ScopeMixin { + bool get scopeClosable => false; + + final scopeFinalizers = >[]; + + Effect addScopeFinalizer( + Effect finalizer, + ) => + Effect.succeedLazy(() { + scopeFinalizers.add(finalizer); + return unit; + }); + + Effect removeScopeFinalizer( + Effect finalizer, + ) => + Effect.succeedLazy(() { + scopeFinalizers.remove(finalizer); + return unit; + }); + + Effect closeScope() => Effect.lazy( + () => scopeFinalizers.reversed.all.zipRight(Effect.succeedLazy( + () { + scopeFinalizers.clear(); + return unit; + }, + )).withEnv(), + ); +} + +class Scope with ScopeMixin { + final bool _closable; + final R env; + Scope._(this.env, this._closable); + + factory Scope.withEnv(R env, {bool closable = false}) => + Scope._(env, closable); + + @override + bool get scopeClosable => _closable; +} diff --git a/packages/fpdart/lib/src/state.dart b/packages/fpdart/lib/src/state.dart deleted file mode 100644 index 0107597b..00000000 --- a/packages/fpdart/lib/src/state.dart +++ /dev/null @@ -1,159 +0,0 @@ -import 'function.dart'; -import 'state_async.dart'; -import 'typeclass/typeclass.export.dart'; -import 'unit.dart'; - -/// Tag the [HKT2] interface for the actual [State]. -abstract final class _StateHKT {} - -/// `State` is used to store, update, and extract state in a functional way. -/// -/// `S` is a State (e.g. the current _State_ of your Bank Account). -/// `A` is value that you _extract out of the [State]_ -/// (Account Balance fetched from the current state of your Bank Account `S`). -final class State extends HKT2<_StateHKT, S, A> - with - Functor2<_StateHKT, S, A>, - Applicative2<_StateHKT, S, A>, - Monad2<_StateHKT, S, A> { - final (A, S) Function(S state) _run; - - /// Build a new [State] given a `(A, S) Function(S)`. - const State(this._run); - - /// Flat a [State] contained inside another [State] to be a single [State]. - factory State.flatten(State> state) => state.flatMap(identity); - - /// Lift a sync [State] to an async [StateAsync]. - StateAsync toStateAsync() => StateAsync.fromState(this); - - /// Used to chain multiple functions that return a [State]. - @override - State flatMap(covariant State Function(A a) f) => - State((state) { - final tuple = run(state); - return f(tuple.$1).run(tuple.$2); - }); - - /// Apply the function contained inside `a` to change the value of type `A` to - /// a value of type `C`. - @override - State ap(covariant State a) => - a.flatMap((f) => flatMap((v) => pure(f(v)))); - - /// Return a `State` containing `c` as value. - @override - State pure(C c) => State((state) => (c, state)); - - /// Change the value inside `State` from type `A` to type `C` using `f`. - @override - State map(C Function(A a) f) => ap(pure(f)); - - /// Change type of this [State] based on its value of type `A` and the - /// value of type `C` of another [State]. - @override - State map2(covariant State m1, D Function(A a, C c) f) => - flatMap((a) => m1.map((c) => f(a, c))); - - /// Change type of this [State] based on its value of type `A`, the - /// value of type `C` of a second [State], and the value of type `D` - /// of a third [State]. - @override - State map3(covariant State m1, covariant State m2, - E Function(A a, C c, D d) f) => - flatMap((a) => m1.flatMap((c) => m2.map((d) => f(a, c, d)))); - - /// Chain the result of `then` to this [State]. - @override - State andThen(covariant State Function() then) => - flatMap((_) => then()); - - /// Chain multiple functions having the same state `S`. - @override - State call(covariant State state) => flatMap((_) => state); - - /// Extract the current state `S`. - State get() => State((state) => (state, state)); - - /// Change the value getter based on the current state `S`. - State gets(A Function(S state) f) => - State((state) => (f(state), state)); - - /// Change the current state `S` using `f` and return nothing ([Unit]). - State modify(S Function(S state) f) => - State((state) => (unit, f(state))); - - /// Set a new state and return nothing ([Unit]). - State put(S state) => State((_) => (unit, state)); - - /// Chain a request that returns another [State], execute it, ignore - /// the result, and return the same value as the current [State]. - /// - /// **Note**: `chainFirst` will not change the value of `first` for the state, - /// but **it will change the value of `second`** when calling `run()`. - @override - State chainFirst( - covariant State Function(A a) chain, - ) => - flatMap((a) => chain(a).map((_) => a)); - - /// Execute `run` and extract the value `A`. - /// - /// To extract both the value and the state use `run`. - /// - /// To extract only the state `S` use `execute`. - A evaluate(S state) => run(state).$1; - - /// Execute `run` and extract the state `S`. - /// - /// To extract both the value and the state use `run`. - /// - /// To extract only the value `A` use `evaluate`. - S execute(S state) => run(state).$2; - - /// Extract value `A` and state `S` by passing the original state `S`. - /// - /// To extract only the value `A` use `evaluate`. - /// - /// To extract only the state `S` use `execute`. - (A, S) run(S state) => _run(state); - - /// {@template fpdart_traverse_list_state} - /// Map each element in the list to a [State] using the function `f`, - /// and collect the result in a `State>`. - /// {@endtemplate} - /// - /// Same as `State.traverseList` but passing `index` in the map function. - static State> traverseListWithIndex( - List list, State Function(A a, int i) f) { - return State((state) { - final resultList = []; - var out = state; - for (var i = 0; i < list.length; i++) { - final (b, s) = f(list[i], i).run(out); - resultList.add(b); - out = s; - } - return (resultList, out); - }); - } - - /// {@macro fpdart_traverse_list_state} - /// - /// Same as `State.traverseListWithIndex` but without `index` in the map function. - static State> traverseList( - List list, State Function(A a) f) => - traverseListWithIndex(list, (a, _) => f(a)); - - /// {@template fpdart_sequence_list_state} - /// Convert a `List>` to a single `State>`. - /// {@endtemplate} - static State> sequenceList(List> list) => - traverseList(list, identity); - - @override - bool operator ==(Object other) => (other is State) && other._run == _run; - - @override - int get hashCode => _run.hashCode; -} diff --git a/packages/fpdart/lib/src/state_async.dart b/packages/fpdart/lib/src/state_async.dart deleted file mode 100644 index 8409ee7f..00000000 --- a/packages/fpdart/lib/src/state_async.dart +++ /dev/null @@ -1,132 +0,0 @@ -import 'function.dart'; -import 'state.dart'; -import 'typeclass/typeclass.export.dart'; -import 'unit.dart'; - -/// Tag the [HKT2] interface for the actual [StateAsync]. -abstract final class _StateAsyncHKT {} - -/// `StateAsync` is used to store, update, and extract async state in a functional way. -/// -/// `S` is a State (e.g. the current _State_ of your Bank Account). -/// `A` is value that you _extract out of the [StateAsync]_ -/// (Account Balance fetched from the current state of your Bank Account `S`). -/// -/// Used when fetching and updating the state is **asynchronous**. Use [State] otherwise. -final class StateAsync extends HKT2<_StateAsyncHKT, S, A> - with - Functor2<_StateAsyncHKT, S, A>, - Applicative2<_StateAsyncHKT, S, A>, - Monad2<_StateAsyncHKT, S, A> { - final Future<(A, S)> Function(S state) _run; - - /// Build a new [StateAsync] given a `Future<(A, S)> Function(S)`. - const StateAsync(this._run); - - /// Flat a [StateAsync] contained inside another [StateAsync] to be a single [StateAsync]. - factory StateAsync.flatten(StateAsync> state) => - state.flatMap(identity); - - /// Build a new [StateAsync] by lifting a sync [State] to async. - factory StateAsync.fromState(State state) => - StateAsync((s) async => state.run(s)); - - /// Used to chain multiple functions that return a [StateAsync]. - @override - StateAsync flatMap(covariant StateAsync Function(A a) f) => - StateAsync((state) async { - final tuple = await run(state); - return f(tuple.$1).run(tuple.$2); - }); - - /// Apply the function contained inside `a` to change the value of type `A` to - /// a value of type `C`. - @override - StateAsync ap(covariant StateAsync a) => - a.flatMap((f) => flatMap((v) => pure(f(v)))); - - /// Return a `StateAsync` containing `c` as value. - @override - StateAsync pure(C c) => StateAsync((state) async => (c, state)); - - /// Change the value inside `StateAsync` from type `A` to type `C` using `f`. - @override - StateAsync map(C Function(A a) f) => ap(pure(f)); - - /// Change type of this [StateAsync] based on its value of type `A` and the - /// value of type `C` of another [StateAsync]. - @override - StateAsync map2( - covariant StateAsync m1, D Function(A a, C c) f) => - flatMap((a) => m1.map((c) => f(a, c))); - - /// Change type of this [StateAsync] based on its value of type `A`, the - /// value of type `C` of a second [StateAsync], and the value of type `D` - /// of a third [StateAsync]. - @override - StateAsync map3(covariant StateAsync m1, - covariant StateAsync m2, E Function(A a, C c, D d) f) => - flatMap((a) => m1.flatMap((c) => m2.map((d) => f(a, c, d)))); - - /// Chain the result of `then` to this [StateAsync]. - @override - StateAsync andThen(covariant StateAsync Function() then) => - flatMap((_) => then()); - - /// Chain multiple functions having the same state `S`. - @override - StateAsync call(covariant StateAsync state) => - flatMap((_) => state); - - /// Extract the current state `S`. - StateAsync get() => StateAsync((state) async => (state, state)); - - /// Change the value getter based on the current state `S`. - StateAsync gets(A Function(S state) f) => - StateAsync((state) async => (f(state), state)); - - /// Change the current state `S` using `f` and return nothing ([Unit]). - StateAsync modify(S Function(S state) f) => - StateAsync((state) async => (unit, f(state))); - - /// Set a new state and return nothing ([Unit]). - StateAsync put(S state) => StateAsync((_) async => (unit, state)); - - /// Execute `run` and extract the value `A`. - /// - /// To extract both the value and the state use `run`. - /// - /// To extract only the state `S` use `execute`. - Future evaluate(S state) async => (await run(state)).$1; - - /// Execute `run` and extract the state `S`. - /// - /// To extract both the value and the state use `run`. - /// - /// To extract only the value `A` use `evaluate`. - Future execute(S state) async => (await run(state)).$2; - - /// Chain a request that returns another [StateAsync], execute it, ignore - /// the result, and return the same value as the current [StateAsync]. - /// - /// **Note**: `chainFirst` will not change the value of `first` for the state, - /// but **it will change the value of `second`** when calling `run()`. - @override - StateAsync chainFirst( - covariant StateAsync Function(A a) chain, - ) => - flatMap((a) => chain(a).map((_) => a)); - - /// Extract value `A` and state `S` by passing the original state `S`. - /// - /// To extract only the value `A` use `evaluate`. - /// - /// To extract only the state `S` use `execute`. - Future<(A, S)> run(S state) => _run(state); - - @override - bool operator ==(Object other) => (other is StateAsync) && other._run == _run; - - @override - int get hashCode => _run.hashCode; -} diff --git a/packages/fpdart/lib/src/task.dart b/packages/fpdart/lib/src/task.dart deleted file mode 100644 index 12dce592..00000000 --- a/packages/fpdart/lib/src/task.dart +++ /dev/null @@ -1,190 +0,0 @@ -import 'either.dart'; -import 'extension/iterable_extension.dart'; -import 'function.dart'; -import 'option.dart'; -import 'task_either.dart'; -import 'task_option.dart'; -import 'typeclass/applicative.dart'; -import 'typeclass/functor.dart'; -import 'typeclass/hkt.dart'; -import 'typeclass/monad.dart'; - -typedef DoAdapterTask = Future Function(Task); -Future _doAdapter(Task task) => task.run(); - -typedef DoFunctionTask = Future Function(DoAdapterTask $); - -/// Tag the [HKT] interface for the actual [Task]. -abstract final class _TaskHKT {} - -/// [Task] represents an asynchronous computation that yields a value of type `A` and **never fails**. -/// -/// If you want to represent an asynchronous computation that may fail, see [TaskEither]. -final class Task extends HKT<_TaskHKT, A> - with Functor<_TaskHKT, A>, Applicative<_TaskHKT, A>, Monad<_TaskHKT, A> { - final Future Function() _run; - - /// Build a [Task] from a function returning a [Future]. - const Task(this._run); - - /// Initialize a **Do Notation** chain. - // ignore: non_constant_identifier_names - factory Task.Do(DoFunctionTask f) => Task(() => f(_doAdapter)); - - /// Build a [Task] that returns `a`. - factory Task.of(A a) => Task(() async => a); - - /// Flat a [Task] contained inside another [Task] to be a single [Task]. - factory Task.flatten(Task> task) => task.flatMap(identity); - - /// Apply the function contained inside `a` to change the value of type `A` to - /// a value of type `B`. - @override - Task ap(covariant Task a) => - Task(() => a.run().then((f) => run().then((v) => f(v)))); - - /// Used to chain multiple functions that return a [Task]. - /// - /// You can extract the value inside the [Task] without actually running it. - @override - Task flatMap(covariant Task Function(A a) f) => - Task(() => run().then((v) => f(v).run())); - - /// Return a [Task] returning the value `b`. - @override - Task pure(B a) => Task(() async => a); - - /// Change the returning value of the [Task] from type - /// `A` to type `B` using `f`. - @override - Task map(B Function(A a) f) => ap(pure(f)); - - /// Change type of this [Task] based on its value of type `A` and the - /// value of type `C` of another [Task]. - @override - Task map2(covariant Task mc, D Function(A a, C c) f) => - flatMap((a) => mc.map((c) => f(a, c))); - - /// Change type of this [Task] based on its value of type `A`, the - /// value of type `C` of a second [Task], and the value of type `D` - /// of a third [Task]. - @override - Task map3(covariant Task mc, covariant Task md, - E Function(A a, C c, D d) f) => - flatMap((a) => mc.flatMap((c) => md.map((d) => f(a, c, d)))); - - /// Run this [Task] and right after the [Task] returned from `then`. - @override - Task andThen(covariant Task Function() then) => - flatMap((_) => then()); - - @override - Task chainFirst(covariant Task Function(A a) chain) => - flatMap((a) => chain(a).map((b) => a)); - - /// Chain multiple [Task] functions. - @override - Task call(covariant Task chain) => flatMap((_) => chain); - - /// Creates a task that will complete after a time delay specified by a [Duration]. - Task delay(Duration duration) => Task(() => Future.delayed(duration, run)); - - /// Run the task and return a [Future]. - Future run() => _run(); - - /// Convert this [Task] to [TaskOption]. - TaskOption toTaskOption() => - TaskOption(() async => Option.of(await run())); - - /// Convert this [Task] to [TaskEither]. - TaskEither toTaskEither() => - TaskEither(() async => Either.of(await run())); - - /// {@template fpdart_traverse_list_task} - /// Map each element in the list to a [Task] using the function `f`, - /// and collect the result in an `Task>`. - /// - /// Each [Task] is executed in parallel. This strategy is faster than - /// sequence, but **the order of the request is not guaranteed**. - /// - /// If you need [Task] to be executed in sequence, use `traverseListWithIndexSeq`. - /// {@endtemplate} - /// - /// Same as `Task.traverseList` but passing `index` in the map function. - static Task> traverseListWithIndex( - List list, - Task Function(A a, int i) f, - ) => - Task>( - () => Future.wait( - list.mapWithIndex( - (a, i) => f(a, i).run(), - ), - ), - ); - - /// {@macro fpdart_traverse_list_task} - /// - /// Same as `Task.traverseListWithIndex` but without `index` in the map function. - static Task> traverseList( - List list, - Task Function(A a) f, - ) => - traverseListWithIndex(list, (a, _) => f(a)); - - /// {@template fpdart_traverse_list_seq_task} - /// Map each element in the list to a [Task] using the function `f`, - /// and collect the result in an `Task>`. - /// - /// Each [Task] is executed in sequence. This strategy **takes more time than - /// parallel**, but it ensures that all the request are executed in order. - /// - /// If you need [Task] to be executed in parallel, use `traverseListWithIndex`. - /// {@endtemplate} - /// - /// Same as `Task.traverseListSeq` but passing `index` in the map function. - static Task> traverseListWithIndexSeq( - List list, - Task Function(A a, int i) f, - ) => - Task>(() async { - List collect = []; - for (var i = 0; i < list.length; i++) { - collect.add(await f(list[i], i).run()); - } - return collect; - }); - - /// {@macro fpdart_traverse_list_seq_task} - /// - /// Same as `Task.traverseListWithIndexSeq` but without `index` in the map function. - static Task> traverseListSeq( - List list, - Task Function(A a) f, - ) => - traverseListWithIndexSeq(list, (a, _) => f(a)); - - /// {@template fpdart_sequence_list_task} - /// Convert a `List>` to a single `Task>`. - /// - /// Each [Task] will be executed in parallel. - /// - /// If you need [Task] to be executed in sequence, use `sequenceListSeq`. - /// {@endtemplate} - static Task> sequenceList( - List> list, - ) => - traverseList(list, identity); - - /// {@template fpdart_sequence_list_seq_task} - /// Convert a `List>` to a single `Task>`. - /// - /// Each [Task] will be executed in sequence. - /// - /// If you need [Task] to be executed in parallel, use `sequenceList`. - /// {@endtemplate} - static Task> sequenceListSeq( - List> list, - ) => - traverseListSeq(list, identity); -} diff --git a/packages/fpdart/lib/src/task_either.dart b/packages/fpdart/lib/src/task_either.dart deleted file mode 100644 index 99793cf5..00000000 --- a/packages/fpdart/lib/src/task_either.dart +++ /dev/null @@ -1,387 +0,0 @@ -import 'either.dart'; -import 'function.dart'; -import 'option.dart'; -import 'task.dart'; -import 'typeclass/alt.dart'; -import 'typeclass/applicative.dart'; -import 'typeclass/functor.dart'; -import 'typeclass/hkt.dart'; -import 'typeclass/monad.dart'; - -final class _TaskEitherThrow { - final L value; - const _TaskEitherThrow(this.value); -} - -typedef DoAdapterTaskEither = Future Function(TaskEither); -DoAdapterTaskEither _doAdapter() => - (taskEither) => taskEither.run().then( - (either) => either.getOrElse((l) => throw _TaskEitherThrow(l)), - ); - -typedef DoFunctionTaskEither = Future Function( - DoAdapterTaskEither $); - -/// Tag the [HKT2] interface for the actual [TaskEither]. -abstract final class _TaskEitherHKT {} - -/// `TaskEither` represents an asynchronous computation that -/// either yields a value of type `R` or fails yielding an error of type `L`. -/// -/// If you want to represent an asynchronous computation that never fails, see [Task]. -final class TaskEither extends HKT2<_TaskEitherHKT, L, R> - with - Functor2<_TaskEitherHKT, L, R>, - Applicative2<_TaskEitherHKT, L, R>, - Monad2<_TaskEitherHKT, L, R>, - Alt2<_TaskEitherHKT, L, R> { - final Future> Function() _run; - - /// Build a [TaskEither] from a function returning a `Future>`. - const TaskEither(this._run); - - /// Initialize a **Do Notation** chain. - // ignore: non_constant_identifier_names - factory TaskEither.Do(DoFunctionTaskEither f) => TaskEither(() async { - try { - return Either.of(await f(_doAdapter())); - } on _TaskEitherThrow catch (e) { - return Either.left(e.value); - } - }); - - /// Used to chain multiple functions that return a [TaskEither]. - /// - /// You can extract the value of every [Right] in the chain without - /// handling all possible missing cases. - /// If running any of the tasks in the chain returns [Left], the result is [Left]. - @override - TaskEither flatMap(covariant TaskEither Function(R r) f) => - TaskEither(() => run().then( - (either) async => either.match( - left, - (r) => f(r).run(), - ), - )); - - /// Chain an [Either] to [TaskEither] by converting it from sync to async. - TaskEither bindEither(Either either) => - flatMap((_) => either.toTaskEither()); - - /// Chain a function that takes the current value `R` inside this [TaskEither] - /// and returns [Either]. - /// - /// Similar to `flatMap`, but `f` returns [Either] instead of [TaskEither]. - TaskEither chainEither(Either Function(R r) f) => flatMap( - (r) => f(r).toTaskEither(), - ); - - /// Returns a [TaskEither] that returns a `Right(a)`. - @override - TaskEither pure(C a) => TaskEither(() async => Right(a)); - - /// Change the return type of this [TaskEither] based on its value of type `R` and the - /// value of type `C` of another [TaskEither]. - @override - TaskEither map2( - covariant TaskEither m1, D Function(R b, C c) f) => - flatMap((b) => m1.map((c) => f(b, c))); - - /// Change the return type of this [TaskEither] based on its value of type `R`, the - /// value of type `C` of a second [TaskEither], and the value of type `D` - /// of a third [TaskEither]. - @override - TaskEither map3(covariant TaskEither m1, - covariant TaskEither m2, E Function(R b, C c, D d) f) => - flatMap((b) => m1.flatMap((c) => m2.map((d) => f(b, c, d)))); - - /// If running this [TaskEither] returns [Right], then return the result of calling `then`. - /// Otherwise return [Left]. - @override - TaskEither andThen(covariant TaskEither Function() then) => - flatMap((_) => then()); - - /// If running this [TaskEither] returns [Right], then change its value from type `R` to - /// type `C` using function `f`. - @override - TaskEither map(C Function(R r) f) => ap(pure(f)); - - /// Change the value in the [Left] of [TaskEither]. - TaskEither mapLeft(C Function(L l) f) => TaskEither( - () async => (await run()).match((l) => Either.left(f(l)), Either.of), - ); - - /// Define two functions to change both the [Left] and [Right] value of the - /// [TaskEither]. - /// - /// {@macro fpdart_bimap_either} - TaskEither bimap(C Function(L l) mLeft, D Function(R r) mRight) => - mapLeft(mLeft).map(mRight); - - /// Apply the function contained inside `a` to change the value on the [Right] from - /// type `R` to a value of type `C`. - @override - TaskEither ap(covariant TaskEither a) => - a.flatMap((f) => flatMap((v) => pure(f(v)))); - - /// Chain multiple functions having the same left type `L`. - @override - TaskEither call(covariant TaskEither chain) => - flatMap((_) => chain); - - /// Change this [TaskEither] from `TaskEither` to `TaskEither`. - TaskEither swap() => - TaskEither(() async => (await run()).match(right, left)); - - /// When this [TaskEither] returns [Right], then return the current [TaskEither]. - /// Otherwise return the result of `orElse`. - /// - /// Used to provide an **alt**ernative [TaskEither] in case the current one returns [Left]. - @override - TaskEither alt(covariant TaskEither Function() orElse) => - TaskEither(() async => (await run()).match((_) => orElse().run(), right)); - - /// If `f` applied on this [TaskEither] as [Right] returns `true`, then return this [TaskEither]. - /// If it returns `false`, return the result of `onFalse` in a [Left]. - TaskEither filterOrElse( - bool Function(R r) f, L Function(R r) onFalse) => - flatMap((r) => f(r) ? TaskEither.of(r) : TaskEither.left(onFalse(r))); - - /// When this [TaskEither] returns a [Left] then return the result of `orElse`. - /// Otherwise return this [TaskEither]. - TaskEither orElse(TaskEither Function(L l) orElse) => - TaskEither(() async => (await run()).match( - (l) => orElse(l).run(), (r) => TaskEither.right(r).run())); - - /// Convert this [TaskEither] to a [Task]. - /// - /// The task returns a [Right] when [TaskEither] returns [Right]. - /// Otherwise map the type `L` of [TaskEither] to type `R` by calling `orElse`. - Task getOrElse(R Function(L l) orElse) => - Task(() async => (await run()).match(orElse, identity)); - - /// Pattern matching to convert a [TaskEither] to a [Task]. - /// - /// Execute `onLeft` when running this [TaskEither] returns a [Left]. - /// Otherwise execute `onRight`. - Task match(A Function(L l) onLeft, A Function(R r) onRight) => - Task(() async => (await run()).match(onLeft, onRight)); - - /// Creates a [TaskEither] that will complete after a time delay specified by a [Duration]. - TaskEither delay(Duration duration) => - TaskEither(() => Future.delayed(duration, run)); - - /// Chain a request that returns another [TaskEither], execute it, ignore - /// the result, and return the same value as the current [TaskEither]. - @override - TaskEither chainFirst( - covariant TaskEither Function(R b) chain, - ) => - flatMap((b) => chain(b).map((c) => b).orElse((l) => TaskEither.right(b))); - - /// Run the task and return a `Future>`. - Future> run() => _run(); - - /// Build a [TaskEither] that returns a `Right(r)`. - /// - /// Same of `TaskEither.right`. - factory TaskEither.of(R r) => TaskEither(() async => Either.of(r)); - - /// Flat a [TaskEither] contained inside another [TaskEither] to be a single [TaskEither]. - factory TaskEither.flatten(TaskEither> taskEither) => - taskEither.flatMap(identity); - - /// Build a [TaskEither] that returns a `Right(right)`. - /// - /// Same of `TaskEither.of`. - factory TaskEither.right(R right) => TaskEither(() async => Either.of(right)); - - /// Build a [TaskEither] that returns a `Left(left)`. - factory TaskEither.left(L left) => TaskEither(() async => Left(left)); - - /// Build a [TaskEither] that returns a [Left] containing the result of running `task`. - factory TaskEither.leftTask(Task task) => - TaskEither(() => task.run().then(left)); - - /// Build a [TaskEither] that returns a [Right] containing the result of running `task`. - /// - /// Same of `TaskEither.fromTask` - factory TaskEither.rightTask(Task task) => - TaskEither(() async => Right(await task.run())); - - /// Build a [TaskEither] from the result of running `task`. - /// - /// Same of `TaskEither.rightTask` - factory TaskEither.fromTask(Task task) => - TaskEither(() async => Right(await task.run())); - - /// {@template fpdart_from_nullable_task_either} - /// If `r` is `null`, then return the result of `onNull` in [Left]. - /// Otherwise return `Right(r)`. - - /// {@endtemplate} - factory TaskEither.fromNullable(R? r, L Function() onNull) => - Either.fromNullable(r, onNull).toTaskEither(); - - /// {@macro fpdart_from_nullable_task_either} - factory TaskEither.fromNullableAsync(R? r, Task onNull) => TaskEither( - () async => r != null ? Either.of(r) : Either.left(await onNull.run())); - - /// When calling `predicate` with `value` returns `true`, then running [TaskEither] returns `Right(value)`. - /// Otherwise return `onFalse`. - factory TaskEither.fromPredicate( - R value, bool Function(R a) predicate, L Function(R a) onFalse) => - TaskEither( - () async => predicate(value) ? Right(value) : Left(onFalse(value))); - - /// Build a [TaskEither] from `option`. - /// - /// When `option` is [Some], then return [Right] when - /// running [TaskEither]. Otherwise return `onNone`. - factory TaskEither.fromOption(Option option, L Function() onNone) => - TaskEither(() async => option.match( - () => Left(onNone()), - Right.new, - )); - - /// Build a [TaskEither] that returns `either`. - factory TaskEither.fromEither(Either either) => - TaskEither(() async => either); - - /// {@template fpdart_try_catch_task_either} - /// Execute an async function ([Future]) and convert the result to [Either]: - /// - If the execution is successful, returns a [Right] - /// - If the execution fails (`throw`), then return a [Left] based on `onError` - /// - /// Used to work with [Future] and exceptions using [Either] instead of `try`/`catch`. - /// {@endtemplate} - /// ```dart - /// /// From [Future] to [TaskEither] - /// Future imperative(String str) async { - /// try { - /// return int.parse(str); - /// } catch (e) { - /// return -1; /// What does -1 means? 🤨 - /// } - /// } - /// - /// TaskEither functional(String str) { - /// return TaskEither.tryCatch( - /// () async => int.parse(str), - /// /// Clear error 🪄 - /// (error, stackTrace) => "Parsing error: $error", - /// ); - /// } - /// ``` - factory TaskEither.tryCatch(Future Function() run, - L Function(Object error, StackTrace stackTrace) onError) => - TaskEither(() async { - try { - return Right(await run()); - } catch (error, stack) { - return Left(onError(error, stack)); - } - }); - - /// {@template fpdart_traverse_list_task_either} - /// Map each element in the list to a [TaskEither] using the function `f`, - /// and collect the result in an `TaskEither>`. - /// - /// Each [TaskEither] is executed in parallel. This strategy is faster than - /// sequence, but **the order of the request is not guaranteed**. - /// - /// If you need [TaskEither] to be executed in sequence, use `traverseListWithIndexSeq`. - /// {@endtemplate} - /// - /// Same as `TaskEither.traverseList` but passing `index` in the map function. - static TaskEither> traverseListWithIndex( - List list, - TaskEither Function(A a, int i) f, - ) => - TaskEither>( - () async => Either.sequenceList( - await Task.traverseListWithIndex>( - list, - (a, i) => Task(() => f(a, i).run()), - ).run(), - ), - ); - - /// {@macro fpdart_traverse_list_task_either} - /// - /// Same as `TaskEither.traverseListWithIndex` but without `index` in the map function. - static TaskEither> traverseList( - List list, - TaskEither Function(A a) f, - ) => - traverseListWithIndex(list, (a, _) => f(a)); - - /// {@template fpdart_sequence_list_task_either} - /// Convert a `List>` to a single `TaskEither>`. - /// - /// Each [TaskEither] will be executed in parallel. - /// - /// If you need [TaskEither] to be executed in sequence, use `sequenceListSeq`. - /// {@endtemplate} - static TaskEither> sequenceList( - List> list, - ) => - traverseList(list, identity); - - /// {@template fpdart_traverse_list_seq_task_either} - /// Map each element in the list to a [TaskEither] using the function `f`, - /// and collect the result in an `TaskEither>`. - /// - /// Each [TaskEither] is executed in sequence. This strategy **takes more time than - /// parallel**, but it ensures that all the request are executed in order. - /// - /// If you need [TaskEither] to be executed in parallel, use `traverseListWithIndex`. - /// {@endtemplate} - /// - /// Same as `TaskEither.traverseList` but passing `index` in the map function. - static TaskEither> traverseListWithIndexSeq( - List list, - TaskEither Function(A a, int i) f, - ) => - TaskEither>( - () async => Either.sequenceList( - await Task.traverseListWithIndexSeq>( - list, - (a, i) => Task(() => f(a, i).run()), - ).run(), - ), - ); - - /// {@macro fpdart_traverse_list_seq_task_either} - /// - /// Same as `TaskEither.traverseListWithIndex` but without `index` in the map function. - static TaskEither> traverseListSeq( - List list, - TaskEither Function(A a) f, - ) => - traverseListWithIndexSeq(list, (a, _) => f(a)); - - /// {@template fpdart_sequence_list_seq_task_either} - /// Convert a `List>` to a single `TaskEither>`. - /// - /// Each [TaskEither] will be executed in sequence. - /// - /// If you need [TaskEither] to be executed in parallel, use `sequenceList`. - /// {@endtemplate} - static TaskEither> sequenceListSeq( - List> list, - ) => - traverseListSeq(list, identity); - - /// {@macro fpdart_try_catch_task_either} - /// - /// It wraps the `TaskEither.tryCatch` factory to make chaining with `flatMap` - /// easier. - static TaskEither Function(T a) tryCatchK( - Future Function(T a) run, - L Function(Object error, StackTrace stackTrace) onError) => - (a) => TaskEither.tryCatch( - () => run(a), - onError, - ); -} diff --git a/packages/fpdart/lib/src/task_option.dart b/packages/fpdart/lib/src/task_option.dart deleted file mode 100644 index b5b31fbe..00000000 --- a/packages/fpdart/lib/src/task_option.dart +++ /dev/null @@ -1,313 +0,0 @@ -import 'either.dart'; -import 'extension/option_extension.dart'; -import 'function.dart'; -import 'option.dart'; -import 'task.dart'; -import 'task_either.dart'; -import 'typeclass/alt.dart'; -import 'typeclass/applicative.dart'; -import 'typeclass/functor.dart'; -import 'typeclass/hkt.dart'; -import 'typeclass/monad.dart'; - -final class _TaskOptionThrow { - const _TaskOptionThrow(); -} - -typedef DoAdapterTaskOption = Future Function(TaskOption); -Future _doAdapter(TaskOption taskOption) => taskOption.run().then( - (option) => option.getOrElse(() => throw const _TaskOptionThrow()), - ); - -typedef DoFunctionTaskOption = Future Function(DoAdapterTaskOption $); - -/// Tag the [HKT] interface for the actual [TaskOption]. -abstract final class _TaskOptionHKT {} - -/// `TaskOption` represents an **asynchronous** computation that -/// may fails yielding a [None] or returns a `Some(R)` when successful. -/// -/// If you want to represent an asynchronous computation that never fails, see [Task]. -/// -/// If you want to represent an asynchronous computation that returns an object when it fails, -/// see [TaskEither]. -final class TaskOption extends HKT<_TaskOptionHKT, R> - with - Functor<_TaskOptionHKT, R>, - Applicative<_TaskOptionHKT, R>, - Monad<_TaskOptionHKT, R>, - Alt<_TaskOptionHKT, R> { - final Future> Function() _run; - - /// Build a [TaskOption] from a function returning a `Future>`. - const TaskOption(this._run); - - /// Initialize a **Do Notation** chain. - // ignore: non_constant_identifier_names - factory TaskOption.Do(DoFunctionTaskOption f) => TaskOption(() async { - try { - return Option.of(await f(_doAdapter)); - } on _TaskOptionThrow catch (_) { - return const Option.none(); - } - }); - - /// Used to chain multiple functions that return a [TaskOption]. - /// - /// You can extract the value of every [Some] in the chain without - /// handling all possible missing cases. - /// If running any of the tasks in the chain returns [None], the result is [None]. - @override - TaskOption flatMap(covariant TaskOption Function(R r) f) => - TaskOption(() => run().then( - (option) async => option.match( - Option.none, - (r) => f(r).run(), - ), - )); - - /// Returns a [TaskOption] that returns `Some(c)`. - @override - TaskOption pure(C c) => TaskOption(() async => Option.of(c)); - - /// Change the return type of this [TaskOption] based on its value of type `R` and the - /// value of type `C` of another [TaskOption]. - @override - TaskOption map2( - covariant TaskOption m1, D Function(R b, C c) f) => - flatMap((b) => m1.map((c) => f(b, c))); - - /// Change the return type of this [TaskOption] based on its value of type `R`, the - /// value of type `C` of a second [TaskOption], and the value of type `D` - /// of a third [TaskOption]. - @override - TaskOption map3(covariant TaskOption m1, - covariant TaskOption m2, E Function(R b, C c, D d) f) => - flatMap((b) => m1.flatMap((c) => m2.map((d) => f(b, c, d)))); - - /// If running this [TaskOption] returns [Some], then return the result of calling `then`. - /// Otherwise return [None]. - @override - TaskOption andThen(covariant TaskOption Function() then) => - flatMap((_) => then()); - - /// Chain multiple [TaskOption] functions. - @override - TaskOption call(covariant TaskOption chain) => flatMap((_) => chain); - - /// If running this [TaskOption] returns [Some], then change its value from type `R` to - /// type `C` using function `f`. - @override - TaskOption map(C Function(R r) f) => ap(pure(f)); - - /// Apply the function contained inside `a` to change the value on the [Some] from - /// type `R` to a value of type `C`. - @override - TaskOption ap(covariant TaskOption a) => - a.flatMap((f) => flatMap((v) => pure(f(v)))); - - /// When this [TaskOption] returns [Some], then return the current [TaskOption]. - /// Otherwise return the result of `orElse`. - /// - /// Used to provide an **alt**ernative [TaskOption] in case the current one returns [None]. - @override - TaskOption alt(covariant TaskOption Function() orElse) => - TaskOption(() async => (await run()).match( - () => orElse().run(), - some, - )); - - /// When this [TaskOption] returns a [None] then return the result of `orElse`. - /// Otherwise return this [TaskOption]. - TaskOption orElse(TaskOption Function() orElse) => - TaskOption(() async => (await run()).match( - () => orElse().run(), - (r) => TaskOption.some(r).run(), - )); - - /// Convert this [TaskOption] to a [Task]. - /// - /// The task returns a [Some] when [TaskOption] returns [Some]. - /// Otherwise map the type `L` of [TaskOption] to type `R` by calling `orElse`. - Task getOrElse(R Function() orElse) => - Task(() async => (await run()).match( - orElse, - identity, - )); - - /// Pattern matching to convert a [TaskOption] to a [Task]. - /// - /// Execute `onNone` when running this [TaskOption] returns a [None]. - /// Otherwise execute `onSome`. - Task match(A Function() onNone, A Function(R r) onSome) => - Task(() async => (await run()).match( - onNone, - onSome, - )); - - /// Creates a [TaskOption] that will complete after a time delay specified by a [Duration]. - TaskOption delay(Duration duration) => - TaskOption(() => Future.delayed(duration, run)); - - /// Run the task and return a `Future>`. - Future> run() => _run(); - - /// Convert this [TaskOption] to [TaskEither]. - /// - /// If the value inside [TaskOption] is [None], then use `onNone` to convert it - /// to a value of type `L`. - TaskEither toTaskEither(L Function() onNone) => - TaskEither(() async => Either.fromOption(await run(), onNone)); - - /// Build a [TaskOption] that returns a `Some(r)`. - /// - /// Same of `TaskOption.some`. - factory TaskOption.of(R r) => TaskOption(() async => Option.of(r)); - - /// Flat a [TaskOption] contained inside another [TaskOption] to be a single [TaskOption]. - factory TaskOption.flatten(TaskOption> taskOption) => - taskOption.flatMap(identity); - - /// Build a [TaskOption] that returns a `Some(r)`. - /// - /// Same of `TaskOption.of`. - factory TaskOption.some(R r) => TaskOption(() async => Option.of(r)); - - /// Build a [TaskOption] that returns a [None]. - factory TaskOption.none() => TaskOption(() async => const Option.none()); - - /// Build a [TaskOption] from the result of running `task`. - factory TaskOption.fromTask(Task task) => - TaskOption(() async => Option.of(await task.run())); - - /// If `r` is `null`, then return [None]. - /// Otherwise return `Right(r)`. - factory TaskOption.fromNullable(R? r) => - Option.fromNullable(r).toTaskOption(); - - /// When calling `predicate` with `value` returns `true`, then running [TaskOption] returns `Some(value)`. - /// Otherwise return [None]. - factory TaskOption.fromPredicate(R value, bool Function(R a) predicate) => - TaskOption( - () async => predicate(value) ? Option.of(value) : const Option.none(), - ); - - /// Converts a [Future] that may throw to a [Future] that never throws - /// but returns a [Option] instead. - /// - /// Used to handle asynchronous computations that may throw using [Option]. - factory TaskOption.tryCatch(Future Function() run) => - TaskOption(() async { - try { - return Option.of(await run()); - } catch (_) { - return const Option.none(); - } - }); - - /// {@template fpdart_traverse_list_task_option} - /// Map each element in the list to a [TaskOption] using the function `f`, - /// and collect the result in an `TaskOption>`. - /// - /// Each [TaskOption] is executed in parallel. This strategy is faster than - /// sequence, but **the order of the request is not guaranteed**. - /// - /// If you need [TaskOption] to be executed in sequence, use `traverseListWithIndexSeq`. - /// {@endtemplate} - /// - /// Same as `TaskOption.traverseList` but passing `index` in the map function. - static TaskOption> traverseListWithIndex( - List list, - TaskOption Function(A a, int i) f, - ) => - TaskOption>( - () async => Option.sequenceList( - await Task.traverseListWithIndex>( - list, - (a, i) => Task(() => f(a, i).run()), - ).run(), - ), - ); - - /// {@macro fpdart_traverse_list_task_option} - /// - /// Same as `TaskOption.traverseListWithIndex` but without `index` in the map function. - static TaskOption> traverseList( - List list, - TaskOption Function(A a) f, - ) => - traverseListWithIndex(list, (a, _) => f(a)); - - /// {@template fpdart_sequence_list_task_option} - /// Convert a `List>` to a single `TaskOption>`. - /// - /// Each [TaskOption] will be executed in parallel. - /// - /// If you need [TaskOption] to be executed in sequence, use `sequenceListSeq`. - /// {@endtemplate} - static TaskOption> sequenceList( - List> list, - ) => - traverseList(list, identity); - - /// {@template fpdart_traverse_list_seq_task_option} - /// Map each element in the list to a [TaskOption] using the function `f`, - /// and collect the result in an `TaskOption>`. - /// - /// Each [TaskOption] is executed in sequence. This strategy **takes more time than - /// parallel**, but it ensures that all the request are executed in order. - /// - /// If you need [TaskOption] to be executed in parallel, use `traverseListWithIndex`. - /// {@endtemplate} - /// - /// Same as `TaskOption.traverseListSeq` but passing `index` in the map function. - static TaskOption> traverseListWithIndexSeq( - List list, - TaskOption Function(A a, int i) f, - ) => - TaskOption>( - () async => Option.sequenceList( - await Task.traverseListWithIndexSeq>( - list, - (a, i) => Task(() => f(a, i).run()), - ).run(), - ), - ); - - /// {@macro fpdart_traverse_list_seq_task_option} - /// - /// Same as `TaskOption.traverseListWithIndexSeq` but without `index` in the map function. - static TaskOption> traverseListSeq( - List list, - TaskOption Function(A a) f, - ) => - traverseListWithIndexSeq(list, (a, _) => f(a)); - - /// {@template fpdart_sequence_list_seq_task_option} - /// Convert a `List>` to a single `TaskOption>`. - /// - /// Each [TaskOption] will be executed in sequence. - /// - /// If you need [TaskOption] to be executed in parallel, use `sequenceList`. - /// {@endtemplate} - static TaskOption> sequenceListSeq( - List> list, - ) => - traverseListSeq(list, identity); - - /// Build a [TaskOption] from `either` that returns [None] when - /// `either` is [Left], otherwise it returns [Some]. - static TaskOption fromEither(Either either) => - TaskOption(() async => either.match((_) => const Option.none(), some)); - - /// Converts a [Future] that may throw to a [Future] that never throws - /// but returns a [Option] instead. - /// - /// Used to handle asynchronous computations that may throw using [Option]. - /// - /// It wraps the `TaskOption.tryCatch` factory to make chaining with `flatMap` - /// easier. - static TaskOption Function(A a) tryCatchK( - Future Function(A a) run) => - (a) => TaskOption.tryCatch(() => run(a)); -} diff --git a/packages/fpdart/lib/src/typeclass/alt.dart b/packages/fpdart/lib/src/typeclass/alt.dart deleted file mode 100644 index 6227f16b..00000000 --- a/packages/fpdart/lib/src/typeclass/alt.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'functor.dart'; -import 'hkt.dart'; - -/// `Alt` type class identifies an associative operation on a type constructor. -/// -/// It provides an `alt` function used to return an alternative value when the -/// current one represents a failure (for example, [None] for [Option]). -mixin Alt on HKT, Functor { - HKT alt(HKT Function() orElse); -} - -mixin Alt2 on HKT2, Functor2 { - HKT2 alt(HKT2 Function() orElse); -} - -mixin Alt3 on HKT3, Functor3 { - HKT3 alt(HKT3 Function() orElse); -} diff --git a/packages/fpdart/lib/src/typeclass/applicative.dart b/packages/fpdart/lib/src/typeclass/applicative.dart deleted file mode 100644 index dac17939..00000000 --- a/packages/fpdart/lib/src/typeclass/applicative.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'functor.dart'; -import 'hkt.dart'; - -mixin Applicative on HKT, Functor { - HKT pure(B b); - HKT ap(HKT a); - - @override - HKT map(B Function(A a) f) => ap(pure(f)); -} - -mixin Applicative2 on HKT2, Functor2 { - HKT2 pure(C c); - HKT2 ap(HKT2 a); - - @override - HKT2 map(C Function(B a) f) => ap(pure(f)); -} - -mixin Applicative3 on HKT3, Functor3 { - HKT3 pure(D a); - HKT3 ap(HKT3 a); - - @override - HKT3 map(D Function(C c) f) => ap(pure(f)); -} diff --git a/packages/fpdart/lib/src/typeclass/band.dart b/packages/fpdart/lib/src/typeclass/band.dart deleted file mode 100644 index a38f6616..00000000 --- a/packages/fpdart/lib/src/typeclass/band.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'semigroup.dart'; - -/// Bands are semigroups whose operation -/// (i.e. `combine`) is also [**idempotent**](https://en.wikipedia.org/wiki/Idempotence) -/// (an operation that can be applied multiple times without changing the result beyond the initial application). -mixin Band on Semigroup { - /// Only apply `combine` operation the first time: - /// - `n == 1`, then return `a` - /// - Otherwise return `combine(a, a)` - @override - T combineN(T a, int n) { - if (n <= 0) { - throw const FormatException( - "Repeated combining for bands must have n > 0"); - } - - return n == 1 ? a : combine(a, a); - } - - /// Create a `Band` instance from the given function. - static Band instance(A Function(A a1, A a2) f) => _Band(f); -} - -class _Band with Semigroup, Band { - final T Function(T x, T y) comb; - - const _Band(this.comb); - - @override - T combine(T x, T y) => comb(x, y); -} diff --git a/packages/fpdart/lib/src/typeclass/bounded_semilattice.dart b/packages/fpdart/lib/src/typeclass/bounded_semilattice.dart deleted file mode 100644 index d2019d5d..00000000 --- a/packages/fpdart/lib/src/typeclass/bounded_semilattice.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'band.dart'; -import 'commutative_monoid.dart'; -import 'commutative_semigroup.dart'; -import 'monoid.dart'; -import 'semigroup.dart'; -import 'semilattice.dart'; - -/// A semilattice in which: -/// -/// > For all elements `x` and `y` of `A`, both the -/// > [**least upper bound**](https://en.wikipedia.org/wiki/Infimum_and_supremum) and -/// > [**greatest lower bound**](https://en.wikipedia.org/wiki/Infimum_and_supremum) -/// > of the set `{x, y}` exist. -/// -/// See also [Semilattice] -mixin BoundedSemilattice on CommutativeMonoid, Semilattice { - /// Return a `BoundedSemilattice` that reverses the order. - @override - BoundedSemilattice reverse() => - _BoundedSemilattice(empty, (x, y) => combine(y, x)); - - /// Return `a`, since `combine(a, a) == a` for a semilattice (idempotent). - /// - /// Return `empty` if `n == 0`. - @override - T combineN(T a, int n) { - if (n < 0) { - throw const FormatException( - "Repeated combining for monoids must have n >= 0"); - } else if (n == 0) { - return empty; - } - - return a; - } - - /// Create a `BoundedSemilattice` instance from the given function and empty value. - static BoundedSemilattice instance( - A emptyValue, A Function(A a1, A a2) f) => - _BoundedSemilattice(emptyValue, f); -} - -class _BoundedSemilattice - with - Semigroup, - Monoid, - CommutativeSemigroup, - Band, - Semilattice, - CommutativeMonoid, - BoundedSemilattice { - final T emp; - final T Function(T x, T y) comb; - - const _BoundedSemilattice(this.emp, this.comb); - - @override - T combine(T x, T y) => comb(x, y); - - @override - T get empty => emp; -} diff --git a/packages/fpdart/lib/src/typeclass/commutative_group.dart b/packages/fpdart/lib/src/typeclass/commutative_group.dart deleted file mode 100644 index 237f5463..00000000 --- a/packages/fpdart/lib/src/typeclass/commutative_group.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'commutative_monoid.dart'; -import 'commutative_semigroup.dart'; -import 'group.dart'; -import 'monoid.dart'; -import 'semigroup.dart'; - -/// An commutative group (also known as an [**abelian group**](https://en.wikipedia.org/wiki/Abelian_group)) -/// is a group whose combine operation is [**commutative**](https://en.wikipedia.org/wiki/Commutative_property). -/// -/// See also [Group] -mixin CommutativeGroup on Group, CommutativeMonoid { - /// Create a `CommutativeGroup` instance from the given function, empty value, and inverse function. - static CommutativeGroup instance( - A emptyValue, A Function(A a1, A a2) f, A Function(A a) inv) => - _CommutativeGroup(emptyValue, f, inv); -} - -class _CommutativeGroup - with - Semigroup, - CommutativeSemigroup, - Monoid, - CommutativeMonoid, - Group, - CommutativeGroup { - final T Function(T a) inv; - final T emp; - final T Function(T x, T y) comb; - - const _CommutativeGroup(this.emp, this.comb, this.inv); - - @override - T combine(T x, T y) => comb(x, y); - - @override - T get empty => emp; - - @override - T inverse(T a) => inv(a); -} diff --git a/packages/fpdart/lib/src/typeclass/commutative_monoid.dart b/packages/fpdart/lib/src/typeclass/commutative_monoid.dart deleted file mode 100644 index 7982edc6..00000000 --- a/packages/fpdart/lib/src/typeclass/commutative_monoid.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'commutative_semigroup.dart'; -import 'monoid.dart'; -import 'semigroup.dart'; - -/// `CommutativeMonoid` represents a commutative monoid. -/// -/// A monoid is [**commutative**](https://en.wikipedia.org/wiki/Commutative_property) -/// if for all `x` and `y`, `combine(x, y) == combine(y, x)`. -mixin CommutativeMonoid on Monoid, CommutativeSemigroup { - /// Return a `CommutativeMonoid` that reverses the order. - @override - CommutativeMonoid reverse() => - _CommutativeMonoid(empty, (x, y) => combine(y, x)); - - /// Create a `CommutativeMonoid` instance from the given function and empty value. - static CommutativeMonoid instance( - A emptyValue, A Function(A a1, A a2) f) => - _CommutativeMonoid(emptyValue, f); -} - -class _CommutativeMonoid - with - Semigroup, - CommutativeSemigroup, - Monoid, - CommutativeMonoid { - final T emp; - final T Function(T x, T y) comb; - - const _CommutativeMonoid(this.emp, this.comb); - - @override - T combine(T x, T y) => comb(x, y); - - @override - T get empty => emp; -} diff --git a/packages/fpdart/lib/src/typeclass/commutative_semigroup.dart b/packages/fpdart/lib/src/typeclass/commutative_semigroup.dart deleted file mode 100644 index 6a24ebd5..00000000 --- a/packages/fpdart/lib/src/typeclass/commutative_semigroup.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'semigroup.dart'; - -/// `CommutativeSemigroup` represents a commutative semigroup. -/// -/// A semigroup is [**commutative**](https://en.wikipedia.org/wiki/Commutative_property) -/// if for all `x` and `y`, `combine(x, y) == combine(y, x)`. -mixin CommutativeSemigroup on Semigroup { - /// Create a `CommutativeSemigroup` instance from the given function. - // ignore: library_private_types_in_public_api - static _CommutativeSemigroup instance(A Function(A a1, A a2) f) => - _CommutativeSemigroup(f); -} - -class _CommutativeSemigroup with Semigroup, CommutativeSemigroup { - final T Function(T x, T y) comb; - - const _CommutativeSemigroup(this.comb); - - @override - T combine(T x, T y) => comb(x, y); -} diff --git a/packages/fpdart/lib/src/typeclass/eq.dart b/packages/fpdart/lib/src/typeclass/eq.dart deleted file mode 100644 index 6e828990..00000000 --- a/packages/fpdart/lib/src/typeclass/eq.dart +++ /dev/null @@ -1,131 +0,0 @@ -/// A type class used to determine equality between 2 instances **of the same type `T`**. -/// Any 2 instances `x` and `y` are equal if `eqv(x, y)` is `true`. -/// -/// Moreover, `eqv` should form an [equivalence relation](https://en.wikipedia.org/wiki/Equivalence_relation) -/// (a binary relation that is reflexive, symmetric, and transitive). -abstract class Eq { - const Eq(); - - /// Returns `true` if `x` and `y` are equivalent, `false` otherwise. - bool eqv(T x, T y); - - /// Returns `false` if `x` and `y` are equivalent, `true` otherwise. - bool neqv(T x, T y) => !eqv(x, y); - - /// Return an `Eq` that gives the result of **and** of `eq1` and `eq2`. - Eq and(Eq eq) => _Eq( - (x, y) => eqv(x, y) && eq.eqv(x, y), - ); - - /// Return an `Eq` that gives the result of **or** of this [Eq] and `eq`. - Eq or(Eq eq) => _Eq( - (x, y) => eqv(x, y) || eq.eqv(x, y), - ); - - /// Return an `Eq` that gives the result of **xor** of this [Eq] and `eq`. - Eq xor(Eq eq) => _Eq( - (x, y) { - final eqThis = eqv(x, y); - final eqOther = eq.eqv(x, y); - return eqThis ? !eqOther : eqOther; - }, - ); - - /// Return an [Eq] instance based on a parameter of type `T` extracted from a class `A`. - /// ```dart - /// class Parent { - /// final int value1; - /// final double value2; - /// const Parent(this.value1, this.value2); - /// } - - /// /// Equality for values of type [Parent] based on their `value1` ([int]). - /// final eqParentInt = Eq.eqInt.contramap( - /// (p) => p.value1, - /// ); - - /// /// Equality for of type [Parent] based on their `value2` ([double]). - /// final eqParentDouble = Eq.eqDouble.contramap( - /// (p) => p.value2, - /// ); - /// ``` - Eq contramap(T Function(A) map) => _Eq( - (a1, a2) => eqv(map(a1), map(a2)), - ); - - /// Convert an implicit `Eq` to an `Eq` using the given function `f`. - /// - /// ```dart - /// /// Convert an `Eq` on `int` to an `Eq` to check `String` length - /// final instance = Eq.instance((a1, a2) => a1 == a2); - /// final by = Eq.by((a) => a.length, instance); - /// - /// expect(by.eqv('abc', 'abc'), true); // Same length - /// expect(by.eqv('abc', 'ab'), false); // Different length - /// ``` - static Eq by(B Function(A a) f, Eq eq) => - _Eq((x, y) => eq.eqv(f(x), f(y))); - - /// Create an `Eq` instance from an `eqv` implementation. - /// - /// ```dart - /// final instance = Eq.instance((a1, a2) => a1.substring(0, 2) == a2.substring(0, 2)); - /// - /// expect(instance.eqv('abc', 'abc'), true); // Same 2 characters prefix - /// expect(instance.eqv('abc', 'acb'), false); // Different 2 characters prefix - /// ``` - static Eq instance(bool Function(A a1, A a2) f) => _Eq(f); - - /// An `Eq` that delegates to universal equality (`==`). - static Eq fromUniversalEquals() => _Eq((x, y) => x == y); - - /// An `Eq` in which everything is the same - /// (calling `eqv` returns always `true`). - static Eq allEqual() => _Eq((x, y) => true); - - /// Instance of `Eq` for `num` using the standard `==` operator. - static Eq eqNum = _Eq((x, y) => x == y); - - /// Instance of `Eq` for `int` using the standard `==` operator. - static Eq eqInt = _Eq((x, y) => x == y); - - /// Instance of `Eq` for `double` using the standard `==` operator. - static Eq eqDouble = _Eq((x, y) => x == y); - - /// Instance of `Eq` for `String` using the standard `==` operator. - static Eq eqString = _Eq((x, y) => x == y); - - /// Instance of `Eq` for `bool` using the standard `==` operator. - static Eq eqBool = _Eq((x, y) => x == y); - - /// [Eq] instance to compare [DateTime] years. - static Eq dateEqYear = _Eq( - (a1, a2) => a1.year == a2.year, - ); - - /// [Eq] instance to compare [DateTime] months. - static Eq dateEqMonth = _Eq( - (a1, a2) => a1.month == a2.month, - ); - - /// [Eq] instance to compare [DateTime] days. - static Eq dateEqDay = _Eq( - (a1, a2) => a1.day == a2.day, - ); - - /// [Eq] instance to compare [DateTime] by year, month, and day. - static Eq dateEqYearMonthDay = _Eq( - (a1, a2) => - dateEqYear.eqv(a1, a2) && - dateEqMonth.eqv(a1, a2) && - dateEqDay.eqv(a1, a2), - ); -} - -class _Eq extends Eq { - final bool Function(T x, T y) eq; - const _Eq(this.eq); - - @override - bool eqv(T x, T y) => eq(x, y); -} diff --git a/packages/fpdart/lib/src/typeclass/extend.dart b/packages/fpdart/lib/src/typeclass/extend.dart deleted file mode 100644 index 3824cedc..00000000 --- a/packages/fpdart/lib/src/typeclass/extend.dart +++ /dev/null @@ -1,22 +0,0 @@ -import '../function.dart'; -import 'functor.dart'; -import 'hkt.dart'; - -mixin Extend on HKT, Functor { - /// Extend the type by applying function `f` to it. - /// - /// ```dart - /// final option = Some(10); - /// final value = option.extend((t) => t.isSome() ? 'valid' : 'invalid'); // -> Some('valid') - /// ``` - HKT extend(Z Function(HKT t) f); - - HKT> duplicate() => extend(identity); -} - -mixin Extend2 on HKT2, Functor2 { - /// Extend the type by applying function `f` to it. - HKT2 extend(Z Function(HKT2 t) f); - - HKT2> duplicate() => extend(identity); -} diff --git a/packages/fpdart/lib/src/typeclass/filterable.dart b/packages/fpdart/lib/src/typeclass/filterable.dart deleted file mode 100644 index e0a4663f..00000000 --- a/packages/fpdart/lib/src/typeclass/filterable.dart +++ /dev/null @@ -1,20 +0,0 @@ -import '../either.dart'; -import '../option.dart'; -import '../typedef.dart'; -import 'functor.dart'; -import 'hkt.dart'; - -mixin Filterable on HKT, Functor { - /// Filter a data structure based on a boolean predicate. - HKT filter(bool Function(A a) f); - - /// Map over a data structure and filter based on a [Option] predicate. - HKT filterMap(Option Function(A a) f); - - /// Partition a data structure based on a boolean predicate. - Separated partition(bool Function(A a) f) => - (filter((a) => !f(a)), filter(f)); - - /// Partition a data structure based on an [Either] predicate. - Separated partitionMap(Either Function(A a) f); -} diff --git a/packages/fpdart/lib/src/typeclass/foldable.dart b/packages/fpdart/lib/src/typeclass/foldable.dart deleted file mode 100644 index 4fb3615f..00000000 --- a/packages/fpdart/lib/src/typeclass/foldable.dart +++ /dev/null @@ -1,76 +0,0 @@ -import '../function.dart'; -import '../typedef.dart'; -import 'hkt.dart'; -import 'monoid.dart'; - -mixin Foldable on HKT { - B foldRight(B b, B Function(B acc, A a) f); - - B foldLeft(B b, B Function(B acc, A a) f) => - foldMap>(dualEndoMonoid(), (a) => (B b) => f(b, a))(b); - - /// Fold implemented by mapping `A` values into `B` and then - /// combining them using the given `Monoid` instance. - /// - /// Use `Monoid` to provide the initial value of the fold (`empty`) and - /// the `combine` function to combine the accumulator `B` with the value of - /// type `B` computed using the function `f` from type `A` (`f(a)`). - B foldMap(Monoid monoid, B Function(A a) f) => - foldRight(monoid.empty, (b, a) => monoid.combine(f(a), b)); - - B foldRightWithIndex(B b, B Function(int i, B acc, A a) f) => - foldRight<(B, int)>( - (b, length() - 1), - (t, a) => (f(t.$2, t.$1, a), t.$2 - 1), - ).$1; - - B foldLeftWithIndex(B b, B Function(int i, B acc, A a) f) => - foldLeft<(B, int)>( - (b, 0), - (t, a) => (f(t.$2, t.$1, a), t.$2 + 1), - ).$1; - - int length() => foldLeft(0, (b, _) => b + 1); - - bool any(bool Function(A a) predicate) => foldMap(boolOrMonoid(), predicate); - bool all(bool Function(A a) predicate) => foldMap(boolAndMonoid(), predicate); - - A concatenate(Monoid monoid) => foldMap(monoid, identity); - - HKT plus(HKT v); - - /// Insert a new element `A` at the beginning. - HKT prepend(A t); - - /// Insert a new element `A` at the end. - HKT append(A t); -} - -mixin Foldable2 on HKT2 { - C foldRight(C b, C Function(C acc, B b) f); - - C foldLeft(C b, C Function(C acc, B b) f) => - foldMap>(dualEndoMonoid(), (b) => (C c) => f(c, b))(b); - - C foldMap(Monoid monoid, C Function(B b) f) => - foldRight(monoid.empty, (c, b) => monoid.combine(f(b), c)); - - C foldRightWithIndex(C c, C Function(int i, C acc, B b) f) => - foldRight<(C, int)>( - (c, length() - 1), - (t, b) => (f(t.$2, t.$1, b), t.$2 - 1), - ).$1; - - C foldLeftWithIndex(C c, C Function(int i, C acc, B b) f) => - foldLeft<(C, int)>( - (c, 0), - (t, b) => (f(t.$2, t.$1, b), t.$2 + 1), - ).$1; - - int length() => foldLeft(0, (b, _) => b + 1); - - bool any(bool Function(B a) predicate) => foldMap(boolOrMonoid(), predicate); - bool all(bool Function(B a) predicate) => foldMap(boolAndMonoid(), predicate); - - B concatenate(Monoid monoid) => foldMap(monoid, identity); -} diff --git a/packages/fpdart/lib/src/typeclass/functor.dart b/packages/fpdart/lib/src/typeclass/functor.dart deleted file mode 100644 index 648b5561..00000000 --- a/packages/fpdart/lib/src/typeclass/functor.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'hkt.dart'; - -/// `Functor extends HKT` to express the fact that the classes implementing -/// the [Functor] interface will need to be higher kinded types. -mixin Functor on HKT { - /// Return type is `HKT`, which expresses the fact that what - /// we return is using exactly the same type constructor represented by the brand `G` - HKT map(B Function(A a) f); -} - -mixin Functor2 on HKT2 { - HKT2 map(C Function(B b) f); -} - -mixin Functor3 on HKT3 { - HKT3 map(D Function(C c) f); -} diff --git a/packages/fpdart/lib/src/typeclass/group.dart b/packages/fpdart/lib/src/typeclass/group.dart deleted file mode 100644 index fd5cb736..00000000 --- a/packages/fpdart/lib/src/typeclass/group.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'monoid.dart'; -import 'semigroup.dart'; - -/// A group is a monoid where each element has an [**inverse**](https://en.wikipedia.org/wiki/Inverse_element). -mixin Group on Monoid { - /// Find the inverse of `a`. - /// - /// `combine(a, inverse(a))` == `combine(inverse(a), a)` == `empty` - T inverse(T a); - - /// Remove the element `b` from `a`. - /// - /// Equivalent to `combine(a, inverse(b))`. - T remove(T a, T b) => combine(a, inverse(b)); - - /// Return `a` appended to itself `n` times. If `n` is negative, then - /// this returns `inverse(a)` appended to itself `n` times. - @override - T combineN(T a, int n) { - if (n > 0) { - return _repeatedCombineN(a, n); - } else if (n == 0) { - return empty; - } - - return _repeatedCombineN(inverse(a), -n); - } - - /// Return `a` combined with itself more than once. - T _repeatedCombineN(T a, int n) => - n == 1 ? a : _repeatedCombineNLoop(a, a, n - 1); - - T _repeatedCombineNLoop(T acc, T source, int k) => k == 1 - ? combine(acc, source) - : _repeatedCombineNLoop(combine(acc, source), source, k - 1); - - /// Create a `Group` instance from the given function, empty value, and inverse function. - static Group instance( - A emptyValue, A Function(A a1, A a2) f, A Function(A a) inv) => - _Group(emptyValue, f, inv); -} - -class _Group with Semigroup, Monoid, Group { - final T Function(T a) inv; - final T emp; - final T Function(T x, T y) comb; - - const _Group(this.emp, this.comb, this.inv); - - @override - T combine(T x, T y) => comb(x, y); - - @override - T get empty => emp; - - @override - T inverse(T a) => inv(a); -} diff --git a/packages/fpdart/lib/src/typeclass/hash.dart b/packages/fpdart/lib/src/typeclass/hash.dart deleted file mode 100644 index f7136c43..00000000 --- a/packages/fpdart/lib/src/typeclass/hash.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'eq.dart'; - -/// A type class used to represent a hashing scheme for objects of a given type. -/// -/// For any two instances `x` and `y` that are considered equivalent under the -/// equivalence relation defined by this object, `hash(x)` should equal `hash(y)`. -abstract class Hash extends Eq { - const Hash(); - - /// Returns the hash code of the given object under this hashing scheme. - int hash(T x); - - /// Constructs a `Hash` instance by using the universal `hashCode` function and the universal equality relation. - static Hash fromUniversalHashCode() => - _Hash((x, y) => x == y, (x) => x.hashCode); -} - -class _Hash extends Hash { - final bool Function(T x, T y) eq; - final int Function(T x) hs; - - const _Hash(this.eq, this.hs); - - @override - bool eqv(T x, T y) => eq(x, y); - - @override - int hash(T x) => hs(x); -} diff --git a/packages/fpdart/lib/src/typeclass/hkt.dart b/packages/fpdart/lib/src/typeclass/hkt.dart deleted file mode 100644 index 7f70d3bc..00000000 --- a/packages/fpdart/lib/src/typeclass/hkt.dart +++ /dev/null @@ -1,20 +0,0 @@ -/// https://marcosh.github.io/post/2020/04/15/higher-kinded-types-php-solution.html -/// https://medium.com/@gcanti/higher-kinded-types-in-flow-275b657992b7 - -/// - [A]: Type parameter -/// - [G]: Type constructor -/// -/// Instead of writing `G`, we will write `HKT`. -/// This is useful because in the expression `HKT`, both `G` and `A` have kind `*`, -/// so we can deal with them with the type system we currently have at our disposal. -abstract class HKT { - const HKT(); -} - -abstract class HKT2 { - const HKT2(); -} - -abstract class HKT3 { - const HKT3(); -} diff --git a/packages/fpdart/lib/src/typeclass/monad.dart b/packages/fpdart/lib/src/typeclass/monad.dart deleted file mode 100644 index a171bb8b..00000000 --- a/packages/fpdart/lib/src/typeclass/monad.dart +++ /dev/null @@ -1,96 +0,0 @@ -import 'applicative.dart'; -import 'hkt.dart'; - -mixin Monad on HKT, Applicative { - HKT flatMap(HKT Function(A a) f); - - @override - HKT ap(covariant Monad a) => - a.flatMap((f) => flatMap((v) => pure(f(v)))); - - HKT map2(Monad mc, D Function(A a, C c) f) => - flatMap((a) => mc.map((c) => f(a, c))); - - HKT map3( - Monad mc, Monad md, E Function(A a, C c, D d) f) => - flatMap((a) => mc.flatMap((c) => md.map((d) => f(a, c, d)))); - - HKT andThen(HKT Function() then) => flatMap((_) => then()); - - HKT chainFirst(covariant Monad Function(A a) chain) => - flatMap((a) => chain(a).map((b) => a)); - - HKT call(HKT chain) => flatMap((_) => chain); -} - -mixin Monad2 on HKT2, Applicative2 { - HKT2 flatMap(HKT2 Function(B a) f); - - /// Derive `ap` from `flatMap`. - /// - /// Use `flatMap` to extract the value from `a` and from the current [Monad]. - /// If both these values are present, apply the function from `a` to the value - /// of the current [Monad], using `pure` to return the correct type. - @override - HKT2 ap(covariant Monad2 a) => - a.flatMap((f) => flatMap((v) => pure(f(v)))); - - HKT2 map2(Monad2 m1, D Function(B b, C c) f) => - flatMap((b) => m1.map((c) => f(b, c))); - - HKT2 map3(Monad2 m1, Monad2 m2, - E Function(B b, C c, D d) f) => - flatMap((b) => m1.flatMap((c) => m2.map((d) => f(b, c, d)))); - - HKT2 andThen(HKT2 Function() then) => - flatMap((_) => then()); - - HKT2 chainFirst( - covariant Monad2 Function(B b) chain) => - flatMap((b) => chain(b).map((c) => b)); - - HKT2 call(HKT2 chain) => flatMap((_) => chain); -} - -mixin Monad3 - on HKT3, Applicative3 { - HKT3 flatMap(HKT3 Function(P3) f); - - /// Derive `ap` from `flatMap`. - /// - /// Use `flatMap` to extract the value from `a` and from the current [Monad]. - /// If both these values are present, apply the function from `a` to the value - /// of the current [Monad], using `pure` to return the correct type. - @override - HKT3 ap( - covariant Monad3 a) => - a.flatMap((f) => flatMap((v) => pure(f(v)))); - - HKT3 map2( - Monad3 m1, - N2 Function(P3, N1) f, - ) => - flatMap((b) => m1.map((c) => f(b, c))); - - HKT3 map3( - Monad3 m1, - Monad3 m2, - N3 Function(P3, N1, N2) f, - ) => - flatMap( - (b) => m1.flatMap((c) => m2.map((d) => f(b, c, d))), - ); - - HKT3 andThen( - HKT3 Function() then, - ) => - flatMap((_) => then()); - - HKT3 chainFirst( - covariant Monad3 Function(P3) chain, - ) => - flatMap((b) => chain(b).map((c) => b)); - - HKT3 call(HKT3 chain) => - flatMap((_) => chain); -} diff --git a/packages/fpdart/lib/src/typeclass/monoid.dart b/packages/fpdart/lib/src/typeclass/monoid.dart deleted file mode 100644 index 19080fe5..00000000 --- a/packages/fpdart/lib/src/typeclass/monoid.dart +++ /dev/null @@ -1,81 +0,0 @@ -import '../function.dart'; -import '../typedef.dart'; -import 'eq.dart'; -import 'semigroup.dart'; - -/// A monoid is a semigroup with an identity (`empty`). -/// -/// A monoid is a specialization of a -/// semigroup, so its operation must be **associative**. -/// -/// Additionally, `combine(x, empty) == combine(empty, x) == x`. -/// -/// For example, if we have `Monoid`, -/// with `combine` as string concatenation, then `empty = ""`: -/// -/// ```dart -/// final instance = Monoid.instance('', (a1, a2) => '$a1$a2'); -/// -/// expect(instance.combine('abc', instance.empty), instance.combine(instance.empty, 'abc')); -/// expect(instance.combine('abc', instance.empty), 'abc'); -/// ``` -mixin Monoid on Semigroup { - /// Return the identity element for this monoid. - T get empty; - - /// Tests if `a` is the identity (`empty`). - bool isEmpty(T a, Eq eq) => eq.eqv(a, empty); - - /// Return `a` appended to itself `n` times. - /// - /// Return `empty` if `n == 0`. - @override - T combineN(T a, int n) { - if (n < 0) { - throw const FormatException( - "Repeated combining for monoids must have n >= 0"); - } else if (n == 0) { - return empty; - } - - return _repeatedCombineN(a, n); - } - - /// Return `a` combined with itself more than once. - T _repeatedCombineN(T a, int n) => - n == 1 ? a : _repeatedCombineNLoop(a, a, n - 1); - - T _repeatedCombineNLoop(T acc, T source, int k) => k == 1 - ? combine(acc, source) - : _repeatedCombineNLoop(combine(acc, source), source, k - 1); - - /// Return a `Monoid` that reverses the order. - @override - Monoid reverse() => _Monoid(empty, (x, y) => combine(y, x)); - - /// Create a `Monoid` instance from the given function and empty value. - static Monoid instance(A emptyValue, A Function(A a1, A a2) f) => - _Monoid(emptyValue, f); -} - -class _Monoid with Semigroup, Monoid { - final T emp; - final T Function(T x, T y) comb; - - const _Monoid(this.emp, this.comb); - - @override - T combine(T x, T y) => comb(x, y); - - @override - T get empty => emp; -} - -Monoid> endoMonoid() => - Monoid.instance>(identity, (e1, e2) => (A a) => e1(e2(a))); - -Monoid> dualEndoMonoid() => - Monoid.instance>(identity, (e1, e2) => (A a) => e2(e1(a))); - -Monoid boolOrMonoid() => Monoid.instance(false, (a1, a2) => a1 || a2); -Monoid boolAndMonoid() => Monoid.instance(true, (a1, a2) => a1 && a2); diff --git a/packages/fpdart/lib/src/typeclass/order.dart b/packages/fpdart/lib/src/typeclass/order.dart deleted file mode 100644 index a3f07766..00000000 --- a/packages/fpdart/lib/src/typeclass/order.dart +++ /dev/null @@ -1,151 +0,0 @@ -import 'partial_order.dart'; - -/// The `Order` type class is used to define a [total ordering](https://en.wikipedia.org/wiki/Total_order) -/// on some type `A`. -/// -/// An order is defined by a relation <=, which obeys the following laws: -/// -/// - either `x <= y` or `y <= x` (totality) -/// - if `x <= y` and `y <= x`, then `x == y` (antisymmetry) -/// - if `x <= y` and `y <= z`, then `x <= z` (transitivity) -/// -/// The truth table for compare is defined as follows: -/// -/// | x <= y | x >= y | int | | -/// | :-- | :-- | --: | :-- | -/// | true | true | = 0 | (corresponds to x == y) | -/// | true | false | < 0 | (corresponds to x < y) | -/// | false | true | > 0 | (corresponds to x > y) | -/// -/// **By the totality law, `x <= y` and `y <= x` cannot be both false**. -abstract class Order extends PartialOrder { - const Order(); - - /// Result of comparing `x` with `y`. Returns an Int whose sign is: - /// - negative iff `x < y` - /// - zero iff `x == y` - /// - positive iff `x > y` - int compare(T x, T y); - - @override - double partialCompare(T x, T y) => compare(x, y).toDouble(); - - /// If `x < y`, return `x`, else return `y`. - T min(T x, T y) => lt(x, y) ? x : y; - - /// If `x > y`, return `x`, else return `y`. - T max(T x, T y) => gt(x, y) ? x : y; - - /// Test whether `value` is between `min` and `max` (**inclusive**). - bool between(T min, T max, T value) => gteqv(value, min) && lteqv(value, max); - - /// Clamp `value` between `min` and `max`. - T clamp(T min, T max, T value) => this.max(this.min(value, max), min); - - /// Return an [Order] instance based on a parameter of type `T` extracted from a class `A`. - /// ```dart - /// class Parent { - /// final int value1; - /// final double value2; - /// const Parent(this.value1, this.value2); - /// } - /// - /// /// Order values of type [Parent] based on their `value1` ([int]). - /// final orderParentInt = Order.orderInt.contramap( - /// (p) => p.value1, - /// ); - /// - /// /// Order values of type [Parent] based on their `value2` ([double]). - /// final orderParentDouble = Order.orderDouble.contramap( - /// (p) => p.value2, - /// ); - /// ``` - @override - Order contramap(T Function(A) map) => Order.from( - (a1, a2) => compare(map(a1), map(a2)), - ); - - /// Return an [Order] reversed. - Order get reverse => _Order((x, y) => compare(y, x)); - - @override - bool eqv(T x, T y) => compare(x, y) == 0; - - @override - bool lteqv(T x, T y) => compare(x, y) <= 0; - - @override - bool lt(T x, T y) => compare(x, y) < 0; - - @override - bool gteqv(T x, T y) => compare(x, y) >= 0; - - @override - bool gt(T x, T y) => compare(x, y) > 0; - - /// Convert an implicit `Order` to an `Order` using the given - /// function `f`. - static Order by(B Function(A a) f, Order ord) => - _Order((x, y) => ord.compare(f(x), f(y))); - - /// Returns a new `Order` instance that first compares by the first - /// `Order` instance and uses the second `Order` instance to "break ties". - /// - /// That is, `Order.whenEqual(x, y)` creates an `Order` that first orders by `x` and - /// then (if two elements are equal) falls back to `y` for the comparison. - static Order whenEqual(Order first, Order second) => - _Order((x, y) { - final ord = first.compare(x, y); - return ord == 0 ? second.compare(x, y) : ord; - }); - - /// Define an `Order` using the given function `f`. - static Order from(int Function(A a1, A a2) f) => _Order(f); - - /// Define an `Order` using the given 'less than' function `f`. - static Order fromLessThan(bool Function(A a1, A a2) f) => - _Order((x, y) => f(x, y) - ? -1 - : f(y, x) - ? 1 - : 0); - - /// An `Order` instance that considers all `A` instances to be equal - /// (`compare` always returns `0`). - static Order allEqual() => _Order((x, y) => 0); - - /// Instance of `Order` for `int`. - static Order orderInt = _Order((x, y) => x == y - ? 0 - : x > y - ? 1 - : -1); - - /// Instance of `Order` for `num`. - static Order orderNum = _Order((x, y) => x == y - ? 0 - : x > y - ? 1 - : -1); - - /// Instance of `Order` for `double`. - static Order orderDouble = _Order((x, y) => x == y - ? 0 - : x > y - ? 1 - : -1); - - /// Instance of `Order` for [DateTime]. - static Order orderDate = _Order( - (a1, a2) => a1.compareTo(a2), - ); -} - -class _Order extends Order { - final int Function(T x, T y) comp; - - const _Order(this.comp); - - @override - int compare(T x, T y) => comp(x, y); -} diff --git a/packages/fpdart/lib/src/typeclass/partial_order.dart b/packages/fpdart/lib/src/typeclass/partial_order.dart deleted file mode 100644 index 490afe14..00000000 --- a/packages/fpdart/lib/src/typeclass/partial_order.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'eq.dart'; - -/// The `PartialOrder` type class is used to define a -/// [partial ordering](https://en.wikipedia.org/wiki/Partially_ordered_set) on some type `A`. -/// -/// A partial order is defined by a relation <=, which obeys the following laws: -/// - x <= x (reflexivity) -/// - if x <= y and y <= x, then x == y (anti-symmetry) -/// - if x <= y and y <= z, then x <= z (transitivity) -/// -/// To compute both <= and >= at the same time, we use a `double` number -/// to encode the result of the comparisons x <= y and x >= y. -/// -/// The truth table is defined as follows: -/// -/// | x <= y | x >= y | result | note | -/// | :-- | :-- | --: | :-- | -/// | true |true | 0.0 | (corresponds to x == y) | -/// | false |false | null | (x and y cannot be compared) | -/// | true |false | -1.0 | (corresponds to x < y) | -/// | false |true | 1.0 | (corresponds to x > y) | -/// -/// **Note**: A partial order under which every pair of elements is comparable -/// is called a [total order](https://en.wikipedia.org/wiki/Total_order) ([Order]). -abstract class PartialOrder extends Eq { - const PartialOrder(); - - /// Result of comparing `x` with `y`. - /// - /// Returns `null` if operands are not comparable. - /// If operands are comparable, returns a `double` whose - /// sign is: - /// - negative iff `x < y` - /// - zero iff `x == y` - /// - positive iff `x > y` - double? partialCompare(T x, T y); - - @override - PartialOrder contramap(T Function(A) map) => PartialOrder.from( - (a1, a2) => partialCompare(map(a1), map(a2)), - ); - - /// Returns `true` if `x` == `y`, `false` otherwise. - @override - bool eqv(T x, T y) { - final c = partialCompare(x, y); - return c != null && c == 0; - } - - /// Returns `true` if `x` <= `y`, `false` otherwise. - bool lteqv(T x, T y) { - final c = partialCompare(x, y); - return c != null && c <= 0; - } - - /// Returns `true` if `x` < `y`, `false` otherwise. - bool lt(T x, T y) { - final c = partialCompare(x, y); - return c != null && c < 0; - } - - /// Returns `true` if `x` >= `y`, `false` otherwise. - bool gteqv(T x, T y) { - final c = partialCompare(x, y); - return c != null && c >= 0; - } - - /// Returns `true` if `x` > `y`, `false` otherwise. - bool gt(T x, T y) { - final c = partialCompare(x, y); - return c != null && c > 0; - } - - /// Convert an implicit `PartialOrder[B]` to an `PartialOrder[A]` using the given - /// function `f`. - static PartialOrder by(B Function(A a) f, PartialOrder po) => - _PartialOrder((x, y) => po.partialCompare(f(x), f(y))); - - /// Defines a partial order on `A` from `p` where all arrows switch direction. - static PartialOrder reverse(PartialOrder p) => - _PartialOrder((x, y) => p.partialCompare(y, x)); - - /// Define a `PartialOrder[A]` using the given function `f`. - static PartialOrder from(double? Function(A a1, A a2) f) => - _PartialOrder(f); -} - -class _PartialOrder extends PartialOrder { - final double? Function(T x, T y) partialO; - - const _PartialOrder(this.partialO); - - @override - double? partialCompare(T x, T y) => partialO(x, y); -} diff --git a/packages/fpdart/lib/src/typeclass/semigroup.dart b/packages/fpdart/lib/src/typeclass/semigroup.dart deleted file mode 100644 index c8e814aa..00000000 --- a/packages/fpdart/lib/src/typeclass/semigroup.dart +++ /dev/null @@ -1,72 +0,0 @@ -/// A semigroup is any set `A` with an [**associative operation**](https://en.wikipedia.org/wiki/Associative_property) (`combine`). -/// -/// `(xy)z = x(yz) = xyz` for all `x`, `y`, `z` in `A` -mixin Semigroup { - /// Associative operation which combines two values. - /// - /// ```dart - /// final instance = Semigroup.instance((a1, a2) => '$a1$a2'); - /// - /// expect(instance.combine('a', 'b'), 'ab'); - /// ``` - T combine(T x, T y); - - /// Return `a` combined with itself `n` times. - T combineN(T a, int n) { - if (n <= 0) { - throw const FormatException( - "Repeated combining for semigroups must have n > 0"); - } - - return _repeatedCombineN(a, n); - } - - /// Return `a` combined with itself more than once. - T _repeatedCombineN(T a, int n) => - n == 1 ? a : _repeatedCombineNLoop(a, a, n - 1); - - T _repeatedCombineNLoop(T acc, T source, int k) => k == 1 - ? combine(acc, source) - : _repeatedCombineNLoop(combine(acc, source), source, k - 1); - - /// Return a `Semigroup` that reverses the order. - /// - /// ```dart - /// final instance = Semigroup.instance((a1, a2) => '$a1$a2'); - /// final reverse = instance.reverse(); - /// - /// expect(reverse.combine('a', 'b'), 'ba'); - /// expect(reverse.combine('a', 'b'), instance.combine('b', 'a')); - /// ``` - Semigroup reverse() => _Semigroup((x, y) => combine(y, x)); - - /// Return a `Semigroup` which inserts `middle` between each pair of elements. - /// - /// ```dart - /// final instance = Semigroup.instance((a1, a2) => '$a1$a2'); - /// final intercalate = instance.intercalate('-'); - /// - /// expect(intercalate.combine('a', 'b'), 'a-b'); - /// expect(intercalate.combineN('a', 3), 'a-a-a'); - /// ``` - Semigroup intercalate(T middle) => - _Semigroup((x, y) => combine(x, combine(middle, y))); - - /// Create a `Semigroup` instance from the given function. - static Semigroup instance(A Function(A a1, A a2) f) => _Semigroup(f); - - /// Create a `Semigroup` instance that always returns the lefthand side. - static Semigroup first() => _Semigroup((x, y) => x); - - /// Create a `Semigroup` instance that always returns the righthand side. - static Semigroup last() => _Semigroup((x, y) => y); -} - -class _Semigroup with Semigroup { - final T Function(T x, T y) comb; - - const _Semigroup(this.comb); - - @override - T combine(T x, T y) => comb(x, y); -} diff --git a/packages/fpdart/lib/src/typeclass/semilattice.dart b/packages/fpdart/lib/src/typeclass/semilattice.dart deleted file mode 100644 index e916876d..00000000 --- a/packages/fpdart/lib/src/typeclass/semilattice.dart +++ /dev/null @@ -1,82 +0,0 @@ -import 'band.dart'; -import 'commutative_semigroup.dart'; -import 'eq.dart'; -import 'partial_order.dart'; -import 'semigroup.dart'; - -/// [**Semilattices**](https://en.wikipedia.org/wiki/Semilattice) -/// are commutative semigroups whose operation -/// (i.e. `combine`) is also [**idempotent**](https://en.wikipedia.org/wiki/Idempotence). -/// -/// **Meet-semilattice** -/// > For all elements `x` and `y` of `A`, the [**greatest lower bound**](https://en.wikipedia.org/wiki/Infimum_and_supremum) -/// > of the set `{x, y}` exists. -/// -/// **Join-semilattice** -/// > For all elements `x` and `y` of `A`, the [**least upper bound**](https://en.wikipedia.org/wiki/Infimum_and_supremum) -/// > of the set `{x, y}` exists. -/// -/// See also [CommutativeSemigroup], [Bind]. -mixin Semilattice on Band, CommutativeSemigroup { - /// Given `Eq`, return a `PartialOrder` using the `combine` - /// operator of `Semilattice` to determine the partial ordering. This method assumes - /// `combine` functions as `meet` (that is, as a **lower bound**). - /// - /// This method returns: - /// - 0.0 if `x == y` - /// - -1.0 if `x == combine(x, y)` - /// - 1.0 if `y == combine(x, y)` - /// - `null` otherwise - PartialOrder asMeetPartialOrder(Eq eq) => PartialOrder.from( - (x, y) { - if (eq.eqv(x, y)) { - return 0; - } - - final z = combine(x, y); - return eq.eqv(x, z) - ? -1 - : eq.eqv(y, z) - ? 1 - : null; - }, - ); - - /// Given `Eq`, return a `PartialOrder` using the `combine` - /// operator of `Semilattice` to determine the partial ordering. This method assumes - /// `combine` functions as `join` (that is, as an **upper bound**). - /// - /// This method returns: - /// - 0.0 if `x == y` - /// - -1.0 if `y == combine(x, y)` - /// - 1.0 if `x == combine(x, y)` - /// - `null` otherwise - PartialOrder asJoinPartialOrder(Eq eq) => PartialOrder.from( - (x, y) { - if (eq.eqv(x, y)) { - return 0; - } - - final z = combine(x, y); - return eq.eqv(y, z) - ? -1 - : eq.eqv(x, z) - ? 1 - : null; - }, - ); - - /// Create a `Semilattice` instance from the given function. - static Semilattice instance(A Function(A a1, A a2) f) => - _Semilattice(f); -} - -class _Semilattice - with Semigroup, CommutativeSemigroup, Band, Semilattice { - final T Function(T x, T y) comb; - - const _Semilattice(this.comb); - - @override - T combine(T x, T y) => comb(x, y); -} diff --git a/packages/fpdart/lib/src/typeclass/typeclass.export.dart b/packages/fpdart/lib/src/typeclass/typeclass.export.dart deleted file mode 100644 index 77145ab0..00000000 --- a/packages/fpdart/lib/src/typeclass/typeclass.export.dart +++ /dev/null @@ -1,21 +0,0 @@ -export 'alt.dart'; -export 'applicative.dart'; -export 'band.dart'; -export 'bounded_semilattice.dart'; -export 'commutative_group.dart'; -export 'commutative_monoid.dart'; -export 'commutative_semigroup.dart'; -export 'eq.dart'; -export 'extend.dart'; -export 'filterable.dart'; -export 'foldable.dart'; -export 'functor.dart'; -export 'group.dart'; -export 'hash.dart'; -export 'hkt.dart'; -export 'monad.dart'; -export 'monoid.dart'; -export 'order.dart'; -export 'partial_order.dart'; -export 'semigroup.dart'; -export 'semilattice.dart'; diff --git a/packages/fpdart/lib/src/typedef.dart b/packages/fpdart/lib/src/typedef.dart deleted file mode 100644 index 0d8225fa..00000000 --- a/packages/fpdart/lib/src/typedef.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'typeclass/hkt.dart'; - -typedef Endo = A Function(A a); -typedef Separated = (HKT, HKT); diff --git a/packages/fpdart/pubspec.yaml b/packages/fpdart/pubspec.yaml index 9f4b5509..6b7e072f 100644 --- a/packages/fpdart/pubspec.yaml +++ b/packages/fpdart/pubspec.yaml @@ -1,8 +1,8 @@ name: fpdart description: > - Functional programming in Dart and Flutter. - All the main functional programming types and patterns fully documented, tested, and with examples. -version: 1.1.0 + Functional Effect System in Dart and Flutter. + Build composable, type safe, maintainable and testable apps with an extensive API fully tested and documented. +version: 2.0.0-dev.3 homepage: https://www.sandromaglione.com/ repository: https://github.com/SandroMaglione/fpdart author: Maglione Sandro @@ -10,14 +10,16 @@ documentation: https://www.sandromaglione.com/course/fpdart-functional-programmi issue_tracker: https://github.com/SandroMaglione/fpdart/issues environment: - sdk: ">=3.0.0 <4.0.0" + sdk: ">=3.3.0 <4.0.0" + +dependencies: + meta: ^1.11.0 dev_dependencies: - lints: ^2.0.1 - test: ^1.23.1 - glados: ^1.1.6 - collection: ^1.17.2 + lints: ^3.0.0 + test: ^1.25.2 + collection: ^1.18.0 screenshots: - - description: "Basic usage of fpdart Option, Either, TaskEither types." + - description: "Basic usage of fpdart Effect type." path: example/screenshot_fpdart.png diff --git a/packages/fpdart/test/src/band_test.dart b/packages/fpdart/test/src/band_test.dart deleted file mode 100644 index 98e93b57..00000000 --- a/packages/fpdart/test/src/band_test.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('Band', () { - group('is a', () { - final instance = Band.instance((a1, a2) => a1 + a2); - - test('Semigroup', () { - expect(instance, isA()); - }); - }); - - test('combineN', () { - final instance = Band.instance((a1, a2) => a1 + a2); - expect(instance.combineN(1, 1), 1); - expect(instance.combineN(1, 10), 2); - }); - }); -} diff --git a/packages/fpdart/test/src/bounded_semilattice_test.dart b/packages/fpdart/test/src/bounded_semilattice_test.dart deleted file mode 100644 index c5b30c09..00000000 --- a/packages/fpdart/test/src/bounded_semilattice_test.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('BoundedSemilattice', () { - group('is a', () { - final instance = BoundedSemilattice.instance(0, (a1, a2) => a1 + a2); - - test('Semigroup', () { - expect(instance, isA()); - }); - - test('Band', () { - expect(instance, isA()); - }); - - test('Semilattice', () { - expect(instance, isA()); - }); - - test('CommutativeSemigroup', () { - expect(instance, isA()); - }); - - test('Monoid', () { - expect(instance, isA()); - }); - - test('CommutativeMonoid', () { - expect(instance, isA()); - }); - }); - - test('combineN', () { - final instance = BoundedSemilattice.instance(0, (a1, a2) => a1 + a2); - expect(instance.combineN(1, 1), 1); - expect(instance.combineN(1, 10), 1); - }); - }); -} diff --git a/packages/fpdart/test/src/commutative_group_test.dart b/packages/fpdart/test/src/commutative_group_test.dart deleted file mode 100644 index a7163b6f..00000000 --- a/packages/fpdart/test/src/commutative_group_test.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('CommutativeGroup', () { - group('is a', () { - final instance = - CommutativeGroup.instance(0, (a1, a2) => a1 + a2, (a) => -a); - - test('Semigroup', () { - expect(instance, isA()); - }); - - test('CommutativeSemigroup', () { - expect(instance, isA()); - }); - - test('CommutativeMonoid', () { - expect(instance, isA()); - }); - - test('Monoid', () { - expect(instance, isA()); - }); - - test('Group', () { - expect(instance, isA()); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/commutative_monoid_test.dart b/packages/fpdart/test/src/commutative_monoid_test.dart deleted file mode 100644 index c077a62d..00000000 --- a/packages/fpdart/test/src/commutative_monoid_test.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('CommutativeMonoid', () { - group('is a', () { - final instance = CommutativeMonoid.instance(0, (a1, a2) => a1 + a2); - - test('Semigroup', () { - expect(instance, isA()); - }); - - test('CommutativeSemigroup', () { - expect(instance, isA()); - }); - - test('Monoid', () { - expect(instance, isA()); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/commutative_semigroup_test.dart b/packages/fpdart/test/src/commutative_semigroup_test.dart deleted file mode 100644 index eb61501d..00000000 --- a/packages/fpdart/test/src/commutative_semigroup_test.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('CommutativeSemigroup', () { - group('is a', () { - final instance = CommutativeSemigroup.instance((a1, a2) => a1 + a2); - - test('Semigroup', () { - expect(instance, isA()); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/date_test.dart b/packages/fpdart/test/src/date_test.dart deleted file mode 100644 index 5ec96846..00000000 --- a/packages/fpdart/test/src/date_test.dart +++ /dev/null @@ -1,96 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:glados/glados.dart'; - -void main() { - group('date', () { - group('[Property-based testing]', () { - Glados2().test('dateOrder', (d1, d2) { - final compare = Order.orderDate.compare(d1, d2); - expect( - compare, - d1.isAfter(d2) - ? 1 - : d1.isBefore(d2) - ? -1 - : 0); - }); - - Glados2().test('dateEqYear', (d1, d2) { - final compare = Eq.dateEqYear.eqv(d1, d2); - expect(compare, d1.year == d2.year); - }); - - Glados2().test('dateEqMonth', (d1, d2) { - final compare = Eq.dateEqMonth.eqv(d1, d2); - expect(compare, d1.month == d2.month); - }); - - Glados2().test('dateEqYearMonthDay', (d1, d2) { - final compare = Eq.dateEqYearMonthDay.eqv(d1, d2); - expect(compare, - d1.year == d2.year && d1.month == d2.month && d1.day == d2.day); - }); - - Glados2().test('eqvYear', (d1, d2) { - final compare = d1.eqvYear(d2); - expect(compare, d1.year == d2.year); - }); - - Glados2().test('eqvMonth', (d1, d2) { - final compare = d1.eqvMonth(d2); - expect(compare, d1.month == d2.month); - }); - - Glados2().test('eqvDay', (d1, d2) { - final compare = d1.eqvDay(d2); - expect(compare, d1.day == d2.day); - }); - - Glados2().test('eqvYearMonthDay', (d1, d2) { - final compare = d1.eqvYearMonthDay(d2); - expect(compare, - d1.year == d2.year && d1.month == d2.month && d1.day == d2.day); - }); - }); - - test('dateEqYear', () { - final date1 = DateTime(2021, 2, 2); - final date2 = DateTime(2021, 3, 3); - final date3 = DateTime(2020, 2, 2); - - expect(Eq.dateEqYear.eqv(date1, date1), true); - expect(Eq.dateEqYear.eqv(date1, date2), true); - expect(Eq.dateEqYear.eqv(date1, date3), false); - }); - - test('dateEqMonth', () { - final date1 = DateTime(2021, 2, 2); - final date2 = DateTime(2021, 3, 3); - final date3 = DateTime(2020, 2, 2); - - expect(Eq.dateEqMonth.eqv(date1, date1), true); - expect(Eq.dateEqMonth.eqv(date1, date2), false); - expect(Eq.dateEqMonth.eqv(date1, date3), true); - }); - - test('dateEqDay', () { - final date1 = DateTime(2021, 2, 2); - final date2 = DateTime(2021, 3, 3); - final date3 = DateTime(2020, 3, 2); - - expect(Eq.dateEqDay.eqv(date1, date1), true); - expect(Eq.dateEqDay.eqv(date1, date2), false); - expect(Eq.dateEqDay.eqv(date1, date3), true); - }); - - test('dateEqYearMonthDay', () { - final date1 = DateTime(2021, 2, 2, 10, 10); - final date2 = DateTime(2021, 2, 2, 11, 11); - final date3 = DateTime(2020, 2, 2, 12, 12); - - expect(Eq.dateEqYearMonthDay.eqv(date1, date1), true); - expect(Eq.dateEqYearMonthDay.eqv(date1, date2), true); - expect(Eq.dateEqYearMonthDay.eqv(date1, date3), false); - }); - }); -} diff --git a/packages/fpdart/test/src/deferred_test.dart b/packages/fpdart/test/src/deferred_test.dart new file mode 100644 index 00000000..be943bc2 --- /dev/null +++ b/packages/fpdart/test/src/deferred_test.dart @@ -0,0 +1,26 @@ +import 'package:fpdart/fpdart.dart'; +import 'package:test/test.dart'; + +void main() { + group('Deferred', () { + group('future', () { + test('suspends and awaits future', () async { + final main = Effect.gen(($) async { + final deferred = $.sync(Deferred.make()); + await $.async(Effect.raceAll([ + Effect.sleep(Duration(milliseconds: 100)) + .zipRight(deferred.completeExit(Right(1))), + Effect.sleep(Duration(milliseconds: 150)) + .zipRight(deferred.completeExit(Right(2))), + ])); + + final value = await $.async(deferred.wait()); + return value; + }); + + final result = await main.runFutureOrThrow(); + expect(result, 1); + }); + }); + }); +} diff --git a/packages/fpdart/test/src/effect/effect_alternatives_test.dart b/packages/fpdart/test/src/effect/effect_alternatives_test.dart new file mode 100644 index 00000000..2b7ccb95 --- /dev/null +++ b/packages/fpdart/test/src/effect/effect_alternatives_test.dart @@ -0,0 +1,39 @@ +import "package:fpdart/fpdart.dart"; +import "package:test/test.dart"; + +class CustomError implements Exception {} + +void main() { + group( + "Effect alternatives", + () { + group('orDie', () { + test('succeed', () { + final main = Effect.succeed(10).orDie; + final result = main.runSyncOrThrow(); + expect(result, 10); + }); + + test('fail', () { + final main = Effect.fail("error").orDie; + expect(() => main.runSyncOrThrow(), throwsA(isA())); + }); + }); + + group('orDieWith', () { + test('succeed', () { + final main = Effect.succeed(10) + .orDieWith((_) => CustomError()); + final result = main.runSyncOrThrow(); + expect(result, 10); + }); + + test('fail', () { + final main = Effect.fail("error") + .orDieWith((_) => CustomError()); + expect(() => main.runSyncOrThrow(), throwsA(isA())); + }); + }); + }, + ); +} diff --git a/packages/fpdart/test/src/effect/effect_collecting_test.dart b/packages/fpdart/test/src/effect/effect_collecting_test.dart new file mode 100644 index 00000000..5c3b74f4 --- /dev/null +++ b/packages/fpdart/test/src/effect/effect_collecting_test.dart @@ -0,0 +1,33 @@ +import "package:fpdart/fpdart.dart"; +import "package:test/test.dart"; + +void main() { + group( + "Effect collecting", + () { + group('all', () { + test('succeeded all', () { + final main = Effect.all([ + Effect.succeed(10), + Effect.succeed(20), + ]); + final result = main.runSyncOrThrow(); + expect(result, [10, 20]); + }); + + test('fail and stop execution', () { + var mutable = 0; + final main = Effect.all([ + Effect.succeed(10), + Effect.fail("10"), + Effect.succeedLazy(() => mutable += 1), + Effect.fail("0"), + ]); + final result = main.flip().runSyncOrThrow(); + expect(mutable, 0); + expect(result, "10"); + }); + }); + }, + ); +} diff --git a/packages/fpdart/test/src/effect/effect_constructors_test.dart b/packages/fpdart/test/src/effect/effect_constructors_test.dart new file mode 100644 index 00000000..b15d9692 --- /dev/null +++ b/packages/fpdart/test/src/effect/effect_constructors_test.dart @@ -0,0 +1,134 @@ +import "package:fpdart/fpdart.dart"; +import "package:test/test.dart"; + +void main() { + group( + "Effect constructors", + () { + test('succeed', () { + final main = Effect.succeed(10); + final result = main.runSyncOrThrow(); + expect(result, 10); + }); + + test('fail', () { + final main = Effect.fail("error"); + final result = main.flip().runSyncOrThrow(); + expect(result, "error"); + }); + + group('async', () { + test('succeed callback', () async { + final main = Effect.async( + (resume) => resume.succeed(10), + ); + final result = await main.runFutureOrThrow(); + expect(result, 10); + }); + + test('fail callback', () async { + final main = Effect.async( + (resume) => resume.fail("error"), + ); + final result = await main.flip().runFutureOrThrow(); + expect(result, "error"); + }); + + test('succeed async callback', () async { + final main = Effect.async( + (resume) => Future.delayed(Duration(milliseconds: 100)).then( + (_) => resume.succeed(10), + ), + ); + final result = await main.runFutureOrThrow(); + expect(result, 10); + }); + + test('fail async callback', () async { + final main = Effect.async( + (resume) => Future.delayed(Duration(milliseconds: 100)).then( + (_) => resume.fail("error"), + ), + ); + final result = await main.flip().runFutureOrThrow(); + expect(result, "error"); + }); + }); + + group('tryCatch', () { + test('executes once', () { + var mutable = 0; + final main = Effect.tryCatch( + execute: () { + mutable += 1; + return 10; + }, + onError: (error, stackTrace) {}, + ); + + main.runSyncOrThrow(); + expect(mutable, 1); + }); + + test('async', () async { + final main = Effect.tryCatch( + execute: () async => 10, + onError: (error, stackTrace) {}, + ); + final result = await main.runFutureOrThrow(); + expect(result, 10); + }); + + test('sync', () { + final main = Effect.tryCatch( + execute: () => 10, + onError: (error, stackTrace) {}, + ); + final result = main.runSyncOrThrow(); + expect(result, 10); + }); + }); + + group('gen', () { + test('sync succeed', () { + final main = Effect.gen(($) { + final value = $.sync(Effect.succeed(10)); + return value; + }); + final result = main.runSyncOrThrow(); + expect(result, 10); + }); + + test('sync fail', () { + final main = Effect.gen(($) { + final value = $.sync(Effect.fail("abc")); + return value; + }); + final result = main.flip().runSyncOrThrow(); + expect(result, "abc"); + }); + + test('async succeed', () async { + final main = Effect.gen(($) async { + final value = + await $.async(Effect.succeedLazy(() => Future.value(10))); + return value; + }); + final result = await main.runFutureOrThrow(); + expect(result, 10); + }); + + test('fail when running async as sync', () async { + final main = Effect.gen(($) { + final value = $.sync(Effect.succeedLazy( + () async => Future.value(10), + )); + return value; + }); + + expect(() => main.runSyncOrThrow(), throwsA(isA())); + }); + }); + }, + ); +} diff --git a/packages/fpdart/test/src/effect/effect_context_test.dart b/packages/fpdart/test/src/effect/effect_context_test.dart new file mode 100644 index 00000000..4d37516f --- /dev/null +++ b/packages/fpdart/test/src/effect/effect_context_test.dart @@ -0,0 +1,83 @@ +import "package:fpdart/fpdart.dart"; +import "package:test/test.dart"; + +import "../test_extension.dart"; + +class CustomError implements Exception { + const CustomError(); +} + +void main() { + group( + "Effect context", + () { + group('provideEnv', () { + test('handle throw in closing scope', () async { + final main = Effect.succeed(10) + .addFinalizer(Effect.succeedLazy( + () => throw const CustomError(), + )) + .provideEnv(Scope.withEnv(null)); + + final result = await main.runFutureExit(); + + result.expectLeft((value) { + expect(value, isA()); + if (value is Die) { + expect(value.error, isA()); + } + }); + }); + + test('handle failure in closing scope', () async { + final main = Effect.succeed(10) + .addFinalizer(Effect.die(const CustomError())) + .provideEnv(Scope.withEnv(null)); + + final result = await main.runFutureExit(); + + result.expectLeft((value) { + expect(value, isA()); + if (value is Die) { + expect(value.error, isA()); + } + }); + }); + }); + + group('provideScope', () { + test('handle throw in closing scope', () async { + final main = Effect.succeed(10) + .addFinalizer(Effect.succeedLazy( + () => throw const CustomError(), + )) + .provideScope; + + final result = await main.runFutureExit(); + + result.expectLeft((value) { + expect(value, isA()); + if (value is Die) { + expect(value.error, isA()); + } + }); + }); + + test('handle failure in closing scope', () async { + final main = Effect.succeed(10) + .addFinalizer(Effect.die(const CustomError())) + .provideScope; + + final result = await main.runFutureExit(); + + result.expectLeft((value) { + expect(value, isA()); + if (value is Die) { + expect(value.error, isA()); + } + }); + }); + }); + }, + ); +} diff --git a/packages/fpdart/test/src/effect/effect_do_notation_test.dart b/packages/fpdart/test/src/effect/effect_do_notation_test.dart new file mode 100644 index 00000000..ff3be2ed --- /dev/null +++ b/packages/fpdart/test/src/effect/effect_do_notation_test.dart @@ -0,0 +1,63 @@ +import "package:fpdart/fpdart.dart"; +import "package:test/test.dart"; + +void main() { + group( + "Effect do notation", + () { + group('provide', () { + test('remove dependency', () { + final main = Effect.gen(($) { + final env = $.sync(Effect.env()); + return env.length; + }); + + final program = main.provideEnv("abc"); + final result = program.runSyncOrThrow(); + expect(result, 3); + }); + }); + + group('provideEffect', () { + test('valid dependency', () { + final main = Effect.gen(($) { + final env = $.sync(Effect.env()); + return env + 1; + }); + + final program = + main.provideEffect(Effect.succeed(10)); + final result = program.runSyncOrThrow(); + expect(result, 11); + }); + + test('invalid dependency', () { + final main = Effect.gen(($) { + final env = $.sync(Effect.env()); + return env + 1; + }); + + final program = + main.provideEffect(Effect.fail("error")); + final result = program.flip().runSyncOrThrow(); + expect(result, "error"); + }); + }); + + group('mapEnv', () { + test('adapt dependency from another program', () { + final subMain = Effect.from( + (context) => Right(context.env + 1)); + final main = Effect.gen(($) { + final value = $.sync(subMain + .mapContext((context) => Context.env(context.env.length))); + return value; + }); + + final result = main.provideEnv("abc").runSyncOrThrow(); + expect(result, 4); + }); + }); + }, + ); +} diff --git a/packages/fpdart/test/src/effect/effect_error_handling_test.dart b/packages/fpdart/test/src/effect/effect_error_handling_test.dart new file mode 100644 index 00000000..c2931d63 --- /dev/null +++ b/packages/fpdart/test/src/effect/effect_error_handling_test.dart @@ -0,0 +1,23 @@ +import "package:fpdart/fpdart.dart"; +import "package:test/test.dart"; + +void main() { + group( + "Effect error handling", + () { + group('catchCause', () { + test('recover from throw', () { + final result = Effect.succeedLazy(() { + throw "fail"; + }) + .catchCause( + (cause) => Effect.succeed("abc"), + ) + .runSyncOrThrow(); + + expect(result, "abc"); + }); + }); + }, + ); +} diff --git a/packages/fpdart/test/src/effect/effect_interruption_test.dart b/packages/fpdart/test/src/effect/effect_interruption_test.dart new file mode 100644 index 00000000..820721db --- /dev/null +++ b/packages/fpdart/test/src/effect/effect_interruption_test.dart @@ -0,0 +1,25 @@ +import "package:fpdart/fpdart.dart"; +import "package:test/test.dart"; + +import "../test_extension.dart"; + +void main() { + group( + "Effect interruption", + () { + group('interrupt', () { + test('fail with Cause.Interrupted', () { + final main = Effect.succeed(10).interrupt().map( + (r) => r + 10, + ); + + final result = main.runSyncExit(); + + result.expectLeft((value) { + expect(value, isA()); + }); + }); + }); + }, + ); +} diff --git a/packages/fpdart/test/src/effect/effect_scoping_test.dart b/packages/fpdart/test/src/effect/effect_scoping_test.dart new file mode 100644 index 00000000..b01ad88b --- /dev/null +++ b/packages/fpdart/test/src/effect/effect_scoping_test.dart @@ -0,0 +1,72 @@ +import "package:fpdart/fpdart.dart"; +import "package:test/test.dart"; + +class CustomError implements Exception {} + +void main() { + group( + "Effect scoping", + () { + test('add and release Scope finalizer', () async { + var mutable = 0; + final main = Effect.succeed(10).addFinalizer( + Effect.succeedLazy(() { + mutable += 1; + return unit; + }), + ).provideScope; + + await main.runFutureOrThrow(); + expect(mutable, 1); + }); + + test('closable Scope', () async { + final scope = Scope.withEnv(true, closable: true); + var mutable = 0; + final main = Effect.succeed(10).addFinalizer( + Effect.succeedLazy(() { + mutable += 1; + return unit; + }), + ); + + await main.provide(Context.env(scope)).runFutureOrThrow(); + expect(mutable, 0); + scope.closeScope().runSyncOrThrow(); + expect(mutable, 1); + }); + + group('acquireRelease', () { + test('release when successful', () async { + var mutable = 0; + final main = Effect.succeed(10) + .acquireRelease( + (r) => Effect.succeedLazy(() { + mutable = r; + return unit; + }), + ) + .provideScope; + + await main.runFutureOrThrow(); + expect(mutable, 10); + }); + + test('no release when failed', () async { + var mutable = 0; + final main = Effect.fail("error") + .acquireRelease( + (r) => Effect.succeedLazy(() { + mutable = r; + return unit; + }), + ) + .provideScope; + + await main.flip().runFutureOrThrow(); + expect(mutable, 0); + }); + }); + }, + ); +} diff --git a/packages/fpdart/test/src/effect/effect_sequencing_test.dart b/packages/fpdart/test/src/effect/effect_sequencing_test.dart new file mode 100644 index 00000000..750d02e7 --- /dev/null +++ b/packages/fpdart/test/src/effect/effect_sequencing_test.dart @@ -0,0 +1,59 @@ +import "package:fpdart/fpdart.dart"; +import "package:test/test.dart"; + +void main() { + group( + "Effect constructors", + () { + test('zipLeft', () { + final main = + Effect.succeed(10).zipLeft(Effect.succeed("10")); + final result = main.runSyncOrThrow(); + expect(result, 10); + }); + + test('zipRight', () { + final main = Effect.succeed(10) + .zipRight(Effect.succeed("10")); + final result = main.runSyncOrThrow(); + expect(result, "10"); + }); + + test('tap', () { + var mutable = 0; + final main = Effect.succeed(10).tap( + (_) => Effect.succeedLazy(() { + mutable += 1; + }), + ); + + expect(mutable, 0); + final result = main.runSyncOrThrow(); + expect(result, 10); + expect(mutable, 1); + }); + + group('race', () { + test('first wins', () async { + final first = Effect.sleep(Duration(milliseconds: 50)) + .map((_) => 1); + final second = Effect.sleep(Duration(milliseconds: 100)) + .map((_) => 2); + + final result = await first.race(second).runFutureOrThrow(); + expect(result, 1); + }); + + test('second wins', () async { + final first = Effect.sleep(Duration(milliseconds: 100)) + .map((_) => 1); + final second = Effect.sleep(Duration(milliseconds: 50)) + .map((_) => 2); + + final result = await first.race(second).runFutureOrThrow(); + expect(result, 2); + }); + }); + }, + ); +} diff --git a/packages/fpdart/test/src/either_test.dart b/packages/fpdart/test/src/either_test.dart deleted file mode 100644 index 2c23c5c8..00000000 --- a/packages/fpdart/test/src/either_test.dart +++ /dev/null @@ -1,1221 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import './utils/utils.dart'; - -void main() { - group('Either', () { - group('[Property-based testing]', () { - group("safeCast", () { - Glados2(any.int, any.letterOrDigits) - .test('always returns Right without typed parameters', - (intValue, stringValue) { - final castInt = Either.safeCast(intValue, (value) => 'Error'); - final castString = Either.safeCast(stringValue, (value) => 'Error'); - expect(castInt, isA>()); - expect(castString, isA>()); - }); - }); - }); - - group('is a', () { - final either = Either.of(10); - - test('Monad', () { - expect(either, isA()); - }); - - test('Applicative', () { - expect(either, isA()); - }); - - test('Functor', () { - expect(either, isA()); - }); - - test('Foldable', () { - expect(either, isA()); - }); - - test('Alt', () { - expect(either, isA()); - }); - - test('Extend', () { - expect(either, isA()); - }); - }); - - group('map', () { - test('Right', () { - final value = Either.of(10); - final map = value.map((a) => a + 1); - map.matchTestRight((r) { - expect(r, 11); - }); - }); - - test('Left', () { - final value = Either.left('abc'); - final map = value.map((a) => a + 1); - map.matchTestLeft((l) => expect(l, 'abc')); - }); - }); - - group('bimap', () { - test('Right', () { - final value = Either.of(10); - final map = value.bimap((l) => "none", (a) => a + 1); - map.matchTestRight((r) { - expect(r, 11); - }); - }); - - test('Left', () { - final value = Either.left('abc'); - final map = value.bimap((l) => "none", (a) => a + 1); - map.matchTestLeft((l) => expect(l, 'none')); - }); - }); - - group('map2', () { - test('Right', () { - final value = Either.of(10); - final map = value.map2( - Either.of(1.5), (a, b) => a + b); - map.match((_) { - fail('should be right'); - }, (r) => expect(r, 11.5)); - }); - - test('Left', () { - final value = Either.left('none'); - final map = value.map2( - Either.of(1.5), (a, b) => a + b); - map.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('map3', () { - test('Right', () { - final value = Either.of(10); - final map = value.map3( - Either.of(1.5), - Either.of(1.5), - (a, b, c) => a + b + c); - map.match((_) { - fail('should be right'); - }, (r) => expect(r, 13.0)); - }); - - test('Left', () { - final value = Either.left('none'); - final map = value.map3( - Either.of(1.5), - Either.of(1.5), - (a, b, c) => a + b + c); - map.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - test('pure', () { - final value = Either.of(10); - final pure = value.pure('abc'); - pure.match((_) { - fail('should be right'); - }, (r) => expect(r, 'abc')); - }); - - group('mapLeft', () { - test('Right', () { - final value = Either.of(10); - final map = value.mapLeft((a) => 'pre-$a'); - map.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () { - final value = Either.left('abc'); - final map = value.mapLeft((a) => 'pre-$a'); - map.match((l) => expect(l, 'pre-abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('foldRight', () { - test('Right', () { - final value = Either.of(10); - final fold = value.foldRight(10, (a, b) => a + b); - expect(fold, 20); - }); - - test('Left', () { - final value = Either.left('abc'); - final fold = value.foldRight(10, (a, b) => a + b); - expect(fold, 10); - }); - }); - - group('foldLeft', () { - test('Right', () { - final value = Either.of(10); - final fold = value.foldLeft(10, (a, b) => a + b); - expect(fold, 20); - }); - - test('Left', () { - final value = Either.left('abc'); - final fold = value.foldLeft(10, (a, b) => a + b); - expect(fold, 10); - }); - }); - - group('foldRightWithIndex', () { - test('Right', () { - final value = Either.of(10); - final fold = value.foldRightWithIndex(10, (i, a, b) => a + b); - expect(fold, 20); - }); - - test('Left', () { - final value = Either.left('abc'); - final fold = value.foldRightWithIndex(10, (i, a, b) => a + b); - expect(fold, 10); - }); - }); - - group('foldLeftWithIndex', () { - test('Right', () { - final value = Either.of(10); - final fold = value.foldLeftWithIndex(10, (i, a, b) => a + b); - expect(fold, 20); - }); - - test('Left', () { - final value = Either.left('abc'); - final fold = value.foldLeftWithIndex(10, (i, a, b) => a + b); - expect(fold, 10); - }); - }); - - group('foldMap', () { - test('Right', () { - final value = Either.of(10); - final fold = value.foldMap( - Monoid.instance(0, (a1, a2) => a1 + a2), (a) => a); - expect(fold, 10); - }); - - test('Left', () { - final value = Either.left('abc'); - final fold = value.foldMap( - Monoid.instance(0, (a1, a2) => a1 + a2), (a) => a); - expect(fold, 0); - }); - }); - - group('ap', () { - test('Right', () { - final value = Either.of(10); - final ap = value.ap(Either.of((n) => n + 1)); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, 11)); - }); - - test('Left', () { - final value = Either.of(10); - final ap = value.ap(Either.left('none')); - ap.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('alt', () { - test('Right', () { - final value = Either.of(10); - final ap = value.alt(() => Either.of(0)); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.alt(() => Either.of(0)); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, 0)); - }); - }); - - group('extend', () { - test('Right', () { - final value = Either.of(10); - final ap = value.extend((t) => t.getOrElse((l) => -1) * 0.5); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, 5.0)); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.extend((t) => t.getOrElse((l) => -1) * 0.5); - ap.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('duplicate', () { - test('Right', () { - final value = Either.of(10); - final ap = value.duplicate(); - expect(ap, isA>>()); - ap.match((_) { - fail('should be right'); - }, - (r) => r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10))); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.duplicate(); - expect(ap, isA>>()); - ap.match( - (l) => expect(l, 'none'), - (r) => r.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - })); - }); - }); - - group('length', () { - test('Right', () { - final value = Either.of(10); - expect(value.length(), 1); - }); - - test('Left', () { - final value = Either.left('none'); - expect(value.length(), 0); - }); - }); - - group('concatenate', () { - test('Right', () { - final value = Either.of(10); - final ap = value.concatenate(Monoid.instance(0, (a1, a2) => a1 + a2)); - expect(ap, 10); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.concatenate(Monoid.instance(0, (a1, a2) => a1 + a2)); - expect(ap, 0); - }); - }); - - group('any', () { - test('Right (true)', () { - final value = Either.of(10); - final ap = value.any((a) => a > 5); - expect(ap, true); - }); - - test('Right (false)', () { - final value = Either.of(10); - final ap = value.any((a) => a < 5); - expect(ap, false); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.any((a) => a > 5); - expect(ap, false); - }); - }); - - group('all', () { - test('Right (true)', () { - final value = Either.of(10); - final ap = value.all((a) => a > 5); - expect(ap, true); - }); - - test('Right (false)', () { - final value = Either.of(10); - final ap = value.all((a) => a < 5); - expect(ap, false); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.all((a) => a > 5); - expect(ap, true); - }); - }); - - group('filterOrElse', () { - test('Right (true)', () { - final value = Either.of(10); - final ap = value.filterOrElse((r) => r > 5, (r) => 'else'); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Right (false)', () { - final value = Either.of(10); - final ap = value.filterOrElse((r) => r < 5, (r) => 'else'); - ap.match((l) => expect(l, 'else'), (_) { - fail('should be left'); - }); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.filterOrElse((r) => r > 5, (r) => 'else'); - ap.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('flatMap', () { - group('Right', () { - test('then Right', () { - final value = Either.of(10); - final ap = value.flatMap((a) => Right('$a')); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, '10')); - }); - - test('then Left', () { - final value = Either.of(10); - final ap = - value.flatMap((a) => Either.left('none')); - ap.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('Left', () { - test('then Right', () { - final value = Either.left('0'); - final ap = - value.flatMap((a) => Either.of('$a')); - ap.match((l) => expect(l, '0'), (_) { - fail('should be left'); - }); - }); - - test('then Left', () { - final value = Either.left('0'); - final ap = - value.flatMap((a) => Either.left('none')); - ap.match((l) => expect(l, '0'), (_) { - fail('should be left'); - }); - }); - }); - }); - - group('toOption', () { - test('Right', () { - final value = Either.of(10); - final ap = value.toOption(); - ap.matchTestSome((t) { - expect(t, 10); - }); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.toOption(); - expect(ap, isA()); - }); - }); - - group('toNullable', () { - test('Right', () { - final value = Either.of(10); - final ap = value.toNullable(); - expect(ap, 10); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.toNullable(); - expect(ap, null); - }); - }); - - group('toIOEither', () { - test('Right', () { - final value = Either.of(10); - final ap = value.toIOEither(); - final result = ap.run(); - expect(result, value); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.toIOEither(); - final result = ap.run(); - expect(result, value); - }); - }); - - group('toTaskEither', () { - test('Right', () async { - final value = Either.of(10); - final ap = value.toTaskEither(); - final result = await ap.run(); - expect(result, value); - }); - - test('Left', () async { - final value = Either.left('none'); - final ap = value.toTaskEither(); - final result = await ap.run(); - expect(result, value); - }); - }); - - group('isLeft', () { - test('Right', () { - final value = Either.of(10); - final ap = value.isLeft(); - expect(ap, false); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.isLeft(); - expect(ap, true); - }); - }); - - group('isRight', () { - test('Right', () { - final value = Either.of(10); - final ap = value.isRight(); - expect(ap, true); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.isRight(); - expect(ap, false); - }); - }); - - group('getLeft', () { - test('Right', () { - final value = Either.of(10); - final ap = value.getLeft(); - expect(ap, isA()); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.getLeft(); - ap.matchTestSome((t) { - expect(t, 'none'); - }); - }); - }); - - group('getRight', () { - test('Right', () { - final value = Either.of(10); - final ap = value.getRight(); - ap.matchTestSome((t) { - expect(t, 10); - }); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.getRight(); - expect(ap, isA()); - }); - }); - - group('getOrElse', () { - test('Right', () { - final value = Either.of(10); - final ap = value.getOrElse((l) => -1); - expect(ap, 10); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.getOrElse((l) => -1); - expect(ap, -1); - }); - }); - - group('match', () { - test('Right', () { - final value = Either.of(10); - final ap = value.match((l) => -1, (r) => 1); - expect(ap, 1); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.match((l) => -1, (r) => 1); - expect(ap, -1); - }); - }); - - group('elem', () { - test('Right (true)', () { - final value = Either.of(10); - final ap = value.elem(10, Eq.instance((a1, a2) => a1 == a2)); - expect(ap, true); - }); - - test('Right (false)', () { - final value = Either.of(10); - final ap = value.elem(0, Eq.instance((a1, a2) => a1 == a2)); - expect(ap, false); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.elem(10, Eq.instance((a1, a2) => a1 == a2)); - expect(ap, false); - }); - }); - - group('exists', () { - test('Right (true)', () { - final value = Either.of(10); - final ap = value.exists((r) => r > 5); - expect(ap, true); - }); - - test('Right (false)', () { - final value = Either.of(10); - final ap = value.exists((r) => r < 5); - expect(ap, false); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.exists((r) => r > 5); - expect(ap, false); - }); - }); - - group('swap', () { - test('Right', () { - final value = Either.of(10); - final ap = value.swap(); - ap.match((l) => expect(l, 10), (_) { - fail('should be left'); - }); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.swap(); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, 'none')); - }); - }); - - group('flatten', () { - test('Right Right', () { - final value = Either>.of(Either.of(10)); - final ap = Either.flatten(value); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Right Left', () { - final value = - Either>.of(Either.left('none')); - final ap = Either.flatten(value); - ap.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - - test('Left', () { - final value = Either>.left('none'); - final ap = Either.flatten(value); - ap.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('orElse', () { - test('Right', () { - final value = Either.of(10); - final ap = value.orElse((l) => Either.of(0)); - ap.match((l) { - fail('should be right'); - }, (r) { - expect(r, 10); - }); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.orElse((l) => Either.of(0)); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, 0)); - }); - }); - - group('andThen', () { - test('Right', () { - final value = Either.of(10); - final ap = value.andThen(() => Either.of('10')); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, '10')); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value.andThen(() => Either.of('10')); - ap.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('call', () { - test('Right', () { - final value = Either.of(10); - final ap = value(Either.of('10')); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, '10')); - }); - - test('Left', () { - final value = Either.left('none'); - final ap = value(Either.of('10')); - ap.match((l) { - expect(l, 'none'); - }, (_) { - fail('should be left'); - }); - }); - }); - - test('of()', () { - final value = Either.of(10); - expect(value, isA()); - value.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('right()', () { - final value = Either.right(10); - expect(value, isA()); - value.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('of() == right()', () { - final of = Either.of(10); - final right = Either.right(10); - expect(of, right); - }); - - test('left()', () { - final value = Either.left('none'); - expect(value, isA()); - value.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - - group('fromOption', () { - test('Some', () { - final value = Option.of(10); - final either = Either.fromOption(value, () => 'none'); - either.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('None', () { - final value = Option.none(); - final either = Either.fromOption(value, () => 'none'); - either.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('fromPredicate', () { - test('Right', () { - final either = - Either.fromPredicate(10, (v) => v > 5, (_) => 'none'); - either.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () { - final either = - Either.fromPredicate(10, (v) => v < 5, (_) => 'none'); - either.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('fromNullable', () { - test('Right', () { - final either = Either.fromNullable(10, () => 'none'); - either.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () { - final either = Either.fromNullable(null, () => 'none'); - either.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('tryCatch', () { - test('Right', () { - final either = Either.tryCatch( - () => int.parse('10'), (o, s) => 'none'); - either.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () { - final either = Either.tryCatch( - () => int.parse('invalid'), (o, s) => 'none'); - either.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('tryCatchK', () { - test('Right', () { - final either = Either.of(10); - final ap = either.flatMap(Either.tryCatchK( - (n) => n + 5, - (_, __) => 'none', - )); - ap.match((_) { - fail('should be right'); - }, (r) => expect(r, 15)); - }); - - test('Left', () { - final either = Either.of(10); - final ap = either.flatMap(Either.tryCatchK( - (_) => int.parse('invalid'), - (_, __) => 'none', - )); - ap.match((l) => expect(l, 'none'), (r) { - fail('should be left'); - }); - }); - }); - - test('getEq', () { - final eq = Either.getEq( - Eq.instance((a1, a2) => a1 == a2), Eq.instance((a1, a2) => a1 == a2)); - final eitherR = Either.of(10); - final eitherL = Either.left('none'); - expect(eq.eqv(eitherR, eitherR), true); - expect(eq.eqv(eitherR, Either.of(10)), true); - expect(eq.eqv(eitherR, Either.of(9)), false); - expect(eq.eqv(eitherR, Either.left('none')), false); - expect(eq.eqv(eitherL, eitherL), true); - expect(eq.eqv(eitherL, Either.left('none')), true); - expect(eq.eqv(eitherL, Either.left('error')), false); - }); - - test('getSemigroup', () { - final sg = Either.getSemigroup( - Semigroup.instance((a1, a2) => a1 + a2)); - final eitherR = Either.of(10); - final eitherL = Either.left('none'); - expect(sg.combine(eitherR, eitherR), Either.of(20)); - expect(sg.combine(eitherR, eitherL), eitherR); - expect(sg.combine(eitherL, eitherR), eitherR); - expect(sg.combine(eitherL, Either.left('error')), eitherL); - }); - - test('Right value', () { - const r = Right(10); - expect(r.value, 10); - }); - - test('Left value', () { - const l = Left('none'); - expect(l.value, 'none'); - }); - - group('sequenceList', () { - test('Right', () { - final list = [right(1), right(2), right(3), right(4)]; - final result = Either.sequenceList(list); - result.matchTestRight((r) { - expect(r, [1, 2, 3, 4]); - }); - }); - - test('Left', () { - final list = [ - right(1), - left("Error"), - right(3), - right(4) - ]; - final result = Either.sequenceList(list); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - }); - }); - - group('traverseList', () { - test('Right', () { - final list = [1, 2, 3, 4, 5, 6]; - final result = - Either.traverseList(list, (a) => right("$a")); - result.matchTestRight((r) { - expect(r, ["1", "2", "3", "4", "5", "6"]); - }); - }); - - test('Left', () { - final list = [1, 2, 3, 4, 5, 6]; - final result = Either.traverseList( - list, - (a) => a % 2 == 0 ? right("$a") : left("Error"), - ); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - }); - }); - - group('traverseListWithIndex', () { - test('Right', () { - final list = [1, 2, 3, 4, 5, 6]; - final result = Either.traverseListWithIndex( - list, (a, i) => right("$a$i")); - result.matchTestRight((r) { - expect(r, ["10", "21", "32", "43", "54", "65"]); - }); - }); - - test('Left', () { - final list = [1, 2, 3, 4, 5, 6]; - final result = Either.traverseListWithIndex( - list, - (a, i) => i % 2 == 0 ? right("$a$i") : left("Error"), - ); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - }); - }); - - test('Right == Right', () { - final r1 = Either.of(10); - final r2 = Either.of(9); - final r3 = Either.of(8.0); - final r4 = Either.of(10); - final r5 = Either.of(10.0); - final l1 = Either.left('none'); - final l2 = Either.left('error'); - final map1 = {'m1': r1, 'm2': r1}; - final map2 = {'m1': r1, 'm2': r2}; - final map3 = {'m1': r1, 'm2': r4}; - final map4 = {'m1': r1, 'm2': r3}; - final map5 = {'m1': r1, 'm2': r5}; - final map6 = {'m1': r1, 'm2': r1}; - final map7 = {'m1': r1, 'm2': l1}; - expect(r1, r1); - expect(r1, r4); - expect(r1, r5); - expect(r1 == r2, false); - expect(r1 == r3, false); - expect(r1 == r3, false); - expect(r1 == l1, false); - expect(r1 == l2, false); - expect(map1, map1); - expect(map1, map6); - expect(map1, map3); - expect(map1, map5); - expect(map1 == map2, false); - expect(map1 == map4, false); - expect(map1 == map7, false); - }); - - test('Left == Left', () { - final r1 = Either.of(10); - final l1 = Either.left('none'); - final l2 = Either.left('error'); - final l3 = Either.left('none'); - final l4 = Either.left(1.0); - final map1 = {'m1': l1, 'm2': l1}; - final map2 = {'m1': l1, 'm2': l3}; - final map3 = {'m1': l1, 'm2': l2}; - final map4 = {'m1': l1, 'm2': l4}; - final map5 = {'m1': l1, 'm2': r1}; - expect(l1, l1); - expect(l1, l3); - expect(l1 == l2, false); - expect(l1 == r1, false); - expect(map1, map1); - expect(map1, map2); - expect(map1 == map3, false); - expect(map1 == map4, false); - expect(map1 == map5, false); - }); - - group('toString', () { - test('Right', () { - final value = Either.of(10); - expect(value.toString(), 'Right(10)'); - }); - - test('Left', () { - final value = Either.left('none'); - expect(value.toString(), 'Left(none)'); - }); - }); - }); - - group('bind', () { - test('Right', () { - final either1 = Either.of(10); - final result = either1.bind((r) => Either.of(r + 10)); - expect(result.getOrElse((l) => 0), 20); - }); - - test('Left', () { - final either1 = Either.left('String'); - final result = either1.bind((r) => Either.of(r + 10)); - expect(result.getOrElse((l) => 0), 0); - expect(result.getLeft().getOrElse(() => ''), 'String'); - }); - }); - - group('bindFuture', () { - test('Right', () async { - final either1 = Either.of(10); - final asyncEither = either1.bindFuture((r) async => Either.of(r + 10)); - final result = await asyncEither.run(); - expect(result.getOrElse((l) => 0), 20); - }); - - test('Left', () async { - final either1 = Either.left('String'); - final asyncEither = either1.bindFuture((r) async => Either.of(r + 10)); - final result = await asyncEither.run(); - expect(result.getOrElse((l) => 0), 0); - expect(result.getLeft().getOrElse(() => ''), 'String'); - }); - }); - - test('chainFirst', () { - final either = Either.of(10); - var sideEffect = 10; - final chain = either.chainFirst((b) { - sideEffect = 100; - return Either.left("abc"); - }); - chain.match( - (l) => fail('should be right'), - (r) { - expect(r, 10); - expect(sideEffect, 100); - }, - ); - }); - - test('rights', () { - final list = [ - right(1), - right(2), - left('a'), - left('b'), - right(3), - ]; - final result = Either.rights(list); - expect(result, [1, 2, 3]); - }); - - test('lefts', () { - final list = [ - right(1), - right(2), - left('a'), - left('b'), - right(3), - ]; - final result = Either.lefts(list); - expect(result, ['a', 'b']); - }); - - test('partitionEithers', () { - final list = [ - right(1), - right(2), - left('a'), - left('b'), - right(3), - ]; - final result = Either.partitionEithers(list); - expect(result.$1, ['a', 'b']); - expect(result.$2, [1, 2, 3]); - }); - - group('safeCast', () { - test('dynamic', () { - final castInt = Either.safeCast(10, (value) => 'Error'); - final castString = Either.safeCast('abc', (value) => 'Error'); - expect(castInt, isA>()); - expect(castString, isA>()); - }); - - test('Right', () { - final cast = Either.safeCast(10, (value) => 'Error'); - cast.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('Left', () { - final cast = Either.safeCast('abc', (value) => 'Error'); - cast.matchTestLeft((l) { - expect(l, "Error"); - }); - }); - }); - - group('safeCastStrict', () { - test('Right', () { - final cast = - Either.safeCastStrict(10, (value) => 'Error'); - cast.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('Left', () { - final cast = - Either.safeCastStrict('abc', (value) => 'Error'); - cast.matchTestLeft((l) { - expect(l, "Error"); - }); - }); - }); - - group('Do Notation', () { - test('should return the correct value', () { - final doEither = Either.Do((_) => _(Either.of(10))); - doEither.matchTestRight((t) { - expect(t, 10); - }); - }); - - test('should extract the correct values', () { - final doEither = Either.Do((_) { - final a = _(Either.of(10)); - final b = _(Either.of(5)); - return a + b; - }); - doEither.matchTestRight((t) { - expect(t, 15); - }); - }); - - test('should return Left if any Either is Left', () { - final doEither = Either.Do((_) { - final a = _(Either.of(10)); - final b = _(Either.of(5)); - final c = _(Either.left('Error')); - return a + b + c; - }); - doEither.matchTestLeft((t) { - expect(t, 'Error'); - }); - }); - - test('should rethrow if throw is used inside Do', () { - final doEither = () => Either.Do((_) { - _(Either.of(10)); - throw UnimplementedError(); - }); - - expect(doEither, throwsA(const TypeMatcher())); - }); - - test('should rethrow if Left is thrown inside Do', () { - final doEither = () => Either.Do((_) { - _(Either.of(10)); - throw Left('Error'); - }); - - expect(doEither, throwsA(const TypeMatcher())); - }); - - test('should no execute past the first Left', () { - var mutable = 10; - final doEitherLeft = Either.Do((_) { - final a = _(Either.of(10)); - final b = _(Either.left("Error")); - mutable += 10; - return a + b; - }); - - expect(mutable, 10); - doEitherLeft.matchTestLeft((l) { - expect(l, "Error"); - }); - - final doEitherRight = Either.Do((_) { - final a = _(Either.of(10)); - mutable += 10; - return a; - }); - - expect(mutable, 20); - doEitherRight.matchTestRight((t) { - expect(t, 10); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/eq_test.dart b/packages/fpdart/test/src/eq_test.dart deleted file mode 100644 index 4ed1b948..00000000 --- a/packages/fpdart/test/src/eq_test.dart +++ /dev/null @@ -1,188 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -class _Parent { - final int value1; - final double value2; - const _Parent(this.value1, this.value2); -} - -void main() { - group('Eq', () { - test('.instance (int)', () { - final instance = Eq.instance((a1, a2) => a1 == (a2 + 1)); - - // eqv - expect(instance.eqv(1, 1), false); - expect(instance.eqv(2, 1), true); - expect(instance.eqv(3, 1), false); - - // neqv - expect(instance.neqv(1, 1), true); - expect(instance.neqv(2, 1), false); - expect(instance.neqv(3, 1), true); - }); - - test('.instance (String)', () { - final instance = Eq.instance( - (a1, a2) => a1.substring(0, 2) == a2.substring(0, 2)); - expect(instance.eqv('abc', 'abc'), true); - expect(instance.eqv('abc', 'acb'), false); - }); - - test('and', () { - final instance1 = Eq.instance( - (a1, a2) => a1.substring(0, 2) == a2.substring(0, 2)); - final instance2 = Eq.instance( - (a1, a2) => a1.substring(2, 4) == a2.substring(2, 4)); - final and = instance1.and(instance2); - expect(instance1.eqv('abef', 'abcd'), true); - expect(instance2.eqv('abef', 'zxef'), true); - expect(and.eqv('abcd', 'abcd'), true); - expect(and.eqv('abdc', 'abcd'), false); - expect(and.eqv('bacd', 'abcd'), false); - }); - - test('or', () { - final instance1 = Eq.instance((a1, a2) => a1 == (a2 + 2)); - final instance2 = Eq.instance((a1, a2) => a1 == (a2 + 3)); - final or = instance1.or(instance2); - expect(or.eqv(2, 1), false); - expect(or.eqv(3, 1), true); - expect(or.eqv(4, 1), true); - expect(or.eqv(5, 1), false); - }); - - test('xor', () { - final instance1 = Eq.instance((a1, a2) => a1 == (a2 + 2)); - final instance2 = Eq.instance((a1, a2) => a1 == (a2 + 3)); - final xor = instance1.xor(instance2); - final xorSame = instance1.xor(instance1); - expect(xor.eqv(2, 1), false); - expect(xor.eqv(3, 1), true); - expect(xor.eqv(4, 1), true); - expect(xorSame.eqv(3, 1), false); - }); - - test('.fromUniversalEquals', () { - final instance = Eq.fromUniversalEquals(); - expect(instance.eqv(1, 1), true); - expect(instance.eqv(1, 2), false); - }); - - test('.allEqual', () { - final instance = Eq.allEqual(); - expect(instance.eqv(1, 1), true); - expect(instance.eqv(1, 2), true); - expect(instance.eqv(2, 1), true); - }); - - test('.by', () { - final instance = Eq.instance((a1, a2) => a1 == a2); - final by = Eq.by((a) => a.length, instance); - expect(by.eqv('abc', 'abc'), true); - expect(by.eqv('abc', 'ab'), false); - }); - - test('.eqNum', () { - final eq = Eq.eqNum; - expect(eq.eqv(10, 10), true); - expect(eq.eqv(10.0, 10), true); - expect(eq.eqv(10.5, 10.5), true); - expect(eq.eqv(-10, -10.0), true); - expect(eq.eqv(10, 10.5), false); - }); - - test('.eqInt', () { - final eq = Eq.eqInt; - expect(eq.eqv(10, 10), true); - expect(eq.eqv(11, 10), false); - expect(eq.eqv(-10, -10), true); - expect(eq.eqv(10, 11), false); - }); - - test('.eqDouble', () { - final eq = Eq.eqDouble; - expect(eq.eqv(10, 10), true); - expect(eq.eqv(10.0, 10), true); - expect(eq.eqv(10.5, 10.5), true); - expect(eq.eqv(-10, -10.0), true); - expect(eq.eqv(10, 10.5), false); - }); - - test('.eqString', () { - final eq = Eq.eqString; - expect(eq.eqv("abc", "abc"), true); - expect(eq.eqv("abc", "abd"), false); - expect(eq.eqv("abc", "ab"), false); - expect(eq.eqv("a", "a"), true); - expect(eq.eqv("a", "ab"), false); - }); - - test('.eqBool', () { - final eq = Eq.eqBool; - expect(eq.eqv(true, true), true); - expect(eq.eqv(false, true), false); - expect(eq.eqv(true, false), false); - expect(eq.eqv(false, false), true); - }); - - group('contramap', () { - test('int', () { - final eqParentInt = Eq.eqInt.contramap<_Parent>( - (p) => p.value1, - ); - - expect( - eqParentInt.eqv( - _Parent(1, 2.5), - _Parent(1, 12.5), - ), - true, - ); - expect( - eqParentInt.eqv( - _Parent(1, 2.5), - _Parent(4, 2.5), - ), - false, - ); - expect( - eqParentInt.eqv( - _Parent(-1, 2.5), - _Parent(1, 12.5), - ), - false, - ); - }); - - test('double', () { - final eqParentDouble = Eq.eqDouble.contramap<_Parent>( - (p) => p.value2, - ); - - expect( - eqParentDouble.eqv( - _Parent(1, 2.5), - _Parent(1, 2.5), - ), - true, - ); - expect( - eqParentDouble.eqv( - _Parent(1, 2.5), - _Parent(1, 12.5), - ), - false, - ); - expect( - eqParentDouble.eqv( - _Parent(-1, 2.5), - _Parent(1, 2), - ), - false, - ); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/extension/curry_extension_test.dart b/packages/fpdart/test/src/extension/curry_extension_test.dart deleted file mode 100644 index 51752254..00000000 --- a/packages/fpdart/test/src/extension/curry_extension_test.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:glados/glados.dart'; - -void main() { - group('Curry/Uncarry extension', () { - group('Curry/Uncarry (2)', () { - int subtract(int n1, int n2) => n1 - n2; - int Function(int) subtractCurried(int n1) => (n2) => n1 - n2; - - Glados2(any.int, any.int).test('curry', (n1, n2) { - expect(subtract(n1, n2), subtract.curry(n1)(n2)); - }); - - Glados2(any.int, any.int).test('curryLast', (n1, n2) { - expect(subtract(n1, n2), subtract.curryLast(n2)(n1)); - }); - - Glados2(any.int, any.int).test('uncurry', (n1, n2) { - expect(subtractCurried(n1)(n2), subtractCurried.uncurry(n1, n2)); - }); - }); - - group('Curry/Uncarry (3)', () { - int subtract(int n1, int n2, int n3) => n1 - n2 - n3; - int Function(int) Function(int) subtractCurriedAll(int n1) => - (n2) => (n3) => n1 - n2 - n3; - - Glados3(any.int, any.int, any.int).test('curry', - (n1, n2, n3) { - expect(subtract(n1, n2, n3), subtract.curry(n1)(n2, n3)); - }); - - Glados3(any.int, any.int, any.int).test('curryLast', - (n1, n2, n3) { - expect(subtract(n1, n2, n3), subtract.curryLast(n3)(n1, n2)); - }); - - Glados3(any.int, any.int, any.int).test('curryAll', - (n1, n2, n3) { - expect(subtract(n1, n2, n3), subtract.curryAll(n1)(n2)(n3)); - }); - - Glados3(any.int, any.int, any.int).test('uncurry', - (n1, n2, n3) { - expect(subtractCurriedAll(n1)(n2)(n3), - subtractCurriedAll.uncurry(n1, n2, n3)); - }); - }); - - group('Curry/Uncarry (4)', () { - int subtract(int n1, int n2, int n3, int n4) => n1 - n2 - n3 - n4; - int Function(int) Function(int) Function(int) subtractCurriedAll( - int n1) => - (n2) => (n3) => (n4) => n1 - n2 - n3 - n4; - - Glados3(any.int, any.int, any.int).test('curry', - (n1, n2, n3) { - expect(subtract(n1, n2, n3, n1), subtract.curry(n1)(n2, n3, n1)); - }); - - Glados3(any.int, any.int, any.int).test('curryLast', - (n1, n2, n3) { - expect(subtract(n1, n2, n3, n2), subtract.curryLast(n2)(n1, n2, n3)); - }); - - Glados3(any.int, any.int, any.int).test('curryAll', - (n1, n2, n3) { - expect(subtract(n1, n2, n3, n1), subtract.curryAll(n1)(n2)(n3)(n1)); - }); - - Glados3(any.int, any.int, any.int).test('uncurry', - (n1, n2, n3) { - expect(subtractCurriedAll(n1)(n2)(n3)(n1), - subtractCurriedAll.uncurry(n1, n2, n3, n1)); - }); - }); - - group('Curry/Uncarry (5)', () { - int subtract(int n1, int n2, int n3, int n4, int n5) => - n1 - n2 - n3 - n4 - n5; - int Function(int) Function(int) Function(int) Function(int) - subtractCurriedAll(int n1) => - (n2) => (n3) => (n4) => (n5) => n1 - n2 - n3 - n4 - n5; - - Glados3(any.int, any.int, any.int).test('curry', - (n1, n2, n3) { - expect( - subtract(n1, n2, n3, n1, n2), subtract.curry(n1)(n2, n3, n1, n2)); - }); - - Glados3(any.int, any.int, any.int).test('curryLast', - (n1, n2, n3) { - expect(subtract(n1, n2, n3, n1, n3), - subtract.curryLast(n3)(n1, n2, n3, n1)); - }); - - Glados3(any.int, any.int, any.int).test('curryAll', - (n1, n2, n3) { - expect(subtract(n1, n2, n3, n1, n2), - subtract.curryAll(n1)(n2)(n3)(n1)(n2)); - }); - - Glados3(any.int, any.int, any.int).test('uncurry', - (n1, n2, n3) { - expect(subtractCurriedAll(n1)(n2)(n3)(n1)(n2), - subtractCurriedAll.uncurry(n1, n2, n3, n1, n2)); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/extension/date_time_extension_test.dart b/packages/fpdart/test/src/extension/date_time_extension_test.dart deleted file mode 100644 index dc539516..00000000 --- a/packages/fpdart/test/src/extension/date_time_extension_test.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import '../utils/utils.dart'; - -void main() { - group('FpdartOnDateTime', () { - group('[Property-based testing]', () { - Glados2().test('eqvYear == dateEqYear', (d1, d2) { - expect(d1.eqvYear(d2), Eq.dateEqYear.eqv(d1, d2)); - }); - - Glados2().test('eqvMonth == dateEqMonth', (d1, d2) { - expect(d1.eqvMonth(d2), Eq.dateEqMonth.eqv(d1, d2)); - }); - - Glados2().test('eqvDay == dateEqDay', (d1, d2) { - expect(d1.eqvDay(d2), Eq.dateEqDay.eqv(d1, d2)); - }); - - Glados2().test('eqvYearMonthDay == dateEqYear', - (d1, d2) { - expect(d1.eqvYearMonthDay(d2), Eq.dateEqYear.eqv(d1, d2)); - }); - }); - - test('eqvYear', () { - final date1 = DateTime(2021, 2, 2); - final date2 = DateTime(2021, 3, 3); - final date3 = DateTime(2020, 2, 2); - - expect(date1.eqvYear(date1), true); - expect(date1.eqvYear(date2), true); - expect(date1.eqvYear(date3), false); - }); - - test('eqvMonth', () { - final date1 = DateTime(2021, 2, 2); - final date2 = DateTime(2021, 3, 3); - final date3 = DateTime(2020, 2, 2); - - expect(date1.eqvMonth(date1), true); - expect(date1.eqvMonth(date2), false); - expect(date1.eqvMonth(date3), true); - }); - - test('eqvDay', () { - final date1 = DateTime(2021, 2, 2); - final date2 = DateTime(2021, 3, 3); - final date3 = DateTime(2020, 3, 2); - - expect(date1.eqvDay(date1), true); - expect(date1.eqvDay(date2), false); - expect(date1.eqvDay(date3), true); - }); - - test('eqvYearMonthDay', () { - final date1 = DateTime(2021, 2, 2, 10, 10); - final date2 = DateTime(2021, 2, 2, 11, 11); - final date3 = DateTime(2020, 2, 2, 12, 12); - - expect(date1.eqvYearMonthDay(date1), true); - expect(date1.eqvYearMonthDay(date2), true); - expect(date1.eqvYearMonthDay(date3), false); - }); - }); -} diff --git a/packages/fpdart/test/src/extension/iterable_extension_test.dart b/packages/fpdart/test/src/extension/iterable_extension_test.dart deleted file mode 100644 index 27cd7de3..00000000 --- a/packages/fpdart/test/src/extension/iterable_extension_test.dart +++ /dev/null @@ -1,1674 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import '../utils/utils.dart'; - -/// Used to test sorting with [DateTime] (`sortWithDate`) -class SortDate { - final int id; - final DateTime date; - const SortDate(this.id, this.date); -} - -void main() { - /// Check if two [Iterable] have the same element in the same order - bool eq(Iterable a, Iterable b) => a.foldLeftWithIndex( - false, - (a, e, i) => e == b.elementAt(i), - ); - - group('FpdartOnList', () { - test('zipWith', () { - final list1 = [1, 2]; - final list2 = ['a', 'b']; - final result = list1.zipWith( - (t, i) => (t + i.length) / 2, - list2, - ); - - expect(eq(result, [1.0, 1.5]), true); - }); - - test('zip', () { - final list1 = [1, 2]; - final list2 = ['a', 'b']; - final ap = list1.zip(list2); - - expect(eq(ap, [(1, 'a'), (2, 'b')]), true); - }); - - test('filter', () { - final list1 = [1, 2, 3, 4, 5, 6]; - final ap = list1.filter((t) => t > 3); - - expect(eq(ap, [4, 5, 6]), true); - }); - - test('filterWithIndex', () { - final list1 = [0, 1, 2, 3, 4, 5, 6]; - final ap = list1.filterWithIndex((t, index) => t > 3 && index < 6); - - expect(eq(ap, [4, 5]), true); - }); - - test('concat', () { - final list1 = [1, 2, 3, 4, 5, 6]; - final ap = list1.concat([7, 8]); - - expect(eq(ap, [1, 2, 3, 4, 5, 6, 7, 8]), true); - }); - - test('append', () { - final list1 = [1, 2, 3, 4, 5, 6]; - final ap = list1.append(7); - - expect(eq(ap, [1, 2, 3, 4, 5, 6, 7]), true); - }); - - test('prepend', () { - final list1 = [1, 2, 3, 4, 5, 6]; - final ap = list1.prepend(0); - - expect(eq(ap, [0, 1, 2, 3, 4, 5, 6]), true); - }); - - test('prependAll', () { - final list1 = [1, 2, 3, 4, 5, 6]; - final ap = list1.prependAll([10, 11, 12]); - - expect(eq(ap, [10, 11, 12, 1, 2, 3, 4, 5, 6]), true); - }); - - test('insertBy', () { - final list1 = [1, 2, 3, 4, 5, 6]; - final ap = list1.insertBy(Order.from((a1, a2) => a1.compareTo(a2)), 4); - - expect(eq(ap, [1, 2, 3, 4, 4, 5, 6]), true); - }); - - test('insertWith', () { - final list1 = [ - SortDate(2, DateTime(2019)), - SortDate(4, DateTime(2017)), - SortDate(1, DateTime(2020)), - SortDate(3, DateTime(2018)), - ]; - final ap = list1.insertWith( - (instance) => instance.date, - Order.orderDate, - SortDate(5, DateTime(2021)), - ); - - expect(ap.elementAt(4).id, 5); - expect(ap.elementAt(4).date.year, 2021); - }); - - test('sortBy', () { - final list1 = [2, 6, 4, 1, 5, 3]; - final ap = list1.sortBy(Order.from((a1, a2) => a1.compareTo(a2))); - - expect(eq(ap, [1, 2, 3, 4, 5, 6]), true); - }); - - test('sortWith', () { - final list1 = [ - SortDate(2, DateTime(2019)), - SortDate(4, DateTime(2017)), - SortDate(1, DateTime(2020)), - SortDate(3, DateTime(2018)), - ]; - final ap = list1.sortWith((instance) => instance.date, Order.orderDate); - - expect(ap.elementAt(0).id, 4); - expect(ap.elementAt(1).id, 3); - expect(ap.elementAt(2).id, 2); - expect(ap.elementAt(3).id, 1); - }); - - test('sortWithDate', () { - final list1 = [ - SortDate(2, DateTime(2019)), - SortDate(4, DateTime(2017)), - SortDate(1, DateTime(2020)), - SortDate(3, DateTime(2018)), - ]; - final ap = list1.sortWithDate((instance) => instance.date); - - expect(ap.elementAt(0).date.year, 2017); - expect(ap.elementAt(1).date.year, 2018); - expect(ap.elementAt(2).date.year, 2019); - expect(ap.elementAt(3).date.year, 2020); - }); - - test('sortBy', () { - final list1 = [2, 6, 4, 1, 5, 3]; - final ap = list1.sortBy(Order.from((a1, a2) => a1.compareTo(a2))); - - expect(eq(ap, [1, 2, 3, 4, 5, 6]), true); - }); - - test('intersect', () { - final list1 = [1, 2, 3, 4, 5, 6]; - final ap = list1.intersect([1, 2, 3, 10, 11, 12]); - - expect(eq(ap, [1, 2, 3]), true); - }); - - test('difference', () { - final list1 = [1, 2, 3]; - final ap = list1.difference( - Eq.instance((a1, a2) => a1 == a2), - [2, 3, 4], - ); - - expect(eq(ap, [1]), true); - }); - - test('intersperse', () { - final ap = [1, 2, 3].intersperse(10); - - expect(eq(ap, [1, 10, 2, 10, 3]), true); - }); - - group('head', () { - test('Some', () { - final list1 = [1, 2]; - final ap = list1.head; - expect(ap, isA()); - expect(ap.getOrElse(() => -1), 1); - }); - - test('None', () { - final List list1 = []; - final ap = list1.head; - expect(ap, isA()); - expect(ap.getOrElse(() => -1), -1); - }); - }); - - group('firstOption', () { - test('Some', () { - final list1 = [1, 2]; - final ap = list1.firstOption; - expect(ap, isA()); - expect(ap.getOrElse(() => -1), 1); - }); - }); - - group('tail', () { - test('Some', () { - final list1 = [1, 2, 3, 4]; - final ap = list1.tail; - expect(ap, isA()); - expect(ap.getOrElse(() => []), [2, 3, 4]); - }); - }); - - group('init', () { - test('Some', () { - final list1 = [1, 2, 3, 4]; - final ap = list1.init; - expect(ap, isA()); - expect(ap.getOrElse(() => []), [1, 2, 3]); - }); - }); - - group('lastOption', () { - test('Some', () { - final list1 = [1, 2, 3, 4]; - final ap = list1.lastOption; - expect(ap, isA()); - expect(ap.getOrElse(() => -1), 4); - }); - }); - - test('takeWhileLeft', () { - final list1 = [1, 2, 3, 4]; - final ap = list1.takeWhileLeft((t) => t < 3); - expect(eq(ap, [1, 2]), true); - }); - - test('dropWhileLeft', () { - final list1 = [1, 2, 3, 4]; - final ap = list1.dropWhileLeft((t) => t < 3); - expect(eq(ap, [3, 4]), true); - }); - - test('span', () { - final list1 = [1, 5, 2, 3, 4]; - final ap = list1.span((t) => t < 3); - expect(ap.$1.length, 1); - expect(ap.$1.elementAt(0), 1); - - expect(ap.$2.length, 4); - expect(ap.$2.elementAt(0), 5); - expect(ap.$2.elementAt(1), 2); - expect(ap.$2.elementAt(2), 3); - expect(ap.$2.elementAt(3), 4); - }); - - test('breakI', () { - final list1 = [4, 5, 1, 3, 4]; - final ap = list1.breakI((t) => t < 3); - - expect(ap.$1.length, 2); - expect(ap.$1.elementAt(0), 4); - expect(ap.$1.elementAt(1), 5); - - expect(ap.$2.length, 3); - expect(ap.$2.elementAt(0), 1); - expect(ap.$2.elementAt(1), 3); - expect(ap.$2.elementAt(2), 4); - }); - - test('splitAt', () { - final list1 = [1, 2, 3, 4]; - final ap = list1.splitAt(2); - expect(eq(ap.$1, [1, 2]), true); - expect(eq(ap.$2, [3, 4]), true); - }); - - test('delete', () { - final list1 = [1, 2, 3, 2]; - final ap = list1.delete(2); - expect(ap.length, 3); - expect(ap.elementAt(0), 1); - expect(ap.elementAt(1), 3); - expect(ap.elementAt(2), 2); - }); - - test('maximumBy', () { - final list1 = [2, 5, 4, 6, 1, 3]; - final ap = list1.maximumBy(Order.from((a1, a2) => a1.compareTo(a2))); - expect(ap.getOrElse(() => -1), 6); - }); - - test('minimumBy', () { - final list1 = [2, 5, 4, 6, 1, 3]; - final ap = list1.minimumBy(Order.from((a1, a2) => a1.compareTo(a2))); - expect(ap.getOrElse(() => -1), 1); - }); - - test('drop', () { - final list1 = [1, 2, 3, 4, 5]; - final ap = list1.drop(2); - expect(eq(ap, [3, 4, 5]), true); - }); - - group('dropRight', () { - test('none', () { - expect([].dropRight(0), isEmpty); - expect([].dropRight(1), isEmpty); - expect([].dropRight(2), isEmpty); - expect([1].dropRight(1), isEmpty); - expect([1, 2].dropRight(2), isEmpty); - expect([1, 2].dropRight(3), isEmpty); - }); - - test('some', () { - expect([1, 2, 3, 4].dropRight(0), [1, 2, 3, 4]); - expect([1, 2, 3, 4].dropRight(1), [1, 2, 3]); - expect([1, 2, 3, 4].dropRight(2), [1, 2]); - expect([1, 2, 3, 4].dropRight(3), [1]); - // Is lazy. - var list = [1, 2, 3]; - var dropList = list.dropRight(5); - list.addAll([4, 5, 6]); - expect(dropList, [1]); - }); - }); - - test('foldLeft', () { - final list1 = [1, 2, 3]; - final ap = list1.foldLeft(0, (b, t) => b - t); - expect(ap, -6); - }); - - test('foldLeftWithIndex', () { - final list1 = [1, 2, 3]; - final ap = list1.foldLeftWithIndex(0, (b, t, i) => b - t - i); - expect(ap, -9); - }); - - test('mapWithIndex', () { - final list1 = [1, 2, 3]; - final ap = list1.mapWithIndex((t, index) => '$t$index'); - expect(eq(ap, ['10', '21', '32']), true); - }); - - test('flatMap', () { - final list1 = [1, 2, 3]; - final ap = list1.flatMap((t) => [t, t + 1]); - expect(eq(ap, [1, 2, 2, 3, 3, 4]), true); - }); - - test('flatMapWithIndex', () { - final list1 = [1, 2, 3]; - final ap = list1.flatMapWithIndex((t, i) => [t, t + i]); - expect(eq(ap, [1, 1, 2, 3, 3, 5]), true); - }); - - test('ap', () { - final list1 = [1, 2, 3]; - final ap = list1.ap([(a) => a + 1, (a) => a + 2]); - expect(eq(ap, [2, 3, 3, 4, 4, 5]), true); - }); - - test('partition', () { - final list1 = [2, 4, 5, 6, 1, 3]; - final ap = list1.partition((t) => t > 2); - - expect(ap.$1.length, 2); - expect(ap.$1.elementAt(0), 2); - expect(ap.$1.elementAt(1), 1); - - expect(ap.$2.length, 4); - expect(ap.$2.elementAt(0), 4); - expect(ap.$2.elementAt(1), 5); - expect(ap.$2.elementAt(2), 6); - expect(ap.$2.elementAt(3), 3); - }); - - group('all', () { - test('true', () { - final list1 = [1, 2, 3, 4]; - final ap = list1.all((t) => t < 5); - expect(ap, true); - }); - - test('false', () { - final list1 = [1, 2, 3, 4]; - final ap = list1.all((t) => t < 4); - expect(ap, false); - }); - }); - - group('elem', () { - test('true', () { - final list1 = [1, 2, 3, 4]; - final ap1 = list1.elem(1); - final ap2 = list1.elem(2); - final ap3 = list1.elem(3); - final ap4 = list1.elem(4); - expect(ap1, true); - expect(ap2, true); - expect(ap3, true); - expect(ap4, true); - }); - - test('false', () { - final list1 = [1, 2, 3, 4]; - final ap1 = list1.elem(-1); - final ap2 = list1.elem(0); - final ap3 = list1.elem(5); - final ap4 = list1.elem(6); - expect(ap1, false); - expect(ap2, false); - expect(ap3, false); - expect(ap4, false); - }); - }); - - group('notElem', () { - test('false', () { - final list1 = [1, 2, 3, 4]; - final ap1 = list1.notElem(1); - final ap2 = list1.notElem(2); - final ap3 = list1.notElem(3); - final ap4 = list1.notElem(4); - expect(ap1, false); - expect(ap2, false); - expect(ap3, false); - expect(ap4, false); - }); - - test('true', () { - final list1 = [1, 2, 3, 4]; - final ap1 = list1.notElem(-1); - final ap2 = list1.notElem(0); - final ap3 = list1.notElem(5); - final ap4 = list1.notElem(6); - expect(ap1, true); - expect(ap2, true); - expect(ap3, true); - expect(ap4, true); - }); - }); - - group('lookupEq', () { - test('none', () { - expect([].lookupEq(Eq.eqInt, 5), isA()); - }); - - test('none found', () { - expect([1, 2, 3, 4].lookupEq(Eq.eqInt, 5), isA()); - }); - - test('found', () { - var find3 = [1, 2, 3, 4].lookupEq(Eq.eqInt, 3); - expect(find3, isA()); - expect(find3.getOrElse(() => throw "not"), 3); - }); - - test('found first', () { - var findMod3 = - [1, 6, 4, 3, 2].lookupEq(Eq.by((n) => n % 3, Eq.eqInt), 0); - expect(findMod3, isA()); - expect(findMod3.getOrElse(() => throw "not"), 6); - }); - }); - }); - - group('FpdartOnMutableIterableOfIterable', () { - test('concat', () { - final list1 = [ - [1, 2], - [2, 3], - [3, 4] - ]; - final ap = list1.flatten; - - expect(eq(ap, [1, 2, 2, 3, 3, 4]), true); - }); - }); - - group('FpdartTraversableIterable', () { - group('traverseOption', () { - test('Some', () { - final list = [1, 2, 3, 4]; - final result = list.traverseOption(some); - result.matchTestSome((t) { - expect(list, t); - }); - }); - - test('None', () { - final list = [1, 2, 3, 4]; - final result = - list.traverseOption((t) => t == 3 ? none() : some(t)); - expect(result, isA()); - }); - }); - - group('traverseOptionWithIndex', () { - test('Some', () { - final list = [1, 2, 3, 4]; - final result = list.traverseOptionWithIndex((a, i) => some(a + i)); - result.matchTestSome((t) { - expect(t, [1, 3, 5, 7]); - }); - }); - - test('None', () { - final list = [1, 2, 3, 4]; - final result = list.traverseOptionWithIndex( - (a, i) => i == 3 ? none() : some(a + i)); - expect(result, isA()); - }); - }); - - group('traverseEither', () { - test('Right', () { - final list = [1, 2, 3, 4]; - final result = list.traverseEither(right); - result.matchTestRight((t) { - expect(list, t); - }); - }); - - test('Left', () { - final list = [1, 2, 3, 4]; - final result = - list.traverseEither((t) => t == 3 ? left("Error") : right(t)); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - }); - }); - - group('traverseEitherWithIndex', () { - test('Right', () { - final list = [1, 2, 3, 4]; - final result = list.traverseEitherWithIndex((a, i) => right(a + i)); - result.matchTestRight((t) { - expect(t, [1, 3, 5, 7]); - }); - }); - - test('Left', () { - final list = [1, 2, 3, 4]; - final result = list.traverseEitherWithIndex( - (a, i) => i == 3 ? left("Error") : right(a + i)); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - }); - }); - - group('traverseIOEither', () { - test('Right', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseIOEither((a) { - sideEffect += 1; - return IOEither.of("$a"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestRight((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, list.length); - }); - - test('Left', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseIOEither((a) { - sideEffect += 1; - return a % 2 == 0 ? IOEither.left("Error") : IOEither.of("$a"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - - group('traverseIOEitherWithIndex', () { - test('Right', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseIOEitherWithIndex((a, i) { - sideEffect += 1; - return IOEither.of("$a$i"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestRight((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, list.length); - }); - - test('Left', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseIOEitherWithIndex((a, i) { - sideEffect += 1; - return a % 2 == 0 ? IOEither.left("Error") : IOEither.of("$a$i"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - - test('traverseIO', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseIO((a) { - sideEffect += 1; - return IO.of("$a"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - expect(result, ['1', '2', '3', '4', '5', '6']); - expect(sideEffect, list.length); - }); - - test('traverseIOWithIndex', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseIOWithIndex((a, i) { - sideEffect += 1; - return IO.of("$a$i"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - expect(result, ['10', '21', '32', '43', '54', '65']); - expect(sideEffect, list.length); - }); - - test('traverseTask', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTask( - (a) => Task( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return "$a"; - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, ['1', '2', '3', '4', '5', '6']); - expect(sideEffect, list.length); - }); - - test('traverseTaskWithIndex', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskWithIndex( - (a, i) => Task( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return "$a$i"; - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, ['10', '21', '32', '43', '54', '65']); - expect(sideEffect, list.length); - }); - - test('traverseTaskSeq', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskSeq( - (a) => Task( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a; - return "$a"; - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, ['1', '2', '3', '4', '5', '6']); - expect(sideEffect, 6); - }); - - test('traverseTaskWithIndexSeq', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskWithIndexSeq( - (a, i) => Task( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a + i; - return "$a$i"; - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, ['10', '21', '32', '43', '54', '65']); - expect(sideEffect, 11); - }); - - group('traverseIOOption', () { - test('Some', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseIOOption( - (a) => IOOption( - () { - sideEffect += 1; - return some("$a"); - }, - ), - ); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestSome((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, list.length); - }); - - test('None', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseIOOption( - (a) => IOOption( - () { - sideEffect += 1; - return a % 2 == 0 ? some("$a") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - - group('traverseTaskOptionWithIndex', () { - test('Some', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskOptionWithIndex( - (a, i) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some("$a$i"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, list.length); - }); - - test('None', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskOptionWithIndex( - (a, i) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return a % 2 == 0 ? some("$a$i") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - - group('traverseTaskOption', () { - test('Some', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskOption( - (a) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some("$a"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, list.length); - }); - - test('None', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskOption( - (a) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return a % 2 == 0 ? some("$a") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - - group('traverseTaskOptionWithIndex', () { - test('Some', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskOptionWithIndex( - (a, i) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some("$a$i"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, list.length); - }); - - test('None', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskOptionWithIndex( - (a, i) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return a % 2 == 0 ? some("$a$i") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - - group('traverseTaskOptionSeq', () { - test('Some', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskOptionSeq( - (a) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a - 1; - return some("$a"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, 5); - }); - - test('None', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskOptionSeq( - (a) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a - 1; - return a % 2 == 0 ? some("$a") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, 5); - }); - }); - - group('traverseTaskOptionWithIndexSeq', () { - test('Some', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskOptionWithIndexSeq( - (a, i) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a + i; - return some("$a$i"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, 11); - }); - - test('None', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskOptionWithIndexSeq( - (a, i) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a + i; - return a % 2 == 0 ? some("$a$i") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, 11); - }); - }); - - group('traverseTaskEither', () { - test('Right', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskEither( - (a) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return right("$a"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, list.length); - }); - - test('Left', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskEither( - (a) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return a % 2 == 0 - ? right("$a") - : left("Error"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - - group('traverseTaskEitherWithIndex', () { - test('Right', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskEitherWithIndex( - (a, i) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return right("$a$i"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, list.length); - }); - - test('Left', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskEitherWithIndex( - (a, i) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return a % 2 == 0 - ? right("$a$i") - : left("Error"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - - group('traverseTaskEitherSeq', () { - test('Right', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskEitherSeq( - (a) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a - 1; - return right("$a"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, 5); - }); - - test('Left', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskEitherSeq( - (a) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a - 1; - return a % 2 == 0 - ? right("$a") - : left("Error"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, 5); - }); - }); - - group('traverseTaskEitherWithIndexSeq', () { - test('Right', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskEitherWithIndexSeq( - (a, i) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a + i; - return right("$a$i"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, 11); - }); - - test('Left', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = list.traverseTaskEitherWithIndexSeq( - (a, i) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a + i; - return a % 2 == 0 - ? right("$a$i") - : left("Error"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, 11); - }); - }); - }); - - group('FpdartSequenceIterableOption', () { - group('sequenceOption', () { - test('Some', () { - final list = [some(1), some(2), some(3), some(4)]; - final result = list.sequenceOption(); - result.matchTestSome((t) { - expect(t, [1, 2, 3, 4]); - }); - }); - - test('None', () { - final list = [some(1), none(), some(3), some(4)]; - final result = list.sequenceOption(); - expect(result, isA()); - }); - }); - }); - - group('FpdartSequenceIterableIO', () { - test('sequenceIO', () { - var sideEffect = 0; - final list = [ - IO(() { - sideEffect += 1; - return 1; - }), - IO(() { - sideEffect += 1; - return 2; - }), - IO(() { - sideEffect += 1; - return 3; - }), - IO(() { - sideEffect += 1; - return 4; - }) - ]; - final traverse = list.sequenceIO(); - expect(sideEffect, 0); - final result = traverse.run(); - expect(result, [1, 2, 3, 4]); - expect(sideEffect, list.length); - }); - }); - - group('FpdartSequenceIterableTask', () { - test('sequenceTask', () async { - var sideEffect = 0; - final list = [ - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return 1; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return 2; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return 3; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return 4; - }), - ]; - final traverse = list.sequenceTask(); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, [1, 2, 3, 4]); - expect(sideEffect, list.length); - }); - - test('sequenceTaskSeq', () async { - var sideEffect = 0; - final list = [ - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect = 0; - return 1; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect = 1; - return 2; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect = 2; - return 3; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect = 3; - return 4; - }), - ]; - final traverse = list.sequenceTaskSeq(); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, [1, 2, 3, 4]); - expect(sideEffect, 3); - }); - }); - - group('FpdartSequenceIterableEither', () { - group('sequenceEither', () { - test('Right', () { - final list = [right(1), right(2), right(3), right(4)]; - final result = list.sequenceEither(); - result.matchTestRight((r) { - expect(r, [1, 2, 3, 4]); - }); - }); - - test('Left', () { - final list = [ - right(1), - left("Error"), - right(3), - right(4) - ]; - final result = list.sequenceEither(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - }); - }); - - test('rightsEither', () { - final list = [ - right(1), - right(2), - left('a'), - left('b'), - right(3), - ]; - final result = list.rightsEither(); - expect(result, [1, 2, 3]); - }); - - test('leftsEither', () { - final list = [ - right(1), - right(2), - left('a'), - left('b'), - right(3), - ]; - final result = list.leftsEither(); - expect(result, ['a', 'b']); - }); - - test('partitionEithersEither', () { - final list = [ - right(1), - right(2), - left('a'), - left('b'), - right(3), - ]; - final result = list.partitionEithersEither(); - expect(result.$1, ['a', 'b']); - expect(result.$2, [1, 2, 3]); - }); - }); - - group('FpdartSequenceIterableIOOption', () { - group('sequenceIOOption', () { - test('Some', () { - var sideEffect = 0; - final list = [ - IOOption(() { - sideEffect += 1; - return some(1); - }), - IOOption(() { - sideEffect += 1; - return some(2); - }), - IOOption(() { - sideEffect += 1; - return some(3); - }), - IOOption(() { - sideEffect += 1; - return some(4); - }), - ]; - final traverse = list.sequenceIOOption(); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestSome((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, list.length); - }); - - test('None', () { - var sideEffect = 0; - final list = [ - IOOption(() { - sideEffect += 1; - return some(1); - }), - IOOption(() { - sideEffect += 1; - return none(); - }), - IOOption(() { - sideEffect += 1; - return some(3); - }), - IOOption(() { - sideEffect += 1; - return some(4); - }), - ]; - final traverse = list.sequenceIOOption(); - expect(sideEffect, 0); - final result = traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - }); - - group('FpdartSequenceIterableTaskOption', () { - group('sequenceTaskOption', () { - test('Some', () async { - var sideEffect = 0; - final list = [ - TaskOption(() async { - sideEffect += 1; - return some(1); - }), - TaskOption(() async { - sideEffect += 1; - return some(2); - }), - TaskOption(() async { - sideEffect += 1; - return some(3); - }), - TaskOption(() async { - sideEffect += 1; - return some(4); - }), - ]; - final traverse = list.sequenceTaskOption(); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, list.length); - }); - - test('None', () async { - var sideEffect = 0; - final list = [ - TaskOption(() async { - sideEffect += 1; - return some(1); - }), - TaskOption(() async { - sideEffect += 1; - return none(); - }), - TaskOption(() async { - sideEffect += 1; - return some(3); - }), - TaskOption(() async { - sideEffect += 1; - return some(4); - }), - ]; - final traverse = list.sequenceTaskOption(); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - - group('sequenceTaskOptionSeq', () { - test('Some', () async { - var sideEffect = 0; - final list = [ - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 0; - return some(1); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 1; - return some(2); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 2; - return some(3); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 3; - return some(4); - }), - ]; - final traverse = list.sequenceTaskOptionSeq(); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, 3); - }); - - test('None', () async { - var sideEffect = 0; - final list = [ - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 0; - return some(1); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 1; - return none(); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 2; - return some(3); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 3; - return some(4); - }), - ]; - final traverse = list.sequenceTaskOptionSeq(); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, 3); - }); - }); - }); - - group('FpdartSequenceIterableTaskEither', () { - group('sequenceTaskEither', () { - test('Right', () async { - var sideEffect = 0; - final list = [ - TaskEither(() async { - sideEffect += 1; - return right(1); - }), - TaskEither(() async { - sideEffect += 1; - return right(2); - }), - TaskEither(() async { - sideEffect += 1; - return right(3); - }), - TaskEither(() async { - sideEffect += 1; - return right(4); - }), - ]; - final traverse = list.sequenceTaskEither(); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, list.length); - }); - - test('Left', () async { - var sideEffect = 0; - final list = [ - TaskEither(() async { - sideEffect += 1; - return right(1); - }), - TaskEither(() async { - sideEffect += 1; - return left("Error"); - }), - TaskEither(() async { - sideEffect += 1; - return right(3); - }), - TaskEither(() async { - sideEffect += 1; - return right(4); - }), - ]; - final traverse = list.sequenceTaskEither(); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - - group('sequenceTaskEitherSeq', () { - test('Right', () async { - var sideEffect = 0; - final list = [ - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 0; - return right(1); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 1; - return right(2); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 2; - return right(3); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 3; - return right(4); - }), - ]; - final traverse = list.sequenceTaskEitherSeq(); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, 3); - }); - - test('Left', () async { - var sideEffect = 0; - final list = [ - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 0; - return right(1); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 1; - return left("Error"); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 2; - return right(3); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 3; - return right(4); - }), - ]; - final traverse = list.sequenceTaskEitherSeq(); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, 3); - }); - }); - }); - - group('FpdartSequenceIterableIOEither', () { - group('sequenceIOEither', () { - test('Right', () { - var sideEffect = 0; - final list = [ - IOEither(() { - sideEffect += 1; - return right(1); - }), - IOEither(() { - sideEffect += 1; - return right(2); - }), - IOEither(() { - sideEffect += 1; - return right(3); - }), - IOEither(() { - sideEffect += 1; - return right(4); - }), - ]; - final traverse = list.sequenceIOEither(); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestRight((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, list.length); - }); - - test('Left', () { - var sideEffect = 0; - final list = [ - IOEither(() { - sideEffect += 1; - return right(1); - }), - IOEither(() { - sideEffect += 1; - return left("Error"); - }), - IOEither(() { - sideEffect += 1; - return right(3); - }), - IOEither(() { - sideEffect += 1; - return right(4); - }), - ]; - final traverse = list.sequenceIOEither(); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/extension/list_extension_test.dart b/packages/fpdart/test/src/extension/list_extension_test.dart deleted file mode 100644 index 8e3139ae..00000000 --- a/packages/fpdart/test/src/extension/list_extension_test.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import '../utils/utils.dart'; - -void main() { - group('FpdartOnList', () { - test('foldRight', () { - final list1 = [1, 2, 3]; - final ap = list1.foldRight(0.0, (t, b) => b - t); - expect(ap, 2); - }); - - test('foldRightWithIndex', () { - final list1 = [1, 2, 3]; - final ap = list1.foldRightWithIndex(0.0, (t, b, i) => b - t - i); - expect(ap, 1); - }); - - test('takeWhileRight', () { - final list1 = [1, 2, 3, 4]; - final ap = list1.takeWhileRight((t) => t > 2); - expect(ap.length, 2); - expect(ap.elementAt(0), 4); - expect(ap.elementAt(1), 3); - }); - - test('dropWhileRight', () { - final list1 = [1, 2, 3, 4]; - final ap = list1.dropWhileRight((t) => t > 2); - expect(ap.length, 2); - expect(ap.elementAt(0), 2); - expect(ap.elementAt(1), 1); - }); - }); -} diff --git a/packages/fpdart/test/src/extension/map_extension_test.dart b/packages/fpdart/test/src/extension/map_extension_test.dart deleted file mode 100644 index d9d80475..00000000 --- a/packages/fpdart/test/src/extension/map_extension_test.dart +++ /dev/null @@ -1,627 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import '../utils/utils.dart'; - -void main() { - group('FpdartOnMutableMap', () { - test('mapValue', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.mapValue((value) => '${value * 2}'), - {'a': '2', 'b': '4', 'c': '6', 'd': '8'}, - ); - }); - }); - - test('mapWithIndex', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.mapWithIndex((value, index) => '${value + index}'), - {'a': '1', 'b': '3', 'c': '5', 'd': '7'}, - ); - }); - }); - - test('filter', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.filter((t) => t > 2), - {'c': 3, 'd': 4}, - ); - }); - }); - - test('filterWithIndex', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.filterWithIndex((t, i) => t > 2 && i != 3), - {'c': 3}, - ); - }); - }); - - test('filterWithKey', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.filterWithKey((k, v) => v > 2 && k != 'd'), - {'c': 3}, - ); - }); - }); - - test('filterWithKeyAndIndex', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.filterWithKeyAndIndex((k, v, i) => v > 1 && i != 1 && k != 'd'), - {'c': 3}, - ); - }); - }); - - group('lookup', () { - test('Some', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - value.lookup('b').matchTestSome((t) { - expect(t, 2); - }); - }); - }); - - test('None', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect(value.lookup('e'), isA()); - }); - }); - }); - - group('lookupEq', () { - test('Some', () { - testImmutableMap({ - DateTime(2000, 1, 1): 1, - DateTime(2001, 1, 1): 2, - }, (value) { - value - .lookupEq(Eq.dateEqYear, DateTime(2000, 10, 10)) - .matchTestSome((t) { - expect(t, 1); - }); - }); - }); - - test('None', () { - testImmutableMap({ - DateTime(2000, 1, 1): 1, - DateTime(2001, 1, 1): 2, - }, (value) { - expect( - value.lookupEq(Eq.dateEqYear, DateTime(2002, 1, 1)), isA()); - }); - }); - }); - - group('lookupWithKeyEq', () { - test('Some', () { - testImmutableMap({ - DateTime(2000, 1, 1): 1, - DateTime(2001, 1, 1): 2, - }, (value) { - value - .lookupWithKeyEq( - Eq.dateEqYear, - DateTime(2000, 10, 10), - ) - .matchTestSome((t) { - expect(t, (DateTime(2000, 1, 1), 1)); - }); - }); - }); - - test('None', () { - testImmutableMap({ - DateTime(2000, 1, 1): 1, - DateTime(2001, 1, 1): 2, - }, (value) { - expect( - value.lookupWithKeyEq(Eq.dateEqYear, DateTime(2002, 1, 1)), - isA(), - ); - }); - }); - }); - - group('lookupWithKey', () { - test('Some', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - value.lookupWithKey('b').matchTestSome((t) { - expect(t.$1, 'b'); - expect(t.$2, 2); - }); - }); - }); - - test('None', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect(value.lookupWithKey('e'), isA()); - }); - }); - }); - - group('lookupKeyEq', () { - test('Some', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - value.lookupKeyEq(Eq.eqString, 'b').matchTestSome((t) { - expect(t, 'b'); - }); - }); - }); - - test('None', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect(value.lookupKeyEq(Eq.eqString, 'e'), isA()); - }); - }); - }); - - group('extract', () { - test('valid', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - value.extract('b').matchTestSome((t) { - expect(t, 2); - }); - }); - }); - - test('wrong type', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect(value.extract('b'), isA()); - }); - }); - }); - - group('extractMap', () { - test('no map', () { - testImmutableMap({'a': 1}, (value) { - expect(value.extractMap('a'), isA()); - }); - }); - - test('one level', () { - testImmutableMap({ - 'a': {'b': 2} - }, (value) { - expect(value.extractMap('a').toNullable(), equals({'b': 2})); - }); - }); - - test('two levels', () { - testImmutableMap({ - 'a': { - 'b': {'c': 3} - } - }, (value) { - expect(value.extractMap('a').extractMap('b').toNullable(), - equals({'c': 3})); - }); - }); - - test('two levels with extract', () { - testImmutableMap({ - 'a': { - 'b': {'c': 3} - } - }, (value) { - value - .extractMap('a') - .extractMap('b') - .extract('c') - .matchTestSome((t) { - expect(t, 3); - }); - }); - }); - }); - - group('modifyAt', () { - test('Some', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - value - .modifyAt( - Eq.instance((a1, a2) => a1 == a2), - (v) => v + 2, - 'b', - ) - .matchTestSome( - (t) => t.lookup('b').matchTestSome((t) { - expect(t, 4); - }), - ); - }); - }); - - test('None', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.modifyAt( - Eq.instance((a1, a2) => a1 == a2), - (v) => v + 2, - 'e', - ), - isA(), - ); - }); - }); - }); - - group('modifyAtIfPresent', () { - test('found', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - value - .modifyAtIfPresent( - Eq.instance((a1, a2) => a1 == a2), - (v) => v + 2, - 'b', - ) - .lookup('b') - .matchTestSome((t) { - expect(t, 4); - }); - }); - }); - - test('not found', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - value - .modifyAtIfPresent( - Eq.instance((a1, a2) => a1 == a2), - (v) => v + 2, - 'e', - ) - .lookup('b') - .matchTestSome((t) { - expect(t, 2); - }); - }); - }); - }); - - group('updateAt', () { - test('Some', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - value.updateAt(Eq.eqString, 'b', 10).matchTestSome( - (t) => t.lookup('b').matchTestSome((t) { - expect(t, 10); - }), - ); - }); - }); - - test('None', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect(value.updateAt(Eq.eqString, 'e', 10), isA()); - }); - }); - }); - - group('updateAtIfPresent', () { - test('found', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - value - .updateAtIfPresent(Eq.instance((a1, a2) => a1 == a2), 'b', 10) - .lookup('b') - .matchTestSome((t) { - expect(t, 10); - }); - }); - }); - - test('not found', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - value - .updateAtIfPresent(Eq.instance((a1, a2) => a1 == a2), 'e', 10) - .lookup('b') - .matchTestSome((t) { - expect(t, 2); - }); - }); - }); - }); - - test('deleteAt', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect(value.lookup('b'), isA()); - - final result = value.deleteAt(Eq.instance((a1, a2) => a1 == a2), 'b'); - expect(value.lookup('b'), isA()); - expect(result.lookup('b'), isA()); - }); - }); - - group('upsertAt', () { - test('insert', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect(value.lookup('e'), isA()); - - final result = - value.upsertAt(Eq.instance((a1, a2) => a1 == a2), 'e', 10); - expect(value.lookup('e'), isA()); - - result.lookup('e').matchTestSome((t) { - expect(t, 10); - }); - }); - }); - - test('update', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - value.lookupEq(Eq.eqString, 'b').matchTestSome((t) { - expect(t, 2); - }); - - final result = value.upsertAt(Eq.eqString, 'b', 10); - value.lookupEq(Eq.eqString, 'b').matchTestSome((t) { - expect(t, 2); - }); - result.lookupEq(Eq.eqString, 'b').matchTestSome((t) { - expect(t, 10); - }); - }); - }); - - test('modify by eq date year', () { - testImmutableMap({}, (value) { - final d1 = DateTime(2001, 1, 1); - final d2 = DateTime(2001, 1, 2); - - final result = value - .upsertAt( - Eq.dateEqYear, - d1, - 1, - ) - .upsertAt( - Eq.dateEqYear, - d2, - 2, - ); - - result.lookupEq(Eq.dateEqYear, d1).matchTestSome((t) { - expect(t, 2); - }); - result.lookupEq(Eq.dateEqYear, d2).matchTestSome((t) { - expect(t, 2); - }); - }); - }); - }); - - group('pop', () { - test('Some', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - final result = value.pop(Eq.instance((a1, a2) => a1 == a2), 'b'); - expect(value.lookup('b'), isA()); - - result.matchTestSome((t) { - expect(t.$1, 2); - expect(t.$2.lookup('b'), isA()); - }); - }); - }); - - test('None', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.pop(Eq.instance((a1, a2) => a1 == a2), 'e'), - isA(), - ); - }); - }); - }); - - test('foldLeft', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.foldLeft(Order.allEqual(), '', (acc, a) => '$acc$a'), - '1234', - ); - }); - }); - - test('foldLeftWithIndex', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.foldLeftWithIndex( - Order.allEqual(), '', (acc, a, i) => '$acc$a$i'), - '10213243', - ); - }); - }); - - test('foldLeftWithKey', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.foldLeftWithKey( - Order.allEqual(), '', (acc, k, v) => '$acc$k$v'), - 'a1b2c3d4', - ); - }); - }); - - test('foldLeftWithKeyAndIndex', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.foldLeftWithKeyAndIndex( - Order.allEqual(), '', (acc, k, v, i) => '$acc$k$v$i'), - 'a10b21c32d43', - ); - }); - }); - - test('foldRight', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.foldRight(Order.allEqual(), '', (a, acc) => '$acc$a'), - '4321', - ); - }); - }); - - test('foldRightWithIndex', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.foldRightWithIndex( - Order.allEqual(), '', (a, acc, i) => '$acc$a$i'), - '40312213', - ); - }); - }); - - test('foldRightWithKey', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.foldRightWithKey( - Order.allEqual(), '', (k, v, acc) => '$acc$k$v'), - 'd4c3b2a1', - ); - }); - }); - - test('foldRightWithKeyAndIndex', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect( - value.foldRightWithKeyAndIndex( - Order.allEqual(), '', (k, v, acc, i) => '$acc$k$v$i'), - 'd40c31b22a13', - ); - }); - }); - - test('size', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - expect(value.size, 4); - }); - }); - - test('toSortedList', () { - testImmutableMap({'c': 3, 'd': 4, 'a': 1, 'b': 2}, (value) { - final result = - value.toSortedList(Order.from((a1, a2) => a1.compareTo(a2))); - expect(result.elementAt(0).value, 1); - expect(result.elementAt(1).value, 2); - expect(result.elementAt(2).value, 3); - expect(result.elementAt(3).value, 4); - expect(result.elementAt(0).key, 'a'); - expect(result.elementAt(1).key, 'b'); - expect(result.elementAt(2).key, 'c'); - expect(result.elementAt(3).key, 'd'); - }); - }); - - test('union', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value1) { - testImmutableMap({'c': 20, 'e': 10}, (value2) { - final ap = value1.union( - Eq.instance((a1, a2) => a1 == a2), - (x, y) => x + y, - value2, - ); - - expect(ap['a'], 1); - expect(ap['b'], 2); - expect(ap['c'], 23); - expect(ap['d'], 4); - expect(ap['e'], 10); - }); - }); - }); - - test('intersection', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value1) { - testImmutableMap({'c': 20, 'e': 10}, (value2) { - final ap = value1.intersection( - Eq.instance((a1, a2) => a1 == a2), - (x, y) => x + y, - value2, - ); - - expect(ap['a'], null); - expect(ap['b'], null); - expect(ap['c'], 23); - expect(ap['d'], null); - expect(ap['e'], null); - }); - }); - }); - - group('isSubmap', () { - test('true', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value1) { - testImmutableMap({'a': 1, 'c': 3}, (value2) { - final result = value2.isSubmap( - Eq.eqString, - Eq.eqInt, - value1, - ); - - expect(result, true); - }); - }); - }); - - test('false (value)', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value1) { - testImmutableMap({'a': 1, 'c': 2}, (value2) { - final result = value2.isSubmap( - Eq.eqString, - Eq.eqInt, - value1, - ); - - expect(result, false); - }); - }); - }); - - test('false (key)', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value1) { - testImmutableMap({'a': 1, 'd': 3}, (value2) { - final result = value2.isSubmap( - Eq.eqString, - Eq.eqInt, - value1, - ); - - expect(result, false); - }); - }); - }); - }); - - test('collect', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value) { - final result = value.collect( - Order.from( - (a1, a2) => a1.compareTo(a2), - ), - (k, v) => '$k$v', - ); - - expect(result.elementAt(0), 'a1'); - expect(result.elementAt(1), 'b2'); - expect(result.elementAt(2), 'c3'); - expect(result.elementAt(3), 'd4'); - }); - }); - - test('difference', () { - testImmutableMap({'a': 1, 'b': 2, 'c': 3, 'd': 4}, (value1) { - testImmutableMap({'a': 1, 'c': 3}, (value2) { - final result = value1.difference(Eq.eqString, value2); - expect(result['a'], null); - expect(result['b'], 2); - expect(result['c'], null); - expect(result['d'], 4); - }); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/extension/option_extension_test.dart b/packages/fpdart/test/src/extension/option_extension_test.dart deleted file mode 100644 index 17344938..00000000 --- a/packages/fpdart/test/src/extension/option_extension_test.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import '../utils/utils.dart'; - -void main() { - group('FpdartOnOption', () { - group('alt', () { - test('Some', () { - final option = Option.of(10); - final value = option.alt(() => Option.of(0)); - value.matchTestSome((some) => expect(some, 10)); - }); - - test('None', () { - final option = Option.none(); - final value = option.alt(() => Option.of(0)); - value.matchTestSome((some) => expect(some, 0)); - }); - }); - - group('getOrElse', () { - test('Some', () { - final option = Option.of(10); - final value = option.getOrElse(() => 0); - expect(value, 10); - }); - - test('None', () { - final option = Option.none(); - final value = option.getOrElse(() => 0); - expect(value, 0); - }); - }); - - test('elem', () { - final m1 = Option.of(10); - final m2 = Option.none(); - final eq = Eq.instance((a1, a2) => a1 == a2); - expect(m1.elem(10, eq), true); - expect(m1.elem(9, eq), false); - expect(m2.elem(10, eq), false); - }); - }); -} diff --git a/packages/fpdart/test/src/extension/predicate_extension_test.dart b/packages/fpdart/test/src/extension/predicate_extension_test.dart deleted file mode 100644 index 5d1c79d7..00000000 --- a/packages/fpdart/test/src/extension/predicate_extension_test.dart +++ /dev/null @@ -1,90 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:glados/glados.dart'; - -void main() { - group('Predicate extension', () { - group('FpdartOnPredicate', () { - Glados(any.bool).test('negate', (boolValue) { - bool fun() => boolValue; - expect(fun(), !fun.negate); - }); - - test('and', () { - bool funTrue() => true; - bool funFalse() => false; - expect(funTrue.and(funTrue)(), true); - expect(funTrue.and(funFalse)(), false); - expect(funFalse.and(funTrue)(), false); - expect(funFalse.and(funFalse)(), false); - }); - - test('or', () { - bool funTrue() => true; - bool funFalse() => false; - expect(funTrue.or(funTrue)(), true); - expect(funTrue.or(funFalse)(), true); - expect(funFalse.or(funTrue)(), true); - expect(funFalse.or(funFalse)(), false); - }); - - test('xor', () { - bool funTrue() => true; - bool funFalse() => false; - expect(funTrue.xor(funTrue)(), false); - expect(funTrue.xor(funFalse)(), true); - expect(funFalse.xor(funTrue)(), true); - expect(funFalse.xor(funFalse)(), false); - }); - }); - - group('FpdartOnPredicate1', () { - Glados(any.int).test('negate', (intValue) { - bool fun(int n) => n % 2 == 0; - expect(fun(intValue), !fun.negate(intValue)); - }); - - test('and', () { - bool fun2(int n) => n % 2 == 0; - bool fun3(int n) => n % 3 == 0; - expect(fun2.and(fun2)(4), true); - expect(fun2.and(fun3)(4), false); - expect(fun2.and(fun3)(6), true); - expect(fun3.and(fun2)(4), false); - expect(fun3.and(fun3)(3), true); - }); - - test('or', () { - bool fun2(int n) => n % 2 == 0; - bool fun3(int n) => n % 3 == 0; - expect(fun2.or(fun2)(4), true); - expect(fun2.or(fun3)(4), true); - expect(fun2.or(fun3)(6), true); - expect(fun3.or(fun2)(4), true); - expect(fun3.or(fun2)(7), false); - expect(fun3.or(fun3)(7), false); - }); - - test('xor', () { - bool fun2(int n) => n % 2 == 0; - bool fun3(int n) => n % 3 == 0; - expect(fun2.xor(fun2)(4), false); - expect(fun2.xor(fun3)(4), true); - expect(fun2.xor(fun3)(6), false); - expect(fun3.xor(fun2)(4), true); - expect(fun3.xor(fun3)(3), false); - expect(fun3.xor(fun2)(7), false); - }); - - test('contramap', () { - bool even(int n) => n % 2 == 0; - final evenLength = even.contramap((a) => a.length); - expect(evenLength("abc"), false); - expect(evenLength("abcd"), true); - expect(evenLength("a"), false); - expect(evenLength("ab"), true); - expect(evenLength("abcde"), false); - expect(evenLength("abcdef"), true); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/extension/string_extension_test.dart b/packages/fpdart/test/src/extension/string_extension_test.dart deleted file mode 100644 index af54be4e..00000000 --- a/packages/fpdart/test/src/extension/string_extension_test.dart +++ /dev/null @@ -1,858 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -import '../utils/match_utils.dart'; - -void main() { - group('FpdartOnString', () { - group('toNumOption', () { - group('Some', () { - test('"10"', () { - final result = "10".toNumOption; - result.matchTestSome((t) { - expect(t, 10); - }); - }); - - test('"10.0"', () { - final result = "10.0".toNumOption; - result.matchTestSome((t) { - expect(t, 10.0); - }); - }); - - test('"10.5"', () { - final result = "10.5".toNumOption; - result.matchTestSome((t) { - expect(t, 10.5); - }); - }); - - test('"10.512"', () { - final result = "10.512".toNumOption; - result.matchTestSome((t) { - expect(t, 10.512); - }); - }); - - test('" 10 "', () { - final result = " 10 ".toNumOption; - result.matchTestSome((t) { - expect(t, 10); - }); - }); - - test('"-10"', () { - final result = "-10".toNumOption; - result.matchTestSome((t) { - expect(t, -10); - }); - }); - - test('" 3.14 \xA0"', () { - final result = " 3.14 \xA0".toNumOption; - result.matchTestSome((t) { - expect(t, 3.14); - }); - }); - - test('"0."', () { - final result = "0.".toNumOption; - result.matchTestSome((t) { - expect(t, 0); - }); - }); - - test('".0"', () { - final result = ".0".toNumOption; - result.matchTestSome((t) { - expect(t, 0); - }); - }); - - test('"-1.e3"', () { - final result = "-1.e3".toNumOption; - result.matchTestSome((t) { - expect(t, -1000); - }); - }); - - test('"1234E+7"', () { - final result = "1234E+7".toNumOption; - result.matchTestSome((t) { - expect(t, 12340000000); - }); - }); - - test('"0xFF"', () { - final result = "0xFF".toNumOption; - result.matchTestSome((t) { - expect(t, 255); - }); - }); - }); - - group('None', () { - test('"- 10"', () { - final result = "- 10".toNumOption; - expect(result, isA()); - }); - - test('"10,0"', () { - final result = "10,0".toNumOption; - expect(result, isA()); - }); - - test('"10a"', () { - final result = "10a".toNumOption; - expect(result, isA()); - }); - - test('"none"', () { - final result = "none".toNumOption; - expect(result, isA()); - }); - - test('"10.512a"', () { - final result = "10.512a".toNumOption; - expect(result, isA()); - }); - - test('"1f"', () { - final result = "1f".toNumOption; - expect(result, isA()); - }); - }); - }); - - group('toIntOption', () { - group('Some', () { - test('"10"', () { - final result = "10".toIntOption; - result.matchTestSome((t) { - expect(t, 10); - }); - }); - - test('"-10"', () { - final result = "-10".toIntOption; - result.matchTestSome((t) { - expect(t, -10); - }); - }); - - test('" 10 "', () { - final result = " 10 ".toIntOption; - result.matchTestSome((t) { - expect(t, 10); - }); - }); - - test('"0xFF"', () { - final result = "0xFF".toIntOption; - result.matchTestSome((t) { - expect(t, 255); - }); - }); - }); - - group('None', () { - test('"- 10"', () { - final result = "- 10".toIntOption; - expect(result, isA()); - }); - - test('"-1.e3"', () { - final result = "-1.e3".toIntOption; - expect(result, isA()); - }); - - test('"1234E+7"', () { - final result = "1234E+7".toIntOption; - expect(result, isA()); - }); - - test('"0."', () { - final result = "0.".toIntOption; - expect(result, isA()); - }); - - test('"10.5"', () { - final result = "10.5".toIntOption; - expect(result, isA()); - }); - - test('"10.0"', () { - final result = "10.0".toIntOption; - expect(result, isA()); - }); - - test('"10.512"', () { - final result = "10.512".toIntOption; - expect(result, isA()); - }); - - test('" 3.14 \xA0"', () { - final result = " 3.14 \xA0".toIntOption; - expect(result, isA()); - }); - - test('".0"', () { - final result = ".0".toIntOption; - expect(result, isA()); - }); - - test('"10,0"', () { - final result = "10,0".toIntOption; - expect(result, isA()); - }); - - test('"10a"', () { - final result = "10a".toIntOption; - expect(result, isA()); - }); - - test('"none"', () { - final result = "none".toIntOption; - expect(result, isA()); - }); - - test('"10.512a"', () { - final result = "10.512a".toIntOption; - expect(result, isA()); - }); - - test('"1f"', () { - final result = "1f".toIntOption; - expect(result, isA()); - }); - }); - }); - - group('toDoubleOption', () { - group('Some', () { - test('"10"', () { - final result = "10".toDoubleOption; - result.matchTestSome((t) { - expect(t, 10.0); - }); - }); - - test('"10.0"', () { - final result = "10.0".toDoubleOption; - result.matchTestSome((t) { - expect(t, 10.0); - }); - }); - - test('"10.5"', () { - final result = "10.5".toDoubleOption; - result.matchTestSome((t) { - expect(t, 10.5); - }); - }); - - test('"10.512"', () { - final result = "10.512".toDoubleOption; - result.matchTestSome((t) { - expect(t, 10.512); - }); - }); - - test('" 10 "', () { - final result = " 10 ".toDoubleOption; - result.matchTestSome((t) { - expect(t, 10.0); - }); - }); - - test('"-10"', () { - final result = "-10".toDoubleOption; - result.matchTestSome((t) { - expect(t, -10.0); - }); - }); - - test('" 3.14 \xA0"', () { - final result = " 3.14 \xA0".toDoubleOption; - result.matchTestSome((t) { - expect(t, 3.14); - }); - }); - - test('"0."', () { - final result = "0.".toDoubleOption; - result.matchTestSome((t) { - expect(t, 0.0); - }); - }); - - test('".0"', () { - final result = ".0".toDoubleOption; - result.matchTestSome((t) { - expect(t, 0.0); - }); - }); - - test('"-1.e3"', () { - final result = "-1.e3".toDoubleOption; - result.matchTestSome((t) { - expect(t, -1000.0); - }); - }); - - test('"1234E+7"', () { - final result = "1234E+7".toDoubleOption; - result.matchTestSome((t) { - expect(t, 12340000000.0); - }); - }); - }); - - group('None', () { - test('"0xFF"', () { - final result = "0xFF".toDoubleOption; - expect(result, isA()); - }); - - test('"- 10"', () { - final result = "- 10".toDoubleOption; - expect(result, isA()); - }); - - test('"10,0"', () { - final result = "10,0".toDoubleOption; - expect(result, isA()); - }); - - test('"10a"', () { - final result = "10a".toDoubleOption; - expect(result, isA()); - }); - - test('"none"', () { - final result = "none".toDoubleOption; - expect(result, isA()); - }); - - test('"10.512a"', () { - final result = "10.512a".toDoubleOption; - expect(result, isA()); - }); - - test('"1f"', () { - final result = "1f".toDoubleOption; - expect(result, isA()); - }); - }); - }); - - group('toBoolOption', () { - group('Some', () { - test('"true"', () { - final result = "true".toBoolOption; - result.matchTestSome((t) { - expect(t, true); - }); - }); - - test('"false"', () { - final result = "false".toBoolOption; - result.matchTestSome((t) { - expect(t, false); - }); - }); - }); - - group('None', () { - test('"TRUE"', () { - final result = "TRUE".toBoolOption; - expect(result, isA()); - }); - - test('"FALSE"', () { - final result = "FALSE".toBoolOption; - expect(result, isA()); - }); - - test('"NO"', () { - final result = "NO".toBoolOption; - expect(result, isA()); - }); - - test('"YES"', () { - final result = "YES".toBoolOption; - expect(result, isA()); - }); - - test('"0"', () { - final result = "0".toBoolOption; - expect(result, isA()); - }); - - test('"1"', () { - final result = "1".toBoolOption; - expect(result, isA()); - }); - }); - }); - - group('toNumEither', () { - group('Right', () { - test('"10"', () { - final result = "10".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10); - }); - }); - - test('"10.0"', () { - final result = "10.0".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10.0); - }); - }); - - test('"10.5"', () { - final result = "10.5".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10.5); - }); - }); - - test('"10.512"', () { - final result = "10.512".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10.512); - }); - }); - - test('" 10 "', () { - final result = " 10 ".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10); - }); - }); - - test('"-10"', () { - final result = "-10".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, -10); - }); - }); - - test('" 3.14 \xA0"', () { - final result = " 3.14 \xA0".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, 3.14); - }); - }); - - test('"0."', () { - final result = "0.".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, 0); - }); - }); - - test('".0"', () { - final result = ".0".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, 0); - }); - }); - - test('"-1.e3"', () { - final result = "-1.e3".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, -1000); - }); - }); - - test('"1234E+7"', () { - final result = "1234E+7".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, 12340000000); - }); - }); - - test('"0xFF"', () { - final result = "0xFF".toNumEither(() => "left"); - result.matchTestRight((t) { - expect(t, 255); - }); - }); - }); - - group('Left', () { - test('"- 10"', () { - final result = "- 10".toNumEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10,0"', () { - final result = "10,0".toNumEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10a"', () { - final result = "10a".toNumEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"none"', () { - final result = "none".toNumEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10.512a"', () { - final result = "10.512a".toNumEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"1f"', () { - final result = "1f".toNumEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - }); - }); - - group('toIntEither', () { - group('Some', () { - test('"10"', () { - final result = "10".toIntEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10); - }); - }); - - test('"-10"', () { - final result = "-10".toIntEither(() => "left"); - result.matchTestRight((t) { - expect(t, -10); - }); - }); - - test('" 10 "', () { - final result = " 10 ".toIntEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10); - }); - }); - - test('"0xFF"', () { - final result = "0xFF".toIntEither(() => "left"); - result.matchTestRight((t) { - expect(t, 255); - }); - }); - }); - - group('None', () { - test('"- 10"', () { - final result = "- 10".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"-1.e3"', () { - final result = "-1.e3".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"1234E+7"', () { - final result = "1234E+7".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"0."', () { - final result = "0.".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10.5"', () { - final result = "10.5".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10.0"', () { - final result = "10.0".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10.512"', () { - final result = "10.512".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('" 3.14 \xA0"', () { - final result = " 3.14 \xA0".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('".0"', () { - final result = ".0".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10,0"', () { - final result = "10,0".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10a"', () { - final result = "10a".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"none"', () { - final result = "none".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10.512a"', () { - final result = "10.512a".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"1f"', () { - final result = "1f".toIntEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - }); - }); - - group('toDoubleEither', () { - group('Some', () { - test('"10"', () { - final result = "10".toDoubleEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10.0); - }); - }); - - test('"10.0"', () { - final result = "10.0".toDoubleEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10.0); - }); - }); - - test('"10.5"', () { - final result = "10.5".toDoubleEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10.5); - }); - }); - - test('"10.512"', () { - final result = "10.512".toDoubleEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10.512); - }); - }); - - test('" 10 "', () { - final result = " 10 ".toDoubleEither(() => "left"); - result.matchTestRight((t) { - expect(t, 10.0); - }); - }); - - test('"-10"', () { - final result = "-10".toDoubleEither(() => "left"); - result.matchTestRight((t) { - expect(t, -10.0); - }); - }); - - test('" 3.14 \xA0"', () { - final result = " 3.14 \xA0".toDoubleEither(() => "left"); - result.matchTestRight((t) { - expect(t, 3.14); - }); - }); - - test('"0."', () { - final result = "0.".toDoubleEither(() => "left"); - result.matchTestRight((t) { - expect(t, 0.0); - }); - }); - - test('".0"', () { - final result = ".0".toDoubleEither(() => "left"); - result.matchTestRight((t) { - expect(t, 0.0); - }); - }); - - test('"-1.e3"', () { - final result = "-1.e3".toDoubleEither(() => "left"); - result.matchTestRight((t) { - expect(t, -1000.0); - }); - }); - - test('"1234E+7"', () { - final result = "1234E+7".toDoubleEither(() => "left"); - result.matchTestRight((t) { - expect(t, 12340000000.0); - }); - }); - }); - - group('None', () { - test('"0xFF"', () { - final result = "0xFF".toDoubleEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"- 10"', () { - final result = "- 10".toDoubleEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10,0"', () { - final result = "10,0".toDoubleEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10a"', () { - final result = "10a".toDoubleEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"none"', () { - final result = "none".toDoubleEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"10.512a"', () { - final result = "10.512a".toDoubleEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"1f"', () { - final result = "1f".toDoubleEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - }); - }); - - group('toBoolEither', () { - group('Some', () { - test('"true"', () { - final result = "true".toBoolEither(() => "left"); - result.matchTestRight((t) { - expect(t, true); - }); - }); - - test('"false"', () { - final result = "false".toBoolEither(() => "left"); - result.matchTestRight((t) { - expect(t, false); - }); - }); - }); - - group('None', () { - test('"TRUE"', () { - final result = "TRUE".toBoolEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"FALSE"', () { - final result = "FALSE".toBoolEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"NO"', () { - final result = "NO".toBoolEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"YES"', () { - final result = "YES".toBoolEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"0"', () { - final result = "0".toBoolEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - - test('"1"', () { - final result = "1".toBoolEither(() => "left"); - result.matchTestLeft((t) { - expect(t, "left"); - }); - }); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/function_test.dart b/packages/fpdart/test/src/function_test.dart deleted file mode 100644 index 8093408c..00000000 --- a/packages/fpdart/test/src/function_test.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:glados/glados.dart'; - -void main() { - group('function', () { - group('[Property-based testing]', () { - Glados(any.letterOrDigits).test('identity', (stringValue) { - expect(identity(stringValue), stringValue); - }); - - Glados(any.letterOrDigits).test('constF', (stringValue) { - final fun = constF(10); - expect(fun(stringValue), 10); - }); - - Glados(any.letterOrDigits).test('identityFuture', (stringValue) async { - final id = await identityFuture(stringValue); - expect(id, stringValue); - }); - - Glados(any.letterOrDigits).test('toNumOption (same as extension)', - (stringValue) { - expect(stringValue.toNumOption, toNumOption(stringValue)); - }); - - Glados(any.letterOrDigits).test('toIntOption (same as extension)', - (stringValue) { - expect(stringValue.toIntOption, toIntOption(stringValue)); - }); - - Glados(any.letterOrDigits).test('toDoubleOption (same as extension)', - (stringValue) { - expect(stringValue.toDoubleOption, toDoubleOption(stringValue)); - }); - - Glados(any.letterOrDigits).test('toBoolOption (same as extension)', - (stringValue) { - expect(stringValue.toBoolOption, toBoolOption(stringValue)); - }); - - Glados(any.letterOrDigits).test('toNumEither (same as extension)', - (stringValue) { - expect(stringValue.toNumEither(() => "left"), - toNumEither(() => "left")(stringValue)); - }); - - Glados(any.letterOrDigits).test('toIntEither (same as extension)', - (stringValue) { - expect(stringValue.toIntEither(() => "left"), - toIntEither(() => "left")(stringValue)); - }); - - Glados(any.letterOrDigits).test('toDoubleEither (same as extension)', - (stringValue) { - expect(stringValue.toDoubleEither(() => "left"), - toDoubleEither(() => "left")(stringValue)); - }); - - Glados(any.letterOrDigits).test('toBoolEither (same as extension)', - (stringValue) { - expect(stringValue.toBoolEither(() => "left"), - toBoolEither(stringValue, () => "left")); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/group_test.dart b/packages/fpdart/test/src/group_test.dart deleted file mode 100644 index a4ddfaf7..00000000 --- a/packages/fpdart/test/src/group_test.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('Group', () { - group('is a', () { - final instance = Group.instance(0, (a1, a2) => a1 + a2, (a) => -a); - - test('Semigroup', () { - expect(instance, isA()); - }); - - test('Monoid', () { - expect(instance, isA()); - }); - }); - - test('inverse', () { - final instance = Group.instance(0, (a1, a2) => a1 + a2, (a) => -a); - expect(instance.inverse(1), -1); - expect(instance.combine(1, instance.inverse(1)), instance.empty); - expect(instance.combine(instance.inverse(1), 1), instance.empty); - }); - - test('remove', () { - final instance = Group.instance(0, (a1, a2) => a1 + a2, (a) => -a); - expect(instance.remove(1, 2), -1); - expect(instance.remove(2, 1), 1); - expect(instance.remove(1, 1), instance.empty); - expect(instance.remove(1, 2), instance.combine(1, instance.inverse(2))); - }); - - test('combineN', () { - final instance = Group.instance(0, (a1, a2) => a1 + a2, (a) => -a); - expect(instance.combineN(1, 2), 2); - expect(instance.combineN(1, 1), 1); - expect(instance.combineN(1, 0), instance.empty); - expect(instance.combineN(1, -1), -1); - expect(instance.combineN(1, -2), -2); - - // Stack Overflow! - // expect(instance.combineN(2, 9223372036854775807), 2); - }); - }); -} diff --git a/packages/fpdart/test/src/hash_test.dart b/packages/fpdart/test/src/hash_test.dart deleted file mode 100644 index 89de271f..00000000 --- a/packages/fpdart/test/src/hash_test.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('Hash', () { - group('is a', () { - final instance = Hash.fromUniversalHashCode(); - - test('Eq', () { - expect(instance, isA()); - }); - }); - - test('.fromUniversalHashCode', () { - const source1 = 1; - const source2 = 1; - final instance = Hash.fromUniversalHashCode(); - expect(instance.hash(source1), source1.hashCode); - expect(instance.eqv(source1, source2), true); - expect(instance.hash(source1), instance.hash(source2)); - }); - }); -} diff --git a/packages/fpdart/test/src/io_either_test.dart b/packages/fpdart/test/src/io_either_test.dart deleted file mode 100644 index d553977c..00000000 --- a/packages/fpdart/test/src/io_either_test.dart +++ /dev/null @@ -1,774 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import './utils/utils.dart'; - -void main() { - group('IOEither', () { - group('tryCatch', () { - test('Success', () { - final task = - IOEither.tryCatch(() => 10, (_, __) => 'error'); - final r = task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Failure', () { - final task = IOEither.tryCatch(() { - throw UnimplementedError(); - }, (_, __) => 'error'); - final r = task.run(); - r.match((l) => expect(l, 'error'), (_) { - fail('should be left'); - }); - }); - - test('throws Exception', () { - final task = IOEither.tryCatch(() { - throw UnimplementedError(); - }, (error, _) { - expect(error, isA()); - return 'error'; - }); - final r = task.run(); - r.match((l) => expect(l, 'error'), (_) { - fail('should be left'); - }); - }); - }); - - group('flatMap', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ap = - task.flatMap((r) => IOEither(() => Either.of(r + 10))); - final r = ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 20)); - }); - - test('Left', () { - final task = IOEither(() => Either.left('abc')); - final ap = - task.flatMap((r) => IOEither(() => Either.of(r + 10))); - final r = ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('flatMapTask', () { - test('Right to Right', () async { - final task = IOEither(() => Either.of(10)); - final ap = task.flatMapTask((r) => TaskEither.of(r + 1)); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 11)); - }); - - test('Left to Right', () async { - final task = IOEither(() => Either.left('abc')); - final ap = task.flatMapTask((r) => TaskEither.of(r + 1)); - final r = await ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - - test('Right to Left', () async { - final task = IOEither(() => Either.of(10)); - final ap = - task.flatMapTask((r) => TaskEither.left('none')); - final r = await ap.run(); - r.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - - test('Left to Left', () async { - final task = IOEither(() => Either.left('abc')); - final ap = - task.flatMapTask((r) => TaskEither.left('none')); - final r = await ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('toTaskEither', () { - test('Some', () async { - final task = IOEither(() => Either.of(10)); - final convert = task.toTaskEither(); - final r = await convert.run(); - r.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('None', () async { - final task = IOEither(() => Either.left('None')); - final convert = task.toTaskEither(); - final r = await convert.run(); - r.matchTestLeft((l) { - expect(l, 'None'); - }); - }); - }); - - group('ap', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ap = task.ap(IOEither(() => Either.of((int c) => c / 2))); - final r = ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 5.0)); - }); - - test('Left', () { - final task = IOEither(() => Either.left('abc')); - final ap = task.ap(IOEither(() => Either.of((int c) => c / 2))); - final r = ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('map', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ap = task.map((r) => r / 2); - final r = ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 5.0)); - }); - - test('Left', () { - final task = IOEither(() => Either.left('abc')); - final ap = task.map((r) => r / 2); - final r = ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('mapLeft', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ap = task.mapLeft((l) => l.length); - final r = ap.run(); - r.matchTestRight((r) => expect(r, 10)); - }); - - test('Left', () { - final task = IOEither(() => Either.left('abc')); - final ap = task.mapLeft((l) => l.length); - final r = ap.run(); - r.matchTestLeft((l) => expect(l, 3)); - }); - }); - - group('bimap', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ap = task.bimap((l) => l.length, (r) => r / 2); - final r = ap.run(); - r.matchTestRight((r) => expect(r, 5.0)); - }); - - test('Left', () { - final task = IOEither(() => Either.left('abc')); - final ap = task.bimap((l) => l.length, (r) => r / 2); - final r = ap.run(); - r.matchTestLeft((l) => expect(l, 3)); - }); - }); - - group('map2', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ap = task.map2( - IOEither(() => Either.of(2)), (b, c) => b / c); - final r = ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 5.0)); - }); - - test('Left', () { - final task = IOEither(() => Either.left('abc')); - final ap = task.map2( - IOEither(() => Either.of(2)), (b, c) => b / c); - final r = ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('map3', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ap = task.map3( - IOEither(() => Either.of(2)), - IOEither(() => Either.of(5)), - (b, c, d) => b * c / d); - final r = ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 4.0)); - }); - - test('Left', () { - final task = IOEither(() => Either.left('abc')); - final ap = task.map3( - IOEither(() => Either.of(2)), - IOEither(() => Either.of(5)), - (b, c, d) => b * c / d); - final r = ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('andThen', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ap = - task.andThen(() => IOEither(() => Either.of(12.5))); - final r = ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 12.5)); - }); - - test('Left', () { - final task = IOEither(() => Either.left('abc')); - final ap = - task.andThen(() => IOEither(() => Either.of(12.5))); - final r = ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('call', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ap = task(IOEither(() => Either.of(12.5))); - final r = ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 12.5)); - }); - - test('Left', () { - final task = IOEither(() => Either.left('abc')); - final ap = task(IOEither(() => Either.of(12.5))); - final r = ap.run(); - r.match((r) { - expect(r, 'abc'); - }, (_) { - fail('should be left'); - }); - }); - }); - - group('filterOrElse', () { - test('Right (true)', () { - final task = IOEither(() => Either.of(10)); - final ap = task.filterOrElse((r) => r > 5, (r) => 'abc'); - final r = ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Right (false)', () { - final task = IOEither(() => Either.of(10)); - final ap = task.filterOrElse((r) => r < 5, (r) => 'none'); - final r = ap.run(); - r.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - - test('Left', () { - final task = IOEither(() => Either.left('abc')); - final ap = task.filterOrElse((r) => r > 5, (r) => 'none'); - final r = ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - test('pure', () { - final task = IOEither(() => Either.left('abc')); - final ap = task.pure('abc'); - final r = ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 'abc')); - }); - - test('run', () { - final task = IOEither(() => Either.of(10)); - final func = task.run(); - expect(func, isA>()); - final r = func; - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - group('fromEither', () { - test('Right', () { - final task = IOEither.fromEither(Either.of(10)); - final r = task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () { - final task = IOEither.fromEither(Either.left('error')); - final r = task.run(); - r.match((l) => expect(l, 'error'), (_) { - fail('should be left'); - }); - }); - }); - - group('fromOption', () { - test('Some', () { - final task = - IOEither.fromOption(Option.of(10), () => 'none'); - final r = task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('None', () { - final task = - IOEither.fromOption(Option.none(), () => 'none'); - final r = task.run(); - r.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('fromNullable', () { - test('Right', () { - final task = IOEither.fromNullable(10, () => "Error"); - final result = task.run(); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('Left', () { - final task = IOEither.fromNullable(null, () => "Error"); - final result = task.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - }); - }); - - group('fromPredicate', () { - test('True', () { - final task = - IOEither.fromPredicate(20, (n) => n > 10, (n) => '$n'); - final r = task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 20)); - }); - - test('False', () { - final task = - IOEither.fromPredicate(10, (n) => n > 10, (n) => '$n'); - final r = task.run(); - r.match((l) => expect(l, '10'), (_) { - fail('should be left'); - }); - }); - }); - - test('fromIO', () { - final task = IOEither.fromIO(IO(() => 10)); - final r = task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('left', () { - final task = IOEither.left('none'); - final r = task.run(); - r.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - - test('right', () { - final task = IOEither.right(10); - final r = task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('leftTask', () { - final task = IOEither.leftIO(IO(() => 'none')); - final r = task.run(); - r.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - - test('rightTask', () { - final task = IOEither.rightIO(IO.of(10)); - final r = task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - group('match', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ex = task.match((l) => l.length, (r) => r + 10); - final r = ex.run(); - expect(r, 20); - }); - - test('Left', () { - final task = IOEither(() => Either.left('none')); - final ex = task.match((l) => l.length, (r) => r + 10); - final r = ex.run(); - expect(r, 4); - }); - }); - - group('getOrElse', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ex = task.getOrElse((l) => l.length); - final r = ex.run(); - expect(r, 10); - }); - - test('Left', () { - final task = IOEither(() => Either.left('none')); - final ex = task.getOrElse((l) => l.length); - final r = ex.run(); - expect(r, 4); - }); - }); - - group('orElse', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ex = task.orElse((l) => IOEither(() => Right(l.length))); - final r = ex.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () { - final task = IOEither(() => Either.left('none')); - final ex = task.orElse((l) => IOEither(() => Right(l.length))); - final r = ex.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 4)); - }); - }); - - group('alt', () { - test('Right', () { - final task = IOEither(() => Either.of(10)); - final ex = task.alt(() => IOEither(() => Either.of(20))); - final r = ex.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () { - final task = IOEither(() => Either.left('none')); - final ex = task.alt(() => IOEither(() => Either.of(20))); - final r = ex.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 20)); - }); - }); - - test('swap', () { - final task = IOEither(() => Either.of(10)); - final ex = task.swap(); - final r = ex.run(); - r.match((l) => expect(l, 10), (_) { - fail('should be left'); - }); - }); - - test('of', () { - final task = IOEither.of(10); - final r = task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('flatten', () { - final task = IOEither>.of( - IOEither.of(10)); - final ap = IOEither.flatten(task); - final r = ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - }); - - test('chainFirst', () async { - final task = IOEither.of(10); - var sideEffect = 10; - final chain = task.chainFirst((b) { - sideEffect = 100; - return IOEither.left("abc"); - }); - final r = await chain.run(); - r.match( - (l) => fail('should be right'), - (r) { - expect(r, 10); - expect(sideEffect, 100); - }, - ); - }); - - group('sequenceList', () { - test('Right', () { - var sideEffect = 0; - final list = [ - IOEither(() { - sideEffect += 1; - return right(1); - }), - IOEither(() { - sideEffect += 1; - return right(2); - }), - IOEither(() { - sideEffect += 1; - return right(3); - }), - IOEither(() { - sideEffect += 1; - return right(4); - }), - ]; - final traverse = IOEither.sequenceList(list); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestRight((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, list.length); - }); - - test('Left', () { - var sideEffect = 0; - final list = [ - IOEither(() { - sideEffect += 1; - return right(1); - }), - IOEither(() { - sideEffect += 1; - return left("Error"); - }), - IOEither(() { - sideEffect += 1; - return right(3); - }), - IOEither(() { - sideEffect += 1; - return right(4); - }), - ]; - final traverse = IOEither.sequenceList(list); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - - group('traverseList', () { - test('Right', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = IOEither.traverseList(list, (a) { - sideEffect += 1; - return IOEither.of("$a"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestRight((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, list.length); - }); - - test('Left', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = IOEither.traverseList(list, (a) { - sideEffect += 1; - return a % 2 == 0 ? IOEither.left("Error") : IOEither.of("$a"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - - group('traverseListWithIndex', () { - test('Right', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = - IOEither.traverseListWithIndex(list, (a, i) { - sideEffect += 1; - return IOEither.of("$a$i"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestRight((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, list.length); - }); - - test('Left', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = - IOEither.traverseListWithIndex(list, (a, i) { - sideEffect += 1; - return a % 2 == 0 ? IOEither.left("Error") : IOEither.of("$a$i"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - - group('Do Notation', () { - test('should return the correct value', () { - final doIOEither = IOEither.Do((_) => _(IOEither.of(10))); - final run = doIOEither.run(); - run.matchTestRight((t) { - expect(t, 10); - }); - }); - - test('should extract the correct values', () { - final doIOEither = IOEither.Do((_) { - final a = _(IOEither.of(10)); - final b = _(IOEither.of(5)); - return a + b; - }); - final run = doIOEither.run(); - run.matchTestRight((t) { - expect(t, 15); - }); - }); - - test('should return Left if any Either is Left', () { - final doIOEither = IOEither.Do((_) { - final a = _(IOEither.of(10)); - final b = _(IOEither.of(5)); - final c = _(IOEither.left('Error')); - return a + b + c; - }); - final run = doIOEither.run(); - run.matchTestLeft((t) { - expect(t, 'Error'); - }); - }); - - test('should rethrow if throw is used inside Do', () { - final doIOEither = IOEither.Do((_) { - _(IOEither.of(10)); - throw UnimplementedError(); - }); - - expect(doIOEither.run, throwsA(const TypeMatcher())); - }); - - test('should rethrow if Left is thrown inside Do', () { - final doIOEither = IOEither.Do((_) { - _(IOEither.of(10)); - throw Left('Error'); - }); - - expect(doIOEither.run, throwsA(const TypeMatcher())); - }); - - test('should no execute past the first Left', () { - var mutable = 10; - final doIOEitherLeft = IOEither.Do((_) { - final a = _(IOEither.of(10)); - final b = _(IOEither.left("Error")); - mutable += 10; - return a + b; - }); - - final runLeft = doIOEitherLeft.run(); - expect(mutable, 10); - runLeft.matchTestLeft((l) { - expect(l, "Error"); - }); - - final doIOEitherRight = IOEither.Do((_) { - final a = _(IOEither.of(10)); - mutable += 10; - return a; - }); - - final runRight = doIOEitherRight.run(); - expect(mutable, 20); - runRight.matchTestRight((t) { - expect(t, 10); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/io_option_test.dart b/packages/fpdart/test/src/io_option_test.dart deleted file mode 100644 index 4a4cd93f..00000000 --- a/packages/fpdart/test/src/io_option_test.dart +++ /dev/null @@ -1,579 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import './utils/utils.dart'; - -void main() { - group('IOOption', () { - group('tryCatch', () { - test('Success', () { - final io = IOOption.tryCatch(() => 10); - final r = io.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('throws Exception', () { - final io = IOOption.tryCatch(() { - throw UnimplementedError(); - }); - final r = io.run(); - expect(r, isA()); - }); - }); - - group('tryCatchK', () { - test('Success', () { - final io = IOOption.of(10); - final ap = io.flatMap(IOOption.tryCatchK( - (n) => n + 5, - )); - final r = ap.run(); - r.matchTestSome((r) => expect(r, 15)); - }); - - test('throws Exception', () { - final io = IOOption.of(10); - final ap = io.flatMap(IOOption.tryCatchK((_) { - throw UnimplementedError(); - })); - final r = ap.run(); - expect(r, isA()); - }); - }); - - group('flatMap', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final ap = io.flatMap((r) => IOOption(() => Option.of(r + 10))); - final r = ap.run(); - r.matchTestSome((r) => expect(r, 20)); - }); - - test('None', () { - final io = IOOption(() => Option.none()); - final ap = io.flatMap((r) => IOOption(() => Option.of(r + 10))); - final r = ap.run(); - expect(r, isA()); - }); - }); - - group('ap', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final ap = io.ap(IOOption(() => Option.of((int c) => c / 2))); - final r = ap.run(); - r.matchTestSome((r) => expect(r, 5.0)); - }); - - test('None', () { - final io = IOOption(() => Option.none()); - final ap = io.ap(IOOption(() => Option.of((int c) => c / 2))); - final r = ap.run(); - expect(r, isA()); - }); - }); - - group('map', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final ap = io.map((r) => r / 2); - final r = ap.run(); - r.matchTestSome((r) => expect(r, 5.0)); - }); - - test('None', () { - final io = IOOption(() => Option.none()); - final ap = io.map((r) => r / 2); - final r = ap.run(); - expect(r, isA()); - }); - }); - - group('map2', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final ap = io.map2( - IOOption(() => Option.of(2)), (b, c) => b / c); - final r = ap.run(); - r.matchTestSome((r) => expect(r, 5.0)); - }); - - test('None', () { - final io = IOOption(() => Option.none()); - final ap = io.map2( - IOOption(() => Option.of(2)), (b, c) => b / c); - final r = ap.run(); - expect(r, isA()); - }); - }); - - group('map3', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final ap = io.map3(IOOption(() => Option.of(2)), - IOOption(() => Option.of(5)), (b, c, d) => b * c / d); - final r = ap.run(); - r.matchTestSome((r) => expect(r, 4.0)); - }); - - test('None', () { - final io = IOOption(() => Option.none()); - final ap = io.map3(IOOption(() => Option.of(2)), - IOOption(() => Option.of(5)), (b, c, d) => b * c / d); - final r = ap.run(); - expect(r, isA()); - }); - }); - - group('andThen', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final ap = io.andThen(() => IOOption(() => Option.of(12.5))); - final r = ap.run(); - r.matchTestSome((r) => expect(r, 12.5)); - }); - - test('None', () { - final io = IOOption(() => Option.none()); - final ap = io.andThen(() => IOOption(() => Option.of(12.5))); - final r = ap.run(); - expect(r, isA()); - }); - }); - - group('call', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final ap = io(IOOption(() => Option.of(12.5))); - final r = ap.run(); - r.matchTestSome((r) => expect(r, 12.5)); - }); - - test('None', () { - final io = IOOption(() => Option.none()); - final ap = io(IOOption(() => Option.of(12.5))); - final r = ap.run(); - expect(r, isA()); - }); - }); - - test('pure', () { - final io = IOOption(() => Option.none()); - final ap = io.pure('abc'); - final r = ap.run(); - r.matchTestSome((r) => expect(r, 'abc')); - }); - - test('run', () { - final io = IOOption(() => Option.of(10)); - final r = io.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - group('fromEither', () { - test('Some', () { - final io = IOOption.fromEither(Either.of(10)); - final r = io.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('None', () { - final io = IOOption.fromEither(Either.left('none')); - final r = io.run(); - expect(r, isA()); - }); - }); - - group('fromNullable', () { - test('Right', () { - final io = IOOption.fromNullable(10); - final result = io.run(); - result.matchTestSome((r) { - expect(r, 10); - }); - }); - - test('Left', () { - final io = IOOption.fromNullable(null); - final result = io.run(); - expect(result, isA()); - }); - }); - - group('fromPredicate', () { - test('True', () { - final io = IOOption.fromPredicate(20, (n) => n > 10); - final r = io.run(); - r.matchTestSome((r) => expect(r, 20)); - }); - - test('False', () { - final io = IOOption.fromPredicate(10, (n) => n > 10); - final r = io.run(); - expect(r, isA()); - }); - }); - - test('none()', () { - final io = IOOption.none(); - final r = io.run(); - expect(r, isA()); - }); - - test('some()', () { - final io = IOOption.some(10); - final r = io.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - group('match', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final ex = io.match(() => -1, (r) => r + 10); - final r = ex.run(); - expect(r, 20); - }); - - test('None', () { - final io = IOOption(() => Option.none()); - final ex = io.match(() => -1, (r) => r + 10); - final r = ex.run(); - expect(r, -1); - }); - }); - - group('getOrElse', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final ex = io.getOrElse(() => -1); - final r = ex.run(); - expect(r, 10); - }); - - test('None', () { - final io = IOOption(() => Option.none()); - final ex = io.getOrElse(() => -1); - final r = ex.run(); - expect(r, -1); - }); - }); - - group('orElse', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final ex = io.orElse(() => IOOption(() => Option.of(-1))); - final r = ex.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('None', () { - final io = IOOption(() => Option.none()); - final ex = io.orElse(() => IOOption(() => Option.of(-1))); - final r = ex.run(); - r.matchTestSome((r) => expect(r, -1)); - }); - }); - - group('alt', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final ex = io.alt(() => IOOption(() => Option.of(20))); - final r = ex.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('None', () { - final io = IOOption(() => Option.none()); - final ex = io.alt(() => IOOption(() => Option.of(20))); - final r = ex.run(); - r.matchTestSome((r) => expect(r, 20)); - }); - }); - - test('of', () { - final io = IOOption.of(10); - final r = io.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('flatten', () { - final io = IOOption>.of(IOOption.of(10)); - final ap = IOOption.flatten(io); - final r = ap.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - group('toTaskOption', () { - test('Some', () async { - final io = IOOption(() => Option.of(10)); - final convert = io.toTaskOption(); - final r = await convert.run(); - r.matchTestSome((r) { - expect(r, 10); - }); - }); - - test('None', () async { - final io = IOOption(() => const Option.none()); - final convert = io.toTaskOption(); - final r = await convert.run(); - expect(r, isA()); - }); - }); - - group('toOptionEither', () { - test('Some', () { - final io = IOOption(() => Option.of(10)); - final convert = io.toIOEither(() => 'None'); - final r = convert.run(); - r.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('None', () { - final io = IOOption(() => const Option.none()); - final convert = io.toIOEither(() => 'None'); - final r = convert.run(); - r.matchTestLeft((l) { - expect(l, 'None'); - }); - }); - }); - - group('toTaskEither', () { - test('Some', () async { - final io = IOOption(() => Option.of(10)); - final convert = io.toTaskEither(() => 'None'); - final r = await convert.run(); - r.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('None', () async { - final io = IOOption(() => const Option.none()); - final convert = io.toTaskEither(() => 'None'); - final r = await convert.run(); - r.matchTestLeft((l) { - expect(l, 'None'); - }); - }); - }); - - group('sequenceList', () { - test('Some', () { - var sideEffect = 0; - final list = [ - IOOption(() { - sideEffect += 1; - return some(1); - }), - IOOption(() { - sideEffect += 1; - return some(2); - }), - IOOption(() { - sideEffect += 1; - return some(3); - }), - IOOption(() { - sideEffect += 1; - return some(4); - }), - ]; - final traverse = IOOption.sequenceList(list); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestSome((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, list.length); - }); - - test('None', () { - var sideEffect = 0; - final list = [ - IOOption(() { - sideEffect += 1; - return some(1); - }), - IOOption(() { - sideEffect += 1; - return none(); - }), - IOOption(() { - sideEffect += 1; - return some(3); - }), - IOOption(() { - sideEffect += 1; - return some(4); - }), - ]; - final traverse = IOOption.sequenceList(list); - expect(sideEffect, 0); - final result = traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - - group('traverseList', () { - test('Some', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = IOOption.traverseList( - list, - (a) => IOOption( - () { - sideEffect += 1; - return some("$a"); - }, - ), - ); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestSome((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, list.length); - }); - - test('None', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = IOOption.traverseList( - list, - (a) => IOOption( - () { - sideEffect += 1; - return a % 2 == 0 ? some("$a") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - - group('traverseListWithIndex', () { - test('Some', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = IOOption.traverseListWithIndex( - list, - (a, i) => IOOption( - () { - sideEffect += 1; - return some("$a$i"); - }, - ), - ); - expect(sideEffect, 0); - final result = traverse.run(); - result.matchTestSome((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, list.length); - }); - - test('None', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = IOOption.traverseListWithIndex( - list, - (a, i) => IOOption( - () { - sideEffect += 1; - return a % 2 == 0 ? some("$a$i") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - - group('Do Notation', () { - test('should return the correct value', () { - final doIOOption = IOOption.Do((_) => _(IOOption.of(10))); - final run = doIOOption.run(); - run.matchTestSome((t) { - expect(t, 10); - }); - }); - - test('should extract the correct values', () { - final doIOOption = IOOption.Do((_) { - final a = _(IOOption.of(10)); - final b = _(IOOption.of(5)); - return a + b; - }); - final run = doIOOption.run(); - run.matchTestSome((t) { - expect(t, 15); - }); - }); - - test('should return Left if any Either is Left', () { - final doIOOption = IOOption.Do((_) { - final a = _(IOOption.of(10)); - final b = _(IOOption.of(5)); - final c = _(IOOption.none()); - return a + b + c; - }); - final run = doIOOption.run(); - expect(run, isA()); - }); - - test('should rethrow if throw is used inside Do', () { - final doIOOption = IOOption.Do((_) { - _(IOOption.of(10)); - throw UnimplementedError(); - }); - - expect( - doIOOption.run, throwsA(const TypeMatcher())); - }); - - test('should rethrow if None is thrown inside Do', () { - final doIOOption = IOOption.Do((_) { - _(IOOption.of(10)); - throw const None(); - }); - - expect(doIOOption.run, throwsA(const TypeMatcher())); - }); - - test('should no execute past the first Left', () { - var mutable = 10; - final doIOOptionNone = IOOption.Do((_) { - final a = _(IOOption.of(10)); - final b = _(IOOption.none()); - mutable += 10; - return a + b; - }); - - final runNone = doIOOptionNone.run(); - expect(mutable, 10); - expect(runNone, isA()); - - final doIOOptionSome = IOOption.Do((_) { - final a = _(IOOption.of(10)); - mutable += 10; - return a; - }); - - final runSome = doIOOptionSome.run(); - expect(mutable, 20); - runSome.matchTestSome((t) { - expect(t, 10); - }); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/io_ref_test.dart b/packages/fpdart/test/src/io_ref_test.dart deleted file mode 100644 index bf6a51f1..00000000 --- a/packages/fpdart/test/src/io_ref_test.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/expect.dart'; -import 'package:test/scaffolding.dart'; - -extension on bool { - void isTrue() => expect(this, true); -} - -void main() { - group("IORef", () { - const value = 1; - - const method = "Method"; - const function = "Function"; - const mEqualsF = "$method equals $function"; - - group("Eq", () { - final first = IORef.create(value); - final second = IORef.create(value); - - test("Pointer equality passes on allocated IORef", () { - final unwrapped = first.run(); - ioRefEq.eqv(unwrapped, unwrapped).isTrue(); - }); - - test( - "Pointer equality fails on two allocations of the same wrapped ref", - () => ioRefEq.neqv(first.run(), first.run()).isTrue(), - ); - test("Pointer equality fails on two different unwrapped refs", () { - final unwrappedFirst = first.run(); - final unwrappedSecond = second.run(); - ioRefEq.neqv(unwrappedFirst, unwrappedSecond).isTrue(); - }); - }); - - group("Read", () { - final ref = IORef.create(value); - - final methodRead = ref.flatMap((ref) => ref.read()).run; - final functionRead = ref.flatMap(readIORef).run; - - test(method, () => expect(methodRead(), value)); - - test(function, () => expect(functionRead(), value)); - - test(mEqualsF, () => expect(methodRead(), functionRead())); - }); - - group( - "Write", - () { - const writingValue = 10; - - final methodWrite = IORef.create(value) - .flatMap( - (ref) => ref.write(writingValue).flatMap((_) => ref.read()), - ) - .run; - - final functionWrite = IORef.create(value) - .flatMap( - (ref) => writeIORef(writingValue, ref).flatMap((_) => ref.read()), - ) - .run; - - test(method, () => expect(methodWrite(), writingValue)); - - test(function, () => expect(functionWrite(), writingValue)); - - test(mEqualsF, () => expect(methodWrite(), functionWrite())); - }, - ); - - group("Modify", () { - int modifyFunction(int value) => value + 4; - final expectedValue = modifyFunction(value); - - final methodModify = IORef.create(value) - .flatMap( - (ref) => ref.modify(modifyFunction).flatMap((_) => ref.read()), - ) - .run; - - final functionModify = IORef.create(value) - .flatMap( - (ref) => - modifyIORef(modifyFunction, ref).flatMap((_) => ref.read()), - ) - .run; - - test(method, () => expect(methodModify(), expectedValue)); - - test(function, () => expect(functionModify(), expectedValue)); - - test(mEqualsF, () => expect(methodModify(), functionModify())); - }); - }); -} diff --git a/packages/fpdart/test/src/io_test.dart b/packages/fpdart/test/src/io_test.dart deleted file mode 100644 index 30b52f64..00000000 --- a/packages/fpdart/test/src/io_test.dart +++ /dev/null @@ -1,222 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import 'utils/utils.dart'; - -void main() { - group('IO', () { - group('is a', () { - final io = IO(() => 10); - - test('Monad', () { - expect(io, isA()); - }); - - test('Applicative', () { - expect(io, isA()); - }); - - test('Functor', () { - expect(io, isA()); - }); - }); - - test('flatMap', () { - final io = IO(() => 10); - final ap = io.flatMap((a) => IO(() => a + 10)); - final r = ap.run(); - expect(r, 20); - }); - - test('flatMapTask', () async { - final io = IO(() => 10); - final ap = io.flatMapTask((a) => Task(() async => a + 10)); - final r = await ap.run(); - expect(r, 20); - }); - - test('toIOEither', () { - final io = IO(() => 10); - final ap = io.toIOEither(); - final r = ap.run(); - r.matchTestRight((r) => expect(r, 10)); - }); - - test('toTask', () async { - final io = IO(() => 10); - final ap = io.toTask(); - final r = await ap.run(); - expect(r, 10); - }); - - test('toTaskEither', () async { - final io = IO(() => 10); - final ap = io.toTaskEither(); - final r = await ap.run(); - r.matchTestRight((r) => expect(r, 10)); - }); - - test('toTaskOption', () async { - final io = IO(() => 10); - final ap = io.toTaskOption(); - final r = await ap.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('toIOOption', () { - final io = IO(() => 10); - final ap = io.toIOOption(); - final r = ap.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('ap', () { - final io = IO(() => 10); - final ap = io.ap(IO(() => (int a) => a * 3)); - final r = ap.run(); - expect(r, 30); - }); - - test('pure', () { - final io = IO(() => 10); - final ap = io.pure('abc'); - final r = ap.run(); - expect(r, 'abc'); - }); - - test('map', () { - final io = IO(() => 10); - final ap = io.map((a) => '$a'); - final r = ap.run(); - expect(r, '10'); - }); - - test('map2', () { - final io = IO(() => 10); - final ap = io.map2(IO(() => 'abc'), (a, c) => a + c.length); - final r = ap.run(); - expect(r, 13); - }); - - test('map3', () { - final io = IO(() => 10); - final ap = io.map3( - IO(() => 'ab'), IO(() => 0.5), (a, c, d) => (a + c.length) * d); - final r = ap.run(); - expect(r, 6.0); - }); - - test('andThen', () { - final io = IO(() => 10); - final ap = io.andThen(() => IO(() => 'abc')); - final r = ap.run(); - expect(r, 'abc'); - }); - - test('call', () { - final io = IO(() => 10); - final ap = io(IO(() => 'abc')); - final r = ap.run(); - expect(r, 'abc'); - }); - - test('flatten', () { - final io = IO(() => IO(() => 10)); - final ap = IO.flatten(io); - expect(ap, isA>()); - final r = ap.run(); - expect(r, 10); - }); - - test('run', () { - final io = IO(() => 10); - final r = io.run(); - expect(r, isA()); - expect(r, 10); - }); - - test('sequenceList', () { - var sideEffect = 0; - final list = [ - IO(() { - sideEffect += 1; - return 1; - }), - IO(() { - sideEffect += 1; - return 2; - }), - IO(() { - sideEffect += 1; - return 3; - }), - IO(() { - sideEffect += 1; - return 4; - }) - ]; - final traverse = IO.sequenceList(list); - expect(sideEffect, 0); - final result = traverse.run(); - expect(result, [1, 2, 3, 4]); - expect(sideEffect, list.length); - }); - - test('traverseList', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = IO.traverseList(list, (a) { - sideEffect += 1; - return IO.of("$a"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - expect(result, ['1', '2', '3', '4', '5', '6']); - expect(sideEffect, list.length); - }); - - test('traverseListWithIndex', () { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = IO.traverseListWithIndex(list, (a, i) { - sideEffect += 1; - return IO.of("$a$i"); - }); - expect(sideEffect, 0); - final result = traverse.run(); - expect(result, ['10', '21', '32', '43', '54', '65']); - expect(sideEffect, list.length); - }); - - group('Do Notation', () { - test('should return the correct value', () { - final doIO = IO.Do((_) => _(IO.of(10))); - final run = doIO.run(); - expect(run, 10); - }); - - test('should extract the correct values', () { - final doIO = IO.Do((_) { - final a = _(IO.of(10)); - final b = _(IO.of(5)); - return a + b; - }); - final run = doIO.run(); - expect(run, 15); - }); - - test('should not execute until run is called', () { - var mutable = 10; - final doIO = IO.Do((_) { - final a = _(IO.of(10)); - final b = _(IO.of(5)); - mutable += 10; - return a + b; - }); - expect(mutable, 10); - final run = doIO.run(); - expect(mutable, 20); - expect(run, 15); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/monoid_test.dart b/packages/fpdart/test/src/monoid_test.dart deleted file mode 100644 index 5fb2badd..00000000 --- a/packages/fpdart/test/src/monoid_test.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('Monoid', () { - group('is a', () { - final instance = Monoid.instance(0, (a1, a2) => a1 + a2); - - test('Semigroup', () { - expect(instance, isA()); - }); - }); - - test('.instance (int)', () { - final instance = Monoid.instance(0, (a1, a2) => a1 + a2); - expect(instance.combine(10, instance.empty), - instance.combine(instance.empty, 10)); - expect(instance.combine(10, instance.empty), 10); - }); - - test('.instance (String)', () { - final instance = Monoid.instance('', (a1, a2) => '$a1$a2'); - expect(instance.combine('abc', instance.empty), - instance.combine(instance.empty, 'abc')); - expect(instance.combine('abc', instance.empty), 'abc'); - }); - - test('.isEmpty', () { - final instance = Monoid.instance(0, (a1, a2) => a1 + a2); - final eq = Eq.instance((a1, a2) => a1 == a2); - expect(instance.isEmpty(instance.empty, eq), true); - expect(instance.isEmpty(0, eq), true); - expect(instance.isEmpty(1, eq), false); - }); - - test('.combineN', () { - final instance = Monoid.instance(0, (a1, a2) => a1 + a2); - expect(instance.combineN(0, 10), 0); - expect(instance.combineN(1, 10), 10); - }); - - test('.reverse', () { - final instance = Monoid.instance('', (a1, a2) => '$a1$a2'); - final reverse = instance.reverse(); - expect(reverse.combine('a', 'b'), 'ba'); - expect(reverse.combine('a', 'b'), instance.combine('b', 'a')); - }); - }); -} diff --git a/packages/fpdart/test/src/option_test.dart b/packages/fpdart/test/src/option_test.dart index 1de5ea38..3bd89501 100644 --- a/packages/fpdart/test/src/option_test.dart +++ b/packages/fpdart/test/src/option_test.dart @@ -1,811 +1,17 @@ -import 'package:fpdart/fpdart.dart'; - -import './utils/utils.dart'; +import "package:fpdart/fpdart.dart"; +import "package:test/test.dart"; void main() { - group('Option', () { - group('[Property-based testing]', () { - group("safeCast", () { - Glados2(any.int, any.letterOrDigits) - .test('always returns Some without typed parameter', - (intValue, stringValue) { - final castInt = Option.safeCast(intValue); - final castString = Option.safeCast(stringValue); - expect(castInt, isA>()); - expect(castString, isA>()); - }); - }); - - group('map', () { - Glados(any.optionInt).test('should keep the same type (Some or None)', - (option) { - final r = option.map(constF); - expect(option.isSome(), r.isSome()); - expect(option.isNone(), r.isNone()); - }); - - Glados2(any.optionInt, any.int) - .test('should updated the value inside Some, or stay None', - (option, value) { - final r = option.map((n) => n + value); - option.match( - () { - expect(option, r); - }, - (val1) { - r.matchTestSome((val2) { - expect(val2, val1 + value); - }); - }, - ); - }); - }); - - group('traverseList', () { - Glados(any.list(any.int)).test( - 'should keep the same structure and content of the original list', - (input) { - final result = Option.traverseList(input, Option.of); - result.matchTestSome((t) { - expect(t, input); - }); - }); - }); - }); - - group('is a', () { - final option = Option.of(10); - - test('Monad', () { - expect(option, isA()); - }); - - test('Applicative', () { - expect(option, isA()); - }); - - test('Functor', () { - expect(option, isA()); - }); - - test('Extend', () { - expect(option, isA()); - }); - - test('Filterable', () { - expect(option, isA()); - }); - }); - - test('map', () { - final option = Option.of(10); - final map = option.map((a) => a + 1); - map.matchTestSome((some) => expect(some, 11)); - }); - - test('map2', () { - final option = Option.of(10); - final map = - option.map2(Option.of('abc'), (a, b) => a + b.length); - map.matchTestSome((some) => expect(some, 13)); - }); - - test('map3', () { - final option = Option.of(10); - final map = option.map3( - Option.of('abc'), Option.of(2.0), (a, b, c) => (a + b.length) / c); - map.matchTestSome((some) => expect(some, 6.5)); - }); - - group('ap', () { - test('Some', () { - final option = Option.of(10); - final pure = option.ap(Option.of((int i) => i + 1)); - pure.matchTestSome((some) => expect(some, 11)); - }); - - test('Some (curried)', () { - final ap = Option.of((int a) => (int b) => a + b) - .ap( - Option.of((f) => f(3)), - ) - .ap( - Option.of((f) => f(5)), - ); - ap.matchTestSome((some) => expect(some, 8)); - }); - - test('None', () { - final option = Option.none(); - final pure = option.ap(Option.of((int i) => i + 1)); - expect(pure, isA()); - }); - }); - - group('flatMap', () { - test('Some', () { - final option = Option.of(10); - final flatMap = option.flatMap((a) => Option.of(a + 1)); - flatMap.matchTestSome((some) => expect(some, 11)); - }); - - test('None', () { - final option = Option.none(); - final flatMap = option.flatMap((a) => Option.of(a + 1)); - expect(flatMap, isA()); - }); - }); - - group('flatMapNullable', () { - test('not null', () { - final option = Option.of(10); - final flatMap = option.flatMapNullable((a) => a + 1); - flatMap.matchTestSome((some) => expect(some, 11)); - }); - - test('null', () { - final option = Option.of(10); - final flatMap = option.flatMapNullable((a) => null); - expect(flatMap, isA()); - }); - }); - - group('flatMapThrowable', () { - test('happy path', () { - final option = Option.of(10); - final flatMap = option.flatMapThrowable((a) => a + 1); - flatMap.matchTestSome((some) => expect(some, 11)); - }); - - test('throws', () { - final option = Option.of(10); - final flatMap = option.flatMapThrowable((a) => throw "fail"); - expect(flatMap, isA()); - }); - }); - - group('extend', () { - test('Some', () { - final option = Option.of(10); - final value = option.extend((t) => t.isSome() ? 'valid' : 'invalid'); - value.matchTestSome((some) => expect(some, 'valid')); - }); - - test('None', () { - final option = Option.none(); - final value = option.extend((t) => t.isSome() ? 'valid' : 'invalid'); - expect(value, isA()); - }); - }); - - group('duplicate', () { - test('Some', () { - final option = Option.of(10); - final value = option.duplicate(); - value.matchTestSome((some) => expect(some, isA())); - }); - - test('None', () { - final option = Option.none(); - final value = option.duplicate(); - expect(value, isA()); - }); - }); - - group('filter', () { - test('Some (true)', () { - final option = Option.of(10); - final value = option.filter((a) => a > 5); - value.matchTestSome((some) => expect(some, 10)); - }); - - test('Some (false)', () { - final option = Option.of(10); - final value = option.filter((a) => a < 5); - expect(value, isA()); - }); - - test('None', () { - final option = Option.none(); - final value = option.filter((a) => a > 5); - expect(value, isA()); - }); - }); - - group('filterMap', () { - test('Some', () { - final option = Option.of(10); - final value = option.filterMap((a) => Option.of('$a')); - value.matchTestSome((some) => expect(some, '10')); - }); - - test('None', () { - final option = Option.none(); - final value = option.filterMap((a) => Option.of('$a')); - expect(value, isA()); - }); - }); - - group('partition', () { - test('Some (true)', () { - final option = Option.of(10); - final value = option.partition((a) => a > 5); - expect(value.$1, isA()); - value.$2.matchTestSome((some) => expect(some, 10)); - }); - - test('Some (false)', () { - final option = Option.of(10); - final value = option.partition((a) => a < 5); - value.$1.matchTestSome((some) => expect(some, 10)); - expect(value.$2, isA()); - }); - - test('None', () { - final option = Option.none(); - final value = option.partition((a) => a > 5); - expect(value.$1, isA()); - expect(value.$2, isA()); - }); - }); - - group('partitionMap', () { - test('Some (right)', () { - final option = Option.of(10); - final value = - option.partitionMap((a) => Either.of(a / 2)); - expect(value.$1, isA()); - value.$2.matchTestSome((some) => expect(some, 5.0)); - }); - - test('Some (left)', () { - final option = Option.of(10); - final value = - option.partitionMap((a) => Either.left('$a')); - value.$1.matchTestSome((some) => expect(some, '10')); - expect(value.$2, isA()); - }); - - test('None', () { - final option = Option.none(); - final value = - option.partitionMap((a) => Either.of(a / 2)); - expect(value.$1, isA()); - expect(value.$2, isA()); - }); - }); - - group('fromEither', () { - test('Right', () { - final option = Option.fromEither(Either.of(10)); - option.matchTestSome((some) => expect(some, 10)); - }); - - test('Left', () { - final option = Option.fromEither(Either.left('none')); - expect(option, isA()); - }); - }); - - group('fromJson', () { - test('int', () { - final option = Option.fromJson(10, (a) => a as int); - option.matchTestSome((some) => expect(some, 10)); - }); - - test('DateTime', () { - final now = DateTime.now(); - final option = Option.fromJson( - now.toIso8601String(), (a) => DateTime.parse(a as String)); - option.matchTestSome((some) => expect(some, now)); - }); - - test('DateTime failure', () { - final option = Option.fromJson( - "fail", (a) => DateTime.parse(a as String)); - expect(option, isA()); - }); - - test('null', () { - final option = Option.fromJson(null, (a) => a as int); - expect(option, isA()); - }); - }); - - group('fromPredicate', () { - test('Some', () { - final option = Option.fromPredicate(10, (a) => a > 5); - option.matchTestSome((some) => expect(some, 10)); - }); - - test('None', () { - final option = Option.fromPredicate(10, (a) => a < 5); - expect(option, isA()); - }); - }); - - group('fromPredicateMap', () { - test('Some', () { - final option = - Option.fromPredicateMap(10, (a) => a > 5, (a) => '$a'); - option.matchTestSome((some) => expect(some, '10')); - }); - - test('None', () { - final option = - Option.fromPredicateMap(10, (a) => a < 5, (a) => '$a'); - expect(option, isA()); - }); - }); - - group('flatten', () { - test('Right', () { - final option = Option.flatten(Option.of(Option.of(10))); - option.matchTestSome((some) => expect(some, 10)); - }); - - test('Left', () { - final option = Option.flatten(Option.of(Option.none())); - expect(option, isA()); - }); - }); - - group('separate', () { - test('Right', () { - final option = Option.separate(Option.of(Either.of(10))); - expect(option.$1, isA()); - option.$2.matchTestSome((some) => expect(some, 10)); - }); - - test('Left', () { - final option = - Option.separate(Option.of(Either.left('none'))); - option.$1.matchTestSome((some) => expect(some, 'none')); - expect(option.$2, isA()); - }); - }); - - test('None', () { - final option = Option.none(); - expect(option, isA()); - }); - - test('of', () { - final option = Option.of(10); - option.matchTestSome((some) => expect(some, 10)); - }); - - test('isSome', () { - final option = Option.of(10); - expect(option.isSome(), true); - expect(option.isNone(), false); - }); - - test('isNone', () { - final option = Option.none(); - expect(option.isNone(), true); - expect(option.isSome(), false); - }); - - test('getEq', () { - final eq = Option.getEq(Eq.instance((a1, a2) => a1 == a2)); - expect(eq.eqv(Option.of(10), Option.of(10)), true); - expect(eq.eqv(Option.of(10), Option.of(9)), false); - expect(eq.eqv(Option.of(10), Option.none()), false); - expect(eq.eqv(Option.none(), Option.none()), true); - }); - - test('getOrder', () { - final order = - Option.getOrder(Order.from((a1, a2) => a1.compareTo(a2))); - final option1 = Option.of(10); - final option2 = Option.of(9); - final option3 = Option.none(); - expect(order.compare(option1, option1), 0); - expect(order.compare(option3, option3), 0); - expect(order.compare(option1, option2), 1); - expect(order.compare(option2, option1), -1); - expect(order.compare(option1, option3), 1); - expect(order.compare(option3, option1), -1); - }); - - test('fromNullable', () { - final m1 = Option.fromNullable(10); - final m2 = Option.fromNullable(null); - expect(m1, isA()); - expect(m2, isA()); - }); - - test('tryCatch', () { - final m1 = Option.tryCatch(() => 10); - final m2 = Option.tryCatch(() => throw UnimplementedError()); - expect(m1, isA()); - expect(m2, isA()); - }); - - test('toEither', () { - final m1 = Option.of(10); - final m2 = Option.none(); - final e1 = m1.toEither(() => 'left'); - final e2 = m2.toEither(() => 'left'); - e1.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - e2.match((l) => expect(l, 'left'), (_) { - fail('should be left'); - }); - }); - - test('toNullable', () { - final m1 = Option.of(10); - final m2 = Option.none(); - expect(m1.toNullable(), 10); - expect(m1.toNullable(), isA()); - expect(m2.toNullable(), null); - }); - - test('pure', () { - final m1 = Option.of(10); - final m2 = Option.none(); - m1.pure('abc').matchTestSome((some) => expect(some, 'abc')); - m2.pure('abc').matchTestSome((some) => expect(some, 'abc')); - }); - - test('andThen', () { - final m1 = Option.of(10); - final m2 = Option.none(); - m1 - .andThen(() => Option.of('abc')) - .matchTestSome((some) => expect(some, 'abc')); - expect(m2.andThen(() => Option.of('abc')), isA()); - }); - - test('call', () { - final m1 = Option.of(10); - final m2 = Option.none(); - m1(Option.of('abc')).matchTestSome((some) => expect(some, 'abc')); - expect(m2(Option.of('abc')), isA()); - }); - - test('match', () { - final m1 = Option.of(10); - final m2 = Option.none(); - expect(m1.match(() => 'none', (some) => 'some'), 'some'); - expect(m2.match(() => 'none', (some) => 'some'), 'none'); - }); - - test('match', () { - final m1 = Option.of(10); - final m2 = Option.none(); - expect(m1.fold(() => 'none', (some) => 'some'), 'some'); - expect(m2.fold(() => 'none', (some) => 'some'), 'none'); - }); - - test('none()', () { - final m = Option.none(); - expect(m, isA()); - }); - - test('of()', () { - final m = Option.of(10); - expect(m, isA>()); - }); - - test('getFirstMonoid', () { - final m = Option.getFirstMonoid(); - expect(m.empty, isA()); - m - .combine(Option.of(10), Option.of(0)) - .matchTestSome((some) => expect(some, 10)); - m - .combine(Option.none(), Option.of(0)) - .matchTestSome((some) => expect(some, 0)); - }); - - test('getLastMonoid', () { - final m = Option.getLastMonoid(); - expect(m.empty, isA()); - m - .combine(Option.of(10), Option.of(0)) - .matchTestSome((some) => expect(some, 0)); - m - .combine(Option.of(10), Option.none()) - .matchTestSome((some) => expect(some, 10)); - }); - - test('getMonoid', () { - final m = Option.getMonoid(Semigroup.instance((a1, a2) => a1 + a2)); - expect(m.empty, isA()); - m - .combine(Option.of(10), Option.of(20)) - .matchTestSome((some) => expect(some, 30)); - expect(m.combine(Option.of(10), Option.none()), isA()); - expect(m.combine(Option.none(), Option.of(10)), isA()); - }); - - group('toString', () { - test('Some', () { - final m = Option.of(10); - expect(m.toString(), 'Some(10)'); - }); - - test('None', () { - final m = Option.none(); - expect(m.toString(), 'None'); - }); - }); - - group('sequenceList', () { - test('Some', () { - final list = [some(1), some(2), some(3), some(4)]; - final result = Option.sequenceList(list); - result.matchTestSome((t) { - expect(t, [1, 2, 3, 4]); - }); - }); - - test('None', () { - final list = [some(1), none(), some(3), some(4)]; - final result = Option.sequenceList(list); - expect(result, isA()); - }); - }); - - group('traverseList', () { - test('Some', () { - final list = [1, 2, 3, 4, 5, 6]; - final result = - Option.traverseList(list, (a) => some("$a")); - result.matchTestSome((t) { - expect(t, ["1", "2", "3", "4", "5", "6"]); - }); - }); - - test('None', () { - final list = [1, 2, 3, 4, 5, 6]; - final result = Option.traverseList( - list, - (a) => a % 2 == 0 ? some("$a") : none(), - ); - expect(result, isA()); - }); - }); - - group('traverseListWithIndex', () { - test('Some', () { - final list = [1, 2, 3, 4, 5, 6]; - final result = Option.traverseListWithIndex( - list, (a, i) => some("$a$i")); - result.matchTestSome((t) { - expect(t, ["10", "21", "32", "43", "54", "65"]); - }); - }); - - test('None', () { - final list = [1, 2, 3, 4, 5, 6]; - final result = Option.traverseListWithIndex( - list, - (a, i) => i % 2 == 0 ? some("$a$i") : none(), - ); - expect(result, isA()); - }); - }); - - group('safeCast', () { - test('dynamic', () { - final castInt = Option.safeCast(10); - final castString = Option.safeCast('abc'); - expect(castInt, isA>()); - expect(castString, isA>()); - }); - - test('Some', () { - final cast = Option.safeCast(10); - cast.matchTestSome((r) { - expect(r, 10); - }); - }); - - test('None', () { - final cast = Option.safeCast('abc'); - expect(cast, isA()); - }); - }); - - group('toTaskOption', () { - test('Some', () async { - final m = Option.of(10); - final taskOption = m.toTaskOption(); - final result = await taskOption.run(); - expect(result, m); - }); - - test('None', () async { - final m = Option.none(); - final taskOption = m.toTaskOption(); - final result = await taskOption.run(); - expect(result, m); - }); - }); - - group('toIOOption', () { - test('Some', () async { - final m = Option.of(10); - final ioOption = m.toIOOption(); - final result = ioOption.run(); - expect(result, m); - }); - - test('None', () { - final m = Option.none(); - final ioOption = m.toIOOption(); - final result = ioOption.run(); - expect(result, m); - }); - }); - - test('Some value', () { - const m = Some(10); - expect(m.value, 10); - }); - - test('Some == Some', () { - final m1 = Option.of(10); - final m2 = Option.of(9); - final m3 = Option.none(); - final m4 = Option.of(10); - final map1 = {'m1': m1, 'm2': m4}; - final map2 = {'m1': m1, 'm2': m2}; - final map3 = {'m1': m1, 'm2': m4}; - expect(m1, m1); - expect(m2, m2); - expect(m1, m4); - expect(m1 == m2, false); - expect(m4 == m2, false); - expect(m1 == m3, false); - expect(m2 == m3, false); - expect(map1, map1); - expect(map1, map3); - expect(map1 == map2, false); - }); - - test('None == None', () { - final m1 = Option.of(10); - final m2 = Option.of(9); - final m3 = Option.none(); - final m4 = Option.none(); - final m5 = Option.none(); - final map1 = {'m1': m3, 'm2': m3}; - final map2 = {'m1': m3, 'm2': m4}; - final map3 = {'m1': m3, 'm2': m5}; - final map4 = {'m1': m3, 'm2': m1}; - expect(m3, m3); - expect(m3, m4); - expect(m5, m5); - expect(m3, m5); - expect(m1 == m3, false); - expect(m2 == m3, false); - expect(map1, map1); - expect(map1, map2); - expect(map1, map3); - expect(map1 == map4, false); - }); - }); - - group('safeCastStrict', () { - test('Some', () { - final cast = Option.safeCastStrict(10); - cast.matchTestSome((r) { - expect(r, 10); - }); - }); - - test('None', () { - final cast = Option.safeCastStrict('abc'); - expect(cast, isA()); - }); - }); - - group('Do Notation', () { - test('should traverse over a list', () async { - const testOption = const Option>.of( - ['/', '/test', null], - ); - - Option> doNotation = Option.Do( - ($) { - List optionList = $(testOption); - return $(optionList.traverseOption( - (stringValue) => optionOf(stringValue).flatMap( - (uri) => optionOf( - Uri.tryParse(uri), - ), - ), - )); - }, - ); - - expect(doNotation, equals(const Option.none())); - }); - - test('should return the correct value', () { - final doOption = Option.Do((_) => _(Option.of(10))); - doOption.matchTestSome((t) { - expect(t, 10); - }); - }); - - test('should extract the correct values', () { - final doOption = Option.Do((_) { - final a = _(Option.of(10)); - final b = _(Option.of(5)); - return a + b; - }); - doOption.matchTestSome((t) { - expect(t, 15); - }); - }); - - test('should return None if any Option is None', () { - final doOption = Option.Do((_) { - final a = _(Option.of(10)); - final b = _(Option.of(5)); - final c = _(Option.none()); - return a + b + c; - }); - - expect(doOption, isA()); - }); - - test('should rethrow if throw is used inside Do', () { - final doOption = () => Option.Do((_) { - _(Option.of(10)); - throw UnimplementedError(); - }); - - expect(doOption, throwsA(const TypeMatcher())); - }); - - test('should rethrow if None is thrown inside Do', () { - final doOption = () => Option.Do((_) { - _(Option.of(10)); - throw None(); - }); - - expect(doOption, throwsA(const TypeMatcher())); - }); - - test('should throw if the error is not None', () { - final doOption = () => Option.Do((_) { - _(Option.of(10)); - throw UnimplementedError(); - }); - - expect(doOption, throwsA(const TypeMatcher())); - }); - - test('should no execute past the first None', () { - var mutable = 10; - final doOptionNone = Option.Do((_) { - final a = _(Option.of(10)); - final b = _(Option.none()); - mutable += 10; - return a + b; - }); - - expect(mutable, 10); - expect(doOptionNone, isA()); - - final doOptionSome = Option.Do((_) { - final a = _(Option.of(10)); - mutable += 10; - return a; - }); - - expect(mutable, 20); - doOptionSome.matchTestSome((t) { - expect(t, 10); - }); - }); - }); + group( + "Option", + () { + group('None', () { + test('const', () { + final none1 = const None(); + final none2 = const None(); + expect(none1, none2); + }); + }); + }, + ); } diff --git a/packages/fpdart/test/src/order_test.dart b/packages/fpdart/test/src/order_test.dart deleted file mode 100644 index 500568b7..00000000 --- a/packages/fpdart/test/src/order_test.dart +++ /dev/null @@ -1,240 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -class _Parent { - final int value1; - final double value2; - const _Parent(this.value1, this.value2); -} - -void main() { - group('Order', () { - group('is a', () { - final instance = Order.from((a1, a2) => a1.compareTo(a2)); - - test('Eq', () { - expect(instance, isA()); - }); - - test('PartialOrder', () { - expect(instance, isA()); - }); - }); - - test('.from', () { - final instance = Order.from((a1, a2) => a1.compareTo(a2)); - expect(instance.compare(1, 1), 0); - expect(instance.compare(1, 2), -1); - expect(instance.compare(2, 1), 1); - }); - - test('reverse', () { - final instance = Order.orderInt; - final reverse = instance.reverse; - expect(reverse.compare(1, 1), 0); - expect(reverse.compare(1, 2), 1); - expect(reverse.compare(2, 1), -1); - }); - - test('.fromLessThan', () { - final instance = Order.fromLessThan((a1, a2) => a1 < a2); - expect(instance.compare(1, 1), 0); - expect(instance.compare(1, 2), -1); - expect(instance.compare(2, 1), 1); - }); - - test('.allEqual', () { - final instance = Order.allEqual(); - expect(instance.compare(1, 1), 0); - expect(instance.compare(1, 2), 0); - expect(instance.compare(2, 1), 0); - }); - - test('.whenEqual', () { - final instance1 = - Order.fromLessThan((a1, a2) => a1.length < a2.length); - final instance2 = Order.from( - (a1, a2) => a1.substring(0, 1).compareTo(a2.substring(0, 1))); - final whenEqual = Order.whenEqual(instance1, instance2); - expect(whenEqual.compare('abc', 'abcd'), -1); - expect(whenEqual.compare('abcd', 'abc'), 1); - expect(whenEqual.compare('abc', 'ebc'), -1); - expect(whenEqual.compare('ebc', 'abc'), 1); - expect(whenEqual.compare('abc', 'abc'), 0); - }); - - test('.by', () { - final instance = Order.from((a1, a2) => a1.compareTo(a2)); - final by = Order.by((a1) => a1.length, instance); - expect(by.compare('abc', 'abc'), 0); - expect(by.compare('abc', 'abcd'), -1); - expect(by.compare('abcd', 'abc'), 1); - }); - - test('min', () { - final instance = Order.from((a1, a2) => a1.compareTo(a2)); - expect(instance.min(0, 10), 0); - expect(instance.min(10, 0), 0); - }); - - test('max', () { - final instance = Order.from((a1, a2) => a1.compareTo(a2)); - expect(instance.max(0, 10), 10); - expect(instance.max(10, 0), 10); - }); - - test('eqv', () { - final instance = Order.from((a1, a2) => a1.compareTo(a2)); - expect(instance.eqv(0, 10), false); - expect(instance.eqv(0, 0), true); - }); - - test('neqv', () { - final instance = Order.from((a1, a2) => a1.compareTo(a2)); - expect(instance.neqv(0, 10), true); - expect(instance.neqv(0, 0), false); - }); - - test('lteqv', () { - final instance = Order.from((a1, a2) => a1.compareTo(a2)); - expect(instance.lteqv(0, 10), true); - expect(instance.lteqv(0, 0), true); - expect(instance.lteqv(0, -1), false); - }); - - test('lt', () { - final instance = Order.from((a1, a2) => a1.compareTo(a2)); - expect(instance.lt(0, 10), true); - expect(instance.lt(0, 0), false); - expect(instance.lt(0, -1), false); - }); - - test('gteqv', () { - final instance = Order.from((a1, a2) => a1.compareTo(a2)); - expect(instance.gteqv(0, 10), false); - expect(instance.gteqv(0, 0), true); - expect(instance.gteqv(0, -1), true); - }); - - test('gt', () { - final instance = Order.from((a1, a2) => a1.compareTo(a2)); - expect(instance.gt(0, 10), false); - expect(instance.gt(0, 0), false); - expect(instance.gt(0, -1), true); - }); - - test('between', () { - final instance = Order.orderInt; - expect(instance.between(0, 10, 4), true); - expect(instance.between(0, 0, 0), true); - expect(instance.between(-1, 0, 0), true); - expect(instance.between(0, 10, 11), false); - expect(instance.between(0, 10, -1), false); - }); - - test('clamp', () { - final instance = Order.orderInt; - expect(instance.clamp(1, 10, 2), 2); - expect(instance.clamp(1, 10, 10), 10); - expect(instance.clamp(1, 10, 20), 10); - expect(instance.clamp(1, 10, 1), 1); - expect(instance.clamp(1, 10, -10), 1); - }); - - test('orderDate', () { - final prevDate = DateTime(2020); - final currDate = DateTime(2021); - final compareNegative = Order.orderDate.compare(prevDate, currDate); - final comparePositive = Order.orderDate.compare(currDate, prevDate); - final compareSame = Order.orderDate.compare(currDate, currDate); - expect(compareNegative, -1); - expect(comparePositive, 1); - expect(compareSame, 0); - }); - - test('orderNum', () { - final ord = Order.orderNum; - expect(ord.eqv(10, 10), true); - expect(ord.eqv(10.0, 10), true); - expect(ord.gt(10, 0), true); - expect(ord.gt(0, 10), false); - expect(ord.lt(0, 10), true); - }); - - test('orderDouble', () { - final ord = Order.orderDouble; - expect(ord.eqv(10.5, 10.5), true); - expect(ord.eqv(10.0, 10), true); - expect(ord.gt(1.5, 1.2), true); - expect(ord.gt(1.001, 1.005), false); - expect(ord.lt(0.5, 1.2), true); - }); - - test('orderInt', () { - final ord = Order.orderInt; - expect(ord.eqv(10, 10), true); - expect(ord.eqv(-10, 10), false); - expect(ord.gt(1, 1), false); - expect(ord.gt(10, 1), true); - expect(ord.lt(-2, 2), true); - }); - - group('contramap', () { - test('int', () { - final orderParentInt = Order.orderInt.contramap<_Parent>( - (p) => p.value1, - ); - - expect( - orderParentInt.eqv( - _Parent(1, 2.5), - _Parent(1, 12.5), - ), - true, - ); - expect( - orderParentInt.eqv( - _Parent(1, 2.5), - _Parent(4, 2.5), - ), - false, - ); - expect( - orderParentInt.eqv( - _Parent(-1, 2.5), - _Parent(1, 12.5), - ), - false, - ); - }); - - test('double', () { - final orderParentDouble = Order.orderDouble.contramap<_Parent>( - (p) => p.value2, - ); - - expect( - orderParentDouble.eqv( - _Parent(1, 2.5), - _Parent(1, 2.5), - ), - true, - ); - expect( - orderParentDouble.eqv( - _Parent(1, 2.5), - _Parent(1, 12.5), - ), - false, - ); - expect( - orderParentDouble.eqv( - _Parent(-1, 2.5), - _Parent(1, 2), - ), - false, - ); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/partial_order_test.dart b/packages/fpdart/test/src/partial_order_test.dart deleted file mode 100644 index aef2052e..00000000 --- a/packages/fpdart/test/src/partial_order_test.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('PartialOrder', () { - group('is a', () { - final instance = PartialOrder.from((a1, a2) => 1); - - test('Eq', () { - expect(instance, isA()); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/reader_task_either_test.dart b/packages/fpdart/test/src/reader_task_either_test.dart deleted file mode 100644 index b2f9569f..00000000 --- a/packages/fpdart/test/src/reader_task_either_test.dart +++ /dev/null @@ -1,943 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import './utils/utils.dart'; - -void main() { - group('ReaderTaskEither', () { - test('ask', () async { - final apply = ReaderTaskEither.ask(); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 12.2); - }); - }); - - test('asks', () async { - final apply = ReaderTaskEither.asks( - (env) => env.toInt(), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 12); - }); - }); - - group('getOrElse', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).getOrElse( - (left) => left.length, - ); - - final result = await apply.run(12.2); - expect(result, 12); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left(env.toString()), - ).getOrElse( - (left) => left.length, - ); - - final result = await apply.run(12.2); - expect(result, 4); - }); - }); - - group('match', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).match( - (left) => left.length, - (right) => right + 10, - ); - - final result = await apply.run(12.2); - expect(result, 22); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left(env.toString()), - ).match( - (left) => left.length, - (right) => right + 10, - ); - - final result = await apply.run(12.2); - expect(result, 4); - }); - }); - - group('tryCatch', () { - test('Success', () async { - final apply = ReaderTaskEither.tryCatch( - (env) => Future.value(env.toInt()), - (_, __) => 'error', - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 12); - }); - }); - - test('Failure', () async { - final apply = ReaderTaskEither.tryCatch( - (env) => Future.error(env.toInt()), - (_, __) => 'error', - ); - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "error"); - }); - }); - - test('throws Exception', () async { - final apply = ReaderTaskEither.tryCatch((_) { - throw UnimplementedError(); - }, (error, _) { - expect(error, isA()); - return 'error'; - }); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "error"); - }); - }); - }); - - group('flatMap', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).flatMap( - (r) => ReaderTaskEither( - (env) async => Either.of(r + env.toInt()), - ), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 24); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left("$env"), - ).flatMap( - (r) => ReaderTaskEither( - (env) async => Either.of(r + env.toInt()), - ), - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12.2"); - }); - }); - }); - - group('ap', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).ap( - ReaderTaskEither( - (env) async => Either.of((c) => c / 2), - ), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 6); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left("$env"), - ).ap( - ReaderTaskEither( - (env) async => Either.of((c) => c / 2), - ), - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12.2"); - }); - }); - }); - - group('map', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).map((r) => r / 2); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 6); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left('$env'), - ).map((r) => r / 2); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12.2"); - }); - }); - }); - - group('mapLeft', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).mapLeft( - (l) => '$l and more', - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 12); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left("$env"), - ).mapLeft( - (l) => '$l and more', - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12.2 and more"); - }); - }); - }); - - group('bimap', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).bimap( - (l) => '$l and more', - (a) => a * 2, - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 24); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left('$env'), - ).bimap( - (l) => '$l and more', - (a) => a * 2, - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12.2 and more"); - }); - }); - }); - - group('map2', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).map2( - ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ), - (b, c) => b / c, - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 1); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left('$env'), - ).map2( - ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ), - (b, c) => b / c, - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12.2"); - }); - }); - }); - - group('map3', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).map3( - ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ), - ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ), - (b, c, d) => b * c / d, - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 12); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left('$env'), - ).map3( - ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ), - ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ), - (b, c, d) => b * c / d, - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12.2"); - }); - }); - }); - - group('andThen', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).andThen( - () => ReaderTaskEither( - (env) async => Either.of( - env.toInt() / 2, - ), - ), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 6); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left('$env'), - ).andThen( - () => ReaderTaskEither( - (env) async => Either.of(env.toInt() / 2), - ), - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12.2"); - }); - }); - }); - - group('call', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - )( - ReaderTaskEither( - (env) async => Either.of(env.toInt() / 2), - ), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 6); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left('$env'), - )( - ReaderTaskEither( - (env) async => Either.of(env.toInt() / 2), - ), - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12.2"); - }); - }); - }); - - group('filterOrElse', () { - test('Right (true)', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).filterOrElse( - (r) => r > 5, - (r) => 'abc', - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 12); - }); - }); - - test('Right (false)', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).filterOrElse( - (r) => r < 5, - (r) => '$r', - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12"); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left("$env"), - ).filterOrElse( - (r) => r > 5, - (r) => 'none', - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12.2"); - }); - }); - }); - - test('pure', () async { - final apply = ReaderTaskEither( - (env) async => Either.left("$env"), - ).pure('abc'); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, "abc"); - }); - }); - - test('run', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ); - - final future = apply.run(12.2); - expect(future, isA()); - final result = await future; - result.matchTestRight((r) { - expect(r, 12); - }); - }); - - group('fromEither', () { - test('Right', () async { - final apply = ReaderTaskEither.fromEither( - Either.of(10), - ); - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither.fromEither( - Either.left('error'), - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "error"); - }); - }); - }); - - group('fromOption', () { - test('Right', () async { - final apply = ReaderTaskEither.fromOption( - Option.of(10), - () => 'none', - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither.fromOption( - Option.none(), - () => 'none', - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "none"); - }); - }); - }); - - group('fromNullable', () { - test('Right', () async { - final apply = ReaderTaskEither.fromNullable( - 10, - () => "Error", - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither.fromNullable( - null, - () => "error", - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "error"); - }); - }); - }); - - group('fromNullableAsync', () { - test('Right', () async { - final apply = ReaderTaskEither.fromNullableAsync( - 10, - Task( - () async => "Error", - ), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither.fromNullableAsync( - null, - Task( - () async => "error", - ), - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "error"); - }); - }); - }); - - test('fromTask', () async { - final apply = ReaderTaskEither.fromTask( - Task( - () async => 10, - ), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - group('fromIOOption', () { - test('Right', () async { - final apply = ReaderTaskEither.fromIOOption( - IOOption.of(10), - () => "none", - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither.fromIOOption( - IOOption.none(), - () => "none", - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "none"); - }); - }); - }); - - group('fromTaskOption', () { - test('Right', () async { - final apply = ReaderTaskEither.fromTaskOption( - TaskOption.of(10), - () => "none", - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither.fromTaskOption( - TaskOption.none(), - () => "none", - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "none"); - }); - }); - }); - - test('fromTaskEither', () async { - final apply = ReaderTaskEither.fromTaskEither( - TaskEither.of(10), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('fromIO', () async { - final apply = ReaderTaskEither.fromIO( - IO( - () => 10, - ), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('fromIOEither', () async { - final apply = ReaderTaskEither.fromIOEither( - IOEither.of(10), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('fromReader', () async { - final apply = ReaderTaskEither.fromReader( - Reader((env) => env.toInt()), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 12); - }); - }); - - test('leftReader', () async { - final apply = ReaderTaskEither.leftReader( - Reader((env) => "$env"), - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, "12.2"); - }); - }); - - test('left', () async { - final apply = ReaderTaskEither.left( - 'none', - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, 'none'); - }); - }); - - test('leftTask', () async { - final apply = ReaderTaskEither.leftTask( - Task( - () async => 'none', - ), - ); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, 'none'); - }); - }); - - group('orElse', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).orElse( - (l) => ReaderTaskEither( - (env) async => Right(l.length), - ), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 12); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left('$env'), - ).orElse( - (l) => ReaderTaskEither( - (env) async => Right(l.length), - ), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 4); - }); - }); - }); - - group('alt', () { - test('Right', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).alt( - () => ReaderTaskEither( - (env) async => Either.of(env.toInt() * 2), - ), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 12); - }); - }); - - test('Left', () async { - final apply = ReaderTaskEither( - (env) async => Either.left('none'), - ).alt( - () => ReaderTaskEither( - (env) async => Either.of(env.toInt() * 12), - ), - ); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 144); - }); - }); - }); - - test('swap', () async { - final apply = ReaderTaskEither( - (env) async => Either.of(env.toInt()), - ).swap(); - - final result = await apply.run(12.2); - result.matchTestLeft((l) { - expect(l, 12); - }); - }); - - test('of', () async { - final apply = ReaderTaskEither.of(10); - - final result = await apply.run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('flatten', () async { - final apply = ReaderTaskEither>.of( - ReaderTaskEither.of(10), - ); - - final result = await ReaderTaskEither.flatten(apply).run(12.2); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('chainFirst', () async { - final apply = ReaderTaskEither.of(10); - var sideEffect = 10; - - final chain = apply.chainFirst((b) { - sideEffect = 100; - return ReaderTaskEither.left("$b"); - }); - - expect(sideEffect, 10); - final result = await chain.run(12.2); - result.matchTestLeft((l) { - expect(l, "10"); - expect(sideEffect, 100); - }); - }); - - group('Do Notation', () { - test('should return the correct value', () async { - final doTaskEither = ReaderTaskEither.Do( - (_) => _( - ReaderTaskEither.asks((env) => env.toInt()), - ), - ); - - final run = await doTaskEither.run(12.2); - run.matchTestRight((r) { - expect(r, 12); - }); - }); - - test('should extract the correct values', () async { - final doTaskEither = - ReaderTaskEither.Do((_) async { - final a = await _(ReaderTaskEither.of(10)); - final b = await _(ReaderTaskEither.asks((env) => env.toInt())); - return a + b; - }); - - final run = await doTaskEither.run(12.2); - run.matchTestRight((r) { - expect(r, 22); - }); - }); - - test('should return Left if any Either is Left', () async { - final doTaskEither = - ReaderTaskEither.Do((_) async { - final a = await _(ReaderTaskEither.of(10)); - final b = await _(ReaderTaskEither.asks((env) => env.toInt())); - final c = await _( - ReaderTaskEither.left('error'), - ); - - return a + b + c; - }); - - final run = await doTaskEither.run(12.2); - run.matchTestLeft((l) { - expect(l, 'error'); - }); - }); - - test('should rethrow if throw is used inside Do', () { - final doTaskEither = ReaderTaskEither.Do((_) { - _(ReaderTaskEither.of(10)); - throw UnimplementedError(); - }); - - expect( - () => doTaskEither.run(12.2), - throwsA( - const TypeMatcher(), - ), - ); - }); - - test('should rethrow if Left is thrown inside Do', () { - final doTaskEither = ReaderTaskEither.Do((_) { - _( - ReaderTaskEither.of(10), - ); - throw Left('error'); - }); - - expect( - () => doTaskEither.run(12.2), - throwsA( - const TypeMatcher(), - ), - ); - }); - - test('should no execute past the first Left', () async { - var mutable = 10; - - final doTaskEitherLeft = - ReaderTaskEither.Do((_) async { - final a = await _(ReaderTaskEither.of(10)); - final b = - await _(ReaderTaskEither.left("error")); - mutable += 10; - return a + b; - }); - - final runLeft = await doTaskEitherLeft.run(12.2); - expect(mutable, 10); - runLeft.matchTestLeft((l) { - expect(l, "error"); - }); - - final doTaskEitherRight = - ReaderTaskEither.Do((_) async { - final a = await _(ReaderTaskEither.asks((env) => env.toInt())); - mutable += 10; - return a; - }); - - final runRight = await doTaskEitherRight.run(12.2); - expect(mutable, 20); - runRight.matchTestRight((r) { - expect(r, 12); - }); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/reader_task_test.dart b/packages/fpdart/test/src/reader_task_test.dart deleted file mode 100644 index 0ae274f9..00000000 --- a/packages/fpdart/test/src/reader_task_test.dart +++ /dev/null @@ -1,228 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import 'utils/utils.dart'; - -void main() { - group('ReaderTask', () { - test('ask', () async { - final apply = ReaderTask.ask(); - - final result = await apply.run("abc"); - expect(result, "abc"); - }); - - test('asks', () async { - final apply = ReaderTask.asks( - (env) => env.length, - ); - - final result = await apply.run("abc"); - expect(result, 3); - }); - - group('map', () { - test('int to int', () async { - final apply = ReaderTask( - (env) async => env.length, - ).map((a) => a + 1); - - final result = await apply.run("abc"); - expect(result, 4); - }); - }); - - test('ap', () async { - final apply = ReaderTask( - (env) async => env.length, - ).ap( - ReaderTask( - (env) async => (a) => a + 1, - ), - ); - - final result = await apply.run("abc"); - expect(result, 4); - }); - - test('flatMap', () async { - final apply = ReaderTask( - (env) async => env.length, - ) - .flatMap( - (a) => ReaderTask( - (env) async => '$a-$env', - ), - ) - .flatMap( - (a) => ReaderTask( - (env) async => a.length + env.length, - ), - ); - - final result = await apply.run("abc"); - expect(result, 8); - }); - - test('pure', () async { - final apply = ReaderTask( - (env) async => env.length, - ).pure('abc'); - - final result = await apply.run("abc"); - expect(result, 'abc'); - }); - - test('map2', () async { - final apply = ReaderTask( - (env) async => env.length, - ).map2( - ReaderTask.of('abc'), - (a, c) => a + c.length, - ); - - final result = await apply.run("abc"); - expect(result, 6); - }); - - test('map3', () async { - final apply = ReaderTask( - (env) async => env.length, - ).map3( - ReaderTask.of(2), - ReaderTask.of('abc'), - (a, c, d) => (a + d.length) / c, - ); - - final result = await apply.run("abc"); - expect(result, 3); - }); - - test('of', () async { - final apply = ReaderTask.of(10); - - final result = await apply.run("abc"); - expect(result, 10); - }); - - test('run', () async { - final apply = ReaderTask.of(10); - final future = apply.run("abc"); - - expect(future, isA>()); - final result = await future; - expect(result, 10); - }); - - test('flatten', () async { - final apply = ReaderTask>.of( - ReaderTask.of(10), - ); - - final mid = await apply.run("abc"); - final flatten = ReaderTask.flatten(apply); - - final resultMid = await mid.run("abc"); - final resultFlatten = await flatten.run("abc"); - - expect(resultMid, 10); - expect(resultFlatten, 10); - expect(resultMid, resultFlatten); - }); - - group('andThen', () { - test('run a Task after another Task', () async { - final apply = ReaderTask( - (env) async => env.length, - ).andThen( - () => ReaderTask( - (env) async => env.length * 2, - ), - ); - - final result = await apply.run("abc"); - expect(result, 6); - }); - - test('never run the second Task since the first throws', () async { - final apply = ReaderTask( - (env) async => throw UnimplementedError(), - ); - - final result = apply.andThen( - () => ReaderTask.of(12.2), - ); - expect(() => result.run("abc"), - throwsA(const TypeMatcher())); - }); - }); - - group('call', () { - test('run a Task after another Task', () async { - final apply = ReaderTask( - (env) async => env.length, - )(ReaderTask.of('abc')); - - final result = await apply.run("abc"); - expect(result, 'abc'); - }); - - test('run the second Task but return throw error', () async { - final apply = - ReaderTask((env) async => throw UnimplementedError())( - ReaderTask.of('abc'), - ); - - expect(() => apply.run("abc"), - throwsA(const TypeMatcher())); - }); - }); - - test('toReaderTaskEither', () async { - final apply = ReaderTask.of(10).toReaderTaskEither(); - - final result = await apply.run("abc"); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - group('Do Notation', () { - test('should return the correct value', () async { - final doTask = ReaderTask.Do( - (_) => _( - ReaderTask.of(10), - ), - ); - - final run = await doTask.run("abc"); - expect(run, 10); - }); - - test('should extract the correct values', () async { - final doTask = ReaderTask.Do((_) async { - final a = await _(ReaderTask((env) async => env.length)); - final b = await _(ReaderTask((env) async => env.length)); - return a + b; - }); - - final run = await doTask.run("abc"); - expect(run, 6); - }); - - test('should not execute until run is called', () async { - var mutable = 10; - final doTask = ReaderTask.Do((_) async { - final a = await _(ReaderTask.of(10)); - final b = await _(ReaderTask.of(5)); - mutable += 10; - return a + b; - }); - - expect(mutable, 10); - final run = await doTask.run("abc"); - expect(mutable, 20); - expect(run, 15); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/reader_test.dart b/packages/fpdart/test/src/reader_test.dart deleted file mode 100644 index 20730b71..00000000 --- a/packages/fpdart/test/src/reader_test.dart +++ /dev/null @@ -1,134 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('Reader', () { - group('is a', () { - final reader = Reader((r) => r.length); - - test('Monad', () { - expect(reader, isA()); - }); - - test('Applicative', () { - expect(reader, isA()); - }); - - test('Functor', () { - expect(reader, isA()); - }); - }); - - test('map', () { - final reader = Reader((r) => r.length); - final ap = reader.map((a) => a + 1); - final result = ap.run('abc'); - expect(result, 4); - }); - - test('map2', () { - final reader = Reader((r) => r.length); - final reader1 = Reader((r) => r.length * 2); - final ap = reader.map2(reader1, (a, c) => a * c); - final result = ap.run('abc'); - expect(result, 18); - }); - - test('map3', () { - final reader = Reader((r) => r.length); - final reader1 = Reader((r) => r.length * 2); - final reader2 = Reader((r) => r.length * 3); - final ap = - reader.map3(reader1, reader2, (a, c, d) => a * c * d); - final result = ap.run('ab'); - expect(result, 48); - }); - - test('ap', () { - final reader = Reader((r) => r.length); - final ap = - reader.ap(Reader((a) => (int n) => (n + a.length) / 2)); - final result = ap.run('abc'); - expect(result, 3.0); - }); - - test('flatMap', () { - final reader = Reader((r) => r.length); - final ap = - reader.flatMap((a) => Reader((b) => a + b.length)); - final result = ap.run('abc'); - expect(result, 6); - }); - - test('pure', () { - final reader = Reader((r) => r.length); - final ap = reader.pure(10); - final result = ap.run('abc'); - expect(result, 10); - }); - - test('andThen', () { - final reader = Reader((r) => r.length); - final ap = - reader.andThen(() => Reader((r) => r.length / 2)); - final result = ap.run('abc'); - expect(result, 1.5); - }); - - test('call', () { - final reader = Reader((r) => r.length); - final ap = reader(Reader((r) => r.length / 2)); - final result = ap.run('abc'); - expect(result, 1.5); - }); - - test('compose', () { - final reader = Reader((r) => r.length); - final ap = reader.compose(Reader((r) => r.length / 2)); - final result = ap.run('abc'); - expect(result, 1.5); - }); - - test('local', () { - final reader = Reader((r) => r.length); - final ap = reader.local((context) => '$context'); - final result = ap.run(7.5); - expect(result, 3); - }); - - test('ask', () { - final reader = Reader((r) => r.length); - final ap = reader.ask(); - final result = ap.run('abc'); - expect(result, 'abc'); - }); - - test('asks', () { - final reader = Reader((r) => r.length); - final ap = reader.asks((r) => r.length * 2); - final result = ap.run('abc'); - expect(result, 6); - }); - - test('flatten', () { - final reader = Reader>( - (r) => Reader((r) => r.length)); - final ap = Reader.flatten(reader); - expect(ap, isA>()); - final result = ap.run('abc'); - expect(result, 3); - }); - }); - - test('chainFirst', () async { - final task = Reader(((r) => r.length)); - var sideEffect = 10; - final chain = task.chainFirst((b) { - sideEffect = 100; - return Reader((r) => r.length / 2); - }); - final r = await chain.run("abc"); - expect(r, 3); - expect(sideEffect, 100); - }); -} diff --git a/packages/fpdart/test/src/semigroup_test.dart b/packages/fpdart/test/src/semigroup_test.dart deleted file mode 100644 index d8470c44..00000000 --- a/packages/fpdart/test/src/semigroup_test.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('Semigroup', () { - test('.instance', () { - final instance = Semigroup.instance((a1, a2) => '$a1$a2'); - expect(instance.combine('a', 'b'), 'ab'); - expect(instance.combine('a', instance.combine('b', 'c')), - instance.combine(instance.combine('a', 'b'), 'c')); - expect(instance.combineN('a', 3), 'aaa'); - }); - - test('.first', () { - final instance = Semigroup.first(); - expect(instance.combine('a', 'b'), 'a'); - expect(instance.combine('a', instance.combine('b', 'c')), - instance.combine(instance.combine('a', 'b'), 'c')); - expect(instance.combineN('a', 3), 'a'); - }); - - test('.last', () { - final instance = Semigroup.last(); - expect(instance.combine('a', 'b'), 'b'); - expect(instance.combine('a', instance.combine('b', 'c')), - instance.combine(instance.combine('a', 'b'), 'c')); - expect(instance.combineN('a', 3), 'a'); - }); - - test('.combineN', () { - final instance = Semigroup.instance((a1, a2) => a1 + a2); - expect(instance.combineN(1, 10), 10); - }); - - test('.intercalate', () { - final instance = Semigroup.instance((a1, a2) => '$a1$a2'); - final intercalate = instance.intercalate('-'); - expect(intercalate.combine('a', 'b'), 'a-b'); - expect(intercalate.combineN('a', 3), 'a-a-a'); - }); - - test('.reverse', () { - final instance = Semigroup.instance((a1, a2) => '$a1$a2'); - final reverse = instance.reverse(); - expect(reverse.combine('a', 'b'), 'ba'); - expect(reverse.combine('a', 'b'), instance.combine('b', 'a')); - }); - }); -} diff --git a/packages/fpdart/test/src/semilattice_test.dart b/packages/fpdart/test/src/semilattice_test.dart deleted file mode 100644 index f1e73bd7..00000000 --- a/packages/fpdart/test/src/semilattice_test.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('Semilattice', () { - group('is a', () { - final instance = Semilattice.instance((a1, a2) => a1 + a2); - - test('Semigroup', () { - expect(instance, isA()); - }); - - test('Band', () { - expect(instance, isA()); - }); - - test('CommutativeSemigroup', () { - expect(instance, isA()); - }); - }); - - test('combineN (from Band)', () { - final instance = Semilattice.instance((a1, a2) => a1 + a2); - expect(instance.combineN(1, 1), 1); - expect(instance.combineN(1, 10), 2); - }); - - test('asMeetPartialOrder', () { - final instance = Semilattice.instance((a1, a2) => a1 + a2); - final eq = Eq.instance((a1, a2) => a1 == a2); - final partialOrder = instance.asMeetPartialOrder(eq); - expect(partialOrder.partialCompare(1, 1), 0); - expect(partialOrder.partialCompare(1, 0), -1); - expect(partialOrder.partialCompare(0, 1), 1); - expect(partialOrder.partialCompare(2, 1), null); - }); - - test('asJoinPartialOrder', () { - final instance = Semilattice.instance((a1, a2) => a1 + a2); - final eq = Eq.instance((a1, a2) => a1 == a2); - final partialOrder = instance.asJoinPartialOrder(eq); - expect(partialOrder.partialCompare(1, 1), 0); - expect(partialOrder.partialCompare(1, 0), 1); - expect(partialOrder.partialCompare(0, 1), -1); - expect(partialOrder.partialCompare(2, 1), null); - }); - }); -} diff --git a/packages/fpdart/test/src/state_async_test.dart b/packages/fpdart/test/src/state_async_test.dart deleted file mode 100644 index da0fb9cf..00000000 --- a/packages/fpdart/test/src/state_async_test.dart +++ /dev/null @@ -1,214 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('StateAsync', () { - group('is a', () { - final state = StateAsync((s) async => (s.length, '${s}a')); - - test('Monad', () { - expect(state, isA()); - }); - - test('Applicative', () { - expect(state, isA()); - }); - - test('Functor', () { - expect(state, isA()); - }); - }); - - test('map', () async { - final state = StateAsync((s) async => (s.length, '${s}a')); - final ap = state.map((a) => a + 1); - final result = await ap.run('aaa'); - expect(result.$1, 4); - expect(result.$2, 'aaaa'); - }); - - test('map2', () async { - final state = StateAsync((s) async => (s.length, '${s}a')); - final state1 = StateAsync( - (s) async => (s.length / 2, '${s}b'), - ); - final ap = state.map2(state1, (a, c) => c * a); - final result = await ap.run('aaa'); - expect(result.$1, 6); - expect(result.$2, 'aaaab'); - }); - - test('map3', () async { - final state = StateAsync( - (s) async => (s.length, '${s}a'), - ); - final state1 = StateAsync( - (s) async => (s.length / 2, '${s}b'), - ); - final state2 = StateAsync( - (s) async => ('${s}aaa', '${s}b'), - ); - final ap = state.map3( - state1, - state2, - (a, c, d) => d.length + (c * a), - ); - final result = await ap.run('aaa'); - expect(result.$1, 14); - expect(result.$2, 'aaaabb'); - }); - - test('ap', () async { - final state = StateAsync( - (s) async => (s.length, '${s}a'), - ); - final ap = state.ap( - StateAsync( - (s) async => ((int n) => '$n$s', s), - ), - ); - final result = await ap.run('aaa'); - expect(result.$1, '3aaa'); - expect(result.$2, 'aaaa'); - }); - - test('andThen', () async { - final state = StateAsync( - (s) async => (s.length, '${s}a'), - ); - final ap = state.andThen( - () => StateAsync( - (s) async => (s.length / 2, '${s}a'), - ), - ); - final result = await ap.run('aaa'); - expect(result.$1, 2); - expect(result.$2, 'aaaaa'); - }); - - test('call', () async { - final state = StateAsync( - (s) async => (s.length, '${s}a'), - ); - final ap = state( - StateAsync( - (s) async => (s.length / 2, '${s}a'), - ), - ); - final result = await ap.run('aaa'); - expect(result.$1, 2); - expect(result.$2, 'aaaaa'); - }); - - test('fromState', () async { - final state = - StateAsync.fromState(State((s) => (s.length, '${s}a'))); - final result = await state.run('aaa'); - expect(result.$1, 3); - expect(result.$2, 'aaaa'); - }); - - test('pure', () async { - final state = StateAsync((s) async => (s.length, '${s}a')); - final ap = state.pure(10); - final result = await ap.run('aaa'); - expect(result.$1, 10); - expect(result.$2, 'aaa'); - }); - - test('flatMap', () async { - final state = - StateAsync, int>((s) async => (s.first, s.sublist(1))); - final ap = state.flatMap( - (a) => StateAsync( - (s) async => (a / 2, s.sublist(1)), - ), - ); - final result = await ap.run([1, 2, 3, 4, 5]); - expect(result.$1, 0.5); - expect(result.$2, [3, 4, 5]); - }); - - test('get', () async { - final state = StateAsync((s) async => (s.length, '${s}a')); - final ap = state.get(); - final result = await ap.run('aaa'); - expect(result.$1, 'aaa'); - expect(result.$2, 'aaa'); - }); - - test('gets', () async { - final state = StateAsync((s) async => (s.length, '${s}a')); - final ap = state.gets((s) => s.length * 2); - final result = await ap.run('aaa'); - expect(result.$1, 6); - expect(result.$2, 'aaa'); - }); - - test('modify', () async { - final state = StateAsync((s) async => (s.length, '${s}a')); - final ap = state.modify((state) => 'b$state'); - final result = await ap.run('aaa'); - expect(result.$1, unit); - expect(result.$2, 'baaa'); - }); - - test('put', () async { - final state = StateAsync((s) async => (s.length, '${s}a')); - final ap = state.put('b'); - final result = await ap.run('aaa'); - expect(result.$2, 'b'); - }); - - test('evaluate', () async { - final state = StateAsync((s) async => (s.length, '${s}a')); - final result = await state.evaluate('aaa'); - expect(result, 3); - }); - - test('execute', () async { - final state = StateAsync((s) async => (s.length, '${s}a')); - final result = await state.execute('aaa'); - expect(result, 'aaaa'); - }); - - test('run', () async { - final state = StateAsync((s) async => (s.length, '${s}a')); - final result = await state.run('aaa'); - expect(result, isA()); - expect(result.$1, 3); - expect(result.$2, 'aaaa'); - }); - - test('flatten', () async { - final state = StateAsync>( - (s) async => ( - StateAsync( - (s) async => (s.length, '${s}a'), - ), - '${s}a', - ), - ); - final ap = StateAsync.flatten(state); - expect(ap, isA>()); - final result = await ap.run('aaa'); - expect(result.$1, 4); - expect(result.$2, 'aaaaa'); - }); - }); - - test('chainFirst', () async { - final state = StateAsync((s) async => (s.length, '${s}a')); - var sideEffect = 10; - final chain = state.chainFirst((b) { - sideEffect = 100; - return StateAsync((s) async => (s.length / 2, 'z${s}')); - }); - final result = await chain.run('abc'); - expect(result.$1, 3); - - // It changes the value of `second`! - expect(result.$2, 'zabca'); - expect(sideEffect, 100); - }); -} diff --git a/packages/fpdart/test/src/state_test.dart b/packages/fpdart/test/src/state_test.dart deleted file mode 100644 index 9be0f845..00000000 --- a/packages/fpdart/test/src/state_test.dart +++ /dev/null @@ -1,266 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('State', () { - group('is a', () { - final state = State((s) => (s.length, '${s}a')); - - test('Monad', () { - expect(state, isA()); - }); - - test('Applicative', () { - expect(state, isA()); - }); - - test('Functor', () { - expect(state, isA()); - }); - }); - - test('map', () { - final state = State((s) => (s.length, '${s}a')); - final ap = state.map((a) => a + 1); - final result = ap.run('aaa'); - expect(result.$1, 4); - expect(result.$2, 'aaaa'); - }); - - test('map2', () { - final state = State((s) => (s.length, '${s}a')); - final state1 = State( - (s) => (s.length / 2, '${s}b'), - ); - final ap = state.map2(state1, (a, c) => c * a); - final result = ap.run('aaa'); - expect(result.$1, 6); - expect(result.$2, 'aaaab'); - }); - - test('map3', () { - final state = State( - (s) => (s.length, '${s}a'), - ); - final state1 = State( - (s) => (s.length / 2, '${s}b'), - ); - final state2 = State( - (s) => ('${s}aaa', '${s}b'), - ); - final ap = state.map3( - state1, - state2, - (a, c, d) => d.length + (c * a), - ); - final result = ap.run('aaa'); - expect(result.$1, 14); - expect(result.$2, 'aaaabb'); - }); - - test('ap', () { - final state = State( - (s) => (s.length, '${s}a'), - ); - final ap = state.ap( - State( - (s) => ((int n) => '$n$s', s), - ), - ); - final result = ap.run('aaa'); - expect(result.$1, '3aaa'); - expect(result.$2, 'aaaa'); - }); - - test('andThen', () { - final state = State( - (s) => (s.length, '${s}a'), - ); - final ap = state.andThen( - () => State( - (s) => (s.length / 2, '${s}a'), - ), - ); - final result = ap.run('aaa'); - expect(result.$1, 2); - expect(result.$2, 'aaaaa'); - }); - - test('call', () { - final state = State( - (s) => (s.length, '${s}a'), - ); - final ap = state( - State( - (s) => (s.length / 2, '${s}a'), - ), - ); - final result = ap.run('aaa'); - expect(result.$1, 2); - expect(result.$2, 'aaaaa'); - }); - - test('toStateAsync', () async { - final state = State((s) => (s.length, '${s}a')); - final ap = state.toStateAsync(); - final result = await ap.run('aaa'); - expect(result.$1, 3); - expect(result.$2, 'aaaa'); - }); - - test('pure', () { - final state = State((s) => (s.length, '${s}a')); - final ap = state.pure(10); - final result = ap.run('aaa'); - expect(result.$1, 10); - expect(result.$2, 'aaa'); - }); - - test('flatMap', () { - final state = State, int>((s) => (s.first, s.sublist(1))); - final ap = state.flatMap( - (a) => State( - (s) => (a / 2, s.sublist(1)), - ), - ); - final result = ap.run([1, 2, 3, 4, 5]); - expect(result.$1, 0.5); - expect(result.$2, [3, 4, 5]); - }); - - test('get', () { - final state = State((s) => (s.length, '${s}a')); - final ap = state.get(); - final result = ap.run('aaa'); - expect(result.$1, 'aaa'); - expect(result.$2, 'aaa'); - }); - - test('gets', () { - final state = State((s) => (s.length, '${s}a')); - final ap = state.gets((s) => s.length * 2); - final result = ap.run('aaa'); - expect(result.$1, 6); - expect(result.$2, 'aaa'); - }); - - test('modify', () { - final state = State((s) => (s.length, '${s}a')); - final ap = state.modify((state) => 'b$state'); - final result = ap.run('aaa'); - expect(result.$1, unit); - expect(result.$2, 'baaa'); - }); - - test('put', () { - final state = State((s) => (s.length, '${s}a')); - final ap = state.put('b'); - final result = ap.run('aaa'); - expect(result.$2, 'b'); - }); - - test('evaluate', () { - final state = State((s) => (s.length, '${s}a')); - final result = state.evaluate('aaa'); - expect(result, 3); - }); - - test('execute', () { - final state = State((s) => (s.length, '${s}a')); - final result = state.execute('aaa'); - expect(result, 'aaaa'); - }); - - test('run', () { - final state = State((s) => (s.length, '${s}a')); - final result = state.run('aaa'); - expect(result, isA()); - expect(result.$1, 3); - expect(result.$2, 'aaaa'); - }); - - test('flatten', () { - final state = State>( - (s) => ( - State( - (s) => (s.length, '${s}a'), - ), - '${s}a', - ), - ); - final ap = State.flatten(state); - expect(ap, isA>()); - final result = ap.run('aaa'); - expect(result.$1, 4); - expect(result.$2, 'aaaaa'); - }); - }); - - test('chainFirst', () { - final state = State((s) => (s.length, '${s}a')); - var sideEffect = 10; - final chain = state.chainFirst((b) { - sideEffect = 100; - return State((s) => (s.length / 2, 'z${s}')); - }); - final result = chain.run('abc'); - expect(result.$1, 3); - - // It changes the value of `second`! - expect(result.$2, 'zabca'); - expect(sideEffect, 100); - }); - - test('traverseListWithIndex', () { - var sideEffect = 0; - final list = ['a', 'b']; - - final traverse = State.traverseListWithIndex( - list, - (a, i) => State((s) { - sideEffect++; - return (a + i.toString(), s); - })); - expect(sideEffect, 0); - final (resultList, resultState) = traverse.run(1); - expect(resultList, ['a0', 'b1']); - expect(resultState, 1); - expect(sideEffect, list.length); - }); - - test('traverseList', () { - var sideEffect = 0; - final list = ['a', 'b']; - final traverse = State.traverseList( - list, - (a) => State((s) { - sideEffect++; - return (a, s); - })); - expect(sideEffect, 0); - final (resultList, resultState) = traverse.run(1); - expect(resultList, ['a', 'b']); - expect(resultState, 1); - expect(sideEffect, list.length); - }); - - test('sequenceList', () { - var sideEffect = 0; - final list = [ - State((s) { - sideEffect++; - return ('a', s); - }), - State((s) { - sideEffect++; - return ('b', s); - }) - ]; - final sequence = State.sequenceList(list); - expect(sideEffect, 0); - final (resultList, resultState) = sequence.run(1); - expect(resultList, ['a', 'b']); - expect(resultState, 1); - expect(sideEffect, list.length); - }); -} diff --git a/packages/fpdart/test/src/task_either_test.dart b/packages/fpdart/test/src/task_either_test.dart deleted file mode 100644 index 2e45e7dc..00000000 --- a/packages/fpdart/test/src/task_either_test.dart +++ /dev/null @@ -1,1027 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import './utils/utils.dart'; - -void main() { - group('TaskEither', () { - group('tryCatch', () { - test('Success', () async { - final task = TaskEither.tryCatch( - () => Future.value(10), (_, __) => 'error'); - final r = await task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Failure', () async { - final task = TaskEither.tryCatch( - () => Future.error(10), (_, __) => 'error'); - final r = await task.run(); - r.match((l) => expect(l, 'error'), (_) { - fail('should be left'); - }); - }); - - test('throws Exception', () async { - final task = TaskEither.tryCatch(() { - throw UnimplementedError(); - }, (error, _) { - expect(error, isA()); - return 'error'; - }); - final r = await task.run(); - r.match((l) => expect(l, 'error'), (_) { - fail('should be left'); - }); - }); - }); - - group('tryCatchK', () { - test('Success', () async { - final task = TaskEither.right(10); - final ap = task.flatMap(TaskEither.tryCatchK( - (n) => Future.value(n + 5), - (_, __) => 'error', - )); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 15)); - }); - - test('Failure', () async { - final task = TaskEither.right(10); - final ap = task.flatMap(TaskEither.tryCatchK( - (n) => Future.error(n + 5), - (_, __) => 'error', - )); - final r = await ap.run(); - r.match((l) => expect(l, 'error'), (_) { - fail('should be left'); - }); - }); - - test('throws Exception', () async { - final task = TaskEither.right(10); - final ap = task.flatMap(TaskEither.tryCatchK((_) { - throw UnimplementedError(); - }, (error, _) { - expect(error, isA()); - return 'error'; - })); - final r = await ap.run(); - r.match((l) => expect(l, 'error'), (_) { - fail('should be left'); - }); - }); - }); - - group('flatMap', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.flatMap( - (r) => TaskEither(() async => Either.of(r + 10))); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 20)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task.flatMap( - (r) => TaskEither(() async => Either.of(r + 10))); - final r = await ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('chainEither', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.chainEither((r) => Either.of(r + 10)); - final r = await ap.run(); - r.matchTestRight((r) => expect(r, 20)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task.chainEither((r) => Either.of(r + 10)); - final r = await ap.run(); - r.matchTestLeft((l) => expect(l, 'abc')); - }); - }); - - group('bindEither', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.bindEither(Either.of(2.5)); - final r = await ap.run(); - r.matchTestRight((r) => expect(r, 2.5)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task.bindEither(Either.of(2.5)); - final r = await ap.run(); - r.matchTestLeft((l) => expect(l, 'abc')); - }); - }); - - group('ap', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task - .ap(TaskEither(() async => Either.of((int c) => c / 2))); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 5.0)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task - .ap(TaskEither(() async => Either.of((int c) => c / 2))); - final r = await ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('map', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.map((r) => r / 2); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 5.0)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task.map((r) => r / 2); - final r = await ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('mapLeft', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.mapLeft((l) => '$l and more'); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task.mapLeft((l) => '$l and more'); - final r = await ap.run(); - r.match((l) => expect(l, 'abc and more'), (_) { - fail('should be left'); - }); - }); - }); - - group('bimap', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.bimap((l) => '$l and more', (a) => a * 2); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 20)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task.bimap((l) => '$l and more', (a) => a * 2); - final r = await ap.run(); - r.match((l) => expect(l, 'abc and more'), (_) { - fail('should be left'); - }); - }); - }); - - group('map2', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.map2( - TaskEither(() async => Either.of(2)), (b, c) => b / c); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 5.0)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task.map2( - TaskEither(() async => Either.of(2)), (b, c) => b / c); - final r = await ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('map3', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.map3( - TaskEither(() async => Either.of(2)), - TaskEither(() async => Either.of(5)), - (b, c, d) => b * c / d); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 4.0)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task.map3( - TaskEither(() async => Either.of(2)), - TaskEither(() async => Either.of(5)), - (b, c, d) => b * c / d); - final r = await ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('andThen', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.andThen( - () => TaskEither(() async => Either.of(12.5))); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 12.5)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task.andThen( - () => TaskEither(() async => Either.of(12.5))); - final r = await ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - group('call', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = - task(TaskEither(() async => Either.of(12.5))); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 12.5)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = - task(TaskEither(() async => Either.of(12.5))); - final r = await ap.run(); - r.match((r) { - expect(r, 'abc'); - }, (_) { - fail('should be left'); - }); - }); - }); - - group('filterOrElse', () { - test('Right (true)', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.filterOrElse((r) => r > 5, (r) => 'abc'); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Right (false)', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.filterOrElse((r) => r < 5, (r) => 'none'); - final r = await ap.run(); - r.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task.filterOrElse((r) => r > 5, (r) => 'none'); - final r = await ap.run(); - r.match((l) => expect(l, 'abc'), (_) { - fail('should be left'); - }); - }); - }); - - test('pure', () async { - final task = TaskEither(() async => Either.left('abc')); - final ap = task.pure('abc'); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 'abc')); - }); - - test('run', () async { - final task = TaskEither(() async => Either.of(10)); - final future = task.run(); - expect(future, isA()); - final r = await future; - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - group('fromEither', () { - test('Right', () async { - final task = TaskEither.fromEither(Either.of(10)); - final r = await task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () async { - final task = TaskEither.fromEither(Either.left('error')); - final r = await task.run(); - r.match((l) => expect(l, 'error'), (_) { - fail('should be left'); - }); - }); - }); - - group('fromOption', () { - test('Right', () async { - final task = - TaskEither.fromOption(Option.of(10), () => 'none'); - final r = await task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () async { - final task = - TaskEither.fromOption(Option.none(), () => 'none'); - final r = await task.run(); - r.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - }); - - group('fromNullable', () { - test('Right', () async { - final task = TaskEither.fromNullable(10, () => "Error"); - final result = await task.run(); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('Left', () async { - final task = TaskEither.fromNullable(null, () => "Error"); - final result = await task.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - }); - }); - - group('fromNullableAsync', () { - test('Right', () async { - final task = TaskEither.fromNullableAsync( - 10, Task(() async => "Error")); - final result = await task.run(); - result.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('Left', () async { - final task = TaskEither.fromNullableAsync( - null, Task(() async => "Error")); - final result = await task.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - }); - }); - - group('fromPredicate', () { - test('True', () async { - final task = TaskEither.fromPredicate( - 20, (n) => n > 10, (n) => '$n'); - final r = await task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 20)); - }); - - test('False', () async { - final task = TaskEither.fromPredicate( - 10, (n) => n > 10, (n) => '$n'); - final r = await task.run(); - r.match((l) => expect(l, '10'), (_) { - fail('should be left'); - }); - }); - }); - - test('fromTask', () async { - final task = TaskEither.fromTask(Task(() async => 10)); - final r = await task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('left', () async { - final task = TaskEither.left('none'); - final r = await task.run(); - r.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - - test('right', () async { - final task = TaskEither.right(10); - final r = await task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('leftTask', () async { - final task = TaskEither.leftTask(Task(() async => 'none')); - final r = await task.run(); - r.match((l) => expect(l, 'none'), (_) { - fail('should be left'); - }); - }); - - test('rightTask', () async { - final task = TaskEither.rightTask(Task.of(10)); - final r = await task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - group('match', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ex = task.match((l) => l.length, (r) => r + 10); - final r = await ex.run(); - expect(r, 20); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('none')); - final ex = task.match((l) => l.length, (r) => r + 10); - final r = await ex.run(); - expect(r, 4); - }); - }); - - group('getOrElse', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ex = task.getOrElse((l) => l.length); - final r = await ex.run(); - expect(r, 10); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('none')); - final ex = task.getOrElse((l) => l.length); - final r = await ex.run(); - expect(r, 4); - }); - }); - - group('orElse', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ex = - task.orElse((l) => TaskEither(() async => Right(l.length))); - final r = await ex.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('none')); - final ex = - task.orElse((l) => TaskEither(() async => Right(l.length))); - final r = await ex.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 4)); - }); - }); - - group('alt', () { - test('Right', () async { - final task = TaskEither(() async => Either.of(10)); - final ex = task.alt(() => TaskEither(() async => Either.of(20))); - final r = await ex.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('Left', () async { - final task = TaskEither(() async => Either.left('none')); - final ex = task.alt(() => TaskEither(() async => Either.of(20))); - final r = await ex.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 20)); - }); - }); - - test('swap', () async { - final task = TaskEither(() async => Either.of(10)); - final ex = task.swap(); - final r = await ex.run(); - r.match((l) => expect(l, 10), (_) { - fail('should be left'); - }); - }); - - test('of', () async { - final task = TaskEither.of(10); - final r = await task.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('flatten', () async { - final task = TaskEither>.of( - TaskEither.of(10)); - final ap = TaskEither.flatten(task); - final r = await ap.run(); - r.match((_) { - fail('should be right'); - }, (r) => expect(r, 10)); - }); - - test('chainFirst', () async { - final task = TaskEither.of(10); - var sideEffect = 10; - final chain = task.chainFirst((b) { - sideEffect = 100; - return TaskEither.left("abc"); - }); - final r = await chain.run(); - r.match( - (l) => fail('should be right'), - (r) { - expect(r, 10); - expect(sideEffect, 100); - }, - ); - }); - - test('delay', () async { - final task = TaskEither(() async => Either.of(10)); - final ap = task.delay(const Duration(seconds: 2)); - final stopwatch = Stopwatch(); - stopwatch.start(); - await ap.run(); - stopwatch.stop(); - expect(stopwatch.elapsedMilliseconds >= 2000, true); - }); - - group('sequenceList', () { - test('Right', () async { - var sideEffect = 0; - final list = [ - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return right(1); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return right(2); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return right(3); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return right(4); - }), - ]; - final traverse = TaskEither.sequenceList(list); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, list.length); - }); - - test('Left', () async { - var sideEffect = 0; - final list = [ - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return right(1); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return left("Error"); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return right(3); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return right(4); - }), - ]; - final traverse = TaskEither.sequenceList(list); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - - group('traverseList', () { - test('Right', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskEither.traverseList( - list, - (a) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return right("$a"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, list.length); - }); - - test('Left', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskEither.traverseList( - list, - (a) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return a % 2 == 0 - ? right("$a") - : left("Error"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - - group('traverseListWithIndex', () { - test('Right', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskEither.traverseListWithIndex( - list, - (a, i) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return right("$a$i"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, list.length); - }); - - test('Left', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskEither.traverseListWithIndex( - list, - (a, i) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return a % 2 == 0 - ? right("$a$i") - : left("Error"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, list.length); - }); - }); - - group('sequenceListSeq', () { - test('Right', () async { - var sideEffect = 0; - final list = [ - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 0; - return right(1); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 1; - return right(2); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 2; - return right(3); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 3; - return right(4); - }), - ]; - final traverse = TaskEither.sequenceListSeq(list); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, 3); - }); - - test('Left', () async { - var sideEffect = 0; - final list = [ - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 0; - return right(1); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 1; - return left("Error"); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 2; - return right(3); - }), - TaskEither(() async { - await AsyncUtils.waitFuture(); - sideEffect = 3; - return right(4); - }), - ]; - final traverse = TaskEither.sequenceListSeq(list); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, 3); - }); - }); - - group('traverseListSeq', () { - test('Right', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskEither.traverseListSeq( - list, - (a) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a - 1; - return right("$a"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, 5); - }); - - test('Left', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskEither.traverseListSeq( - list, - (a) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a - 1; - return a % 2 == 0 - ? right("$a") - : left("Error"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, 5); - }); - }); - - group('traverseListWithIndexSeq', () { - test('Right', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = - TaskEither.traverseListWithIndexSeq( - list, - (a, i) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a + i; - return right("$a$i"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestRight((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, 11); - }); - - test('Left', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = - TaskEither.traverseListWithIndexSeq( - list, - (a, i) => TaskEither( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a + i; - return a % 2 == 0 - ? right("$a$i") - : left("Error"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestLeft((l) { - expect(l, "Error"); - }); - expect(sideEffect, 11); - }); - }); - - group('Do Notation', () { - test('should return the correct value', () async { - final doTaskEither = - TaskEither.Do((_) => _(TaskEither.of(10))); - final run = await doTaskEither.run(); - run.matchTestRight((t) { - expect(t, 10); - }); - }); - - test('should extract the correct values', () async { - final doTaskEither = TaskEither.Do((_) async { - final a = await _(TaskEither.of(10)); - final b = await _(TaskEither.of(5)); - return a + b; - }); - final run = await doTaskEither.run(); - run.matchTestRight((t) { - expect(t, 15); - }); - }); - - test('should return Left if any Either is Left', () async { - final doTaskEither = TaskEither.Do((_) async { - final a = await _(TaskEither.of(10)); - final b = await _(TaskEither.of(5)); - final c = await _(TaskEither.left('Error')); - return a + b + c; - }); - final run = await doTaskEither.run(); - run.matchTestLeft((t) { - expect(t, 'Error'); - }); - }); - - test('should rethrow if throw is used inside Do', () { - final doTaskEither = TaskEither.Do((_) { - _(TaskEither.of(10)); - throw UnimplementedError(); - }); - - expect( - doTaskEither.run, throwsA(const TypeMatcher())); - }); - - test('should rethrow if Left is thrown inside Do', () { - final doTaskEither = TaskEither.Do((_) { - _(TaskEither.of(10)); - throw Left('Error'); - }); - - expect(doTaskEither.run, throwsA(const TypeMatcher())); - }); - - test('should no execute past the first Left', () async { - var mutable = 10; - final doTaskEitherLeft = TaskEither.Do((_) async { - final a = await _(TaskEither.of(10)); - final b = await _(TaskEither.left("Error")); - mutable += 10; - return a + b; - }); - - final runLeft = await doTaskEitherLeft.run(); - expect(mutable, 10); - runLeft.matchTestLeft((l) { - expect(l, "Error"); - }); - - final doTaskEitherRight = TaskEither.Do((_) async { - final a = await _(TaskEither.of(10)); - mutable += 10; - return a; - }); - - final runRight = await doTaskEitherRight.run(); - expect(mutable, 20); - runRight.matchTestRight((t) { - expect(t, 10); - }); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/task_option_test.dart b/packages/fpdart/test/src/task_option_test.dart deleted file mode 100644 index 0c1a727d..00000000 --- a/packages/fpdart/test/src/task_option_test.dart +++ /dev/null @@ -1,748 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import './utils/utils.dart'; - -void main() { - group('TaskOption', () { - group('tryCatch', () { - test('Success', () async { - final task = TaskOption.tryCatch(() => Future.value(10)); - final r = await task.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('Failure', () async { - final task = TaskOption.tryCatch(() => Future.error(10)); - final r = await task.run(); - expect(r, isA()); - }); - - test('throws Exception', () async { - final task = TaskOption.tryCatch(() { - throw UnimplementedError(); - }); - final r = await task.run(); - expect(r, isA()); - }); - }); - - group('tryCatchK', () { - test('Success', () async { - final task = TaskOption.of(10); - final ap = task.flatMap(TaskOption.tryCatchK( - (n) => Future.value(n + 5), - )); - final r = await ap.run(); - r.matchTestSome((r) => expect(r, 15)); - }); - - test('Failure', () async { - final task = TaskOption.of(10); - final ap = task.flatMap(TaskOption.tryCatchK( - (n) => Future.error(n + 5), - )); - final r = await ap.run(); - expect(r, isA()); - }); - - test('throws Exception', () async { - final task = TaskOption.of(10); - final ap = task.flatMap(TaskOption.tryCatchK((_) { - throw UnimplementedError(); - })); - final r = await ap.run(); - expect(r, isA()); - }); - }); - - group('flatMap', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final ap = - task.flatMap((r) => TaskOption(() async => Option.of(r + 10))); - final r = await ap.run(); - r.matchTestSome((r) => expect(r, 20)); - }); - - test('None', () async { - final task = TaskOption(() async => Option.none()); - final ap = - task.flatMap((r) => TaskOption(() async => Option.of(r + 10))); - final r = await ap.run(); - expect(r, isA()); - }); - }); - - group('ap', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final ap = task - .ap(TaskOption(() async => Option.of((int c) => c / 2))); - final r = await ap.run(); - r.matchTestSome((r) => expect(r, 5.0)); - }); - - test('None', () async { - final task = TaskOption(() async => Option.none()); - final ap = task - .ap(TaskOption(() async => Option.of((int c) => c / 2))); - final r = await ap.run(); - expect(r, isA()); - }); - }); - - group('map', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final ap = task.map((r) => r / 2); - final r = await ap.run(); - r.matchTestSome((r) => expect(r, 5.0)); - }); - - test('None', () async { - final task = TaskOption(() async => Option.none()); - final ap = task.map((r) => r / 2); - final r = await ap.run(); - expect(r, isA()); - }); - }); - - group('map2', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final ap = task.map2( - TaskOption(() async => Option.of(2)), (b, c) => b / c); - final r = await ap.run(); - r.matchTestSome((r) => expect(r, 5.0)); - }); - - test('None', () async { - final task = TaskOption(() async => Option.none()); - final ap = task.map2( - TaskOption(() async => Option.of(2)), (b, c) => b / c); - final r = await ap.run(); - expect(r, isA()); - }); - }); - - group('map3', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final ap = task.map3( - TaskOption(() async => Option.of(2)), - TaskOption(() async => Option.of(5)), - (b, c, d) => b * c / d); - final r = await ap.run(); - r.matchTestSome((r) => expect(r, 4.0)); - }); - - test('None', () async { - final task = TaskOption(() async => Option.none()); - final ap = task.map3( - TaskOption(() async => Option.of(2)), - TaskOption(() async => Option.of(5)), - (b, c, d) => b * c / d); - final r = await ap.run(); - expect(r, isA()); - }); - }); - - group('andThen', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final ap = - task.andThen(() => TaskOption(() async => Option.of(12.5))); - final r = await ap.run(); - r.matchTestSome((r) => expect(r, 12.5)); - }); - - test('None', () async { - final task = TaskOption(() async => Option.none()); - final ap = - task.andThen(() => TaskOption(() async => Option.of(12.5))); - final r = await ap.run(); - expect(r, isA()); - }); - }); - - group('call', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final ap = task(TaskOption(() async => Option.of(12.5))); - final r = await ap.run(); - r.matchTestSome((r) => expect(r, 12.5)); - }); - - test('None', () async { - final task = TaskOption(() async => Option.none()); - final ap = task(TaskOption(() async => Option.of(12.5))); - final r = await ap.run(); - expect(r, isA()); - }); - }); - - test('pure', () async { - final task = TaskOption(() async => Option.none()); - final ap = task.pure('abc'); - final r = await ap.run(); - r.matchTestSome((r) => expect(r, 'abc')); - }); - - test('run', () async { - final task = TaskOption(() async => Option.of(10)); - final future = task.run(); - expect(future, isA()); - final r = await future; - r.matchTestSome((r) => expect(r, 10)); - }); - - group('fromEither', () { - test('Some', () async { - final task = TaskOption.fromEither(Either.of(10)); - final r = await task.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('None', () async { - final task = TaskOption.fromEither(Either.left('none')); - final r = await task.run(); - expect(r, isA()); - }); - }); - - group('fromNullable', () { - test('Right', () async { - final task = TaskOption.fromNullable(10); - final result = await task.run(); - result.matchTestSome((r) { - expect(r, 10); - }); - }); - - test('Left', () async { - final task = TaskOption.fromNullable(null); - final result = await task.run(); - expect(result, isA()); - }); - }); - - group('fromPredicate', () { - test('True', () async { - final task = TaskOption.fromPredicate(20, (n) => n > 10); - final r = await task.run(); - r.matchTestSome((r) => expect(r, 20)); - }); - - test('False', () async { - final task = TaskOption.fromPredicate(10, (n) => n > 10); - final r = await task.run(); - expect(r, isA()); - }); - }); - - test('fromTask', () async { - final task = TaskOption.fromTask(Task(() async => 10)); - final r = await task.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('none()', () async { - final task = TaskOption.none(); - final r = await task.run(); - expect(r, isA()); - }); - - test('some()', () async { - final task = TaskOption.some(10); - final r = await task.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - group('match', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final ex = task.match(() => -1, (r) => r + 10); - final r = await ex.run(); - expect(r, 20); - }); - - test('None', () async { - final task = TaskOption(() async => Option.none()); - final ex = task.match(() => -1, (r) => r + 10); - final r = await ex.run(); - expect(r, -1); - }); - }); - - group('getOrElse', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final ex = task.getOrElse(() => -1); - final r = await ex.run(); - expect(r, 10); - }); - - test('None', () async { - final task = TaskOption(() async => Option.none()); - final ex = task.getOrElse(() => -1); - final r = await ex.run(); - expect(r, -1); - }); - }); - - group('orElse', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final ex = - task.orElse(() => TaskOption(() async => Option.of(-1))); - final r = await ex.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('None', () async { - final task = TaskOption(() async => Option.none()); - final ex = - task.orElse(() => TaskOption(() async => Option.of(-1))); - final r = await ex.run(); - r.matchTestSome((r) => expect(r, -1)); - }); - }); - - group('alt', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final ex = task.alt(() => TaskOption(() async => Option.of(20))); - final r = await ex.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('None', () async { - final task = TaskOption(() async => Option.none()); - final ex = task.alt(() => TaskOption(() async => Option.of(20))); - final r = await ex.run(); - r.matchTestSome((r) => expect(r, 20)); - }); - }); - - test('of', () async { - final task = TaskOption.of(10); - final r = await task.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('flatten', () async { - final task = TaskOption>.of(TaskOption.of(10)); - final ap = TaskOption.flatten(task); - final r = await ap.run(); - r.matchTestSome((r) => expect(r, 10)); - }); - - test('delay', () async { - final task = TaskOption(() async => Option.of(10)); - final ap = task.delay(const Duration(seconds: 2)); - final stopwatch = Stopwatch(); - stopwatch.start(); - await ap.run(); - stopwatch.stop(); - expect(stopwatch.elapsedMilliseconds >= 2000, true); - }); - - group('toTaskEither', () { - test('Some', () async { - final task = TaskOption(() async => Option.of(10)); - final convert = task.toTaskEither(() => 'None'); - final r = await convert.run(); - r.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('None', () async { - final task = TaskOption(() async => const Option.none()); - final convert = task.toTaskEither(() => 'None'); - final r = await convert.run(); - r.matchTestLeft((l) { - expect(l, 'None'); - }); - }); - }); - - group('sequenceList', () { - test('Some', () async { - var sideEffect = 0; - final list = [ - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some(1); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some(2); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some(3); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some(4); - }), - ]; - final traverse = TaskOption.sequenceList(list); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, list.length); - }); - - test('None', () async { - var sideEffect = 0; - final list = [ - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some(1); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return none(); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some(3); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some(4); - }), - ]; - final traverse = TaskOption.sequenceList(list); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - - group('traverseList', () { - test('Some', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskOption.traverseList( - list, - (a) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some("$a"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, list.length); - }); - - test('None', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskOption.traverseList( - list, - (a) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return a % 2 == 0 ? some("$a") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - - group('traverseListWithIndex', () { - test('Some', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskOption.traverseListWithIndex( - list, - (a, i) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return some("$a$i"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, list.length); - }); - - test('None', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskOption.traverseListWithIndex( - list, - (a, i) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return a % 2 == 0 ? some("$a$i") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, list.length); - }); - }); - - group('sequenceListSeq', () { - test('Some', () async { - var sideEffect = 0; - final list = [ - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 0; - return some(1); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 1; - return some(2); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 2; - return some(3); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 3; - return some(4); - }), - ]; - final traverse = TaskOption.sequenceListSeq(list); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, [1, 2, 3, 4]); - }); - expect(sideEffect, 3); - }); - - test('None', () async { - var sideEffect = 0; - final list = [ - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 0; - return some(1); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 1; - return none(); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 2; - return some(3); - }), - TaskOption(() async { - await AsyncUtils.waitFuture(); - sideEffect = 3; - return some(4); - }), - ]; - final traverse = TaskOption.sequenceListSeq(list); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, 3); - }); - }); - - group('traverseListSeq', () { - test('Some', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskOption.traverseListSeq( - list, - (a) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a - 1; - return some("$a"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, ['1', '2', '3', '4', '5', '6']); - }); - expect(sideEffect, 5); - }); - - test('None', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskOption.traverseListSeq( - list, - (a) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a - 1; - return a % 2 == 0 ? some("$a") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, 5); - }); - }); - - group('traverseListWithIndexSeq', () { - test('Some', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskOption.traverseListWithIndexSeq( - list, - (a, i) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a + i; - return some("$a$i"); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - result.matchTestSome((t) { - expect(t, ['10', '21', '32', '43', '54', '65']); - }); - expect(sideEffect, 11); - }); - - test('None', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = TaskOption.traverseListWithIndexSeq( - list, - (a, i) => TaskOption( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a + i; - return a % 2 == 0 ? some("$a$i") : none(); - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, isA()); - expect(sideEffect, 11); - }); - }); - - group('Do Notation', () { - test('should return the correct value', () async { - final doTaskOption = TaskOption.Do((_) => _(TaskOption.of(10))); - final run = await doTaskOption.run(); - run.matchTestSome((t) { - expect(t, 10); - }); - }); - - test('should extract the correct values', () async { - final doTaskOption = TaskOption.Do((_) async { - final a = await _(TaskOption.of(10)); - final b = await _(TaskOption.of(5)); - return a + b; - }); - final run = await doTaskOption.run(); - run.matchTestSome((t) { - expect(t, 15); - }); - }); - - test('should return Left if any Either is Left', () async { - final doTaskOption = TaskOption.Do((_) async { - final a = await _(TaskOption.of(10)); - final b = await _(TaskOption.of(5)); - final c = await _(TaskOption.none()); - return a + b + c; - }); - final run = await doTaskOption.run(); - expect(run, isA()); - }); - - test('should rethrow if throw is used inside Do', () { - final doTaskOption = TaskOption.Do((_) { - _(TaskOption.of(10)); - throw UnimplementedError(); - }); - - expect( - doTaskOption.run, throwsA(const TypeMatcher())); - }); - - test('should rethrow if None is thrown inside Do', () { - final doTaskOption = TaskOption.Do((_) { - _(TaskOption.of(10)); - throw const None(); - }); - - expect(doTaskOption.run, throwsA(const TypeMatcher())); - }); - - test('should no execute past the first Left', () async { - var mutable = 10; - final doTaskOptionNone = TaskOption.Do((_) async { - final a = await _(TaskOption.of(10)); - final b = await _(TaskOption.none()); - mutable += 10; - return a + b; - }); - - final runNone = await doTaskOptionNone.run(); - expect(mutable, 10); - expect(runNone, isA()); - - final doTaskOptionSome = TaskOption.Do((_) async { - final a = await _(TaskOption.of(10)); - mutable += 10; - return a; - }); - - final runSome = await doTaskOptionSome.run(); - expect(mutable, 20); - runSome.matchTestSome((t) { - expect(t, 10); - }); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/task_test.dart b/packages/fpdart/test/src/task_test.dart deleted file mode 100644 index 22c78c6c..00000000 --- a/packages/fpdart/test/src/task_test.dart +++ /dev/null @@ -1,318 +0,0 @@ -import 'package:fpdart/fpdart.dart'; - -import 'utils/utils.dart'; - -void main() { - group('Task', () { - group('map', () { - test('int to int', () async { - final task = Task(() async => 10); - final ap = task.map((a) => a + 1); - expect(ap, isA>()); - final r = await ap.run(); - expect(r, 11); - }); - - test('String to int', () async { - final task = Task(() async => 'abc'); - final ap = task.map((a) => a.length); - expect(ap, isA>()); - final r = await ap.run(); - expect(r, 3); - }); - }); - - test('ap', () async { - final task = Task(() async => 10); - final ap = task.ap(Task(() async => (int a) => a + 1)); - expect(ap, isA()); - final r = await ap.run(); - expect(r, 11); - }); - - test('flatMap', () async { - final task = Task(() async => 10); - final ap = task - .flatMap((a) => Task(() async => '$a')) - .flatMap((a) => Task(() async => a.length)); - expect(ap, isA()); - final r = await ap.run(); - expect(r, 2); - }); - - test('pure', () async { - final task = Task(() async => 10); - final ap = task.pure('abc'); - final r = await ap.run(); - expect(r, 'abc'); - }); - - test('map2', () async { - final task = Task(() async => 10); - final m2 = task.map2(Task.of('abc'), (a, c) => a + c.length); - final r = await m2.run(); - expect(r, 13); - }); - - test('map3', () async { - final task = Task(() async => 10); - final m3 = task.map3( - Task.of(2), Task.of('abc'), (a, c, d) => (a + d.length) / c); - final r = await m3.run(); - expect(r, 6.5); - }); - - test('delay', () async { - final task = Task(() async => 10); - final ap = task.delay(const Duration(seconds: 2)); - final stopwatch = Stopwatch(); - stopwatch.start(); - await ap.run(); - stopwatch.stop(); - expect(stopwatch.elapsedMilliseconds >= 2000, true); - }); - - test('of', () async { - final task = Task.of(10); - final r = await task.run(); - expect(r, 10); - }); - - test('run', () async { - final task = Task.of(10); - final future = task.run(); - expect(future, isA>()); - final r = await future; - expect(r, 10); - }); - - test('flatten', () async { - final task = Task.of(Task.of(10)); - final t1 = await task.run(); - final t2 = await t1.run(); - final ap = Task.flatten(task); - final r = await ap.run(); - expect(r, 10); - expect(t2, 10); - expect(r, t2); - }); - - group('andThen', () { - test('run a Task after another Task', () async { - final task = Task(() async => 10); - final ap = task.andThen(() => Task.of('abc')); - final r = await ap.run(); - expect(r, 'abc'); - }); - - test('never run the second Task since the first throws', () async { - final task = Task(() async => throw UnimplementedError()); - final ap = task.andThen(() => Task.of('abc')); - expect(ap.run, throwsA(const TypeMatcher())); - }); - }); - - group('call', () { - test('run a Task after another Task', () async { - final task = Task(() async => 10); - final ap = task(Task.of('abc')); - final r = await ap.run(); - expect(r, 'abc'); - }); - - test('run the second Task but return throw error', () async { - final task = Task(() async => throw UnimplementedError()); - final ap = task(Task.of('abc')); - expect(ap.run, throwsA(const TypeMatcher())); - }); - }); - - test('toTaskOption', () async { - final io = Task.of(10); - final convert = io.toTaskOption(); - final r = await convert.run(); - r.matchTestSome((r) { - expect(r, 10); - }); - }); - - test('toTaskEither', () async { - final io = Task.of(10); - final convert = io.toTaskEither(); - final r = await convert.run(); - r.matchTestRight((r) { - expect(r, 10); - }); - }); - - test('sequenceList', () async { - var sideEffect = 0; - final list = [ - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return 1; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return 2; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return 3; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return 4; - }), - ]; - final traverse = Task.sequenceList(list); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, [1, 2, 3, 4]); - expect(sideEffect, list.length); - }); - - test('sequenceListSeq', () async { - var sideEffect = 0; - final list = [ - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect = 0; - return 1; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect = 1; - return 2; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect = 2; - return 3; - }), - Task(() async { - await AsyncUtils.waitFuture(); - sideEffect = 3; - return 4; - }), - ]; - final traverse = Task.sequenceListSeq(list); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, [1, 2, 3, 4]); - expect(sideEffect, 3); - }); - - test('traverseList', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = Task.traverseList( - list, - (a) => Task( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return "$a"; - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, ['1', '2', '3', '4', '5', '6']); - expect(sideEffect, list.length); - }); - - test('traverseListWithIndex', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = Task.traverseListWithIndex( - list, - (a, i) => Task( - () async { - await AsyncUtils.waitFuture(); - sideEffect += 1; - return "$a$i"; - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, ['10', '21', '32', '43', '54', '65']); - expect(sideEffect, list.length); - }); - - test('traverseListSeq', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = Task.traverseListSeq( - list, - (a) => Task( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a; - return "$a"; - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, ['1', '2', '3', '4', '5', '6']); - expect(sideEffect, 6); - }); - - test('traverseListWithIndexSeq', () async { - final list = [1, 2, 3, 4, 5, 6]; - var sideEffect = 0; - final traverse = Task.traverseListWithIndexSeq( - list, - (a, i) => Task( - () async { - await AsyncUtils.waitFuture(); - sideEffect = a + i; - return "$a$i"; - }, - ), - ); - expect(sideEffect, 0); - final result = await traverse.run(); - expect(result, ['10', '21', '32', '43', '54', '65']); - expect(sideEffect, 11); - }); - - group('Do Notation', () { - test('should return the correct value', () async { - final doTask = Task.Do((_) => _(Task.of(10))); - final run = await doTask.run(); - expect(run, 10); - }); - - test('should extract the correct values', () async { - final doTask = Task.Do((_) async { - final a = await _(Task.of(10)); - final b = await _(Task.of(5)); - return a + b; - }); - final run = await doTask.run(); - expect(run, 15); - }); - - test('should not execute until run is called', () async { - var mutable = 10; - final doTask = Task.Do((_) async { - final a = await _(Task.of(10)); - final b = await _(Task.of(5)); - mutable += 10; - return a + b; - }); - expect(mutable, 10); - final run = await doTask.run(); - expect(mutable, 20); - expect(run, 15); - }); - }); - }); -} diff --git a/packages/fpdart/test/src/test_extension.dart b/packages/fpdart/test/src/test_extension.dart new file mode 100644 index 00000000..8f9b6f2c --- /dev/null +++ b/packages/fpdart/test/src/test_extension.dart @@ -0,0 +1,22 @@ +import 'package:fpdart/fpdart.dart'; +import 'package:test/test.dart'; + +extension EitherTest on Either { + void expectLeft(Function(L value) onLeft) { + switch (this) { + case Right(value: final value): + fail("Either expected to be Left, Right instead: $value"); + case Left(value: final value): + onLeft(value); + } + } + + void expectRight(Function(R value) onRight) { + switch (this) { + case Right(value: final value): + onRight(value); + case Left(value: final value): + fail("Either expected to be Right, Left instead: $value"); + } + } +} diff --git a/packages/fpdart/test/src/unit_test.dart b/packages/fpdart/test/src/unit_test.dart deleted file mode 100644 index 01db0aa6..00000000 --- a/packages/fpdart/test/src/unit_test.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:fpdart/src/unit.dart'; -import 'package:test/test.dart'; - -void main() { - group('Unit', () { - test('only one instance', () { - const unit1 = unit; - const unit2 = unit; - expect(unit1, unit2); - expect(unit1.hashCode, unit2.hashCode); - }); - - test('toString', () async { - expect(unit.toString(), '()'); - }); - }); -} diff --git a/packages/fpdart/test/src/utils/async_utils.dart b/packages/fpdart/test/src/utils/async_utils.dart deleted file mode 100644 index f2e535ca..00000000 --- a/packages/fpdart/test/src/utils/async_utils.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'dart:math'; - -abstract class AsyncUtils { - /// Wait a random number of milliseconds between - /// 0 and `maxMilliseconds`. - static Future waitFuture({ - /// Max number of milliseconds to wait - int maxMilliseconds = 300, - }) => - Future.delayed( - Duration( - milliseconds: Random().nextInt(maxMilliseconds), - ), - ); -} diff --git a/packages/fpdart/test/src/utils/collection_utils.dart b/packages/fpdart/test/src/utils/collection_utils.dart deleted file mode 100644 index fa90b144..00000000 --- a/packages/fpdart/test/src/utils/collection_utils.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:test/test.dart'; - -final objectDeepEquality = const DeepCollectionEquality().equals; - -void testImmutableMap( - Map source, - void Function(Map value) test, -) { - final originalSource = {...source}; - test(source); - expect( - objectDeepEquality(originalSource, source), - true, - reason: - "The provided element is not immutable: ${source} should be ${originalSource}", - ); -} diff --git a/packages/fpdart/test/src/utils/glados_utils.dart b/packages/fpdart/test/src/utils/glados_utils.dart deleted file mode 100644 index 16e6e8ff..00000000 --- a/packages/fpdart/test/src/utils/glados_utils.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:glados/glados.dart'; - -extension AnyOption on Any { - /// `glados` [Generator] for [Option] of any type [T], given - /// a generator for type [T]. - /// - /// `ratioNone` defines the ratio of [None] in the test (default 10%). - Generator> optionGenerator( - Generator source, { - double ratioNone = 0.1, - }) => - (random, size) => (random.nextDouble() > ratioNone - ? source.map(some) - : source.map((value) => none()))(random, size); - - /// [Generator] for `Option` - Generator> get optionInt => optionGenerator(any.int); - - /// [Generator] for `Option` - Generator> get optionDouble => optionGenerator(any.double); - - /// [Generator] for `Option` - Generator> get optionString => - optionGenerator(any.letterOrDigits); -} - -extension AnyEither on Any { - /// `glados` [Generator] for [Either] of any type [L] and [R], given - /// a generator for type [L] and [R]. - /// - /// `ratioLeft` defines the ratio of [Left] in the test (default 50%). - Generator> eitherGenerator( - Generator leftSource, - Generator rightSource, { - double ratioLeft = 0.5, - }) => - (random, size) => (random.nextDouble() > ratioLeft - ? leftSource.map>(left) - : rightSource.map>(right))(random, size); - - /// [Generator] for `Either` - Generator> get eitherStringInt => - eitherGenerator(any.letterOrDigits, any.int); -} diff --git a/packages/fpdart/test/src/utils/match_utils.dart b/packages/fpdart/test/src/utils/match_utils.dart deleted file mode 100644 index 1d6c0bc7..00000000 --- a/packages/fpdart/test/src/utils/match_utils.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:fpdart/fpdart.dart'; -import 'package:test/test.dart'; - -extension OptionMatch on Option { - /// Run test on [Some], call `fail` if [None]. - void matchTestSome(void Function(T t) testing) => match(() { - fail("should be some, found none"); - }, testing); -} - -extension EitherMatch on Either { - /// Run test on [Right], call `fail` if [Left]. - void matchTestRight(void Function(R r) testing) => match((l) { - fail("should be right, found left ('$l')"); - }, testing); - - /// Run test on [Left], call `fail` if [Right]. - void matchTestLeft(void Function(L l) testing) => match(testing, (r) { - fail("should be left, found right ('$r')"); - }); -} diff --git a/packages/fpdart/test/src/utils/utils.dart b/packages/fpdart/test/src/utils/utils.dart deleted file mode 100644 index f05a0172..00000000 --- a/packages/fpdart/test/src/utils/utils.dart +++ /dev/null @@ -1,6 +0,0 @@ -export 'package:glados/glados.dart'; - -export './async_utils.dart'; -export './collection_utils.dart'; -export './glados_utils.dart'; -export './match_utils.dart';