├── .gitignore ├── .scalafmt.conf ├── LICENSE ├── README.md ├── build.sbt ├── project └── build.properties ├── sbt-launch.jar ├── sbt.bat ├── sbt.sh └── src ├── main └── scala │ ├── drawing │ └── Canvas.scala │ ├── films │ ├── Director.scala │ ├── Film.scala │ └── TestData.scala │ ├── intro │ └── HelloWorld.scala │ ├── part1 │ ├── Example1Expressions.scala │ ├── Exercise2Expressions.scala │ ├── Exercise3aRecursion.scala │ ├── Exercise3bRecursion.scala │ ├── Exercise4PatternMatching.scala │ ├── Exercise5Functions.scala │ └── Exercise6Films.scala │ ├── part2 │ ├── Example7Counter.scala │ ├── Exercise10Draw.scala │ ├── Exercise11IntList.scala │ ├── Exercise12Calculator.scala │ ├── Exercise13SafeCalculator.scala │ ├── Exercise14GenericList.scala │ ├── Exercise15Json.scala │ ├── Exercise8Vec.scala │ └── Exercise9ColorAndShape.scala │ ├── part3 │ ├── Exercise16aOptionAndEither.scala │ ├── Exercise16bOptionFoldAndMap.scala │ ├── Exercise17FoldLeftAndRight.scala │ ├── Exercise18FlatMap.scala │ ├── Exercise19ForComprehensions.scala │ ├── Exercise20OptionCalculator.scala │ ├── Exercise21EitherCalculator.scala │ ├── Exercise22Sorting.scala │ ├── Exercise23HarderProblems.scala │ ├── Exercise24aFibonacci.scala │ └── Exercise24bUptime.scala │ ├── part4 │ ├── Exercise25Ordering.scala │ ├── Exercise26JsonWriter.scala │ └── Exercise27ExtensionMethods.scala │ ├── sandbox.worksheet.sc │ └── timing │ └── Time.scala └── test └── scala ├── intro └── HelloWorldSpec.scala ├── part1 ├── Exercise2ExpressionsSpec.scala ├── Exercise3bRecursionSpec.scala ├── Exercise4PatternMatchingSpec.scala ├── Exercise5FunctionsSpec.scala └── Exercise6FilmsSpec.scala ├── part2 ├── Exercise11IntListSpec.scala ├── Exercise12CalculatorSpec.scala ├── Exercise13SafeCalculatorSpec.scala ├── Exercise14aGenericListSpec.scala ├── Exercise14bCovariantListSpec.scala ├── Exercise15JsonSpec.scala ├── Exercise7CounterSpec.scala ├── Exercise8aVecSpec.scala ├── Exercise8bVecCaseClassSpec.scala └── Exercise9ColorAndShapeSpec.scala ├── part3 ├── Exercise16aOptionAndEitherSpec.scala ├── Exercise16bOptionFoldAndMapSpec.scala ├── Exercise17FoldLeftAndRightSpec.scala ├── Exercise18FlatMapSpec.scala ├── Exercise19ForComprehensionsSpec.scala ├── Exercise20OptionCalculatorSpec.scala ├── Exercise21EitherCalculatorSpec.scala └── Exercise22SortingSpec.scala └── part4 ├── Exercise25OrderingSpec.scala ├── Exercise26JsonWriterSpec.scala └── Exercise27ExtensionMethodsSpec.scala /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/scala,ensime,intellij,eclipse,sbt,sublimetext,emacs,vim,visualstudiocode,metals,bloop,visualstudiocode 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=scala,ensime,intellij,eclipse,sbt,sublimetext,emacs,vim,visualstudiocode,metals,bloop,visualstudiocode 4 | 5 | ### Bloop ### 6 | .bloop/ 7 | 8 | ### Eclipse ### 9 | .metadata 10 | bin/ 11 | tmp/ 12 | *.tmp 13 | *.bak 14 | *.swp 15 | *~.nib 16 | local.properties 17 | .settings/ 18 | .loadpath 19 | .recommenders 20 | 21 | # External tool builders 22 | .externalToolBuilders/ 23 | 24 | # Locally stored "Eclipse launch configurations" 25 | *.launch 26 | 27 | # PyDev specific (Python IDE for Eclipse) 28 | *.pydevproject 29 | 30 | # CDT-specific (C/C++ Development Tooling) 31 | .cproject 32 | 33 | # CDT- autotools 34 | .autotools 35 | 36 | # Java annotation processor (APT) 37 | .factorypath 38 | 39 | # PDT-specific (PHP Development Tools) 40 | .buildpath 41 | 42 | # sbteclipse plugin 43 | .target 44 | 45 | # Tern plugin 46 | .tern-project 47 | 48 | # TeXlipse plugin 49 | .texlipse 50 | 51 | # STS (Spring Tool Suite) 52 | .springBeans 53 | 54 | # Code Recommenders 55 | .recommenders/ 56 | 57 | # Annotation Processing 58 | .apt_generated/ 59 | .apt_generated_test/ 60 | 61 | # Scala IDE specific (Scala & Java development for Eclipse) 62 | .cache-main 63 | .scala_dependencies 64 | .worksheet 65 | 66 | # Uncomment this line if you wish to ignore the project description file. 67 | # Typically, this file would be tracked if it contains build/dependency configurations: 68 | #.project 69 | 70 | ### Eclipse Patch ### 71 | # Spring Boot Tooling 72 | .sts4-cache/ 73 | 74 | ### Emacs ### 75 | # -*- mode: gitignore; -*- 76 | *~ 77 | \#*\# 78 | /.emacs.desktop 79 | /.emacs.desktop.lock 80 | *.elc 81 | auto-save-list 82 | tramp 83 | .\#* 84 | 85 | # Org-mode 86 | .org-id-locations 87 | *_archive 88 | ltximg/** 89 | 90 | # flymake-mode 91 | *_flymake.* 92 | 93 | # eshell files 94 | /eshell/history 95 | /eshell/lastdir 96 | 97 | # elpa packages 98 | /elpa/ 99 | 100 | # reftex files 101 | *.rel 102 | 103 | # AUCTeX auto folder 104 | /auto/ 105 | 106 | # cask packages 107 | .cask/ 108 | dist/ 109 | 110 | # Flycheck 111 | flycheck_*.el 112 | 113 | # server auth directory 114 | /server/ 115 | 116 | # projectiles files 117 | .projectile 118 | 119 | # directory configuration 120 | .dir-locals.el 121 | 122 | # network security 123 | /network-security.data 124 | 125 | 126 | ### Ensime ### 127 | # Ensime specific 128 | .ensime 129 | .ensime_cache/ 130 | .ensime_lucene/ 131 | 132 | ### Intellij ### 133 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 134 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 135 | 136 | .idea 137 | 138 | # User-specific stuff 139 | .idea/**/workspace.xml 140 | .idea/**/tasks.xml 141 | .idea/**/usage.statistics.xml 142 | .idea/**/dictionaries 143 | .idea/**/shelf 144 | 145 | # Generated files 146 | .idea/**/contentModel.xml 147 | 148 | # Sensitive or high-churn files 149 | .idea/**/dataSources/ 150 | .idea/**/dataSources.ids 151 | .idea/**/dataSources.local.xml 152 | .idea/**/sqlDataSources.xml 153 | .idea/**/dynamic.xml 154 | .idea/**/uiDesigner.xml 155 | .idea/**/dbnavigator.xml 156 | 157 | # Gradle 158 | .idea/**/gradle.xml 159 | .idea/**/libraries 160 | 161 | # Gradle and Maven with auto-import 162 | # When using Gradle or Maven with auto-import, you should exclude module files, 163 | # since they will be recreated, and may cause churn. Uncomment if using 164 | # auto-import. 165 | # .idea/artifacts 166 | # .idea/compiler.xml 167 | # .idea/jarRepositories.xml 168 | # .idea/modules.xml 169 | # .idea/*.iml 170 | # .idea/modules 171 | # *.iml 172 | # *.ipr 173 | 174 | # CMake 175 | cmake-build-*/ 176 | 177 | # Mongo Explorer plugin 178 | .idea/**/mongoSettings.xml 179 | 180 | # File-based project format 181 | *.iws 182 | 183 | # IntelliJ 184 | out/ 185 | 186 | # mpeltonen/sbt-idea plugin 187 | .idea_modules/ 188 | 189 | # JIRA plugin 190 | atlassian-ide-plugin.xml 191 | 192 | # Cursive Clojure plugin 193 | .idea/replstate.xml 194 | 195 | # Crashlytics plugin (for Android Studio and IntelliJ) 196 | com_crashlytics_export_strings.xml 197 | crashlytics.properties 198 | crashlytics-build.properties 199 | fabric.properties 200 | 201 | # Editor-based Rest Client 202 | .idea/httpRequests 203 | 204 | # Android studio 3.1+ serialized cache file 205 | .idea/caches/build_file_checksums.ser 206 | 207 | ### Intellij Patch ### 208 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 209 | 210 | # *.iml 211 | # modules.xml 212 | # .idea/misc.xml 213 | # *.ipr 214 | 215 | # Sonarlint plugin 216 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 217 | .idea/**/sonarlint/ 218 | 219 | # SonarQube Plugin 220 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 221 | .idea/**/sonarIssues.xml 222 | 223 | # Markdown Navigator plugin 224 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 225 | .idea/**/markdown-navigator.xml 226 | .idea/**/markdown-navigator-enh.xml 227 | .idea/**/markdown-navigator/ 228 | 229 | # Cache file creation bug 230 | # See https://youtrack.jetbrains.com/issue/JBR-2257 231 | .idea/$CACHE_FILE$ 232 | 233 | # CodeStream plugin 234 | # https://plugins.jetbrains.com/plugin/12206-codestream 235 | .idea/codestream.xml 236 | 237 | ### Metals ### 238 | .metals/ 239 | project/**/metals.sbt 240 | 241 | ### SBT ### 242 | # Simple Build Tool 243 | # http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control 244 | 245 | dist/* 246 | target/ 247 | lib_managed/ 248 | src_managed/ 249 | project/boot/ 250 | project/plugins/project/ 251 | .history 252 | .cache 253 | .lib/ 254 | .bsp 255 | 256 | ### Scala ### 257 | *.class 258 | *.log 259 | 260 | ### SublimeText ### 261 | # Cache files for Sublime Text 262 | *.tmlanguage.cache 263 | *.tmPreferences.cache 264 | *.stTheme.cache 265 | 266 | # Workspace files are user-specific 267 | *.sublime-workspace 268 | 269 | # Project files should be checked into the repository, unless a significant 270 | # proportion of contributors will probably not be using Sublime Text 271 | # *.sublime-project 272 | 273 | # SFTP configuration file 274 | sftp-config.json 275 | 276 | # Package control specific files 277 | Package Control.last-run 278 | Package Control.ca-list 279 | Package Control.ca-bundle 280 | Package Control.system-ca-bundle 281 | Package Control.cache/ 282 | Package Control.ca-certs/ 283 | Package Control.merged-ca-bundle 284 | Package Control.user-ca-bundle 285 | oscrypto-ca-bundle.crt 286 | bh_unicode_properties.cache 287 | 288 | # Sublime-github package stores a github token in this file 289 | # https://packagecontrol.io/packages/sublime-github 290 | GitHub.sublime-settings 291 | 292 | ### Vim ### 293 | # Swap 294 | [._]*.s[a-v][a-z] 295 | !*.svg # comment out if you don't need vector files 296 | [._]*.sw[a-p] 297 | [._]s[a-rt-v][a-z] 298 | [._]ss[a-gi-z] 299 | [._]sw[a-p] 300 | 301 | # Session 302 | Session.vim 303 | Sessionx.vim 304 | 305 | # Temporary 306 | .netrwhist 307 | # Auto-generated tag files 308 | tags 309 | # Persistent undo 310 | [._]*.un~ 311 | 312 | ### VisualStudioCode ### 313 | .vscode/* 314 | !.vscode/tasks.json 315 | !.vscode/launch.json 316 | *.code-workspace 317 | 318 | ### VisualStudioCode Patch ### 319 | # Ignore all local history of files 320 | .ionide 321 | 322 | # End of https://www.toptal.com/developers/gitignore/api/scala,ensime,intellij,eclipse,sbt,sublimetext,emacs,vim,visualstudiocode,metals,bloop,visualstudiocode 323 | -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = "2.4.1" 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Essential Scala Code 2 | 3 | This repository contains exercises and solutions for 4 | [Underscore's Essential Scala][course] training course. 5 | 6 | If you want to discuss the content or exercises with the authors, 7 | join us in our chat room on [Gitter][gitter]. 8 | 9 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)][gitter] 10 | 11 | ## Using the Source Code 12 | 13 | This repository contains two branches: one for `exercises` and one for `solutions`. 14 | The directory structure is the same in each branch. 15 | 16 | You will need to have Git and Java and an internet connection to run the exercises. 17 | All other dependencies are either included with the repo 18 | or downloaded on demand during compilation. 19 | 20 | ### Notes on Editors and IDEs 21 | 22 | If you don't have a particular preference for a Scala editor or IDE, 23 | we recommend you do the exercises for this course using 24 | the [Visual Studio Code][vscode] editor and a Linux or OS X terminal. 25 | See the instructions below to get started. 26 | 27 | If you want to use [Scala IDE][scala-ide] for Eclipse, 28 | we recommend using [sbteclipse][sbteclipse]. 29 | Follow the instructions on the `sbteclipse` web page to install it as a global SBT plugin. 30 | 31 | If you want to use IntelliJ IDEA, 32 | follow the instructions for [Importing an SBT Project][intellij-setup] 33 | in the IntelliJ online documentation. 34 | 35 | ### Getting Started on Linux or OS X 36 | 37 | To get started: 38 | 39 | 1. To run these exercises, you need a Java 8 compatible JDK on your machine. 40 | If you don't have this already, you can download and install one from 41 | [Oracle Java SE Development Kit 8+][oraclejdk] or 42 | [OpenJDK 8+][openjdk]. 43 | 44 | 2. Clone this repository to a directory on your hard drive, 45 | e.g. `~/essential-scala-code`: 46 | 47 | ~~~ 48 | bash$ git clone https://github.com/underscoreio/essential-scala-code.git 49 | ~~~ 50 | 51 | 3. Change to the root directory in the repository: 52 | 53 | ~~~ 54 | bash$ cd essential-scala-code 55 | ~~~ 56 | 57 | 4. Run the `sbt.sh` script. 58 | You may have to wait while SBT downloads various dependencies: 59 | 60 | ~~~ 61 | bash$ ./sbt.sh 62 | # Lots of output here... 63 | # The first run will take a while... 64 | 65 | > 66 | ~~~ 67 | 68 | 5. Type `runMain intro.HelloWorld` at the SBT prompt. 69 | You may have to wait while SBT downloads various dependencies. 70 | 71 | 5. If you see the message `"Hello world!"`, you're ready to go! 72 | 73 | *If you have any problems getting started, get in touch on [Gitter][gitter].* 74 | 75 | ### Getting Started on Windows 76 | 77 | You will need to have installed Git and Java (we recommend Oracle's Java 7 SDK). 78 | Complete the following steps outlined in Chapter 1 in the section entitled 79 | "Setting up SBT for This Book": 80 | 81 | 1. To run these exercises, you need a Java 8 compatible JDK on your machine. 82 | If you don't have this already, you can download and install one from 83 | [Oracle Java SE Development Kit 8+][oraclejdk] or 84 | [OpenJDK 8+][openjdk]. 85 | 86 | 2. Clone this repository to a directory on your hard drive, 87 | e.g. `C:\essential-scala-code`: 88 | 89 | ~~~ 90 | C:\> git clone https://github.com/underscoreio/essential-scala-code.git ↩ 91 | C:\essential-scala-code 92 | ~~~ 93 | 94 | 3. Change to the root directory in the repository: 95 | 96 | ~~~ 97 | C:\> cd\essential-scala-code 98 | ~~~ 99 | 100 | 4. Run the `sbt.bat` script. 101 | You may have to wait while SBT downloads various dependencies: 102 | 103 | ~~~ 104 | C:\essential-scala-code> sbt 105 | # Lots of output here... 106 | # The first run will take a while... 107 | 108 | > 109 | ~~~ 110 | 111 | 5. Type `runMain intro.HelloWorld` at the SBT prompt. 112 | You may have to wait while SBT downloads various dependencies. 113 | 114 | 6. If you see the message `"Hello world!"`, you're ready to go! 115 | 116 | *If you have any problems getting started, get in touch on [Gitter][gitter].* 117 | 118 | 119 | [course]: http://underscore.io/training/courses/essential-scala 120 | [atom]: https://atom.io 121 | [vscode]: https://code.visualstudio.com 122 | [scala-ide]: http://scala-ide.org 123 | [sbteclipse]: https://github.com/typesafehub/sbteclipse 124 | [intellij-idea]: https://www.jetbrains.com/idea 125 | [intellij-setup]: https://www.jetbrains.com/help/idea/2016.1/getting-started-with-sbt.html#import_project 126 | [gitter]: https://gitter.im/underscoreio/scala?utm_source=essential-scala-readme&utm_medium=badge&utm_campaign=essential-scala 127 | [oraclejdk]: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 128 | [openjdk]: http://openjdk.java.net/install/ 129 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | scalaVersion := "2.12.10" 2 | 3 | logLevel := Level.Error 4 | logLevel in run := Level.Error 5 | 6 | libraryDependencies ++= Seq( 7 | "org.scalactic" %% "scalactic" % "3.1.1" % Test, 8 | "org.scalatest" %% "scalatest" % "3.1.1" % Test 9 | ) 10 | 11 | scalacOptions ++= Seq( 12 | "-deprecation", // Emit warning and location for usages of deprecated APIs. 13 | "-encoding", 14 | "utf-8", // Specify character encoding used by source files. 15 | "-explaintypes", // Explain type errors in more detail. 16 | "-feature", // Emit warning and location for usages of features that should be imported explicitly. 17 | "-language:existentials", // Existential types (besides wildcard types) can be written and inferred 18 | "-language:experimental.macros", // Allow macro definition (besides implementation and application) 19 | "-language:higherKinds", // Allow higher-kinded types 20 | "-language:implicitConversions", // Allow definition of implicit functions called views 21 | "-unchecked", // Enable additional warnings where generated code depends on assumptions. 22 | "-Xcheckinit", // Wrap field accessors to throw an exception on uninitialized access. 23 | "-Xfatal-warnings", // Fail the compilation if there are any warnings. 24 | "-Xfuture", // Turn on future language features. 25 | "-Xlint:adapted-args", // Warn if an argument list is modified to match the receiver. 26 | "-Xlint:by-name-right-associative", // By-name parameter of right associative operator. 27 | "-Xlint:constant", // Evaluation of a constant arithmetic expression results in an error. 28 | "-Xlint:delayedinit-select", // Selecting member of DelayedInit. 29 | "-Xlint:doc-detached", // A Scaladoc comment appears to be detached from its element. 30 | "-Xlint:inaccessible", // Warn about inaccessible types in method signatures. 31 | "-Xlint:infer-any", // Warn when a type argument is inferred to be `Any`. 32 | "-Xlint:missing-interpolator", // A string literal appears to be missing an interpolator id. 33 | "-Xlint:nullary-override", // Warn when non-nullary `def f()' overrides nullary `def f'. 34 | "-Xlint:nullary-unit", // Warn when nullary methods return Unit. 35 | "-Xlint:option-implicit", // Option.apply used implicit view. 36 | "-Xlint:package-object-classes", // Class or object defined in package object. 37 | "-Xlint:poly-implicit-overload", // Parameterized overloaded implicit methods are not visible as view bounds. 38 | "-Xlint:private-shadow", // A private field (or class parameter) shadows a superclass field. 39 | "-Xlint:stars-align", // Pattern sequence wildcard must align with sequence component. 40 | "-Xlint:type-parameter-shadow", // A local type parameter shadows a type already in scope. 41 | "-Xlint:unsound-match", // Pattern match may not be typesafe. 42 | "-Yno-adapted-args", // Do not adapt an argument list (either by inserting () or creating a tuple) to match the receiver. 43 | "-Ypartial-unification", // Enable partial unification in type constructor inference 44 | // "-Ywarn-dead-code", // Warn when dead code is identified. 45 | "-Ywarn-extra-implicit", // Warn when more than one implicit parameter section is defined. 46 | "-Ywarn-inaccessible", // Warn about inaccessible types in method signatures. 47 | "-Ywarn-infer-any", // Warn when a type argument is inferred to be `Any`. 48 | "-Ywarn-nullary-override" // Warn when non-nullary `def f()' overrides nullary `def f'. 49 | // "-Ywarn-nullary-unit" // Warn when nullary methods return Unit. 50 | // "-Ywarn-numeric-widen", // Warn when numerics are widened. 51 | // "-Ywarn-unused:implicits", // Warn if an implicit parameter is unused. 52 | // "-Ywarn-unused:imports", // Warn if an import selector is not referenced. 53 | // "-Ywarn-unused:locals", // Warn if a local definition is unused. 54 | // "-Ywarn-unused:params", // Warn if a value parameter is unused. 55 | // "-Ywarn-unused:patvars", // Warn if a variable bound in a pattern is unused. 56 | // "-Ywarn-unused:privates", // Warn if a private member is unused. 57 | // "-Ywarn-value-discard" // Warn when non-Unit expression results are unused. 58 | ) 59 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.3.8 2 | -------------------------------------------------------------------------------- /sbt-launch.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/underscoreio/essential-scala-code/7a269f7d2e86dccee59f7443a1edff8d543b889c/sbt-launch.jar -------------------------------------------------------------------------------- /sbt.bat: -------------------------------------------------------------------------------- 1 | java -Xmx3g -Xms3g -XX:+TieredCompilation -XX:ReservedCodeCacheSize=256m -XX:+UseNUMA -XX:+UseParallelGC -XX:+CMSClassUnloadingEnabled -jar sbt-launch.jar %* 2 | -------------------------------------------------------------------------------- /sbt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | java -Xmx3g -Xms3g -XX:+TieredCompilation -XX:ReservedCodeCacheSize=256m -XX:+UseNUMA -XX:+UseParallelGC -XX:+CMSClassUnloadingEnabled -jar sbt-launch.jar "$@" 4 | -------------------------------------------------------------------------------- /src/main/scala/drawing/Canvas.scala: -------------------------------------------------------------------------------- 1 | package drawing 2 | 3 | import java.awt.geom.{Ellipse2D, Rectangle2D} 4 | import java.awt.{Color, Graphics, Graphics2D} 5 | import javax.swing.{JFrame, JPanel} 6 | 7 | abstract class Canvas { 8 | def setColor(r: Double, g: Double, b: Double): Unit 9 | def fillCircle(x: Double, y: Double, r: Double): Unit 10 | def fillRect(x: Double, y: Double, w: Double, h: Double): Unit 11 | } 12 | 13 | object Canvas { 14 | def show(width: Int, height: Int, draw: Canvas => Unit): Unit = { 15 | val frame = new JFrame("Drawing") 16 | val panel = new CanvasPanel(draw) 17 | frame.setContentPane(panel) 18 | frame.setSize(width, height) 19 | frame.setVisible(true) 20 | } 21 | 22 | private class Graphics2DCanvas(graphics: Graphics2D) extends Canvas { 23 | override def setColor(r: Double, g: Double, b: Double): Unit = { 24 | graphics.setPaint(new Color((r * 255).toInt, (g * 255).toInt, (b * 255).toInt)) 25 | } 26 | 27 | override def fillCircle(x: Double, y: Double, r: Double): Unit = { 28 | graphics.fill(new Ellipse2D.Double(x - r, y - r, 2 * r, 2 * r)) 29 | } 30 | 31 | override def fillRect(x: Double, y: Double, w: Double, h: Double): Unit = { 32 | graphics.fill(new Rectangle2D.Double(x - w/2, y - h/2, w, h)) 33 | } 34 | } 35 | 36 | private class CanvasPanel(draw: Canvas => Unit) extends JPanel { 37 | override def paintComponent(g: Graphics): Unit = { 38 | val canvas = new Graphics2DCanvas(g.asInstanceOf[Graphics2D]) 39 | val size = getSize() 40 | g.setColor(Color.black) 41 | g.fillRect(0, 0, size.getWidth.toInt, size.getHeight.toInt) 42 | g.setColor(Color.white) 43 | draw(canvas) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/scala/films/Director.scala: -------------------------------------------------------------------------------- 1 | package films 2 | 3 | final case class Director( 4 | firstName: String, 5 | lastName: String, 6 | yearOfBirth: Int, 7 | films: List[Film] 8 | ) { 9 | def name: String = 10 | s"$firstName $lastName" 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/films/Film.scala: -------------------------------------------------------------------------------- 1 | package films 2 | 3 | final case class Film( 4 | name: String, 5 | yearOfRelease: Int, 6 | imdbRating: Double 7 | ) 8 | -------------------------------------------------------------------------------- /src/main/scala/films/TestData.scala: -------------------------------------------------------------------------------- 1 | package films 2 | 3 | object TestData { 4 | val memento = Film("Memento", 2000, 8.5) 5 | val darkKnight = Film("Dark Knight", 2008, 9.0) 6 | val inception = Film("Inception", 2010, 8.8) 7 | 8 | val highPlainsDrifter = Film("High Plains Drifter", 1973, 7.7) 9 | val outlawJoseyWales = Film("The Outlaw Josey Wales", 1976, 7.9) 10 | val unforgiven = Film("Unforgiven", 1992, 8.3) 11 | val granTorino = Film("Gran Torino", 2008, 8.2) 12 | val invictus = Film("Invictus", 2009, 7.4) 13 | 14 | val predator = Film("Predator", 1987, 7.9) 15 | val dieHard = Film("Die Hard", 1988, 8.3) 16 | val huntForRedOctober = Film("The Hunt for Red October", 1990, 7.6) 17 | val thomasCrownAffair = Film("The Thomas Crown Affair", 1999, 6.8) 18 | 19 | val eastwood = Director( 20 | "Clint", 21 | "Eastwood", 22 | 1930, 23 | List(highPlainsDrifter, outlawJoseyWales, unforgiven, granTorino, invictus) 24 | ) 25 | 26 | val mcTiernan = Director( 27 | "John", 28 | "McTiernan", 29 | 1951, 30 | List(predator, dieHard, huntForRedOctober, thomasCrownAffair) 31 | ) 32 | 33 | val nolan = Director( 34 | "Christopher", 35 | "Nolan", 36 | 1970, 37 | List(memento, darkKnight, inception) 38 | ) 39 | 40 | val someGuy = Director( 41 | "Just", 42 | "Some Guy", 43 | 1990, 44 | Nil 45 | ) 46 | 47 | val directors: List[Director] = List( 48 | someGuy, 49 | mcTiernan, 50 | nolan, 51 | eastwood, 52 | ) 53 | 54 | val films: List[Film] = List( 55 | memento, 56 | darkKnight, 57 | inception, 58 | highPlainsDrifter, 59 | outlawJoseyWales, 60 | unforgiven, 61 | granTorino, 62 | invictus, 63 | predator, 64 | dieHard, 65 | huntForRedOctober, 66 | thomasCrownAffair, 67 | ) 68 | } 69 | -------------------------------------------------------------------------------- /src/main/scala/intro/HelloWorld.scala: -------------------------------------------------------------------------------- 1 | package intro 2 | 3 | object HelloWorld { 4 | val message = "Hello world!" 5 | 6 | def main(args: Array[String]): Unit = { 7 | println(message) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/scala/part1/Example1Expressions.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | object Example1Expressions { 4 | // _ _ _ _ 5 | // | | (_) |_ ___ _ __ __ _| |___ 6 | // | | | | __/ _ \ '__/ _` | / __| 7 | // | |___| | || __/ | | (_| | \__ \ 8 | // |_____|_|\__\___|_| \__,_|_|___/ 9 | 10 | val literals1 = 123 11 | val literals2 = 123L 12 | val literals3 = 123.0 13 | val literals4 = true 14 | val literals5 = "a" 15 | val literals6 = 'a' 16 | 17 | val literals7 = """A string with "double quotes" in it""" 18 | 19 | val literals8 = null 20 | val literals9 = () 21 | 22 | // ___ _ 23 | // / _ \ _ __ ___ _ __ __ _| |_ ___ _ __ ___ 24 | // | | | | '_ \ / _ \ '__/ _` | __/ _ \| '__/ __| 25 | // | |_| | |_) | __/ | | (_| | || (_) | | \__ \ 26 | // \___/| .__/ \___|_| \__,_|\__\___/|_| |___/ 27 | // |_| 28 | 29 | val operators1 = (1 + 2) * (3 + 4) 30 | val operators2 = 1 + 2 * 3 + 4 31 | 32 | val operators3 = "Hello" + "world!" 33 | val operators4 = true && !false 34 | 35 | val operators5 = 123 + 456 36 | val operators6 = 123 + 456L 37 | val operators7 = 123 + "456" 38 | 39 | val operators8 = "a" == "a" 40 | val operators9 = "a" != "a" 41 | 42 | // __ __ _ _ _ _ _ 43 | // | \/ | ___| |_| |__ ___ __| | ___ __ _| | |___ 44 | // | |\/| |/ _ \ __| '_ \ / _ \ / _` | / __/ _` | | / __| 45 | // | | | | __/ |_| | | | (_) | (_| | | (_| (_| | | \__ \ 46 | // |_| |_|\___|\__|_| |_|\___/ \__,_| \___\__,_|_|_|___/ 47 | 48 | import scala.io.StdIn 49 | 50 | val methodCalls1 = "Hello world!".take(5) 51 | val methodCalls2 = "Hello world!".length 52 | val methodCalls3 = "Hello world!".toUpperCase 53 | 54 | def methodCalls4() = StdIn.readLine 55 | def methodCalls5() = math.random 56 | def methodCalls6() = println("Hello world!") 57 | 58 | val methodCalls7 = Math.random 59 | val methodCalls8 = List.apply(1, 2, 3) 60 | 61 | val methodCalls9 = methodCalls8.head 62 | val methodCalls10 = methodCalls8.tail 63 | val methodCalls11 = methodCalls8.apply(2) 64 | 65 | val methodCalls12 = 123.toString 66 | val methodCalls13 = "123".toInt 67 | 68 | // ___ __ _ _ 69 | // |_ _|_ __ / _(_)_ __ ___ _ _ _ __ | |_ __ ___ __ 70 | // | || '_ \| |_| \ \/ / / __| | | | '_ \| __/ _` \ \/ / 71 | // | || | | | _| |> < \__ \ |_| | | | | || (_| |> < 72 | // |___|_| |_|_| |_/_/\_\ |___/\__, |_| |_|\__\__,_/_/\_\ 73 | // |___/ 74 | 75 | val infixOperators1 = 1 + 2 76 | val infixOperators2 = 1.+(2) 77 | val infixOperators3 = "Hello world".take(5) 78 | val infixOperators4 = "Hello world" take 5 79 | 80 | // val infixOperators5 = a b c d e 81 | 82 | // ____ _ _ _ _ _ 83 | // / ___|___ _ __ __| (_) |_(_) ___ _ __ __ _| |___ 84 | // | | / _ \| '_ \ / _` | | __| |/ _ \| '_ \ / _` | / __| 85 | // | |__| (_) | | | | (_| | | |_| | (_) | | | | (_| | \__ \ 86 | // \____\___/|_| |_|\__,_|_|\__|_|\___/|_| |_|\__,_|_|___/ 87 | 88 | val conditionals1 = if(Math.random < 0.5) "Alien" else "Predator" 89 | val conditionals2 = if(Math.random < 0.5) "Alien" else 2001 90 | 91 | // ____ _ _ 92 | // | __ )| | ___ ___| | _____ 93 | // | _ \| |/ _ \ / __| |/ / __| 94 | // | |_) | | (_) | (__| <\__ \ 95 | // |____/|_|\___/ \___|_|\_\___/ 96 | 97 | def blocks1() = { 98 | println("Calculating the answer...") 99 | 6 * 7 100 | } 101 | 102 | val blocks2 = { 103 | val a = 1 104 | val b = 2 105 | a + b 106 | } 107 | 108 | // ____ _ _ _ _ _ _ _ 109 | // / ___|| |_ _ __(_)_ __ __ _ (_)_ __ | |_ ___ _ __ _ __ ___ | | __ _| |_(_) ___ _ __ 110 | // \___ \| __| '__| | '_ \ / _` | | | '_ \| __/ _ \ '__| '_ \ / _ \| |/ _` | __| |/ _ \| '_ \ 111 | // ___) | |_| | | | | | | (_| | | | | | | || __/ | | |_) | (_) | | (_| | |_| | (_) | | | | 112 | // |____/ \__|_| |_|_| |_|\__, | |_|_| |_|\__\___|_| | .__/ \___/|_|\__,_|\__|_|\___/|_| |_| 113 | // |___/ |_| 114 | 115 | val interpolation1 = 116 | s"The value of the first expression was $literals1" 117 | 118 | val interpolation2 = 119 | s"The sum of the first two expressions was ${literals1 + literals2}" 120 | 121 | val interpolation3 = 122 | s"A string with a literal $$ in it." 123 | 124 | // ___ _ _ _ 125 | // / _ \| |_| |__ ___ _ __ _____ ___ __ _ __ ___ ___ ___(_) ___ _ __ ___ 126 | // | | | | __| '_ \ / _ \ '__| / _ \ \/ / '_ \| '__/ _ \/ __/ __| |/ _ \| '_ \/ __| 127 | // | |_| | |_| | | | __/ | | __/> <| |_) | | | __/\__ \__ \ | (_) | | | \__ \ 128 | // \___/ \__|_| |_|\___|_| \___/_/\_\ .__/|_| \___||___/___/_|\___/|_| |_|___/ 129 | // |_| 130 | 131 | def other1 = ??? 132 | 133 | // - for comprehensions 134 | // - try/catch expressions 135 | // - pattern matching 136 | 137 | // ____ __ _ _ _ _ 138 | // | _ \ ___ / _(_)_ __ (_) |_(_) ___ _ __ ___ 139 | // | | | |/ _ \ |_| | '_ \| | __| |/ _ \| '_ \/ __| 140 | // | |_| | __/ _| | | | | | |_| | (_) | | | \__ \ 141 | // |____/ \___|_| |_|_| |_|_|\__|_|\___/|_| |_|___/ 142 | 143 | val definitions1 = "A value" 144 | def definitions2 = "A method" 145 | 146 | def definitions3: String = "Another value" 147 | def definitions4: String = "Another method" 148 | 149 | def definitions5(a: Int, b: Int) = 150 | a + b 151 | 152 | def definitions6(a: Int, b: Int): Int = 153 | a + b 154 | 155 | // val definitions7 = { 156 | // println("Calculating the answer...") 157 | // 6 * 7 158 | // } 159 | 160 | // def definitions8 = { 161 | // println("Calculating the answer...") 162 | // 6 * 7 163 | // } 164 | 165 | // ____ _ _ 166 | // / ___| ___ _ __ ___ ___ _ __ _ _ _______| | ___ _ __ ___| | 167 | // \___ \ / _ \| '_ ` _ \ / _ \ | '_ \| | | |_ /_ / |/ _ \ '__/ __| | 168 | // ___) | (_) | | | | | | __/ | |_) | |_| |/ / / /| | __/ | \__ \_| 169 | // |____/ \___/|_| |_| |_|\___| | .__/ \__,_/___/___|_|\___|_| |___(_) 170 | // |_| 171 | 172 | val puzzler1 = "Hello world!".toUpperCase.reverse 173 | def puzzler2() = println("Hello world!".toUpperCase.reverse.toLowerCase.reverse) 174 | 175 | val puzzler3 = "Hello " + "world".take(2) 176 | val puzzler4 = "Hello " + "world" take 2 177 | 178 | def puzzler5 = "3".toInt 179 | def puzzler6 = "cake".toInt 180 | 181 | def puzzler7 = if(math.random < 0.5) "Hello" else null 182 | def puzzler8 = if(math.random < 0.5) "Hello" else throw new Exception("Aaargh!") 183 | } 184 | -------------------------------------------------------------------------------- /src/main/scala/part1/Exercise2Expressions.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | object Exercise2Expressions { 4 | def greet(name: String): Unit = { 5 | ??? 6 | } 7 | 8 | def greeting(name: String): String = { 9 | ??? 10 | } 11 | 12 | // Hint - You can reverse a string with `string.reverse` 13 | def palindrome(str: String): Boolean = { 14 | ??? 15 | } 16 | 17 | def factorial(n: Int): Int = { 18 | ??? 19 | } 20 | 21 | def main(args: Array[String]): Unit = { 22 | println("greet") 23 | // println(greet("Earthlings")) 24 | 25 | println("palindrome") 26 | // println(palindrome("taco")) 27 | 28 | println("factorial") 29 | // println(factorial(10)) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/scala/part1/Exercise3aRecursion.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | object Exercise3aRecursion { 4 | def greetNTimes(name: String, n: Int): Unit = { 5 | ??? 6 | } 7 | 8 | def main(args: Array[String]): Unit = { 9 | println("greetNTimes") 10 | // println(greetNTimes("world", 5)) 11 | // println(greetNTimes("nope", 0)) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/scala/part1/Exercise3bRecursion.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | object Exercise3bRecursion { 4 | def contains(numbers: List[Int], num: Int): Boolean = { 5 | ??? 6 | } 7 | 8 | def doubleEachNumber(numbers: List[Int]): List[Int] = { 9 | ??? 10 | } 11 | 12 | def total(numbers: List[Int]): Int = { 13 | ??? 14 | } 15 | 16 | def range(from: Int, to: Int): List[Int] = { 17 | ??? 18 | } 19 | 20 | def append(a: List[Int], b: List[Int]): List[Int] = { 21 | ??? 22 | } 23 | 24 | def main(args: Array[String]): Unit = { 25 | println("contains") 26 | // println(contains(List(1, 2, 3), 2)) 27 | // println(contains(List(1, 2, 3), 4)) 28 | // println(contains(Nil, 1)) 29 | 30 | println("doubleEachNumber") 31 | // println(doubleEachNumber(List(1, 2, 3, 4))) 32 | // println(doubleEachNumber(Nil)) 33 | 34 | println("total") 35 | // println(total(List(1, 2, 3, 4))) 36 | // println(total(Nil)) 37 | 38 | println("range") 39 | // println(range(3, 5)) 40 | 41 | println("append") 42 | // println(append(List(1, 2, 3), List(4, 5, 6))) 43 | // println(append(Nil, Nil)) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/scala/part1/Exercise4PatternMatching.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | object Exercise4PatternMatching { 4 | def greetNTimes(name: String, n: Int): Unit = { 5 | ??? 6 | } 7 | 8 | def contains(numbers: List[Int], num: Int): Boolean = { 9 | ??? 10 | } 11 | 12 | def doubleEachNumber(numbers: List[Int]): List[Int] = { 13 | ??? 14 | } 15 | 16 | def total(numbers: List[Int]): Int = { 17 | ??? 18 | } 19 | 20 | def append(a: List[Int], b: List[Int]): List[Int] = { 21 | ??? 22 | } 23 | 24 | def main(args: Array[String]): Unit = { 25 | println("greetNTimes") 26 | // println(greetNTimes("world", 5)) 27 | // println(greetNTimes("nope", 0)) 28 | 29 | println("contains") 30 | // println(contains(List(1, 2, 3), 2)) 31 | // println(contains(List(1, 2, 3), 4)) 32 | // println(contains(Nil, 1)) 33 | 34 | println("doubleEachNumber") 35 | // println(doubleEachNumber(List(1, 2, 3, 4))) 36 | // println(doubleEachNumber(Nil)) 37 | 38 | println("total") 39 | // println(total(List(1, 2, 3, 4))) 40 | // println(total(Nil)) 41 | 42 | println("append") 43 | // println(append(List(1, 2, 3), List(4, 5, 6))) 44 | // println(append(Nil, Nil)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/scala/part1/Exercise5Functions.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | object Exercise5Functions { 4 | def contains(numbers: List[Int], num: Int): Boolean = { 5 | ??? 6 | } 7 | 8 | def containsEvenNumbers(numbers: List[Int]): Boolean = { 9 | ??? 10 | } 11 | 12 | def evenNumbersOnly(numbers: List[Int]): List[Int] = { 13 | ??? 14 | } 15 | 16 | def doubleEachNumber(numbers: List[Int]): List[Int] = { 17 | ??? 18 | } 19 | 20 | def multiplyEachNumberBy(numbers: List[Int], num: Int): List[Int] = { 21 | ??? 22 | } 23 | 24 | def evenNumbersOnlyDoubled(numbers: List[Int]): List[Int] = { 25 | ??? 26 | } 27 | 28 | def main(args: Array[String]): Unit = { 29 | println("contains") 30 | // println(contains(List(1, 2, 3), 2)) 31 | // println(contains(List(1, 2, 3), 4)) 32 | // println(contains(Nil, 1)) 33 | 34 | println("containsEvenNumbers") 35 | // println(containsEvenNumbers(List(1, 2, 3))) 36 | // println(containsEvenNumbers(List(1, 3, 5))) 37 | // println(containsEvenNumbers(Nil)) 38 | 39 | println("evenNumbersOnly") 40 | // println(evenNumbersOnly(List(1, 2, 3, 4))) 41 | // println(evenNumbersOnly(Nil)) 42 | 43 | println("doubleEachNumber") 44 | // println(doubleEachNumber(List(1, 2, 3, 4))) 45 | // println(doubleEachNumber(Nil)) 46 | 47 | println("multiplyEachNumberBy") 48 | // println(multiplyEachNumberBy(List(1, 2, 3, 4), 5)) 49 | // println(multiplyEachNumberBy(List(1, 2, 3, 4), 10)) 50 | // println(multiplyEachNumberBy(Nil, 100)) 51 | 52 | println("evenNumbersOnlyDoubled") 53 | // println(evenNumbersOnlyDoubled(List(1, 2, 3, 4))) 54 | // println(evenNumbersOnlyDoubled(Nil)) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/scala/part1/Exercise6Films.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | import films.{Director, Film} 4 | 5 | object Exercise6Films { 6 | // Complete the following methods. 7 | // The exercises value gradually more complex as you go on. 8 | // The idea is to practice chaining methods together. 9 | // You DO NOT need to reference previous answers in later ones. 10 | 11 | def nameOfFilm(film: Film): String = { 12 | ??? 13 | } 14 | 15 | def filmsByDirector(director: Director): List[Film] = { 16 | ??? 17 | } 18 | 19 | def directorsWithBackCatalogOfSize(directors: List[Director], numberOfFilms: Int): List[Director] = { 20 | ??? 21 | } 22 | 23 | def directorsBornBefore(directors: List[Director], year: Int): List[Director] = { 24 | ??? 25 | } 26 | 27 | def directorsBornBeforeWithBackCatalogOfSize(directors: List[Director], year: Int, numberOfFilms: Int): List[Director] = { 28 | ??? 29 | } 30 | 31 | def namesOfFilms(films: List[Film]): List[String] = { 32 | ??? 33 | } 34 | 35 | def namesOfFilmsByDirector(director: Director): List[String] = { 36 | ??? 37 | } 38 | 39 | def namesOfFilmsByDirectorScoringAtLeast(director: Director, imdbRating: Double): List[String] = { 40 | ??? 41 | } 42 | 43 | def main(args: Array[String]): Unit = { 44 | import films.TestData._ 45 | 46 | println("nameOfFilm") 47 | println(nameOfFilm(memento)) 48 | println(nameOfFilm(darkKnight)) 49 | 50 | println("filmsByDirector") 51 | println(filmsByDirector(nolan)) 52 | println(filmsByDirector(eastwood)) 53 | 54 | println("directorsWithBackCatalogOfSize") 55 | println(directorsWithBackCatalogOfSize(directors, 1)) 56 | println(directorsWithBackCatalogOfSize(directors, 4)) 57 | println(directorsWithBackCatalogOfSize(directors, 5)) 58 | println(directorsWithBackCatalogOfSize(Nil, 1)) 59 | 60 | println("directorsBornBefore") 61 | println(directorsBornBefore(directors, 1930)) 62 | println(directorsBornBefore(directors, 1931)) 63 | println(directorsBornBefore(directors, 1951)) 64 | println(directorsBornBefore(directors, 1952)) 65 | println(directorsBornBefore(Nil, 2000)) 66 | 67 | println("directorsBornBeforeWithBackCatalogOfSize") 68 | println(directorsBornBeforeWithBackCatalogOfSize(directors, 1931, 5)) 69 | println(directorsBornBeforeWithBackCatalogOfSize(directors, 1931, 6)) 70 | println(directorsBornBeforeWithBackCatalogOfSize(directors, 1930, 5)) 71 | println(directorsBornBeforeWithBackCatalogOfSize(Nil, 2000, 1)) 72 | 73 | println("namesOfFilms") 74 | println(namesOfFilms(List(memento, darkKnight))) 75 | println(namesOfFilms(Nil)) 76 | 77 | println("namesOfFilmsByDirector") 78 | println(namesOfFilmsByDirector(nolan)) 79 | println(namesOfFilmsByDirector(eastwood)) 80 | println(namesOfFilmsByDirector(someGuy)) 81 | 82 | println("namesOfFilmsByDirectorScoringAtLeast") 83 | println(namesOfFilmsByDirectorScoringAtLeast(nolan, 8.8)) 84 | println(namesOfFilmsByDirectorScoringAtLeast(nolan, 8.9)) 85 | println(namesOfFilmsByDirectorScoringAtLeast(someGuy, 0.0)) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/scala/part2/Example7Counter.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | // ---------------------------------------------- 4 | 5 | // Write your Counter class (and companion object) here! 6 | 7 | // ---------------------------------------------- 8 | 9 | object Example7Counter { 10 | def main(args: Array[String]): Unit = { 11 | println("constructors") 12 | // val counter1 = new Counter(10) 13 | // val counter2 = new Counter(20) 14 | // println(counter1.value) 15 | // println(counter2.value) 16 | 17 | println("increment") 18 | // val counter3 = new Counter(41) 19 | // val counter4 = counter3.increment 20 | // println(counter3.value) 21 | // println(counter4.value) 22 | 23 | println("toString") 24 | // println(counter1) 25 | // println(counter4) 26 | 27 | println("equality") 28 | // val counter5 = new Counter(100) 29 | // val counter6 = new Counter(100) 30 | // println(counter5 == counter6) 31 | 32 | println("companion object") 33 | // println(Counter.zero.increment.increment.increment) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/scala/part2/Exercise10Draw.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | import drawing.Canvas 4 | 5 | object Exercise10Draw { 6 | // def draw(canvas: Canvas, x: Double, y: Double, shape: Shape): Unit = { 7 | // ??? 8 | // } 9 | 10 | def main(args: Array[String]): Unit = { 11 | Canvas.show(500, 500, canvas => { 12 | // draw(canvas, 100, 100, Circle(40, Color(1, 1, 0))) 13 | // draw(canvas, 200, 200, Rect(80, 60, Color(1, 0 ,0))) 14 | }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/scala/part2/Exercise11IntList.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | // ---------------------------------------------- 4 | 5 | // Write a definition for IntList here! 6 | 7 | // Implement the following methods on IntList: 8 | // - def contains(num: Int): Boolean 9 | // Does the list contain `num`? 10 | // 11 | // - def addToEach(num: Int): IntList 12 | // Add `num` to every item in the list, returning a new list 13 | // 14 | // - def total: Int 15 | // Add up the items in the list and return the total 16 | // 17 | // - def append(that: IntList): IntList 18 | // Append two lists 19 | // 20 | // - def evensOnly: IntList 21 | // Return a new list comprising only the even numbers from this list 22 | 23 | // ---------------------------------------------- 24 | 25 | object Exercise11IntList { 26 | // val numbers = IntPair(1, IntPair(2, IntPair(3, IntNil()))) 27 | 28 | def main(args: Array[String]): Unit = { 29 | println("contains") 30 | // println(numbers.contains(1)) 31 | // println(numbers.contains(5)) 32 | 33 | println("addToEach") 34 | // println(numbers.addToEach(1)) 35 | // println(numbers.addToEach(5)) 36 | 37 | println("total") 38 | // println(numbers.total) 39 | 40 | println("append") 41 | // println(numbers.append(numbers)) 42 | 43 | println("evensOnly") 44 | // println(numbers.evensOnly) 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/scala/part2/Exercise12Calculator.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | // ---------------------------------------------- 4 | 5 | // Step 1. Write a definition for Expr here! 6 | 7 | sealed abstract class Expr 8 | 9 | // Handle the following types of equation: 10 | // - addition 11 | // - subtraction 12 | // - multiplication 13 | // - division 14 | // - square root 15 | 16 | // Give it a `stringify` method 17 | // that renders the expression as a string. 18 | 19 | // ---------------------------------------------- 20 | 21 | // Step 2. Implement eval 22 | // for each of the "calculator" objects below: 23 | 24 | object Calculator { 25 | def eval(calc: Expr): Double = { 26 | ??? 27 | } 28 | } 29 | 30 | object IntCalculator { 31 | def eval(calc: Expr): Int = { 32 | ??? 33 | } 34 | } 35 | 36 | // ---------------------------------------------- 37 | 38 | // Step 3. Write some convenience methods 39 | // for constructing common calculations: 40 | 41 | // ---------------------------------------------- 42 | 43 | object Expr { 44 | // def pythag(a: Double, b: Double): Expr = { 45 | // ??? 46 | // } 47 | 48 | // def factorial(n: Int): Expr = { 49 | // ??? 50 | // } 51 | } 52 | 53 | object Exercise11Calculator { 54 | // val calc1 = Add(Num(1.1), Mul(Num(2.2), Num(3.3))) 55 | // val calc2 = Add(Mul(Num(1.1), Num(2.2)), Num(3.3)) 56 | 57 | def main(args: Array[String]): Unit = { 58 | println("stringify") 59 | // println(calc1.stringify) 60 | // println(calc2.stringify) 61 | 62 | println("Calculator.eval") 63 | // println(Calculator.eval(calc1)) 64 | // println(Calculator.eval(calc2)) 65 | 66 | println("IntCalculator.eval") 67 | // println(IntCalculator.eval(calc1)) 68 | // println(IntCalculator.eval(calc2)) 69 | 70 | println("pythag") 71 | // println(Expr.pythag(3, 4)) 72 | // println(Calculator.eval(Expr.pythag(3, 4))) 73 | // println(IntCalculator.eval(Expr.pythag(3, 4))) 74 | 75 | println("factorial") 76 | // println(Expr.factorial(4)) 77 | // println(Calculator.eval(Expr.factorial(4))) 78 | // println(IntCalculator.eval(Expr.factorial(4))) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/scala/part2/Exercise13SafeCalculator.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | // ---------------------------------------------- 4 | 5 | // Step 1. Implement a `Result` type 6 | 7 | sealed abstract class Result 8 | 9 | // A Result is: 10 | // - a Pass containing a Double result, or 11 | // - a Fail containing a String error message 12 | 13 | // ---------------------------------------------- 14 | 15 | // Step 2. Implement eval below: 16 | 17 | object SafeCalculator { 18 | def eval(calc: Expr): Result = { 19 | ??? 20 | } 21 | } 22 | 23 | object Exercise13SafeCalculator { 24 | def main(args: Array[String]): Unit = { 25 | println("SaveCalculator.eval") 26 | // println(SafeCalculator.eval(Add(Num(1), Num(2)))) 27 | // println(SafeCalculator.eval(Sqrt(Num(-1)))) 28 | // println(SafeCalculator.eval(Div(Num(1), Num(0)))) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/scala/part2/Exercise14GenericList.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | // ---------------------------------------------- 4 | 5 | // Step 1. Implement MyList[A] below 6 | 7 | sealed abstract class MyList[A] 8 | 9 | // Step 2. Implement the following methods 10 | // using methods from IntList as templates: 11 | 12 | // - exists(func) 13 | // Does the list contain a particular value? 14 | // Use `contains` as a template 15 | 16 | // - map(func) 17 | // Applies `func` to each item, returning a list of the results 18 | // Use `addToEach` as a template 19 | 20 | // Harder methods: 21 | 22 | // - filter(predicate) 23 | // Applies `predicate` to each item to get a boolean result 24 | // Return a new list, but only include items for which `predicate` returns true 25 | // Use `evensOnly` as a template 26 | 27 | // - reduce(accum, func) 28 | // Start with `accum`. Use `func` to combine it with the head of the list. 29 | // Then use the result as the `accum` to reduce the tail of the list. 30 | // Use `total` as a template 31 | 32 | // - append(list) 33 | // Append two lists 34 | 35 | // ---------------------------------------------- 36 | 37 | object Exercise14GenericList { 38 | // val numbers: MyList[Int] = 39 | // MyPair(1, MyPair(3, MyPair(5, MyNil()))) 40 | 41 | // val strings: MyList[String] = 42 | // MyPair("foo", MyPair("bar", MyPair("baz", MyNil()))) 43 | 44 | // val shapes: MyList[Shape] = 45 | // MyPair( 46 | // Circle(20, Color(1, 1, 0)), 47 | // MyPair( 48 | // Circle(10, Color(1, 1, 0)), 49 | // MyPair( 50 | // Rect(30, 20, Color(1, 0, 1)), 51 | // MyNil()))) 52 | 53 | println("exists") 54 | // println(numbers.exists(n => n > 1)) 55 | // println(strings.exists(s => s.startsWith("b"))) 56 | // println(shapes.exists(s => s.area > 100)) 57 | 58 | println("map") 59 | // println(numbers.map(n => n + 1)) 60 | // println(strings.map(s => s + "!")) 61 | // println(shapes.map(s => s.toString)) 62 | 63 | println("reduce") 64 | // println(numbers.reduce(0, (a, b) => a + b)) 65 | // println(strings.reduce("", (a, b) => a + b)) 66 | 67 | println("append") 68 | // println(numbers.append(numbers)) 69 | // println(strings.append(strings)) 70 | // println(shapes.append(shapes)) 71 | 72 | println("filter") 73 | // println(numbers.filter(n => n > 1)) 74 | // println(strings.filter(s => s.startsWith("b"))) 75 | // println(shapes.filter(s => s.area > 50)) 76 | } 77 | -------------------------------------------------------------------------------- /src/main/scala/part2/Exercise15Json.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | // ---------------------------------------------- 4 | 5 | // Step 1. Implement an ADT `JsValue` to represent unstructured JSON data 6 | 7 | sealed abstract class JsValue 8 | 9 | // Include subtypes for each of the main types of JSON 10 | 11 | // ---------------------------------------------- 12 | 13 | // Step 2. Implement a `stringify` method on the companion object for `JsValue` 14 | 15 | object JsValue { 16 | def stringify(json: JsValue): String = { 17 | ??? 18 | } 19 | } 20 | 21 | // ---------------------------------------------- 22 | 23 | object Exercise15Json { 24 | // val json1: JsValue = 25 | // JsString("hello") 26 | 27 | // val json2: JsValue = 28 | // JsArray(List( 29 | // JsNumber(1), 30 | // JsNumber(2), 31 | // JsNumber(3), 32 | // )) 33 | 34 | // val json3: JsValue = 35 | // JsNull 36 | 37 | // val json4: JsValue = 38 | // JsObject(List( 39 | // ("foo", json1), 40 | // ("bar", json2), 41 | // ("baz", json3), 42 | // )) 43 | 44 | def main(args: Array[String]): Unit = { 45 | println("stringify") 46 | // println(JsValue.stringify(json1)) 47 | // println(JsValue.stringify(json2)) 48 | // println(JsValue.stringify(json3)) 49 | // println(JsValue.stringify(json4)) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/scala/part2/Exercise8Vec.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | // ---------------------------------------------- 4 | 5 | // Write your Vec class (and companion object) here! 6 | 7 | // ---------------------------------------------- 8 | 9 | object Exercise8Vec { 10 | // val vec1 = new Vec(3, 4) 11 | // val vec2 = new Vec(5, 12) 12 | 13 | def main(args: Array[String]): Unit = { 14 | println("length") 15 | // println(vec1.length) 16 | // println(vec2.length) 17 | 18 | println("+") 19 | // println(vec1 + vec2) 20 | // println((vec1 + vec2).length) 21 | 22 | println("*") 23 | // println(vec1 * 10) 24 | // println((vec1 * 10).length) 25 | 26 | println("zero, unitX, unitY") 27 | // println(Vec.zero) 28 | // println(Vec.unitX * 3 + Vec.unitY * 4) 29 | 30 | println("longest(Vec, Vec)") 31 | // println(Vec.longest(vec1, vec2)) 32 | // println(Vec.longest(Vec.unitX * 2, Vec.unitY)) 33 | 34 | println("longest(List[Vec])") 35 | // println(Vec.longest(List(Vec.unitX, Vec.unitX + Vec.unitY, Vec.unitY))) 36 | // println(Vec.longest(Nil)) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/scala/part2/Exercise9ColorAndShape.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | // ---------------------------------------------- 4 | 5 | // Write a definition for Color here! 6 | 7 | // Write definitions for Shape, Circle, and Rect here! 8 | 9 | // ---------------------------------------------- 10 | 11 | object Exercise9ColorAndShape { 12 | def main(args: Array[String]): Unit = { 13 | println("color") 14 | // println(Color(1, 1, 0)) 15 | // println(Color(1, 0, 1)) 16 | 17 | println("circle") 18 | // val circle = Circle(30, Color(1, 1, 0)) 19 | // println(circle) 20 | // println(circle.area) 21 | // println(circle.perimeter) 22 | 23 | println("rect") 24 | // val rect = Rect(50, 30, Color(1, 0, 1)) 25 | // println(rect) 26 | // println(rect.area) 27 | // println(rect.perimeter) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/scala/part3/Exercise16aOptionAndEither.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import films.{Director, Film} 4 | 5 | object Exercise16aOptionAndEither { 6 | def directorWithLastName(directors: List[Director], lastName: String): Option[Director] = { 7 | ??? 8 | } 9 | 10 | def directorWithLastNameOrFailure(directors: List[Director], lastName: String): Either[String, Director] = { 11 | ??? 12 | } 13 | 14 | def yearOfBirthOfDirectorWithLastName(directors: List[Director], lastName: String): Option[Int] = { 15 | ??? 16 | } 17 | 18 | def yearOfBirthOfDirectorWithLastNameOrFailure(directors: List[Director], lastName: String): Either[String, Int] = { 19 | ??? 20 | } 21 | 22 | def filmsByDirectorWithLastName(directors: List[Director], lastName: String): List[Film] = { 23 | ??? 24 | } 25 | 26 | def earliestFilmByDirectorWithLastName(directors: List[Director], lastName: String): Option[Film] = { 27 | ??? 28 | } 29 | 30 | def earliestFilmByDirectorWithLastNameOrFailure(directors: List[Director], lastName: String): Either[String, Film] = { 31 | ??? 32 | } 33 | 34 | def namesOfFilmsByDirectorWithLastName(directors: List[Director], lastName: String): List[String] = { 35 | ??? 36 | } 37 | 38 | def nameOfEarliestFilmByDirectorWithLastName(directors: List[Director], lastName: String): Option[String] = { 39 | ??? 40 | } 41 | 42 | def nameOfEarliestFilmByDirectorWithLastNameOrFailure(directors: List[Director], lastName: String): Either[String, String] = { 43 | ??? 44 | } 45 | 46 | def main(args: Array[String]): Unit = { 47 | import films.TestData._ 48 | 49 | println("directorWithLastName") 50 | // println(directorWithLastName(directors, "Nolan")) 51 | // println(directorWithLastName(directors, "Guy")) 52 | // println(directorWithLastName(directors, "DROP TABLE *;")) 53 | 54 | println("directorWithLastNameOrFailure") 55 | // println(directorWithLastNameOrFailure(directors, "Nolan")) 56 | // println(directorWithLastNameOrFailure(directors, "Guy")) 57 | // println(directorWithLastNameOrFailure(directors, "DROP TABLE *;")) 58 | 59 | println("yearOfBirthOfDirectorWithLastName") 60 | // println(yearOfBirthOfDirectorWithLastName(directors, "Nolan")) 61 | // println(yearOfBirthOfDirectorWithLastName(directors, "Guy")) 62 | // println(yearOfBirthOfDirectorWithLastName(directors, "DROP TABLE *;")) 63 | 64 | println("yearOfBirthOfDirectorWithLastNameOrFailure") 65 | // println(yearOfBirthOfDirectorWithLastNameOrFailure(directors, "Nolan")) 66 | // println(yearOfBirthOfDirectorWithLastNameOrFailure(directors, "Guy")) 67 | // println(yearOfBirthOfDirectorWithLastNameOrFailure(directors, "DROP TABLE *;")) 68 | 69 | println("filmsByDirectorWithLastName") 70 | // println(filmsByDirectorWithLastName(directors, "Nolan")) 71 | // println(filmsByDirectorWithLastName(directors, "Guy")) 72 | // println(filmsByDirectorWithLastName(directors, "DROP TABLE *;")) 73 | 74 | println("earliestFilmByDirectorWithLastName") 75 | // println(earliestFilmByDirectorWithLastName(directors, "Nolan")) 76 | // println(earliestFilmByDirectorWithLastName(directors, "Guy")) 77 | // println(earliestFilmByDirectorWithLastName(directors, "DROP TABLE *;")) 78 | 79 | println("earliestFilmByDirectorWithLastNameOrFailure") 80 | // println(earliestFilmByDirectorWithLastNameOrFailure(directors, "Nolan")) 81 | // println(earliestFilmByDirectorWithLastNameOrFailure(directors, "Guy")) 82 | // println(earliestFilmByDirectorWithLastNameOrFailure(directors, "DROP TABLE *;")) 83 | 84 | println("namesOfFilmsByDirectorWithLastName") 85 | // println(namesOfFilmsByDirectorWithLastName(directors, "Nolan")) 86 | // println(namesOfFilmsByDirectorWithLastName(directors, "Guy")) 87 | // println(namesOfFilmsByDirectorWithLastName(directors, "DROP TABLE *;")) 88 | 89 | println("nameOfEarliestFilmByDirectorWithLastName") 90 | // println(nameOfEarliestFilmByDirectorWithLastName(directors, "Nolan")) 91 | // println(nameOfEarliestFilmByDirectorWithLastName(directors, "Guy")) 92 | // println(nameOfEarliestFilmByDirectorWithLastName(directors, "DROP TABLE *;")) 93 | 94 | println("nameOfEarliestFilmByDirectorWithLastNameOrFailure") 95 | // println(nameOfEarliestFilmByDirectorWithLastNameOrFailure(directors, "Nolan")) 96 | // println(nameOfEarliestFilmByDirectorWithLastNameOrFailure(directors, "Guy")) 97 | // println(nameOfEarliestFilmByDirectorWithLastNameOrFailure(directors, "DROP TABLE *;")) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/scala/part3/Exercise16bOptionFoldAndMap.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import films.Director 4 | 5 | object Exercise16bOptionFoldAndMap { 6 | def directorWithLastName(directors: List[Director], lastName: String): Option[Director] = { 7 | ??? 8 | } 9 | 10 | def directorWithLastNameOrFailure(directors: List[Director], lastName: String): Either[String, Director] = { 11 | ??? 12 | } 13 | 14 | def yearOfBirthOfDirectorWithLastName(directors: List[Director], lastName: String): Option[Int] = { 15 | ??? 16 | } 17 | 18 | def yearOfBirthOfDirectorWithLastNameOrFailure(directors: List[Director], lastName: String): Either[String, Int] = { 19 | ??? 20 | } 21 | 22 | def namesOfFilmsByDirectorWithLastName(directors: List[Director], lastName: String): List[String] = { 23 | ??? 24 | } 25 | 26 | def main(args: Array[String]): Unit = { 27 | import films.TestData._ 28 | 29 | println("directorWithLastName") 30 | // println(directorWithLastName(directors, "Nolan")) 31 | // println(directorWithLastName(directors, "Guy")) 32 | // println(directorWithLastName(directors, "DROP TABLE *;")) 33 | 34 | println("directorWithLastNameOrFailure") 35 | // println(directorWithLastNameOrFailure(directors, "Nolan")) 36 | // println(directorWithLastNameOrFailure(directors, "Guy")) 37 | // println(directorWithLastNameOrFailure(directors, "DROP TABLE *;")) 38 | 39 | println("yearOfBirthOfDirectorWithLastName") 40 | // println(yearOfBirthOfDirectorWithLastName(directors, "Nolan")) 41 | // println(yearOfBirthOfDirectorWithLastName(directors, "Guy")) 42 | // println(yearOfBirthOfDirectorWithLastName(directors, "DROP TABLE *;")) 43 | 44 | println("yearOfBirthOfDirectorWithLastNameOrFailure") 45 | // println(yearOfBirthOfDirectorWithLastNameOrFailure(directors, "Nolan")) 46 | // println(yearOfBirthOfDirectorWithLastNameOrFailure(directors, "Guy")) 47 | // println(yearOfBirthOfDirectorWithLastNameOrFailure(directors, "DROP TABLE *;")) 48 | 49 | println("namesOfFilmsByDirectorWithLastName") 50 | println(namesOfFilmsByDirectorWithLastName(directors, "Nolan")) 51 | println(namesOfFilmsByDirectorWithLastName(directors, "Guy")) 52 | println(namesOfFilmsByDirectorWithLastName(directors, "DROP TABLE *;")) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/scala/part3/Exercise17FoldLeftAndRight.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import films.Film 4 | 5 | object Exercise17FoldLeftAndRight { 6 | def totalImdbRating(films: List[Film]): Double = { 7 | ??? 8 | } 9 | 10 | def averageImdbRating(films: List[Film]): Double = { 11 | ??? 12 | } 13 | 14 | def reverseUsingFold[A](items: List[A]): List[A] = { 15 | ??? 16 | } 17 | 18 | def filterUsingFold[A](items: List[A], pred: A => Boolean): List[A] = { 19 | ??? 20 | } 21 | 22 | def main(args: Array[String]): Unit = { 23 | import films.TestData._ 24 | 25 | println("totalImdbRating") 26 | // println(totalImdbRating(List(memento, outlawJoseyWales, thomasCrownAffair))) 27 | // println(totalImdbRating(Nil)) 28 | 29 | println("averageImdbRating") 30 | // println(averageImdbRating(List(memento, outlawJoseyWales, thomasCrownAffair))) 31 | // println(averageImdbRating(Nil)) 32 | 33 | println("reverseUsingFold") 34 | // println(reverseUsingFold(List(1, 2, 3))) 35 | // println(reverseUsingFold(Nil)) 36 | 37 | println("filterUsingFold") 38 | // println(filterUsingFold(List(1, 2, 3, 4, 5), (n: Int) => n % 2 == 0)) 39 | // println(filterUsingFold(Nil, (n: Int) => n % 2 == 0)) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/scala/part3/Exercise18FlatMap.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import films.{Director, Film} 4 | 5 | object Exercise18FlatMap { 6 | def filmsByDirector(director: Director): List[Film] = { 7 | ??? 8 | } 9 | 10 | def namesOfFilmsByDirector(director: Director): List[String] = { 11 | ??? 12 | } 13 | 14 | def filmsByAllDirectors(directors: List[Director]): List[Film] = { 15 | ??? 16 | } 17 | 18 | def namesOfFilmsByAllDirectors(directors: List[Director]): List[String] = { 19 | ??? 20 | } 21 | 22 | // Return a list of messages of the form "Tonight only! by !" 23 | def tonightOnlyMessages(directors: List[Director]): List[String] = { 24 | ??? 25 | } 26 | 27 | def main(args: Array[String]): Unit = { 28 | import films.TestData._ 29 | 30 | println("filmsByDirector") 31 | // println(filmsByDirector(nolan)) 32 | // println(filmsByDirector(mcTiernan)) 33 | // println(filmsByDirector(someGuy)) 34 | 35 | println("namesOfFilmsByDirector") 36 | // println(namesOfFilmsByDirector(nolan)) 37 | // println(namesOfFilmsByDirector(mcTiernan)) 38 | // println(namesOfFilmsByDirector(someGuy)) 39 | 40 | println("filmsByAllDirectors") 41 | // println(filmsByAllDirectors(List(nolan, mcTiernan))) 42 | // println(filmsByAllDirectors(List(eastwood, someGuy))) 43 | 44 | println("namesOfFilmsByAllDirectors") 45 | // println(namesOfFilmsByAllDirectors(List(nolan, mcTiernan))) 46 | // println(namesOfFilmsByAllDirectors(List(eastwood, someGuy))) 47 | 48 | println("tonightOnlyMessages") 49 | // println(tonightOnlyMessages(List(nolan, mcTiernan))) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/scala/part3/Exercise19ForComprehensions.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import films.{Director, Film} 4 | 5 | object Exercise19ForComprehensions { 6 | def filmsByDirector(director: Director): List[Film] = { 7 | ??? 8 | } 9 | 10 | def namesOfFilmsByDirector(director: Director): List[String] = { 11 | ??? 12 | } 13 | 14 | def filmsByAllDirectors(directors: List[Director]): List[Film] = { 15 | ??? 16 | } 17 | 18 | def namesOfFilmsByAllDirectors(directors: List[Director]): List[String] = { 19 | ??? 20 | } 21 | 22 | // Return a list of messages of the form "Tonight! by !" 23 | def tonightOnlyMessages(directors: List[Director]): List[String] = { 24 | ??? 25 | } 26 | 27 | def main(args: Array[String]): Unit = { 28 | import films.TestData._ 29 | 30 | println("filmsByDirector") 31 | // println(filmsByDirector(nolan)) 32 | // println(filmsByDirector(mcTiernan)) 33 | // println(filmsByDirector(someGuy)) 34 | 35 | println("namesOfFilmsByDirector") 36 | // println(namesOfFilmsByDirector(nolan)) 37 | // println(namesOfFilmsByDirector(mcTiernan)) 38 | // println(namesOfFilmsByDirector(someGuy)) 39 | 40 | println("filmsByAllDirectors") 41 | // println(filmsByAllDirectors(List(nolan, mcTiernan))) 42 | // println(filmsByAllDirectors(List(eastwood, someGuy))) 43 | 44 | println("namesOfFilmsByAllDirectors") 45 | // println(namesOfFilmsByAllDirectors(List(nolan, mcTiernan))) 46 | // println(namesOfFilmsByAllDirectors(List(eastwood, someGuy))) 47 | 48 | println("tonightOnlyMessages") 49 | // println(tonightOnlyMessages(List(nolan, mcTiernan))) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/scala/part3/Exercise20OptionCalculator.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import part2._ 4 | 5 | object OptionCalculator { 6 | def eval(calc: Expr): Option[Double] = { 7 | ??? 8 | } 9 | } 10 | 11 | object Exercise20OptionCalculator { 12 | def main(args: Array[String]): Unit = { 13 | println("OptionCalculator.eval") 14 | // println(OptionCalculator.eval(Add(Num(1), Num(2)))) 15 | // println(OptionCalculator.eval(Sqrt(Num(-1)))) 16 | // println(OptionCalculator.eval(Div(Num(1), Num(0)))) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/part3/Exercise21EitherCalculator.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import part2._ 4 | 5 | object EitherCalculator { 6 | def eval(expr: Expr): Either[String, Double] = { 7 | ??? 8 | } 9 | } 10 | 11 | object Exercise21EitherCalculator { 12 | def main(args: Array[String]): Unit = { 13 | println("EitherCalculator.eval") 14 | // println(EitherCalculator.eval(Add(Num(1), Num(2)))) 15 | // println(EitherCalculator.eval(Sqrt(Num(-1)))) 16 | // println(EitherCalculator.eval(Div(Num(1), Num(0)))) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/part3/Exercise22Sorting.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import films.{Director, Film} 4 | 5 | object Exercise22Sorting { 6 | def filmsSortedByImdb(films: List[Film]): List[Film] = { 7 | ??? 8 | } 9 | 10 | def filmsByDirectorSortedByImdb(director: Director): List[Film] = { 11 | ??? 12 | } 13 | 14 | def filmsByAllDirectorsSortedByImdb(directors: List[Director]): List[Film] = { 15 | ??? 16 | } 17 | 18 | def filmsByAllDirectorsSortedByDirectorNameThenImdb(directors: List[Director]): List[Film] = { 19 | ??? 20 | } 21 | 22 | def averageImdbRating(films: List[Film]): Double = { 23 | ??? 24 | } 25 | 26 | def averageImdbRatingAcrossDirectors(directors: List[Director]): Double = { 27 | ??? 28 | } 29 | 30 | def main(args:Array[String]): Unit = { 31 | import films.TestData._ 32 | 33 | println("filmsSortedByImdb") 34 | // println(filmsSortedByImdb(mcTiernan.films)) 35 | // println(filmsSortedByImdb(eastwood.films)) 36 | 37 | println("filmsByDirectorSortedByImdb") 38 | // println(filmsByDirectorSortedByImdb(mcTiernan)) 39 | // println(filmsByDirectorSortedByImdb(eastwood)) 40 | 41 | println("filmsByAllDirectorsSortedByImdb") 42 | // println(filmsByAllDirectorsSortedByImdb(List(nolan, mcTiernan))) 43 | 44 | println("filmsByAllDirectorsSortedByDirectorNameThenImdb") 45 | // println(filmsByAllDirectorsSortedByDirectorNameThenImdb(List(nolan, mcTiernan))) 46 | 47 | println("averageImdbRating") 48 | // println(averageImdbRating(nolan.films)) 49 | // println(averageImdbRating(someGuy.films)) 50 | 51 | println("averageImdbRatingAcrossDirectors") 52 | // println(averageImdbRatingAcrossDirectors(directors)) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/scala/part3/Exercise23HarderProblems.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import films.{Director, Film} 4 | 5 | object Exercise23HarderProblems { 6 | def earliestFilmsByAllDirectors(directors: List[Director]): List[(Director, Option[Film])] = { 7 | ??? 8 | } 9 | 10 | def earliestFilmsByAllDirectorsAsMap(directors: List[Director]): Map[Director, Option[Film]] = { 11 | ??? 12 | } 13 | 14 | def averageImdbRatingAcrossDirectors(directors: List[Director]): Double = { 15 | ??? 16 | } 17 | 18 | def earliestFilmByAnyDirector(directors: List[Director]): Option[Film] = { 19 | ??? 20 | } 21 | 22 | def earliestFilmByOldestDirector(directors: List[Director]): Option[Film] = { 23 | ??? 24 | } 25 | 26 | def filmsByAllDirectorsSortedByDirectorNameAndImdb(directors: List[Director], asc: Boolean): List[Film] = { 27 | ??? 28 | } 29 | 30 | def main(args: Array[String]): Unit = { 31 | import films.TestData._ 32 | 33 | println("earliestFilmsByAllDirectors") 34 | // earliestFilmsByAllDirectors(directors).foreach { 35 | // case (key, value) => 36 | // println(key + " -> " + value) 37 | // } 38 | 39 | println("earliestFilmsByAllDirectorsAsMap") 40 | // earliestFilmsByAllDirectorsAsMap(directors).foreach { 41 | // case (key, value) => 42 | // println(key + " -> " + value) 43 | // } 44 | 45 | println("averageImdbRatingAcrossDirectors") 46 | // println(averageImdbRatingAcrossDirectors(directors)) 47 | 48 | println("earliestFilmByAnyDirector") 49 | // println(earliestFilmByAnyDirector(directors)) 50 | 51 | println("earliestFilmByOldestDirector") 52 | // println(earliestFilmByOldestDirector(directors)) 53 | 54 | println("filmsByAllDirectorsSortedByDirectorNameAndImdb asc") 55 | // filmsByAllDirectorsSortedByDirectorNameAndImdb(directors, true).foreach(println) 56 | 57 | println("filmsByAllDirectorsSortedByDirectorNameAndImdb asc") 58 | // filmsByAllDirectorsSortedByDirectorNameAndImdb(directors, false).foreach(println) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/scala/part3/Exercise24aFibonacci.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import scala.concurrent._ 4 | import scala.concurrent.ExecutionContext.Implicits.global 5 | import scala.concurrent.duration._ 6 | import timing._ 7 | 8 | object Exercise24aFibonacci { 9 | // fib(n) is a computation of exponential complixity in terms of n. 10 | // - at n ~= 40 it will start taking a noticeable amount of time. 11 | // - at n ~= 50 it'll take an extremely long time. 12 | def fib(n: Int): Int = 13 | if(n <= 2) 1 else fib(n-1) + fib(n-2) 14 | 15 | def main(args: Array[String]): Unit = { 16 | // Step 1. 17 | // The computations below run in sequence. 18 | // Make them run in parallel. 19 | println("simple fibonacci calculations") 20 | val fibA = Time.sync("fibA")(() => fib(45)) 21 | val fibB = Time.sync("fibB")(() => fib(45)) 22 | val fibC = Time.sync("fibC")(() => fib(45)) 23 | val fibD = Time.sync("fibD")(() => fib(45)) 24 | 25 | // Step 2. 26 | // Find the sum of the four fibonacci numbers above 27 | // (ideally without blocking any threads). 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/scala/part3/Exercise24bUptime.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import scala.concurrent.{Future, Await} 4 | import scala.concurrent.ExecutionContext.Implicits.global 5 | import scala.concurrent.duration._ 6 | 7 | case class Stats(hostname: String, uptime: Long, requests: Int) 8 | 9 | object Stats { 10 | def forHost(hostname: String): Future[Stats] = { 11 | ??? 12 | } 13 | 14 | def forHosts(hostnames: List[String]): Future[List[Stats]] = { 15 | ??? 16 | } 17 | 18 | // Use this helper method in your answers: 19 | def fetchUptime(hostname: String): Future[Long] = { 20 | Future { 21 | Thread.sleep((math.random * 100).toLong) 22 | hostname.hashCode % 10000L 23 | } 24 | } 25 | 26 | // Use this helper method in your answers: 27 | def fetchRequestsHandled(hostname: String): Future[Int] = { 28 | Future { 29 | Thread.sleep((math.random * 100).toLong) 30 | hostname.reverse.hashCode % 100 31 | } 32 | } 33 | } 34 | 35 | object Exercise24bUptime { 36 | val host1 = "alice.example.com" 37 | val host2 = "bob.example.com" 38 | val host3 = "charlie.example.com" 39 | 40 | def main(args: Array[String]): Unit = { 41 | println("Stats.forHost") 42 | // println(Await.result(Stats.forHost(host1), 1.second)) 43 | // println(Await.result(Stats.forHost(host2), 1.second)) 44 | // println(Await.result(Stats.forHost(host3), 1.second)) 45 | 46 | println("Stats.forHosts") 47 | // println(Await.result(Stats.forHosts(List(host1, host2, host3)), 1.second)) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/scala/part4/Exercise25Ordering.scala: -------------------------------------------------------------------------------- 1 | package part4 2 | 3 | import scala.math.Ordering 4 | 5 | final case class Email(address: String) 6 | 7 | object Email { 8 | implicit val ordering: Ordering[Email] = 9 | Ordering.fromLessThan((x, y) => x.address < y.address) 10 | } 11 | 12 | final case class Person(name: String, email: Email) 13 | 14 | object Person { 15 | // Implement orderings for Person here 16 | } 17 | 18 | object Exercise25Ordering { 19 | val email1 = Email("alice@cool.com") 20 | val email2 = Email("charlie@excellent.com") 21 | val email3 = Email("bob@awesome.com") 22 | val emails = List(email1, email2, email3) 23 | 24 | val person1 = Person("Alice", Email("alice@cool.com")) 25 | val person2 = Person("Charlie", Email("charlie@excellent.com")) 26 | val person3 = Person("Bob", Email("bob@awesome.com")) 27 | val people = List(person1, person2, person3) 28 | 29 | def main(args: Array[String]): Unit = { 30 | println("ordering.compare") 31 | // println(Email.ordering.compare(email1, email2)) 32 | // println(Person.ordering.compare(person1, person2)) 33 | 34 | println("sorting") 35 | // println(emails.sorted) 36 | // println(people.sorted) 37 | 38 | println("non-standard orders") 39 | // println(emails.sorted(Email.ordering.reverse)) 40 | // println(people.sorted(Person.orderingByEmail)) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/scala/part4/Exercise26JsonWriter.scala: -------------------------------------------------------------------------------- 1 | package part4 2 | 3 | import part2._ 4 | 5 | // ---------------------------------------------- 6 | 7 | // Step 1. Implement a type class JsonWriter[A] 8 | 9 | // Give it a method write() that: 10 | // - accepts a parameter of type A 11 | // - returns a JsValue 12 | 13 | // ---------------------------------------------- 14 | 15 | // Step 2. In a companion object for JsonWriter implement: 16 | 17 | // - an instance for Email 18 | // - an instance for Person 19 | 20 | // ---------------------------------------------- 21 | 22 | // Step 3. In a companion object for JsonWriter implement: 23 | 24 | // - an instance for Lists (of any type of data) 25 | 26 | // ---------------------------------------------- 27 | 28 | object Exercise26JsonWriter { 29 | // def write[A](value: A)(implicit writer: JsonWriter[A]): JsValue = 30 | // writer.write(value) 31 | 32 | def main(args: Array[String]): Unit = { 33 | println("email") 34 | // write(Email("dave@example.com")) 35 | 36 | println("person") 37 | // write(Person("Alice", Email("alice@example.com"))) 38 | // write(Person("Bob", Email("bob@example.com"))) 39 | 40 | println("list of people") 41 | // write(List( 42 | // Person("Alice", Email("alice@example.com")), 43 | // Person("Bob", Email("bob@example.com")), 44 | // )) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/scala/part4/Exercise27ExtensionMethods.scala: -------------------------------------------------------------------------------- 1 | package part4 2 | 3 | import part2._ 4 | 5 | object Syntax { 6 | // Implement an extension method on List[Int]: 7 | // - `toIntList` converts the data to an IntList 8 | 9 | // Implement an extension method on Int: 10 | // - `times(func)` runs `func` N times, passing in each integer from 0 upwards 11 | // (see below for an example) 12 | 13 | // Implement an extension method on any data type A: 14 | // - `toJson` converts the data to a JsValue 15 | } 16 | 17 | object Exercise27ExtensionMethods { 18 | import Syntax._ 19 | 20 | def main(args: Array[String]): Unit = { 21 | println("toIntList") 22 | // println(List(1, 2, 3).toIntList) 23 | // println(List.empty[Int].toIntList) 24 | 25 | println("times") 26 | // 5.times(i => println(i * 10)) 27 | // 3.times(i => println(i + "!")) 28 | 29 | println("toJson") 30 | // println(Person("Dave", Email("dave@example.com")).toJson) 31 | // println(List( 32 | // Person("Alice", Email("alice@example.com")), 33 | // Person("Bob", Email("bob@example.com")), 34 | // ).toJson) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/scala/sandbox.worksheet.sc: -------------------------------------------------------------------------------- 1 | "Hello world!" 2 | -------------------------------------------------------------------------------- /src/main/scala/timing/Time.scala: -------------------------------------------------------------------------------- 1 | package timing 2 | 3 | import scala.concurrent._ 4 | import scala.concurrent.ExecutionContext.Implicits.global 5 | 6 | object Time { 7 | def sync[A](name: String)(func: () => A): A = { 8 | println(s"Started $name") 9 | val start = System.currentTimeMillis 10 | val answer = func() 11 | val finish = System.currentTimeMillis 12 | println(s"Finished $name after ${finish - start}ms") 13 | answer 14 | } 15 | 16 | def async[A](name: String)(func: () => Future[A]): Future[A] = { 17 | println(s"Started $name") 18 | val start = System.currentTimeMillis 19 | func().map { a => 20 | val finish = System.currentTimeMillis 21 | println(s"Finished $name after ${finish - start}ms") 22 | a 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/test/scala/intro/HelloWorldSpec.scala: -------------------------------------------------------------------------------- 1 | package intro 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class HelloWorldSpec extends AnyFlatSpec with Matchers { 7 | "greeting message" should "be nice and friendly" in { 8 | HelloWorld.message should equal("Hello world!") 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/test/scala/part1/Exercise2ExpressionsSpec.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise2ExpressionsSpec extends AnyFlatSpec with Matchers { 7 | import Exercise2Expressions._ 8 | 9 | "greeting" should "be nice and friendly" in { 10 | pending 11 | // greeting("World") should equal("Hello World!") 12 | // greeting("Dave") should equal("Hello Dave!") 13 | } 14 | 15 | "palindrome" should "seek the tastiest mexican food felines" in { 16 | pending 17 | // palindrome("tacocat") should equal(true) 18 | // palindrome("tacobat") should equal(false) 19 | } 20 | 21 | "factorial" should "multiply some numbers and stuff" in { 22 | pending 23 | // factorial(3) should equal (3 * 2 * 1) 24 | // factorial(5) should equal (5 * 4 * 3 * 2 * 1) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/scala/part1/Exercise3bRecursionSpec.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise3bRecursionSpec extends AnyFlatSpec with Matchers { 7 | import Exercise3bRecursion._ 8 | 9 | "contains" should "find elements in a list" in { 10 | pending 11 | // contains(List(1, 2, 3), 2) should equal(true) 12 | // contains(List(1, 2, 3), 4) should equal(false) 13 | // contains(Nil, 1) should equal(false) 14 | } 15 | 16 | "doubleEachNumber" should "double all elements in a list" in { 17 | pending 18 | // doubleEachNumber(List(1, 2, 3)) should equal(List(2, 4, 6)) 19 | // doubleEachNumber(Nil) should equal(Nil) 20 | } 21 | 22 | "total" should "add up all the elements in a list" in { 23 | pending 24 | // total(List(1, 2, 3)) should equal(1 + 2 + 3) 25 | // total(Nil) should equal(0) 26 | } 27 | 28 | "range" should "return a range [min,max] inclusive" in { 29 | pending 30 | // range(2, 5) should equal(List(2, 3, 4, 5)) 31 | // range(2, 2) should equal(List(2)) 32 | // range(2, 0) should equal(Nil) 33 | } 34 | 35 | "append" should "append two lists" in { 36 | pending 37 | // append(List(1, 2, 3), List(4, 5, 6)) should equal(List(1, 2, 3, 4, 5, 6)) 38 | // append(List(1, 2, 3), Nil) should equal(List(1, 2, 3)) 39 | // append(Nil, List(1, 2, 3)) should equal(List(1, 2, 3)) 40 | // append(Nil, Nil) should equal(Nil) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/scala/part1/Exercise4PatternMatchingSpec.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise4PatternMatchingSpec extends AnyFlatSpec with Matchers { 7 | import Exercise4PatternMatching._ 8 | 9 | "contains" should "find elements in a list" in { 10 | pending 11 | // contains(List(1, 2, 3), 2) should equal(true) 12 | // contains(List(1, 2, 3), 4) should equal(false) 13 | // contains(Nil, 1) should equal(false) 14 | } 15 | 16 | "doubleEachNumber" should "double all elements in a list" in { 17 | pending 18 | // doubleEachNumber(List(1, 2, 3)) should equal(List(2, 4, 6)) 19 | // doubleEachNumber(Nil) should equal(Nil) 20 | } 21 | 22 | "total" should "add up all the elements in a list" in { 23 | pending 24 | // total(List(1, 2, 3)) should equal(1 + 2 + 3) 25 | // total(Nil) should equal(0) 26 | } 27 | 28 | "append" should "append two lists" in { 29 | pending 30 | // append(List(1, 2, 3), List(4, 5, 6)) should equal(List(1, 2, 3, 4, 5, 6)) 31 | // append(List(1, 2, 3), Nil) should equal(List(1, 2, 3)) 32 | // append(Nil, List(1, 2, 3)) should equal(List(1, 2, 3)) 33 | // append(Nil, Nil) should equal(Nil) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/scala/part1/Exercise5FunctionsSpec.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise5FunctionsSpec extends AnyFlatSpec with Matchers { 7 | import Exercise5Functions._ 8 | 9 | "contains" should "find elements in a list" in { 10 | pending 11 | // contains(List(1, 2, 3), 2) should equal(true) 12 | // contains(List(1, 2, 3), 4) should equal(false) 13 | // contains(Nil, 1) should equal(false) 14 | } 15 | 16 | "containsEvenNumbers" should "find even elements" in { 17 | pending 18 | // containsEvenNumbers(List(1, 2, 3)) should equal(true) 19 | // containsEvenNumbers(Nil) should equal(false) 20 | } 21 | 22 | "evenNumbersOnly" should "filter for even elements" in { 23 | pending 24 | // evenNumbersOnly(List(1, 2, 3, 4)) should equal(List(2, 4)) 25 | // evenNumbersOnly(Nil) should equal(Nil) 26 | } 27 | 28 | "doubleEachNumber" should "filter for even elements" in { 29 | pending 30 | // doubleEachNumber(List(1, 2, 3, 4)) should equal(List(2, 4, 6, 8)) 31 | // doubleEachNumber(Nil) should equal(Nil) 32 | } 33 | 34 | "multiplyEachNumberBy" should "filter for even elements" in { 35 | pending 36 | // multiplyEachNumberBy(List(1, 2, 3, 4), 3) should equal(List(3, 6, 9, 12)) 37 | // multiplyEachNumberBy(Nil, 3) should equal(Nil) 38 | // multiplyEachNumberBy(List(1, 2, 3, 4), 0) should equal(List(0, 0, 0, 0)) 39 | } 40 | 41 | "evenNumbersOnlyDoubled" should "filter for even elements" in { 42 | pending 43 | // evenNumbersOnlyDoubled(List(1, 2, 3, 4)) should equal(List(4, 8)) 44 | // evenNumbersOnlyDoubled(Nil) should equal(Nil) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/scala/part1/Exercise6FilmsSpec.scala: -------------------------------------------------------------------------------- 1 | package part1 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise6FilmsSpec extends AnyFlatSpec with Matchers { 7 | import films.TestData._ 8 | import Exercise6Films._ 9 | 10 | "nameOfFilm" should "work as expected" in { 11 | pending 12 | // nameOfFilm(memento) should equal(memento.name) 13 | // nameOfFilm(darkKnight) should equal(darkKnight.name) 14 | } 15 | 16 | "filmsByDirector" should "work as expected" in { 17 | pending 18 | // filmsByDirector(nolan) should contain theSameElementsAs nolan.films 19 | // filmsByDirector(eastwood) should contain theSameElementsAs eastwood.films 20 | } 21 | 22 | "directorsWithBackCatalogOfSize" should "work as expected" in { 23 | pending 24 | // directorsWithBackCatalogOfSize(directors, 1) should contain theSameElementsAs List(eastwood, mcTiernan, nolan) 25 | // directorsWithBackCatalogOfSize(directors, 4) should contain theSameElementsAs List(eastwood, mcTiernan) 26 | // directorsWithBackCatalogOfSize(directors, 5) should contain theSameElementsAs List(eastwood) 27 | // directorsWithBackCatalogOfSize(Nil, 1) should contain theSameElementsAs Nil 28 | } 29 | 30 | "directorsBornBefore" should "work as expected" in { 31 | pending 32 | // directorsBornBefore(directors, 1930) should contain theSameElementsAs Nil 33 | // directorsBornBefore(directors, 1931) should contain theSameElementsAs List(eastwood) 34 | // directorsBornBefore(directors, 1951) should contain theSameElementsAs List(eastwood) 35 | // directorsBornBefore(directors, 1952) should contain theSameElementsAs List(eastwood, mcTiernan) 36 | // directorsBornBefore(Nil, 2000) should contain theSameElementsAs Nil 37 | } 38 | 39 | "directorsBornBeforeWithBackCatalogOfSize" should "work as expected" in { 40 | pending 41 | // directorsBornBeforeWithBackCatalogOfSize(directors, 1931, 5) should contain theSameElementsAs List(eastwood) 42 | // directorsBornBeforeWithBackCatalogOfSize(directors, 1931, 6) should contain theSameElementsAs Nil 43 | // directorsBornBeforeWithBackCatalogOfSize(directors, 1930, 5) should contain theSameElementsAs Nil 44 | // directorsBornBeforeWithBackCatalogOfSize(Nil, 2000, 1) should contain theSameElementsAs Nil 45 | } 46 | 47 | "namesOfFilms" should "work as expected" in { 48 | pending 49 | // namesOfFilms(List(memento, darkKnight)) should contain theSameElementsAs List(memento.name, darkKnight.name) 50 | // namesOfFilms(Nil) should equal(Nil) 51 | } 52 | 53 | "namesOfFilmsByDirector" should "work as expected" in { 54 | pending 55 | // namesOfFilmsByDirector(nolan) should contain theSameElementsAs nolan.films.map(_.name) 56 | // namesOfFilmsByDirector(eastwood) should contain theSameElementsAs eastwood.films.map(_.name) 57 | // namesOfFilmsByDirector(someGuy) should equal(Nil) 58 | } 59 | 60 | "namesOfFilmsByDirectorScoringAtLeast" should "work as expected" in { 61 | pending 62 | // namesOfFilmsByDirectorScoringAtLeast(nolan, 8.8) should contain theSameElementsAs List(darkKnight.name, inception.name) 63 | // namesOfFilmsByDirectorScoringAtLeast(nolan, 8.9) should contain theSameElementsAs List(darkKnight.name) 64 | // namesOfFilmsByDirectorScoringAtLeast(someGuy, 0.0) should equal(Nil) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/scala/part2/Exercise11IntListSpec.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise11IntListSpec extends AnyFlatSpec with Matchers { 7 | // def pair(h: Int, t: IntList): IntPair = 8 | // IntPair(h, t) 9 | 10 | // val nil: IntList = 11 | // IntNil() 12 | 13 | // val numbers1: IntList = 14 | // pair(1, pair(2, pair(3, nil))) 15 | 16 | // val numbers2: IntList = 17 | // pair(4, pair(5, pair(6, nil))) 18 | 19 | "contains" should "return true and false appropriately" in { 20 | pending 21 | // numbers1.contains(1) should equal(true) 22 | // numbers1.contains(5) should equal(false) 23 | // numbers2.contains(5) should equal(true) 24 | // numbers2.contains(1) should equal(false) 25 | // nil.contains(1) should equal(false) 26 | } 27 | 28 | "addToEach" should "increment every element in the list" in { 29 | pending 30 | // numbers1.addToEach(1) should equal(pair(2, pair(3, pair(4, nil)))) 31 | // numbers2.addToEach(3) should equal(pair(7, pair(8, pair(9, nil)))) 32 | // nil.addToEach(10) should equal(nil) 33 | } 34 | 35 | "total" should "total all elements" in { 36 | pending 37 | // numbers1.total should equal(1 + 2 + 3) 38 | // numbers2.total should equal(4 + 5 + 6) 39 | // nil.total should equal(0) 40 | } 41 | 42 | "append" should "append lists" in { 43 | pending 44 | // nil.append(nil) should equal(nil) 45 | // nil.append(numbers2) should equal(numbers2) 46 | // numbers1.append(nil) should equal(numbers1) 47 | // numbers1.append(numbers2) should equal(pair(1, pair(2, pair(3, pair(4, pair(5, pair(6, nil))))))) 48 | } 49 | 50 | "evensOnly" should "filter the list" in { 51 | pending 52 | // numbers1.evensOnly should equal(pair(2, nil)) 53 | // numbers2.evensOnly should equal(pair(4, pair(6, nil))) 54 | // numbers1.append(numbers2).evensOnly should equal(pair(2, pair(4, pair(6, nil)))) 55 | // nil.evensOnly should equal(nil) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/scala/part2/Exercise12CalculatorSpec.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise12CalculatorSpec extends AnyFlatSpec with Matchers { 7 | // val calc1 = Add(Num(1.1), Mul(Num(2.2), Num(3.3))) 8 | // val calc2 = Mul(Add(Num(1.1), Num(2.2)), Num(3.3)) 9 | // val calc3 = Div(Num(1.0), Num(0.0)) 10 | // val calc4 = Sqrt(Num(-1.0)) 11 | 12 | "stringify" should "stringify an expression" in { 13 | pending 14 | // calc1.stringify should equal("1.1 + 2.2 * 3.3") 15 | } 16 | 17 | "Calculator.eval" should "return a double or some weird infinite thing" in { 18 | pending 19 | // Calculator.eval(calc1) should equal(1.1 + 2.2 * 3.3) 20 | // Calculator.eval(calc2) should equal((1.1 + 2.2) * 3.3) 21 | // Calculator.eval(calc3).isPosInfinity should equal(true) 22 | // Calculator.eval(calc4).isNaN should equal(true) 23 | } 24 | 25 | "IntCalculator.eval" should "return an integer or throw an exception" in { 26 | pending 27 | // IntCalculator.eval(calc1) should equal(1 + 2 * 3) 28 | // IntCalculator.eval(calc2) should equal((1 + 2) * 3) 29 | // intercept[ArithmeticException] { IntCalculator.eval(calc3) } 30 | // IntCalculator.eval(calc4) should equal(0) // Double.NaN.toInt is apparently 0! 31 | } 32 | 33 | "pythag" should "produce the correct form of expression" in { 34 | pending 35 | // IntCalculator.eval(Expr.pythag(3, 4)) should equal(5) 36 | // IntCalculator.eval(Expr.pythag(5, 12)) should equal(13) 37 | } 38 | 39 | "factorial" should "produce the correct form of expression" in { 40 | pending 41 | // IntCalculator.eval(Expr.factorial(5)) should equal(5 * 4 * 3 * 2 * 1) 42 | // IntCalculator.eval(Expr.factorial(3)) should equal(3 * 2 * 1) 43 | // IntCalculator.eval(Expr.factorial(1)) should equal(1) 44 | } 45 | 46 | "stringify" should "parenthesise expression correctly (harder)" in { 47 | pending 48 | // calc2.stringify should equal("(1.1 + 2.2) * 3.3") 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/scala/part2/Exercise13SafeCalculatorSpec.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise13SafeCalculatorSpec extends AnyFlatSpec with Matchers { 7 | // val calc1 = Add(Num(1.1), Mul(Num(2.2), Num(3.3))) 8 | // val calc2 = Mul(Add(Num(1.1), Num(2.2)), Num(3.3)) 9 | // val calc3 = Div(Num(1.0), Num(0.0)) 10 | // val calc4 = Sqrt(Num(-1.0)) 11 | 12 | "SafeCalculator.eval" should "succeed on valid expressions" in { 13 | pending 14 | //SafeCalculator.eval(calc1) should equal(Pass(1.1 + 2.2 * 3.3)) 15 | //SafeCalculator.eval(calc2) should equal(Pass((1.1 + 2.2) * 3.3)) 16 | } 17 | 18 | it should "fail grcefully on division by zero and negative square root" in { 19 | pending 20 | // You may want to edit these tests to check your error messages 21 | // SafeCalculator.eval(calc3) shouldBe a[Fail] 22 | // SafeCalculator.eval(calc4) shouldBe a[Fail] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/scala/part2/Exercise14aGenericListSpec.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise14aGenericListSpec extends AnyFlatSpec with Matchers { 7 | // def pair[A](h: A, t: MyList[A]): MyList[A] = 8 | // MyPair(h, t) 9 | 10 | // def nil[A]: MyList[A] = 11 | // MyNil() 12 | 13 | // val numbers1: MyList[Int] = 14 | // pair(1, pair(2, pair(3, nil))) 15 | 16 | // val numbers2: MyList[Int] = 17 | // pair(4, pair(5, pair(6, nil))) 18 | 19 | // val strings1: MyList[String] = 20 | // pair("foo", pair("bar", pair("baz", nil))) 21 | 22 | "exists" should "work as expected" in { 23 | pending 24 | // numbers1.exists(n => n < 2) should equal(true) 25 | // numbers1.exists(n => n < 1) should equal(false) 26 | // numbers1.exists(n => n > 2) should equal(true) 27 | // numbers1.exists(n => n > 3) should equal(false) 28 | } 29 | 30 | "map" should "work on integers" in { 31 | pending 32 | // numbers1.map(n => n + 1) should equal(pair(2, pair(3, pair(4, nil)))) 33 | // numbers2.map(n => n + 3) should equal(pair(7, pair(8, pair(9, nil)))) 34 | // strings1.map(s => s + "!") should equal(pair("foo!", pair("bar!", pair("baz!", nil)))) 35 | } 36 | 37 | "reduce" should "accumulate from left to right" in { 38 | pending 39 | // numbers1.reduce(0, (a, b) => a + b) should equal(6) 40 | // numbers2.reduce(0, (a, b) => a + b) should equal(15) 41 | // strings1.reduce("", (a, b) => a + b) should equal("foobarbaz") 42 | } 43 | 44 | "append" should "work as expected" in { 45 | pending 46 | // nil[Int].append(nil) should equal(nil[Int]) 47 | // nil[Int].append(numbers1) should equal(numbers1) 48 | // numbers1.append(nil[Int]) should equal(numbers1) 49 | // numbers1.append(numbers2) should equal(pair(1, pair(2, pair(3, pair(4, pair(5, pair(6, nil))))))) 50 | } 51 | 52 | "filter" should "work as expected" in { 53 | pending 54 | // numbers1.filter(n => n > 0) should equal(numbers1) 55 | // numbers1.filter(n => n < 0) should equal(nil) 56 | // numbers1.filter(n => n > 2) should equal(pair(3, nil)) 57 | // numbers2.filter(n => n > 0) should equal(numbers2) 58 | // numbers2.filter(n => n < 0) should equal(nil) 59 | // numbers2.filter(n => n > 4) should equal(pair(5, pair(6, nil))) 60 | // strings1.filter(s => s.contains('b')) should equal(pair("bar", pair("baz", nil))) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/scala/part2/Exercise14bCovariantListSpec.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise14bCovariantListSpec extends AnyFlatSpec with Matchers { 7 | // def pair[A](h: A, t: MyList[A]): MyList[A] = 8 | // MyPair(h, t) 9 | 10 | // def nil[A]: MyList[A] = 11 | // MyNil 12 | 13 | // val numbers1: MyList[Int] = 14 | // pair(1, pair(2, pair(3, nil))) 15 | 16 | // val numbers2: MyList[Int] = 17 | // pair(4, pair(5, pair(6, nil))) 18 | 19 | // val strings1: MyList[String] = 20 | // pair("foo", pair("bar", pair("baz", nil))) 21 | 22 | "exists" should "work as expected" in { 23 | pending 24 | // numbers1.exists(n => n < 2) should equal(true) 25 | // numbers1.exists(n => n < 1) should equal(false) 26 | // numbers1.exists(n => n > 2) should equal(true) 27 | // numbers1.exists(n => n > 3) should equal(false) 28 | } 29 | 30 | "map" should "work on integers" in { 31 | pending 32 | // numbers1.map(n => n + 1) should equal(pair(2, pair(3, pair(4, nil)))) 33 | // numbers2.map(n => n + 3) should equal(pair(7, pair(8, pair(9, nil)))) 34 | // strings1.map(s => s + "!") should equal(pair("foo!", pair("bar!", pair("baz!", nil)))) 35 | } 36 | 37 | "append" should "work as expected" in { 38 | pending 39 | // nil[Int].append(nil) should equal(nil[Int]) 40 | // nil[Int].append(numbers1) should equal(numbers1) 41 | // numbers1.append(nil[Int]) should equal(numbers1) 42 | // numbers1.append(numbers2) should equal(pair(1, pair(2, pair(3, pair(4, pair(5, pair(6, nil))))))) 43 | } 44 | 45 | "filter" should "work as expected" in { 46 | pending 47 | // numbers1.filter(n => n > 0) should equal(numbers1) 48 | // numbers1.filter(n => n < 0) should equal(nil) 49 | // numbers1.filter(n => n > 2) should equal(pair(3, nil)) 50 | // numbers2.filter(n => n > 0) should equal(numbers2) 51 | // numbers2.filter(n => n < 0) should equal(nil) 52 | // numbers2.filter(n => n > 4) should equal(pair(5, pair(6, nil))) 53 | // strings1.filter(s => s.contains('b')) should equal(pair("bar", pair("baz", nil))) 54 | } 55 | 56 | "reduce" should "accumulate from left to right" in { 57 | pending 58 | // numbers1.reduce[Int](0, (a, b) => a + b) should equal(6) 59 | // numbers2.reduce[Int](0, (a, b) => a + b) should equal(15) 60 | // strings1.reduce[String]("", (a, b) => a + b) should equal("foobarbaz") 61 | // numbers1.reduce[String]("", (a, b) => a + b) should equal("123") 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/scala/part2/Exercise15JsonSpec.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise15JsonSpec extends AnyFlatSpec with Matchers { 7 | // val json1: JsValue = 8 | // JsString("hello") 9 | 10 | // You may have to change this definition 11 | // depending on how you structured JsArray: 12 | // val json2: JsValue = 13 | // JsArray(List( 14 | // JsNumber(1), 15 | // JsNumber(2), 16 | // JsNumber(3), 17 | // )) 18 | 19 | // val json3: JsValue = 20 | // JsNull 21 | 22 | // You may have to change this definition 23 | // depending on how you structured JsObject: 24 | // val json4: JsValue = 25 | // JsObject(List( 26 | // ("foo", json1), 27 | // ("bar", json2), 28 | // ("baz", json3), 29 | // )) 30 | 31 | "stringify" should "handle the examples" in { 32 | pending 33 | // JsValue.stringify(json1) should equal(""""hello"""") 34 | // JsValue.stringify(json2) should equal("""[1.0,2.0,3.0]""") 35 | // JsValue.stringify(json3) should equal("""null""") 36 | // JsValue.stringify(json4) should equal("""{"foo":"hello","bar":[1.0,2.0,3.0],"baz":null}""") 37 | } 38 | 39 | // Harder: only do this if you have time: 40 | it should "escape string literals" in { 41 | pending 42 | // val actual: String = 43 | // JsValue.stringify(JsString("""Hello "world"!""")) 44 | // 45 | // val expected: String = 46 | // """"Hello \"world\"!"""" 47 | // 48 | // actual should equal(expected) 49 | } 50 | 51 | // Harder: only do this if you have time: 52 | it should "escape object field names" in { 53 | pending 54 | // val actual: String = 55 | // JsValue.stringify(JsObject(List( 56 | // (""""name"""", JsString(""""value"""")) 57 | // ))) 58 | // 59 | // val expected: String = 60 | // """{"\"name\"":"\"value\""}""" 61 | // 62 | // actual should equal(expected) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/scala/part2/Exercise7CounterSpec.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise7CounterSpec extends AnyFlatSpec with Matchers { 7 | // val counter1 = new Counter(123) 8 | // val counter2 = new Counter(321) 9 | 10 | "constructor" should "create a counter with the correct value" in { 11 | pending 12 | // counter1.value should equal(123) 13 | // counter2.value should equal(321) 14 | } 15 | 16 | "increment" should "copy the counter and increment the value by 1" in { 17 | pending 18 | // val counter3 = counter1.increment 19 | // val counter4 = counter2.increment 20 | // counter1.value should equal(123) 21 | // counter2.value should equal(321) 22 | // counter3.value should equal(124) 23 | // counter4.value should equal(322) 24 | } 25 | 26 | "equals method" should "compare counters by value" in { 27 | pending 28 | // (counter1 == counter1) should equal(true) 29 | // (counter1 == counter1.increment) should equal(false) 30 | // (counter1.increment == new Counter(124)) should equal(true) 31 | // (counter1.increment == counter1.increment) should equal(true) 32 | } 33 | 34 | "toString method" should "pretty print a counter" in { 35 | pending 36 | // counter1.toString should equal("Counter(123)") 37 | // counter2.toString should equal("Counter(321)") 38 | // counter1.increment.toString should equal("Counter(124)") 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/scala/part2/Exercise8aVecSpec.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise8aVecSpec extends AnyFlatSpec with Matchers { 7 | // val vec1 = new Vec(3, 4) 8 | // val vec2 = new Vec(5, 12) 9 | 10 | "length" should "calculate the correct value" in { 11 | pending 12 | // vec1.length should equal(5) 13 | // vec2.length should equal(13) 14 | } 15 | 16 | "+" should "calculate the correct value" in { 17 | pending 18 | // (vec1 + vec2) should equal(new Vec(8, 16)) 19 | // (vec1 + vec2).length should equal(math.sqrt(8*8 + 16*16)) 20 | } 21 | 22 | "*" should "calculate the correct value" in { 23 | pending 24 | // (vec1 * 10) should equal(new Vec(30, 40)) 25 | // (vec1 * 10).length should equal(50) 26 | } 27 | 28 | "zero, unitX, unitY" should "calculate the correct value" in { 29 | pending 30 | // Vec.zero should equal(new Vec(0, 0)) 31 | // (Vec.unitX * 3 + Vec.unitY * 4) should equal(new Vec(3, 4)) 32 | } 33 | 34 | "longest(Vec, Vec)" should "calculate the correct value" in { 35 | pending 36 | // Vec.longest(vec1, vec2) should equal(vec2) 37 | // Vec.longest(Vec.unitX * 2, Vec.unitY) should equal(Vec.unitX * 2) 38 | } 39 | 40 | "longest(List[Vec])" should "calculate the correct value" in { 41 | pending 42 | // Vec.longest(List( 43 | // Vec.unitX, 44 | // Vec.unitX + Vec.unitY, 45 | // Vec.unitY 46 | // )) should equal(Vec.unitX + Vec.unitY) 47 | // 48 | // Vec.longest(Nil) should equal(Vec.zero) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/scala/part2/Exercise8bVecCaseClassSpec.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise8bVecCaseClassSpec extends AnyFlatSpec with Matchers { 7 | // val vec1 = Vec(3, 4) 8 | // val vec2 = Vec(5, 12) 9 | 10 | "accessors" should "return fields from the Vec" in { 11 | pending 12 | // vec1.x should equal(3) 13 | // vec1.y should equal(4) 14 | // vec2.x should equal(5) 15 | // vec2.y should equal(12) 16 | } 17 | 18 | "copy constructor" should "create new Vecs" in { 19 | pending 20 | // vec1.copy(x = 100) should equal(Vec(100, 4)) 21 | // vec2.copy(y = 100) should equal(Vec(5, 100)) 22 | } 23 | 24 | "equals method" should "compare on contents, not on reference equality" in { 25 | pending 26 | // (vec1 == vec1.copy()) should equal(true) 27 | // (vec2 eq vec1.copy()) should equal(false) 28 | } 29 | 30 | "companion object apply method" should "create a Vec" in { 31 | pending 32 | // val vec3 = Vec(1, 2) 33 | // vec3.x should equal(1) 34 | // vec3.y should equal(2) 35 | } 36 | 37 | "companion object unapply method" should "allow destructuring with pattern matching" in { 38 | pending 39 | // vec1 match { 40 | // case Vec(x0, y0) => 41 | // x0 should equal(3) 42 | // y0 should equal(4) 43 | // } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/scala/part2/Exercise9ColorAndShapeSpec.scala: -------------------------------------------------------------------------------- 1 | package part2 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise9ColorAndShapeSpec extends AnyFlatSpec with Matchers { 7 | // val shape1: Shape = Circle(10, Color(1, 1, 0)) 8 | // val shape2: Shape = Rect(3, 5, Color(1, 0, 1)) 9 | 10 | "area" should "calculate the area of a shape" in { 11 | pending 12 | // shape1.area should equal(math.Pi * 10 * 10) 13 | // shape2.area should equal(3 * 5) 14 | } 15 | 16 | "perimeter" should "calculate the perimeter of a shape" in { 17 | pending 18 | // shape1.perimeter should equal(2 * math.Pi * 10) 19 | // shape2.perimeter should equal(3 * 2 + 5 * 2) 20 | } 21 | 22 | "every shape" should "have a color" in { 23 | pending 24 | // shape1.color should equal(Color(1, 1, 0)) 25 | // shape2.color should equal(Color(1, 0, 1)) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/scala/part3/Exercise16aOptionAndEitherSpec.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import films.{Director, Film} 4 | import org.scalatest.flatspec.AnyFlatSpec 5 | import org.scalatest.matchers.should.Matchers 6 | 7 | class Exercise16aOptionAndEitherSpec extends AnyFlatSpec with Matchers { 8 | import Exercise16aOptionAndEither._ 9 | import films.TestData._ 10 | 11 | "directorWithLastName" should "do the right thing" in { 12 | pending 13 | // directorWithLastName(directors, "Nolan") should equal(Some(nolan)) 14 | // directorWithLastName(directors, "Some Guy") should equal(Some(someGuy)) 15 | // directorWithLastName(directors, "DROP TABLE *;") should equal(None) 16 | } 17 | 18 | "directorWithLastNameOrFailure" should "do the right thing" in { 19 | pending 20 | // directorWithLastNameOrFailure(directors, "Nolan") should equal(Right(nolan)) 21 | // directorWithLastNameOrFailure(directors, "Some Guy") should equal(Right(someGuy)) 22 | // directorWithLastNameOrFailure(directors, "DROP TABLE *;") shouldBe a[Left[_, _]] 23 | } 24 | 25 | "yearOfBirthOfDirectorWithLastName" should "do the right thing" in { 26 | pending 27 | // yearOfBirthOfDirectorWithLastName(directors, "Nolan") should equal(Some(nolan.yearOfBirth)) 28 | // yearOfBirthOfDirectorWithLastName(directors, "Some Guy") should equal(Some(someGuy.yearOfBirth)) 29 | // yearOfBirthOfDirectorWithLastName(directors, "DROP TABLE *;") should equal(None) 30 | } 31 | 32 | "yearOfBirthOfDirectorWithLastNameOrFailure" should "do the right thing" in { 33 | pending 34 | // yearOfBirthOfDirectorWithLastNameOrFailure(directors, "Nolan") should equal(Right(nolan.yearOfBirth)) 35 | // yearOfBirthOfDirectorWithLastNameOrFailure(directors, "Some Guy") should equal(Right(someGuy.yearOfBirth)) 36 | // yearOfBirthOfDirectorWithLastNameOrFailure(directors, "DROP TABLE *;") shouldBe a[Left[_, _]] 37 | } 38 | 39 | "filmsByDirectorWithLastName" should "do the right thing" in { 40 | pending 41 | // filmsByDirectorWithLastName(directors, "Nolan") should equal(nolan.films) 42 | // filmsByDirectorWithLastName(directors, "Some Guy") should equal(Nil) 43 | // filmsByDirectorWithLastName(directors, "DROP TABLE *;") should equal(Nil) 44 | } 45 | 46 | "earliestFilmByDirectorWithLastName" should "do the right thing" in { 47 | pending 48 | // earliestFilmByDirectorWithLastName(directors, "Nolan") should equal(Some(memento)) 49 | // earliestFilmByDirectorWithLastName(directors, "Some Guy") should equal(None) 50 | // earliestFilmByDirectorWithLastName(directors, "DROP TABLE *;") should equal(None) 51 | } 52 | 53 | "earliestFilmByDirectorWithLastNameOrFailure" should "do the right thing" in { 54 | pending 55 | // earliestFilmByDirectorWithLastNameOrFailure(directors, "Nolan") should equal(Right(memento)) 56 | // earliestFilmByDirectorWithLastNameOrFailure(directors, "Some Guy") shouldBe a[Left[_, _]] 57 | // earliestFilmByDirectorWithLastNameOrFailure(directors, "DROP TABLE *;") shouldBe a[Left[_, _]] 58 | } 59 | 60 | "namesOfFilmsByDirectorWithLastName" should "do the right thing" in { 61 | pending 62 | // namesOfFilmsByDirectorWithLastName(directors, "Nolan") should equal(nolan.films.map(f => f.name)) 63 | // namesOfFilmsByDirectorWithLastName(directors, "Some Guy") should equal(Nil) 64 | // namesOfFilmsByDirectorWithLastName(directors, "DROP TABLE *;") should equal(Nil) 65 | } 66 | 67 | "nameOfEarliestFilmByDirectorWithLastName" should "do the right thing" in { 68 | pending 69 | // nameOfEarliestFilmByDirectorWithLastName(directors, "Nolan") should equal(Some(memento.name)) 70 | // nameOfEarliestFilmByDirectorWithLastName(directors, "Some Guy") should equal(None) 71 | // nameOfEarliestFilmByDirectorWithLastName(directors, "DROP TABLE *;") should equal(None) 72 | } 73 | 74 | "nameOfEarliestFilmByDirectorWithLastNameOrFailure" should "do the right thing" in { 75 | pending 76 | // nameOfEarliestFilmByDirectorWithLastNameOrFailure(directors, "Nolan") should equal(Right(memento.name)) 77 | // nameOfEarliestFilmByDirectorWithLastNameOrFailure(directors, "Some Guy") shouldBe a[Left[_, _]] 78 | // nameOfEarliestFilmByDirectorWithLastNameOrFailure(directors, "DROP TABLE *;") shouldBe a[Left[_, _]] 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/scala/part3/Exercise16bOptionFoldAndMapSpec.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import films.Director 4 | import org.scalatest.flatspec.AnyFlatSpec 5 | import org.scalatest.matchers.should.Matchers 6 | 7 | class Exercise16bOptionFoldAndMapSpec extends AnyFlatSpec with Matchers { 8 | import Exercise16bOptionFoldAndMap._ 9 | import films.TestData._ 10 | 11 | "directorWithLastName" should "do the right thing" in { 12 | pending 13 | // directorWithLastName(directors, "Nolan") should equal(Some(nolan)) 14 | // directorWithLastName(directors, "Some Guy") should equal(Some(someGuy)) 15 | // directorWithLastName(directors, "DROP TABLE *;") should equal(None) 16 | } 17 | 18 | "directorWithLastNameOrFailure" should "do the right thing" in { 19 | pending 20 | // directorWithLastNameOrFailure(directors, "Nolan") should equal(Right(nolan)) 21 | // directorWithLastNameOrFailure(directors, "Some Guy") should equal(Right(someGuy)) 22 | // directorWithLastNameOrFailure(directors, "DROP TABLE *;") shouldBe a[Left[_, _]] 23 | } 24 | 25 | "yearOfBirthOfDirectorWithLastName" should "do the right thing" in { 26 | pending 27 | // yearOfBirthOfDirectorWithLastName(directors, "Nolan") should equal(Some(nolan.yearOfBirth)) 28 | // yearOfBirthOfDirectorWithLastName(directors, "Some Guy") should equal(Some(someGuy.yearOfBirth)) 29 | // yearOfBirthOfDirectorWithLastName(directors, "DROP TABLE *;") should equal(None) 30 | } 31 | 32 | "yearOfBirthOfDirectorWithLastNameOrFailure" should "do the right thing" in { 33 | pending 34 | // yearOfBirthOfDirectorWithLastNameOrFailure(directors, "Nolan") should equal(Right(nolan.yearOfBirth)) 35 | // yearOfBirthOfDirectorWithLastNameOrFailure(directors, "Some Guy") should equal(Right(someGuy.yearOfBirth)) 36 | // yearOfBirthOfDirectorWithLastNameOrFailure(directors, "DROP TABLE *;") shouldBe a[Left[_, _]] 37 | } 38 | 39 | "namesOfFilmsByDirectorWithLastName" should "do the right thing" in { 40 | pending 41 | // namesOfFilmsByDirectorWithLastName(directors, "Nolan") should equal(nolan.films.map(f => f.name)) 42 | // namesOfFilmsByDirectorWithLastName(directors, "Some Guy") should equal(Nil) 43 | // namesOfFilmsByDirectorWithLastName(directors, "DROP TABLE *;") should equal(Nil) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/scala/part3/Exercise17FoldLeftAndRightSpec.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise17FoldLeftAndRightSpec extends AnyFlatSpec with Matchers { 7 | import Exercise17FoldLeftAndRight._ 8 | import films.TestData._ 9 | 10 | "totalImdbRating" should "do the right thing" in { 11 | pending 12 | // totalImdbRating(List(memento, outlawJoseyWales, thomasCrownAffair)) should equal(memento.imdbRating + outlawJoseyWales.imdbRating + thomasCrownAffair.imdbRating) 13 | // totalImdbRating(Nil) should equal(0.0) 14 | } 15 | 16 | "averageImdbRating" should "do the right thing" in { 17 | pending 18 | // averageImdbRating(List(memento, outlawJoseyWales, thomasCrownAffair)) should equal((memento.imdbRating + outlawJoseyWales.imdbRating + thomasCrownAffair.imdbRating) / 3.0) 19 | // averageImdbRating(Nil).isNaN should equal(true) 20 | } 21 | 22 | "reverseUsingFold" should "do the right thing" in { 23 | pending 24 | // reverseUsingFold(List(1, 2, 3)) should equal(List(3, 2, 1)) 25 | // reverseUsingFold(Nil) should equal(Nil) 26 | } 27 | 28 | "filterUsingFold" should "do the right thing" in { 29 | pending 30 | // filterUsingFold(List(1, 2, 3, 4, 5), (n: Int) => n % 2 == 0) should equal(List(2, 4)) 31 | // filterUsingFold(Nil, (n: Int) => n % 2 == 0) should equal(Nil) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/scala/part3/Exercise18FlatMapSpec.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise18FlatMapSpec extends AnyFlatSpec with Matchers { 7 | import Exercise18FlatMap._ 8 | import films.TestData._ 9 | 10 | "filmsByDirector" should "do the right thing" in { 11 | pending 12 | // filmsByDirector(nolan) should contain theSameElementsAs List(memento, darkKnight, inception) 13 | // filmsByDirector(someGuy) should equal(Nil) 14 | } 15 | 16 | "namesOfFilmsByDirector" should "do the right thing" in { 17 | pending 18 | // namesOfFilmsByDirector(nolan) should contain theSameElementsAs List(memento.name, darkKnight.name, inception.name) 19 | // namesOfFilmsByDirector(someGuy) should equal(Nil) 20 | } 21 | 22 | "filmsByAllDirectors" should "do the right thing" in { 23 | pending 24 | // filmsByAllDirectors(List(nolan, mcTiernan)) should contain theSameElementsAs (nolan.films ++ mcTiernan.films) 25 | // filmsByAllDirectors(List(eastwood, someGuy)) should contain theSameElementsAs eastwood.films 26 | } 27 | 28 | "namesOfFilmsByAllDirectors" should "do the right thing" in { 29 | pending 30 | // namesOfFilmsByAllDirectors(List(nolan, mcTiernan)) should contain theSameElementsAs (nolan.films ++ mcTiernan.films).map(f => f.name) 31 | // namesOfFilmsByAllDirectors(List(eastwood, someGuy)) should contain theSameElementsAs eastwood.films.map(f => f.name) 32 | } 33 | 34 | "tonightOnlyMessages" should "do the right thing" in { 35 | pending 36 | // tonightOnlyMessages(List(nolan, mcTiernan)) should contain theSameElementsAs List( 37 | // "Tonight only! Memento by Christopher Nolan!", 38 | // "Tonight only! Dark Knight by Christopher Nolan!", 39 | // "Tonight only! Inception by Christopher Nolan!", 40 | // "Tonight only! Predator by John McTiernan!", 41 | // "Tonight only! Die Hard by John McTiernan!", 42 | // "Tonight only! The Hunt for Red October by John McTiernan!", 43 | // "Tonight only! The Thomas Crown Affair by John McTiernan!", 44 | // ) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/scala/part3/Exercise19ForComprehensionsSpec.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise19ForComprehensionsSpec extends AnyFlatSpec with Matchers { 7 | import Exercise19ForComprehensions._ 8 | import films.TestData._ 9 | 10 | "filmsByDirector" should "do the right thing" in { 11 | pending 12 | // filmsByDirector(nolan) should contain theSameElementsAs List(memento, darkKnight, inception) 13 | // filmsByDirector(someGuy) should equal(Nil) 14 | } 15 | 16 | "namesOfFilmsByDirector" should "do the right thing" in { 17 | pending 18 | // namesOfFilmsByDirector(nolan) should contain theSameElementsAs List(memento.name, darkKnight.name, inception.name) 19 | // namesOfFilmsByDirector(someGuy) should equal(Nil) 20 | } 21 | 22 | "filmsByAllDirectors" should "do the right thing" in { 23 | pending 24 | // filmsByAllDirectors(List(nolan, mcTiernan)) should contain theSameElementsAs (nolan.films ++ mcTiernan.films) 25 | // filmsByAllDirectors(List(eastwood, someGuy)) should contain theSameElementsAs eastwood.films 26 | } 27 | 28 | "namesOfFilmsByAllDirectors" should "do the right thing" in { 29 | pending 30 | // namesOfFilmsByAllDirectors(List(nolan, mcTiernan)) should contain theSameElementsAs (nolan.films ++ mcTiernan.films).map(f => f.name) 31 | // namesOfFilmsByAllDirectors(List(eastwood, someGuy)) should contain theSameElementsAs eastwood.films.map(f => f.name) 32 | } 33 | 34 | "tonightOnlyMessages" should "do the right thing" in { 35 | pending 36 | // tonightOnlyMessages(List(nolan, mcTiernan)) should contain theSameElementsAs List( 37 | // "Tonight only! Memento by Christopher Nolan!", 38 | // "Tonight only! Dark Knight by Christopher Nolan!", 39 | // "Tonight only! Inception by Christopher Nolan!", 40 | // "Tonight only! Predator by John McTiernan!", 41 | // "Tonight only! Die Hard by John McTiernan!", 42 | // "Tonight only! The Hunt for Red October by John McTiernan!", 43 | // "Tonight only! The Thomas Crown Affair by John McTiernan!", 44 | // ) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/scala/part3/Exercise20OptionCalculatorSpec.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | import part2._ 6 | 7 | class Exercise20OptionCalculatorSpec extends AnyFlatSpec with Matchers { 8 | // val calc1 = Add(Num(1.1), Mul(Num(2.2), Num(3.3))) 9 | // val calc2 = Mul(Add(Num(1.1), Num(2.2)), Num(3.3)) 10 | // val calc3 = Div(Num(1.0), Num(0.0)) 11 | // val calc4 = Sqrt(Num(-1.0)) 12 | 13 | "OptionCalculator.eval" should "succeed on valid expressions" in { 14 | pending 15 | // OptionCalculator.eval(calc1) should equal(Some(1.1 + 2.2 * 3.3)) 16 | // OptionCalculator.eval(calc2) should equal(Some((1.1 + 2.2) * 3.3)) 17 | } 18 | 19 | it should "fail grcefully on division by zero and negative square root" in { 20 | pending 21 | // You may want to edit these tests to check your error messages 22 | // OptionCalculator.eval(calc3) should equal(None) 23 | // OptionCalculator.eval(calc4) should equal(None) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/scala/part3/Exercise21EitherCalculatorSpec.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | import part2._ 6 | 7 | class Exercise21EitherCalculatorSpec extends AnyFlatSpec with Matchers { 8 | // val calc1 = Add(Num(1.1), Mul(Num(2.2), Num(3.3))) 9 | // val calc2 = Mul(Add(Num(1.1), Num(2.2)), Num(3.3)) 10 | // val calc3 = Div(Num(1.0), Num(0.0)) 11 | // val calc4 = Sqrt(Num(-1.0)) 12 | 13 | "EitherCalculator.eval" should "succeed on valid expressions" in { 14 | pending 15 | // EitherCalculator.eval(calc1) should equal(Right(1.1 + 2.2 * 3.3)) 16 | // EitherCalculator.eval(calc2) should equal(Right((1.1 + 2.2) * 3.3)) 17 | } 18 | 19 | it should "fail grcefully on division by zero and negative square root" in { 20 | pending 21 | // You may want to edit these tests to check your error messages 22 | // EitherCalculator.eval(calc3) shouldBe a[Left[_, _]] 23 | // EitherCalculator.eval(calc4) shouldBe a[Left[_, _]] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/scala/part3/Exercise22SortingSpec.scala: -------------------------------------------------------------------------------- 1 | package part3 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise22SortingSpec extends AnyFlatSpec with Matchers { 7 | import Exercise22Sorting._ 8 | import films.TestData._ 9 | 10 | "filmsSortedByImdb" should "do the right thing" in { 11 | pending 12 | // filmsSortedByImdb(nolan.films) should equal(List(memento, inception, darkKnight)) 13 | // filmsSortedByImdb(eastwood.films) should equal(List(invictus, highPlainsDrifter, outlawJoseyWales, granTorino, unforgiven)) 14 | } 15 | 16 | "filmsByDirectorSortedByImdb" should "do the right thing" in { 17 | pending 18 | // filmsByDirectorSortedByImdb(nolan) should equal(List(memento, inception, darkKnight)) 19 | // filmsByDirectorSortedByImdb(eastwood) should equal(List(invictus, highPlainsDrifter, outlawJoseyWales, granTorino, unforgiven)) 20 | } 21 | 22 | "filmsByAllDirectorsSortedByImdb" should "do the right thing" in { 23 | pending 24 | // filmsByAllDirectorsSortedByImdb(List(nolan, mcTiernan)) should equal(List( 25 | // thomasCrownAffair, 26 | // huntForRedOctober, 27 | // predator, 28 | // dieHard, 29 | // memento, 30 | // inception, 31 | // darkKnight, 32 | // )) 33 | } 34 | 35 | "filmsByAllDirectorsSortedByDirectorNameThenImdb" should "do the right thing" in { 36 | pending 37 | // filmsByAllDirectorsSortedByDirectorNameThenImdb(List(nolan, mcTiernan)) should equal(List( 38 | // memento, 39 | // inception, 40 | // darkKnight, 41 | // thomasCrownAffair, 42 | // huntForRedOctober, 43 | // predator, 44 | // dieHard, 45 | // )) 46 | } 47 | 48 | "averageImdbRating" should "do the right thing" in { 49 | pending 50 | // averageImdbRating(nolan.films) should equal(8.766 +- 0.001) 51 | // averageImdbRating(someGuy.films).isNaN should be(true) 52 | } 53 | 54 | "averageImdbRatingAcrossDirectors" should "do the right thing" in { 55 | pending 56 | // averageImdbRatingAcrossDirectors(directors) should equal(8.033 +- 0.001) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/scala/part4/Exercise25OrderingSpec.scala: -------------------------------------------------------------------------------- 1 | package part4 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class Exercise25OrderingSpec extends AnyFlatSpec with Matchers { 7 | // val email1 = Email("z@example.com") 8 | // val email2 = Email("y@example.com") 9 | // val email3 = Email("x@example.com") 10 | // val emails = List(email1, email2, email3) 11 | 12 | // val person1 = Person("Alice", email1) 13 | // val person2 = Person("Charlie", email2) 14 | // val person3 = Person("Bob", email3) 15 | // val people = List(person1, person2, person3) 16 | 17 | "Email.ordering" should "sort emails" in { 18 | pending 19 | // val actual = emails.sorted(Email.ordering) 20 | // val expected = List(email3, email2, email1) 21 | // actual should equal(expected) 22 | } 23 | 24 | it should "be the default sort order for emails" in { 25 | pending 26 | // val actual = emails.sorted 27 | // val expected = List(email3, email2, email1) 28 | // actual should equal(expected) 29 | } 30 | 31 | "Person.ordering" should "sort people" in { 32 | pending 33 | // val actual = people.sorted(Person.ordering) 34 | // val expected = List(person1, person3, person2) 35 | // actual should equal(expected) 36 | } 37 | 38 | it should "be the default sort order for people" in { 39 | pending 40 | // val actual = people.sorted 41 | // val expected = List(person1, person3, person2) 42 | // actual should equal(expected) 43 | } 44 | 45 | "Person.ordringByEmail" should "sort people by email" in { 46 | pending 47 | // val actual = people.sorted(Person.orderingByEmail) 48 | // val expected = List(person3, person2, person1) 49 | // actual should equal(expected) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/scala/part4/Exercise26JsonWriterSpec.scala: -------------------------------------------------------------------------------- 1 | package part4 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | import part2._ 6 | 7 | class Exercise26JsonWriterSpec extends AnyFlatSpec with Matchers { 8 | // val alice = Person("Alice", Email("alice@example.com")) 9 | // val bob = Person("Bob", Email("bob@example.com")) 10 | // val people = List(alice, bob) 11 | 12 | "JsonWriter.write" should "write a String" in { 13 | pending 14 | // JsonWriter.write("Hello") should equal(JsString("Hello")) 15 | } 16 | 17 | it should "write an Int" in { 18 | pending 19 | // JsonWriter.write(123) should equal(JsNumber(123.0)) 20 | } 21 | 22 | it should "write an Email" in { 23 | pending 24 | // JsonWriter.write(alice.email) should equal(JsString(alice.email.address)) 25 | } 26 | 27 | it should "write a Person" in { 28 | pending 29 | // JsonWriter.write(bob) should equal(JsObject(List( 30 | // "name" -> JsString(bob.name), 31 | // "email" -> JsString(bob.email.address) 32 | // ))) 33 | } 34 | 35 | it should "write a List[Person]" in { 36 | pending 37 | // JsonWriter.write(people) should equal(JsArray(List( 38 | // JsonWriter.write(alice), 39 | // JsonWriter.write(bob), 40 | // ))) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/scala/part4/Exercise27ExtensionMethodsSpec.scala: -------------------------------------------------------------------------------- 1 | package part4 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | import part2._ 6 | 7 | class Exercise27ExtensionMethodsSpec extends AnyFlatSpec with Matchers { 8 | // import Syntax._ 9 | 10 | "toIntList" should "create an IntList" in { 11 | pending 12 | // List(1, 2, 3).toIntList should equal(IntPair(1, IntPair(2, IntPair(3, IntNil())))) 13 | } 14 | 15 | "toJson" should "write json" in { 16 | pending 17 | // "Hello".toJson should equal(JsString("Hello")) 18 | } 19 | } 20 | --------------------------------------------------------------------------------