├── .github └── workflows │ └── dart.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── assets └── koan_example.gif ├── bin ├── dart_koans_runner.dart └── main.dart ├── doc └── .DS_Store ├── lib ├── chapter_1_about_asserts.dart └── chapter_2_about_string.dart ├── pubspec.yaml └── test ├── chapter_1_about_asserts_test.dart └── chapter_2_about_string_test.dart /.github/workflows/dart.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | name: Test Run Dart Koans 7 | 8 | on: 9 | push: 10 | branches: [ main ] 11 | pull_request: 12 | branches: [ main ] 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | # Note: This workflow uses the latest stable version of the Dart SDK. 22 | # You can specify other versions if desired, see documentation here: 23 | # https://github.com/dart-lang/setup-dart/blob/main/README.md 24 | # - uses: dart-lang/setup-dart@v1 25 | - uses: dart-lang/setup-dart@9a04e6d73cca37bd455e0608d7e5092f881fd603 26 | 27 | - name: Install dependencies 28 | run: dart pub get 29 | 30 | # Uncomment this step to verify the use of 'dart format' on each commit. 31 | # - name: Verify formatting 32 | # run: dart format --output=none --set-exit-if-changed . 33 | 34 | # Consider passing '--fatal-infos' for slightly stricter analysis. 35 | - name: Analyze project source 36 | run: dart analyze 37 | 38 | # Your project will need to have tests in test/ and a dependency on 39 | # package:test for this step to succeed. Note that Flutter projects will 40 | # want to change this to 'flutter test'. 41 | - name: Run tests 42 | run: dart test 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | # Remove the following pattern if you wish to check in your lock file 5 | pubspec.lock 6 | 7 | # Conventional directory for build outputs 8 | build/ 9 | 10 | # Directory created by dartdoc 11 | doc/api/ 12 | 13 | .vscode 14 | 15 | .idea 16 | *.iml -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | - Initial version, created by Stagehand 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | Thanks for even thinking to participate at this project! 3 | 4 | ## Guidelines 5 | 6 | ## Issues 7 | If you see any problems or have any feature requests please let us know in the [Issue section](https:///github.com/MyracleDesign/dart_koans/issues). -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Max Weber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Odysee Badge](https://img.shields.io/static/v1?label=Odysee&message=Invite&color=purple&style=flat-square&logo=odysee&logoColor=purple)](https://odysee.com/$/invite/@flutterexplained:7) 2 | [![YouTube Badge](https://img.shields.io/static/v1?label=YouTube&message=Subscribe&color=red&style=flat-square&logo=youtube&logoColor=red)](https://youtube.com/c/flutterexplained?sub_confirmation=1) 3 | [![Twitch Badge](https://img.shields.io/static/v1?label=Twitch&message=Follow&color=violet&style=flat-square&logo=twitch&logoColor=violet)](https://www.twitch.tv/maxflutter) 4 | [![Flutter Explained](https://img.shields.io/static/v1?label=Homepage&message=FlutterExplained&color=blue&style=flat-square)](https://flutter-explained.dev/) 5 | 6 | # Dart Koan 7 | 8 | A Koan is a learning method to learn a new programming language as developer friendly as possible. 9 | That means you will work and correct code in an IDE with the right tools that you would also use in a Work environment. 10 | 11 | This idea came up because there is currently a big interest in flutter and therefore also in Dart. 12 | 13 | 14 | 15 | ## Available Chapters 16 | - [Chapter 1: Asserts](./lib/chapter_1_about_asserts.dart) - Find your enlightment by working with asserts in Dart. 17 | - [Chapter 2: Strings](./lib/chapter_2_about_string.dart) - Working with Strings, concatinations and learning methods of the String object. 18 | 19 | ## Recommended Tools 20 | ### Intellij 21 | If you have Android Studio / Intellij from Jetbrains you have the testing framework already in place. 22 | 23 | 1) Install the Plugin for Dart 24 | 2) Install a Dart SDK 25 | 26 | Now you have a nice visual overlay for all your tests and can start learning dart. 27 | 28 | ### Visual Studio Code 29 | 1) Install the Plugin for Dart 30 | 2) Install a Dart SDK 31 | 32 | Now you have a nice visual overlay for all your tests and can start learning dart. 33 | 34 | ## How it works 35 | ![Koan Example](./assets/koan_example.gif) 36 | 37 | You have two options to start that project. 38 | 39 | ### Running it from the terminal 40 | 41 | Just start the 42 | 43 | ``` 44 | dart ./bin/main.dart 45 | ``` 46 | 47 | this will start the runner, you will have the task to change the code in the lib/folder to solve the challenges. 48 | 49 | ## Contribution 50 | Feel free to contribute to this project. 51 | 52 | # Special Thanks 53 | - [Buttermat](https://github.com/butlermatt) - For the initial idea 54 | - [Python Koans](https://github.com/gregmalcolm/python_koans) - My inspiration 55 | - [Stagehand](https://github.com/dart-lang/stagehand/blob/master/LICENSE) - They made it very easy to create this project 56 | - [Dart Team](https://dart.dev/) - For making this project even possible 57 | - [Flutter Team](https://flutter.dev/) - To motivate me to start with Dart in the first place 58 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | # see https://github.com/dart-lang/pedantic#enabled-lints. 4 | include: package:pedantic/analysis_options.yaml 5 | 6 | # For lint rules and documentation, see http://dart-lang.github.io/linter/lints. 7 | # Uncomment to specify additional rules. 8 | linter: 9 | rules: 10 | error: 11 | - public_member_api_docs 12 | 13 | info: 14 | - prefer_double_quotes 15 | - unused_local_variable 16 | -------------------------------------------------------------------------------- /assets/koan_example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flutter-Explained/dart_koans/bcc172d13f3f6772041032c2019f98aebec2c7d7/assets/koan_example.gif -------------------------------------------------------------------------------- /bin/dart_koans_runner.dart: -------------------------------------------------------------------------------- 1 | import 'dart:mirrors'; 2 | 3 | import 'package:ansicolor/ansicolor.dart'; 4 | import 'package:dart_koans/chapter_1_about_asserts.dart'; 5 | import 'package:dart_koans/chapter_2_about_string.dart'; 6 | 7 | void main() { 8 | ansiColorDisabled = false; 9 | List runnableChapters = [Chapter_I_asserts, Chapter_II_about_string]; 10 | bool isError = false; 11 | int classIndex = 0; 12 | 13 | while (!isError && classIndex < runnableChapters.length) { 14 | ClassMirror classMirror = reflectClass(runnableChapters[classIndex]); 15 | Map learningPathMethods = classMirror.instanceMembers; 16 | int methodIndex = 0; 17 | 18 | print(""); 19 | print( 20 | "Thinking About ${_createSymbolString(classMirror.simpleName)}", 21 | ); 22 | 23 | while (!isError && learningPathMethods.length != methodIndex) { 24 | var entry = learningPathMethods.entries.toList()[methodIndex]; 25 | methodIndex++; 26 | if (entry.value.simpleName.toString().contains("koan_")) { 27 | try { 28 | InstanceMirror instance = classMirror.newInstance(Symbol(""), []); 29 | instance.invoke(entry.key, []); 30 | AnsiPen pen = new AnsiPen()..green(bold: true); 31 | print( 32 | pen("✓ ${_createSymbolString(entry.key)} has expanded your awareness."), 33 | ); 34 | } catch (e) { 35 | AnsiPen penError = new AnsiPen()..red(bold: true); 36 | AnsiPen penWarning = new AnsiPen()..yellow(bold: true); 37 | print( 38 | penError("✖ ${_createSymbolString(entry.key)} has destroyed your karma"), 39 | ); 40 | print(""); 41 | print("Please think about the following:"); 42 | print(penWarning(e.toString())); 43 | isError = true; 44 | } 45 | } 46 | } 47 | if (!isError) { 48 | AnsiPen penSuccess = new AnsiPen()..green(bold: true); 49 | print(""); 50 | print( 51 | penSuccess( 52 | 'You completed ${_createSymbolString(classMirror.simpleName)} successful! 🎉🎉🎉', 53 | ), 54 | ); 55 | } 56 | 57 | classIndex++; 58 | } 59 | } 60 | 61 | /// Create the method name out of a Symbol 62 | String _createSymbolString(Symbol symbol) => symbol.toString().split('"')[1]; 63 | -------------------------------------------------------------------------------- /bin/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:io/io.dart'; 2 | import 'package:path/path.dart' as path; 3 | import 'package:watcher/watcher.dart'; 4 | 5 | main(List arguments) async { 6 | var watcher = DirectoryWatcher(path.relative("lib")); 7 | 8 | final manager = ProcessManager(); 9 | await manager.spawn( 10 | "dart", 11 | [ 12 | "--enable-asserts", 13 | path.absolute(path.relative("./bin/dart_koans_runner.dart")) 14 | ], 15 | ); 16 | 17 | print("Debug: Watcher is watching!"); 18 | watcher.events.listen((event) async { 19 | final manager = ProcessManager(); 20 | 21 | try { 22 | print("test"); 23 | await manager.spawn( 24 | "dart", 25 | [ 26 | "--enable-asserts", 27 | path.absolute(path.relative("./bin/dart_koans_runner.dart")) 28 | ], 29 | ); 30 | } catch (e) { 31 | print(e); 32 | } 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /doc/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flutter-Explained/dart_koans/bcc172d13f3f6772041032c2019f98aebec2c7d7/doc/.DS_Store -------------------------------------------------------------------------------- /lib/chapter_1_about_asserts.dart: -------------------------------------------------------------------------------- 1 | /// This is the first Chapter About Asserts 2 | /// it contains all tests to solve to learn Dart Asserts 3 | class Chapter_I_asserts { 4 | dynamic your_answer = null; 5 | 6 | void koan_about_asserts() { 7 | assert(true == false, "Hint: Change false to true"); 8 | } 9 | 10 | /// Should learn how to use our tests 11 | void koan_compare_values_with_each_other() { 12 | var expectedValue = 0; 13 | var realValue = 1 + 1; 14 | 15 | assert(realValue == expectedValue, 16 | 'Hint: The expectedValue seems to be wrong'); 17 | } 18 | 19 | void koan_also_type_is_important() { 20 | /// This is a variable it can store all kinds of data 21 | /// by just initialize it with the *var* keyword 22 | var expectedValue = '2'; 23 | 24 | /// You can also be precise and enter the type of the variable before 25 | int realValue = 1 + 1; 26 | 27 | /// Hint: Is a string a number? 28 | assert(realValue == expectedValue); 29 | } 30 | 31 | void koan_enter_values_to_succeed() { 32 | assert(your_answer == 'Congratulations!'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/chapter_2_about_string.dart: -------------------------------------------------------------------------------- 1 | class Chapter_II_about_string { 2 | dynamic your_answer = null; 3 | 4 | void koan_double_quoted_strings_are_strings() { 5 | var double_quoted_string = "Hello, world"; 6 | assert(your_answer is String, "Hint: Replace your_answer with string"); 7 | } 8 | 9 | void koan_single_quoted_strings_are_strings() { 10 | var single_quoted_string = 'Goodbye, world'; 11 | assert(your_answer is String, "Hint: Replace your_answer with string"); 12 | } 13 | 14 | void koan_triple_quoted_strings_are_also_strings() { 15 | var triple_quoted_string = """Hallo Welt"""; 16 | assert(your_answer is String, 17 | "Hint Replace your_answer with triple_quoted_string"); 18 | } 19 | 20 | void koan_triple_single_quoted_strings_work_too() { 21 | var triple_single_quoted_string = '''Bonjour tout le monde!'''; 22 | assert(your_answer is String, 23 | "Hint Replace your_answer with triple_single_quoted_string"); 24 | } 25 | 26 | void koan_raw_strings_are_also_strings() { 27 | var rawString = r"Konnichi wa, world!"; 28 | assert(your_answer is String, "Hint Replace your_answer with rawString"); 29 | } 30 | 31 | void koan_use_single_quotes_to_create_string_with_double_quotes() { 32 | var string = 'He said, "Go Away."'; 33 | assert(your_answer == string); 34 | } 35 | 36 | void koan_use_double_quotes_to_create_string_with_single_quotes() { 37 | var string = "Don't"; 38 | assert(your_answer == string); 39 | } 40 | 41 | void koan_use_backslash_for_escaping_quotes_in_strings() { 42 | var a = "He said, \"Don't\""; 43 | var b = 'He said, "Don\'t"'; 44 | assert(a != b); 45 | } 46 | 47 | void koan_triple_quoted_strings_can_span_lines() { 48 | var string = """ 49 | Greetings, 50 | Partner! 51 | """; 52 | 53 | assert(your_answer == string.length); 54 | } 55 | 56 | void koan_triple_quoted_strings_need_less_escaping() { 57 | var a = "Hello \"world\"."; 58 | var b = """Hello "world"."""; 59 | 60 | assert(a != b); 61 | } 62 | 63 | void koan_escaping_quotes_at_the_end_of_a_triple_quoted_string() { 64 | var string = """Hello "world\""""; 65 | assert(your_answer == string); 66 | } 67 | 68 | void koan_plus_concatenates_strings() { 69 | var string = "Hello" + ", " + "World"; 70 | assert(your_answer == string); 71 | } 72 | 73 | void koan_$_is_a_better_concatination() { 74 | var a = "Hello"; 75 | var b = "World"; 76 | 77 | assert(your_answer == "$a, $b"); 78 | } 79 | 80 | void koan_dollar_plus_curly_brackets_allows_attributes_selection() { 81 | var string = "Concatenation is great!"; 82 | assert(your_answer == "${string.length}"); 83 | } 84 | 85 | void koan_adjacent_strings_are_concatenated_automatically() { 86 | var string = "Hello" ", " "World"; 87 | assert(your_answer == string); 88 | } 89 | 90 | void koan_plus_will_not_modify_the_original_strings() { 91 | var foo = "Hello, "; 92 | var bar = "World"; 93 | var string = foo + bar; 94 | 95 | assert(your_answer == foo); 96 | assert(your_answer == bar); 97 | } 98 | 99 | void koan_plus_equals_will_append_to_the_end_of_the_string() { 100 | var foo = "Hello, "; 101 | var bar = "World"; 102 | foo += bar; 103 | assert(your_answer == foo); 104 | } 105 | 106 | void koan_plus_equals_also_leaves_original_string_unmodified() { 107 | var original = "Hello, "; 108 | var foo = original; 109 | var bar = "World"; 110 | foo += bar; 111 | assert(your_answer == original); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_koans 2 | description: A sample command-line application. 3 | version: 0.0.2 4 | homepage: https://github.com/md-weber/dart_koans 5 | author: Max Weber 6 | 7 | environment: 8 | sdk: '>=2.12.0 <3.0.0' 9 | 10 | dependencies: 11 | path: ^1.8.0 12 | watcher: ^1.0.0 13 | ansicolor: ^2.0.1 14 | 15 | dev_dependencies: 16 | lints: ^1.0.1 17 | test: ^1.17.12 18 | -------------------------------------------------------------------------------- /test/chapter_1_about_asserts_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_koans/chapter_1_about_asserts.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | main() { 5 | group("Chapter 1 About Asserts", () { 6 | late Chapter_I_asserts subject; 7 | setUp(() { 8 | subject = Chapter_I_asserts(); 9 | }); 10 | 11 | test("koan_about_asserts", () { 12 | expect( 13 | () => subject.koan_about_asserts(), 14 | throwsA(isA()), 15 | ); 16 | }); 17 | 18 | test("koan_compare_values_with_each_other", () { 19 | expect( 20 | () => subject.koan_compare_values_with_each_other(), 21 | throwsA(isA()), 22 | ); 23 | }); 24 | 25 | test("koan_also_type_is_important", () { 26 | expect( 27 | () => subject.koan_also_type_is_important(), 28 | throwsA(isA()), 29 | ); 30 | }); 31 | 32 | test("koan_enter_values_to_succeed", () { 33 | expect( 34 | () => subject.koan_enter_values_to_succeed(), 35 | throwsA(isA()), 36 | ); 37 | }); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /test/chapter_2_about_string_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_koans/chapter_2_about_string.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | const dynamic your_answer = null; 5 | 6 | void main() { 7 | late Chapter_II_about_string subject; 8 | 9 | group('About Strings', () { 10 | setUp(() { 11 | subject = Chapter_II_about_string(); 12 | }); 13 | 14 | test("koan_double_quoted_strings_are_strings", () { 15 | expect( 16 | () => subject.koan_double_quoted_strings_are_strings(), 17 | throwsA(isA()), 18 | ); 19 | }); 20 | test("koan_single_quoted_strings_are_strings", () { 21 | expect( 22 | () => subject.koan_single_quoted_strings_are_strings(), 23 | throwsA(isA()), 24 | ); 25 | }); 26 | test("koan_triple_quoted_strings_are_also_strings", () { 27 | expect( 28 | () => subject.koan_triple_quoted_strings_are_also_strings(), 29 | throwsA(isA()), 30 | ); 31 | }); 32 | test("koan_triple_single_quoted_strings_work_too", () { 33 | expect( 34 | () => subject.koan_triple_single_quoted_strings_work_too(), 35 | throwsA(isA()), 36 | ); 37 | }); 38 | test("koan_raw_strings_are_also_strings", () { 39 | expect( 40 | () => subject.koan_raw_strings_are_also_strings(), 41 | throwsA(isA()), 42 | ); 43 | }); 44 | test("koan_use_single_quotes_to_create_string_with_double_quotes", () { 45 | expect( 46 | () => subject 47 | .koan_use_single_quotes_to_create_string_with_double_quotes(), 48 | throwsA(isA()), 49 | ); 50 | }); 51 | test("koan_use_double_quotes_to_create_string_with_single_quotes", () { 52 | expect( 53 | () => subject 54 | .koan_use_double_quotes_to_create_string_with_single_quotes(), 55 | throwsA(isA()), 56 | ); 57 | }); 58 | test("koan_use_backslash_for_escaping_quotes_in_strings", () { 59 | expect( 60 | () => subject.koan_use_backslash_for_escaping_quotes_in_strings(), 61 | throwsA(isA()), 62 | ); 63 | }); 64 | test("koan_triple_quoted_strings_can_span_lines", () { 65 | expect( 66 | () => subject.koan_triple_quoted_strings_can_span_lines(), 67 | throwsA(isA()), 68 | ); 69 | }); 70 | test("koan_triple_quoted_strings_need_less_escaping", () { 71 | expect( 72 | () => subject.koan_triple_quoted_strings_need_less_escaping(), 73 | throwsA(isA()), 74 | ); 75 | }); 76 | test("koan_escaping_quotes_at_the_end_of_a_triple_quoted_string", () { 77 | expect( 78 | () => 79 | subject.koan_escaping_quotes_at_the_end_of_a_triple_quoted_string(), 80 | throwsA(isA()), 81 | ); 82 | }); 83 | test("koan_plus_concatenates_strings", () { 84 | expect( 85 | () => subject.koan_plus_concatenates_strings(), 86 | throwsA(isA()), 87 | ); 88 | }); 89 | 90 | test("koan_\$_is_a_better_concatination", () { 91 | expect( 92 | () => subject.koan_$_is_a_better_concatination(), 93 | throwsA(isA()), 94 | ); 95 | }); 96 | test("koan_dollar_plus_curly_brackets_allows_attributes_selection", () { 97 | expect( 98 | () => subject 99 | .koan_dollar_plus_curly_brackets_allows_attributes_selection(), 100 | throwsA(isA()), 101 | ); 102 | }); 103 | test("koan_adjacent_strings_are_concatenated_automatically", () { 104 | expect( 105 | () => subject.koan_adjacent_strings_are_concatenated_automatically(), 106 | throwsA(isA()), 107 | ); 108 | }); 109 | test("koan_plus_will_not_modify_the_original_strings", () { 110 | expect( 111 | () => subject.koan_plus_will_not_modify_the_original_strings(), 112 | throwsA(isA()), 113 | ); 114 | }); 115 | test("koan_plus_equals_will_append_to_the_end_of_the_string", () { 116 | expect( 117 | () => subject.koan_plus_equals_will_append_to_the_end_of_the_string(), 118 | throwsA(isA()), 119 | ); 120 | }); 121 | test("koan_plus_equals_also_leaves_original_string_unmodified", () { 122 | expect( 123 | () => subject.koan_plus_equals_also_leaves_original_string_unmodified(), 124 | throwsA(isA()), 125 | ); 126 | }); 127 | }); 128 | } 129 | --------------------------------------------------------------------------------