diff --git a/README.md b/README.md index fab5a25c..fb58ac93 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ Outline * [Getting Set Up](outline/setup.md) *DONE* * [Introduction to Programming with Clojure](outline/intro.md) *DONE* * [Data Structures](outline/data_structures.md) *DONE* -* [Functions](outline/functions.md) **TODO** -* [Flow Control](outline/flow_control.md) **IN-PROGRESS** -* [Making Your First Program](outline/first-program.md) **TODO** -* [Introduction to Web Applications](outline/web.md) **TODO** +* [Functions](outline/functions.md) *DONE* +* [Flow Control](outline/flow_control.md) *DONE* +* [Making Your First Program](outline/first-program.md) *DONE* +* [Introduction to Web Applications](outline/web.md) *DONE* * [Making Your Own Web Application](outline/app.md) **IN-PROGRESS** * [Putting Your Application Online](outline/deploy.md) **TODO** diff --git a/outline/app.md b/outline/app.md index 6aa9c496..5ec1db16 100644 --- a/outline/app.md +++ b/outline/app.md @@ -130,7 +130,7 @@ Turn it into a function. Some supporting functions ------------------------- -Just type these into the REPL. We aren't talking about these. +Just copy/paste these into the REPL. We aren't talking about these. (def list-size 10) @@ -155,7 +155,7 @@ Call get-indicator-all to get the pump price indicator for 2012. (def inds (get-indicator-all "EP.PMP.SGAS.CD" "2012" :country :value)) -Go through the results, making sure that they are actually countries by matching up against the country-ids, then ... +Go through the results, making sure that they are actually countries by matching up against the country-ids, then get the value from the country and convert the value from a string. (for [[k v] inds :when (and v (country-ids (:id k)))] @@ -196,3 +196,6 @@ Make that into a function. + +[The rest of this will be to plug calls to the above functions into provided code.] + diff --git a/outline/first-program.md b/outline/first-program.md index b9f158fb..9a1546a1 100644 --- a/outline/first-program.md +++ b/outline/first-program.md @@ -1,11 +1,166 @@ Making Your First Program ========================= -* What is the difference between source code and the REPL? -* Structure of a Clojure project -* Namespaces -* TODO +Now that you know a bit about how to write Clojure code, let's look at how to create a standalone application. - Design first program. Make sure it contains data structures and explain them. +In order to do that, you'll first create a *project*. You'll learn how to organize your project with *namespaces*. You'll also learn how to specify your project's *dependencies*. Finally, you'll learn how to *build* your project to create the standalone application. - Make sure it uses at least one dependency and show how to add that and use it. \ No newline at end of file +## Create a Project + +Up until now you've been experimenting in a REPL. Unfortunately, all the work you do in a REPL is lost when you close the REPL. You can think of a project as a permanent home for your code. You'll be using a tool called "Leiningen" to help you create and manage your project. To create a new project, run this command: + +```clojure +lein new app world-bank +``` + +This should create a directory structure that looks like this: + +``` +| .gitignore +| doc +| | intro.md +| project.clj +| resources +| README.md +| src +| | world_bank +| | | core.clj +| test +| | world_bank +| | | core_test.clj +``` + +There's nothing inherently special or Clojure-y about this project skeleton. It's just a convention used by Leiningen. You'll be using Leiningen to build and run Clojure apps, and Leiningen expects your app to be laid out this way. Here's the function of each part of the skeleton: + +- `project.clj` is a configuration file for Leiningen. It helps + Leiningen answer questions like, "What dependencies does this + project have?" and "When this Clojure program runs, what function + should get executed first?" +- `src/world_bank/core.clj` is where we'll be doing our + Clojure coding for awhile. In general, your source code will fall + under `src/{world_bank}` +- The `test` directory obviously contains tests, which we won't be covering. +- `resources` is a place for you to store assets like images; we won't + be using it for awhile. + +Now let's go ahead and actually run this project. Enter this at the command line: + +``` +cd world_bank +lein run +``` + +You should see this: + +``` +Hello, world! +``` + +## Modify Project + +Pretty cool! But also pretty useless. To change the behavior of this project, open up `src/world_bank/core.clj` and monkey around with the `-main` function. Try changing it so that it reads: + +```clojure +(defn -main + [& args] + (println "Hello, ClojureBridge!")) +``` + +If you run `lein run` again, you should see `Hello, ClojureBridge!` printed. + +The `-main` function is the *entry point* to your program. Other than that there's nothing special about it. It acts just like any other Clojure function. It just happens to be the function which gets called first when you run your program. For example, you can write your own functions have `-main` call them: + +```clojure +(defn quotify + [quote author] + (str quote "\n\n-- " author)) +(defn -main + [& args] + (println (quotify "A man who carries a cat by the tail learns something he can learn in no other way." + "Mark Twain"))) +``` + +This should output: + +``` +A man who carries a cat by the tail learns something he can learn in no other way. + +-- Mark Twain +``` + +So, you can write programs of arbitrary complexity. Just make sure to use `-main` to kick them off. + +## Organization + +As your programs get more complex, you'll need to organize them. You organize your Clojure code by placing related functions and data in separate files. Clojure expects each file to correspond to a *namespace*, so you must *declare* a namespace at the top of each file. + +Until now, you haven't really had to care about namespaces. Namespaces allow you to define new functions and data structures without worrying about whether the name you'd like is already taken. For example, you could create a function named `println` within the custom namespace `my-special-namespace`, and it would not interfere with Clojure's built-in `println` function. You can use the *fully-qualified name* `my-special-namespace/println` to distinguish your function from the built-in `println`. + +Let's create a new namespace for making world bank API calls. First, create the file `src/world_bank/api.clj`. Then write this in it: + +```clojure +(ns world-bank.api) +``` + +This line establishes that everything you define in this file will be stored within the `world-bank.api` namespace. For example, add this to your file: + +```clojure +(def base-uri "http://api.worldbank.org") +``` + +You should be able to access that from your `core.clj` file. Change that file so that it reads: + +```clojure +(ns world-bank.core) +(require '[world-bank.api :as api]) + +(defn -main + [& args] + (println api/base-uri)) +``` + +If you run the `-main` function it should print `http://api.worldbank.org`. + +There are couple things going on here. First, you use `require` to tell Clojure to load another namespace. The `:as` part of `require` allows you to *alias* the namespace, letting you refer to its definitions without having to type out the entire namespace. In this case, you can use `api/base-uri` instead of `world-bank.api/base-uri`. + +## Dependencies + +The final part of working with projects is managing their *dependencies*. Dependencies are just code libraries that others have written which you can incorporate in your own project. + +To add a dependency, open `project.clj`. You should see a line which reads + +``` +:dependencies [[org.clojure/clojure "1.5.1"]] +``` + +That's where you specify your dependencies. You can add a dependency by adding another vector with the dependency's name and its version. Let's add the `clj-http` and `cheshire` projects. `clj-http` will let us make HTTP calls so that we can get data using the World Bank API. `cheshire` will let us decode the results. Update the dependencies line in your `project.clj` so that it looks like this: + +``` +:dependencies [[org.clojure/clojure "1.5.1"] + [clj-http "0.9.0"] + [cheshire "5.3.1"]] +``` + +Now you can require the namespaces defined in `clj-http` within your own project. Update `src/world_bank/api.clj` so that it looks like this: + +```clojure +(ns world-bank.api) +(require '[clj-http.client :as client]) +(require '[cheshire.core :as json] + +(def base-uri "http://api.worldbank.org") +(def query-params {:format "json" :per_page 10000}) + +(defn get-api + "Returns map representing API response." + [path qp] + (let [base-path (str base-uri path) + query-params (merge qp {:format "json" :per_page 10000}) + response (parse-json (:body (client/get base-path {:query-params query-params}))) + metadata (first response) + results (second response)] + {:metadata metadata + :results results})) +``` + +Ta-da! diff --git a/outline/flow_control.md b/outline/flow_control.md index 7c4b6112..a79d94f5 100644 --- a/outline/flow_control.md +++ b/outline/flow_control.md @@ -1,11 +1,150 @@ Flow Control ============ -* Review of booleans -* cond -* do -* if (maybe?) -* doseq (?) -* dotimes (?) - -I'm not even sure we should touch `doseq` or `dotimes`. Recursion is completely unnecessary for this course. \ No newline at end of file +"Flow control" is the programming term for deciding how to react to a given circumstance. We make decisions like this all the time. *If* it's a nice day out, *then* we should visit the park; *otherwise* we should stay inside and play board games. *If* your car's tank is empty, *then* you should visit a gas station; *otherwise* you should continue to your destination. + +Software is also full of these decisions. *If* the user's input is valid, *then* we should save her data; *otherwise* we show an error message. The common pattern here is that you test some condition and react differently based on whether the condition is *true* or *false*. + +## if + +In Clojure, the most basic tool we have for this process is the `if` operator. Here's how you might code the data validation scenario: + +```clojure +(if (valid? data) + (save! data) + (error "Your data was invalid")) +``` + +The general form of the `if` operator is: + +```clojure +(if conditional-expression + expression-to-evaluate-when-true + expression-to-evaluate-when-false) +``` + +When testing the truth of an expression, Clojure considers the values `nil` and `false` to be false and everything else to be true. Here are some examples: + +```clojure +(if (> 3 1) + "3 is greater than 1" + "3 is not greater than 1") +;=> "3 is greater than 1" + +(if (> 1 3) + "1 is greater than 3" + "1 is not greater than 3") +;=> "1 is not greater than 3" + +(if "anything other than nil or false is considered true" + "A string is considered true" + "A string is not considered true") +;=> "A string is considered true" + +(if nil + "nil is considered true" + "nil is not considered true") +;=> "nil is not considered true" + +(if (get {:a 1} :b) + "expressions which evaluate to nil are considered true" + "expressions which evaluate to nil are not considered true") +;=> "expressions which evaluate to nil are not considered true" +``` + +### EXERCISE: Even more name formatting + +Write a function `format-name` that takes a map representing a user, with keys `:first`, `:last`, and possibly `:middle`. It should return their name as a string, like so: + +```clj +(format-name {:first "Margaret" :last "Atwood"}) +;=> "Margaret Atwood" + +(format-name {:first "Ursula" :last "Le Guin" :middle "K."}) +;=> "Ursula K. Le Guin" +``` + +### BONUS: Flexible name formatting + +Change `format-name` to take a second argument, `order`. If `order` equals `:last`, then the format should be "Last, First Middle"; otherwise, it should be "First Middle Last." + + +## Boolean logic with and, or, and not + +`if` statements are not limited to testing only one thing. You can test multiple conditions using boolean logic. _Boolean logic_ refers to combining and changing the results of predicates using `and`, `or`, and `not`. + +If you've never seen this concept in programming before, remember that it follows the common sense way you look at things normally. Is this _and_ that true? Only if both are true. Is this _or_ that true? Yes, if either -- or both! -- are. Is this _not_ true? Yes, if it's false. + +Look at this truth table: + +| x | y | (and x y) | (or x y) | (not x) | (not y) | +| ----- | ----- | --------- | -------- | ------- | ------- | +| false | false | false | false | true | true | +| true | false | false | true | false | true | +| true | true | true | true | false | false | +| false | true | false | true | true | false | + +`and`, `or`, and `not` work like other functions (they aren't exactly functions, but work like them), so they are in _prefix notation_, like we've seen with arithmetic. + +`and`, `or`, and `not` can be combined. This can be hard to read. Here's an example: + +```clj +(defn leap-year? + "Every four years, except years divisible by 100, but yes for years divisible by 400." + [year] + (and (zero? (mod year 4)) + (or (zero? (mod year 400)) + (not (zero? (mod year 100)))))) +``` + + +## cond + +Sometimes you might want to do multiple conditional checks. For example, you might want to check whether a number is within a certain range. Here's the general form of `cond`: + +```clojure +(cond + test-condition-1 expression-to-evaluate-when-test-condition-1-is-true + test-condition-2 expression-to-evaluate-when-test-condition-2-is-true + test-condition-3 expression-to-evaluate-when-test-condition-3-is-true + :else expression-to-evaluate-when-no-test-conditions-are-true) +``` + +Here's how you could use it to check that a number is within a range: + +```clojure +(let [breaths-taken-today 100] + (cond + (and (> breaths-taken-today 0) (< breaths-taken-today 50)) + "That's a good start! You probably want to breathe more, though." + + (and (> breaths-taken-today 51) (< breaths-taken-today 100)) + "Wow, you're breathing like a pro!" + + :else + "Hold on there buddy, that's a lot of breathing. Might want to hold off on that a bit.")) +``` + +Clojure has other conditional operators, but they're just there to make your code slightly more concise. `if`, `do`, and `cond` will allow you to express the behavior you want for every condition! + +### EXERCISE: Revisit leap year + +Rewrite the `leap-year?` function shown earlier to use `cond` instead of nested boolean logic. + + +## do + +One thing you may have noticed is that you are only allowed to evaluate one expression for each branch of the `if` expression. The `do` operator allows you to "bundle up" multiple expressions so that you can "do" multiple things. Here's an example: + +```clojure +(if (> 5 0) + (do + (println "5 is indeed greater than 0!") + (println "I wonder if 0 has low self-esteem")) + (do + (println "0 is indeed greater than 5!") + (println "Because numbers have been broken I guess"))) +; => "5 is indeed greater than 0!" +; => "I wonder if 0 has low self-esteem" +``` + diff --git a/outline/functions.md b/outline/functions.md index 4db12f1e..2db302b9 100644 --- a/outline/functions.md +++ b/outline/functions.md @@ -1,9 +1,223 @@ Functions ========= -* What are functions? -* Using functions -* Naming functions -* `let` +## What are functions? -We could include a section on anonymous functions, as they'll be used with `map` and the like, but we don't have to. All functions could be named. \ No newline at end of file +You have already seen some functions, such as `count`, `conj`, `first`, and `rest`. All the arithmetic we did had functions as well: `+`, `-`, `*`, and `/`. What does it mean to be a function, though? + +A function is a discrete piece of code that takes in some values (called _arguments_) and returns other values. Let's see an example: + +```clj +(defn triple + "Given a number, return 3 times that number." + [x] + (+ x x x)) +``` + +In this code: + +* `defn` specifies that we are defining a function. +* `triple` is the name of this function. +* The string on the next line is the documentation for the function. This is optional. +* `[x]` is the list of arguments. We have one argument called `x`. +* `(+ x x x)` is the _body_ of the function. This is what executes when we use this function. + +To use `triple`, we _call the function_, just like we did with all the functions we've already used. + +```clj +(triple 2) ;=> 6 +(triple 3/2) ;=> 9/2 +(triple 30.3) ;=> 90.9 +``` + +Functions can take more than one argument. Let's make an `average` function that takes two numbers and gives us the average of those two numbers: + +```clj +(defn average + [x y] + (/ (+ x y) 2)) + +(average 2 3) ;=> 5/2 +``` + +### EXERCISE: Make a function to format names + +The `str` function can take any number of arguments, and it concatenates them together to make a string. Write a function called `format-name` that takes two arguments, `first-name` and `last-name`. This function should output the name like so: `Last, First`. + +## Naming functions + +Function names are symbols, just like the symbols we used with _def_ when assigning names to values. + +Symbols have to begin with a non-numeric character and can contain alphanumeric characters and *, +, !, -, _, and ?. This flexibility is important with functions, as we have certain idioms we use. + +Functions that return true or false -- called _predicates_ -- usually end in `?`. + +* `zero?` +* `vector?` +* `empty?` + +## Important functions + +There are some functions that are essential to know to use Clojure. The arithmetic ones and `str` have already been covered, and you need to know them. Let's look at some others. + +### Comparison functions + +You will often need to test the equality of two things. `=` is the function you use to do that. Imagine a function called `vegetarian?` that determines if a person is vegetarian or not: + +```clj +(defn vegetarian? + [person] + (= :vegetarian (get person :dietary-restrictions))) +``` + +Other comparison functions are `>`, `>=`, `<`, `<=`, and `not=`. All but the last of these are for use with numbers. Because they, like all Clojure functions, are used as prefixes, they can be a little tricky. Here's some examples: + +```clj +(> 4 3) ;=> true +(>= 4 5) ;=> false +(< -1 1) ;=> true +(<= -1 -2) ;=> false +``` + +### String functions + +A large part of programming is manipulating strings. The most important string function in Clojure to remember is `str`, which concatenates all of its arguments into one string. + +```clj +(str "Chocolate" ", " "strawberry" ", and " "vanilla") +;=> "Chocolate, strawberry, and vanilla" +``` + +TODO add more string functions from clojure.string? + +### Collection functions + +When we learned about data structures, we saw many functions that operated on those data structures. Some of them were: + +* count +* conj +* first +* rest +* nth +* assoc +* dissoc +* merge + +Some of the most powerful functions you can use with collections can take other functions as arguments. That's a complicated idea, so we'll learn more about that next. + +## Functions that take other functions + +One of the most magical things about Clojure -- and many other programming languages -- is that it can have functions that take other functions as arguments. That may not make sense at first, so let's look at an example. + +```clj +(defn triple + [x] + (+ x x x)) + +(map triple [1 2 3]) ;=> [3 6 9] +``` + +`map` is a function that takes another function and a collection. It then calls the function provided to it on each member of the collection and returns a new collection with the results of those function calls. This is a weird concept, but is at the core of Clojure and functional programming in general. + +Let's look at another function that takes a function. This one is `reduce`, and it is used to turn collections into a single value. + +```clj +(defn add + [x y] + (+ x y)) + +(reduce add [1 2 3]) ;=> 6 +``` + +This is what `reduce` does: it takes the first two members of the collection provided and calls the provided function with those members. It then calls the function again, using the result of the previous function call and the next member of the collection. It does this over and over until it reaches the end of the collection. + +This is complicated, so let's illustrate it further. + +```clj +(defn join-with-space + [string1 string2] + (str string1 " " string2)) + +(reduce join-with-space ["i" "like" "peanut" "butter" "and" "jelly"]) +;=> "i like peanut butter and jelly" +``` + +First, `reduce` calls `join-with-space` with "i" and "like", returning "i like". Then, in order, it makes the following function calls: + +* `(join-with-space "i like" "peanut")` +* `(join-with-space "i like peanut" "butter")` +* `(join-with-space "i like peanut butter" "and")` +* `(join-with-space "i like peanut butter and" "jelly")` + +### Anonymous functions + +So far, all the functions we've seen have names, like `+` and `str` and `reduce`. Functions don't have to have names, though, just like values don't have to have names. We call functions without names _anonymous functions_. + +Before we go forward, you should understand that you can _always_ feel free to name all of your functions. There is nothing wrong at all with doing that. However, you will see Clojure code with anonymous functions, so you should be able to understand it. + +An anonymous function is created with `fn`, like so: + +```clj +(fn [string1 string2] (str string1 " " string2)) +``` + +You might recognize that as the function we created before that we called `join-with-space`. `fn` works a lot like `defn`: we still have arguments listed as a vector and a function body. I didn't break the line in the anonymous function above, but you can, just like you can in a named function. + +Why would you ever do this? Anonymous functions can be very useful when we have functions that take other functions. Let's take each of our examples above, but use anonymous functions instead of named functions. + +```clj +(map (fn [x] (+ x x x)) [1 2 3]) ;=> [3 6 9] +(reduce (fn [x y] (+ x y)) [1 2 3]) ;=> 6 +(reduce + (fn [s1 s2] (str s1 " " s2)) + ["i" "like" "peanut" "butter" "and" "jelly"]) +;=> "i like peanut butter and jelly" +``` + +### EXERCISE: Find the average + +Create a function called `average` that takes a vector of numbers and returns the average of those numbers. + +Hint: you will need to use `reduce` and `count`. + +### EXERCISE: Get the names of people + +Create a function called `get-names` that takes a vector of maps of people and returns a vector of their names. + +Here is an example of how it should work: + +```clj +(get-names [{:first "Margaret" :last "Atwood"} + {:first "Doris" :last "Lessing"} + {:first "Ursula" :last "Le Guin"} + {:first "Alice" "Munro"}]) + +;=> ["Margaret Atwood" "Doris Lessing" "Ursula Le Guin" "Alice Munro"] +``` + +## `let` + +Sometimes when you are creating functions, you may want to assign names to values in order to reuse them or make your code more readable. Inside a function, however, you should _not_ use `def`, like you would outside a function. You use a special form called `let`. Let's look at an example: + +```clj +(defn spread + "Given a collection of numbers, return the difference between the largest and smallest number." + [numbers] + (let [largest (reduce max numbers) + smallest (reduce min numbers)] + (- largest smallest))) + +(spread [10 7 3 -3 8]) ;=> 13 +``` + +This is the most complicated function we've seen yet, so let's go through each step. First, we have the name of the function, the documentation string, and the arguments, like in other functions. + +Next, we see `let`. `let` takes a vector of alternating names and values. `largest` is the first name, and we assign the result of `(reduce max numbers)` to it. We assign the result of `(reduce min numbers)` to `smallest`. + +After the vector of names and values, there is the body of the `let`. Just like a the body of a function, this executes and returns a value. Within the `let`, `largest` and `smallest` are defined. + +Type the `spread` function into your instarepl and see how it evaluates. + +### EXERCISE: Rewrite average + +Go back to the `average` function you created before and use `let` to make it easier to read. diff --git a/outline/intro.md b/outline/intro.md index 4e97cbe3..0358670d 100644 --- a/outline/intro.md +++ b/outline/intro.md @@ -56,11 +56,11 @@ How about the last line? That has a thing called a string in it, which we'll lea REPL stands for Read-Eval-Print-Loop, which still doesn't make a ton of sense without context. Many programming languages, including Clojure, have a way to execute code interactively so you get instant feedback. In other words, the code is read, then it is evaluated, then the result is printed, and you begin again, thus, a loop. -Clojure has a REPL that you can run from the terminal easily, and we'll touch on that more later, but for now, let's use LightTable's "insta-REPL," a nice way to interact from within LightTable. +Clojure has a REPL that you can run from the terminal easily, and we'll touch on that more later, but for now, let's use Light Table's "insta-REPL," a nice way to interact from within Light Table. -Go ahead and start LightTable if you haven't already. Once it's started, go to the View menu and click "Commands." Notice that you can get to the command by typing ctrl+space from now on, if that's faster for you. Type "insta" and press enter when the "Instarepl: Open a Clojure instarepl" choice is highlighted. +Go ahead and start Light Table if you haven't already. Once it's started, go to the View menu and click "Commands." Notice that you can get to the command by typing ctrl+space from now on, if that's faster for you. Type "insta" and press enter when the "Instarepl: Open a Clojure instarepl" choice is highlighted. -After you hit enter, a blank new page will open. At the bottom of LightTable, you should see a message about connecting. Wait for the instarepl to finish connecting before typing anything. Once that's done, let's try out the REPL together! Type `(+ 2 3)` and see what happens. Did you see the result appearing beside what you were typing? Once you'd done that, hit enter and type `(max 8 17 2)`. You might see an error in red while typing. This happens because LightTable is continually evaluating what you are typing, and before you finish, the code might not be valid. +After you hit enter, a blank new page will open. At the bottom of Light Table, you should see a message about connecting. Wait for the instarepl to finish connecting before typing anything. Once that's done, let's try out the REPL together! Type `(+ 2 3)` and see what happens. Did you see the result appearing beside what you were typing? Once you'd done that, hit enter and type `(max 8 17 2)`. You might see an error in red while typing. This happens because Light Table is continually evaluating what you are typing, and before you finish, the code might not be valid. ## Simple values diff --git a/outline/setup.md b/outline/setup.md index ee2f5a4e..698319ba 100644 --- a/outline/setup.md +++ b/outline/setup.md @@ -3,7 +3,7 @@ Getting Set Up ## Requirements -Everyone in the workshop should have a laptop. If it is running Windows, it should be running Windows 7 or above. If it is running OS X, it should be running 10.7 or above. If it is running Linux, you are probably fine. +Everyone in the workshop should have a laptop. If it is running Windows, it should be running Windows 7 or above. If it is running OS X, it should be running 10.7 "Lion" or above. If it is running Linux, you are probably fine. If anyone attending does not have access to a laptop running one of the above choices, let the instructors know. You can either pair with someone else, or we can provide a virtual machine that you can run if you have a laptop. @@ -13,7 +13,7 @@ By the end of these instructions, you will have the following installed: * Java, a "virtual machine" that Clojure runs atop of * Leiningen, a tool for running Clojure programs -* LightTable, an editor for Clojure and other programming languages +* Light Table, an editor for Clojure and other programming languages * The Heroku Toolbelt, a program for putting your Clojure application on the web * Git, a program for managing your program's code, which is included in the Heroku Toolbelt diff --git a/outline/setup_osx.md b/outline/setup_osx.md index 8328fa38..22f19a16 100644 --- a/outline/setup_osx.md +++ b/outline/setup_osx.md @@ -4,13 +4,13 @@ OS X Setup * Start a terminal * Make sure Java is installed * Get Leiningen installed -* Get LightTable installed +* Get Light Table installed * Get Heroku installed (includes Git) * Test installation ## Starting a terminal -For these instructions, and for much of the class, you will need to have a terminal, or command line, open. This is a text-based interface to talk to your computer and you can open it by running Terminal.app, which is found under `/Applications/Utilities`. If you have never used the terminal before, you may want to spend some time [reading up on command-line basics](http://blog.teamtreehouse.com/command-line-basics). +For these instructions, and for much of the class, you will need to have a terminal, or command line, open. This is a text-based interface to talk to your computer, and you can open it by running Terminal.app, which is found under `/Applications/Utilities`. If you have never used the terminal before, you may want to spend some time [reading up on command-line basics](http://blog.teamtreehouse.com/command-line-basics). Go ahead and open your terminal now. It should look something like this: @@ -28,7 +28,7 @@ If Java is installed, you will see something like this in your terminal: ![Java version](img/os_x/java_version.png) -The details of Java's version may differ from what you see above: that is perfectly fine. +The details of Java's version may differ from what you see above; that is perfectly fine. ## Installing Leiningen @@ -41,17 +41,18 @@ Go to the [Leiningen website](http://leiningen.org/). You will see a link to the After that, run the following commands in your terminal. You will be prompted to enter your password. ``` -sudo mv ~/Downloads/lein /usr/local/bin/lein +sudo mkdir -p /usr/local/bin/ +sudo mv ~/Downloads/lein* /usr/local/bin/lein sudo chmod a+x /usr/local/bin/lein ``` -After you run the above commands, run the `lein` command. It should take a while to run, as it will download some resources it needs the first time. If it completes succesfully, you are golden! If not, ask an instructor for help. +After you run the above commands, run the `lein version` command. It should take a while to run, as it will download some resources it needs the first time. If it completes successfully, you are golden! If not, ask an instructor for help. -## Installing LightTable +## Installing Light Table -Go to the [LightTable site](http://www.lighttable.com/). On the page there, you should see a set of buttons that have download links for LightTable. Click the "OS X 10.7+" button and you will download a .zip file. +Go to the [Light Table site](http://www.lighttable.com/). On the page there, you should see a set of buttons that have download links for Light Table. Click the "OS X 10.7+" button and you will download a .zip file. -![LightTable downloads](img/os_x/light-table-download.png) +![Light Table downloads](img/os_x/light-table-download.png) Unzip the downloaded file. It should be in your Downloads folder and be named LightTableMac.zip. Once unzipped, move LightTable.app to your Applications folder. @@ -75,17 +76,21 @@ After all that, you should be at your Heroku dashboard. There will be a link on ![Heroku dashboard](img/heroku-dashboard.png) -This will download a .pkg file. Click it to install the Heroku Toolbelt and follow all prompts from the installation wizard. You will need your password to complete installation. Once installation, go to your terminal and run the command `heroku login`. You will be prompted for your email and password on Heroku. If you enter them and the command ends successfully, congratulations! +If you do not see this link on your dashboard, you can download the toolbelt from [toolbelt.heroku.com](https://toolbelt.heroku.com/). + +This will download a .pkg file. Click it to install the Heroku Toolbelt and follow all prompts from the installation wizard. You will need your OS X account password to complete installation. Once installation, go to your terminal and run the command `heroku login`. You will be prompted for your email and password on Heroku. If you enter them and the command ends successfully, congratulations! ![Heroku login](img/os_x/heroku_login.png) ## Testing your setup -You have set up Java, Leiningen, LightTable, Git, and Heroku on your computer, all the tools you will need for this program. Before starting, we need to test them out. +You have set up Java, Leiningen, Light Table, Git, and Heroku on your computer, all the tools you will need for this course. Before starting, we need to test them out. Go to your terminal and run the following command: -`git clone https://github.com/heroku/clojure-sample.git` +``` +git clone https://github.com/heroku/clojure-sample.git +``` This will check out a sample Clojure application from GitHub, a central repository for lots of source code. Your terminal should look similar to this picture: @@ -93,11 +98,15 @@ This will check out a sample Clojure application from GitHub, a central reposito Then run the command: -`cd clojure-sample` +``` +cd clojure-sample +``` This will put you in the directory with the source code for this sample bit of Clojure code. After that completes, run: -`lein repl` +``` +lein repl +``` This could take a long time, and will download many other pieces of code it relies on. You should see lines that start with `Retrieving ...` on your screen. When it finishes, your terminal should look like the following: @@ -105,15 +114,15 @@ This could take a long time, and will download many other pieces of code it reli This is starting a REPL, which we will learn about soon. It's a special terminal for Clojure. At the REPL prompt, type `(+ 1 1)` and press Return. Did you get the answer `2` back? You will learn more about that in the course. For now, press the Control button and D button on your keyboard together (abbreviated as Ctrl+D). This should take you out of the Clojure REPL and back to your normal terminal prompt. -Now, start LightTable. Once it is started, press the Control button and Space Bar together (abbreviated Ctrl+Space). This is how you start giving Light Table a command. Start typing the word "instarepl" and you should see a menu of options, like below. Choose "Instarepl: open a clojure instarepl." +Now, start Light Table. Once it is started, press the Control button and Space Bar together (abbreviated Ctrl+Space). This is how you start giving Light Table a command. Start typing the word "instarepl" and you should see a menu of options, like below. Choose "Instarepl: open a clojure instarepl." -![Testing LightTable - starting instarepl](img/os_x/testing-step3.png) +![Testing Light Table - starting instarepl](img/os_x/testing-step3.png) At the bottom of the screen, you will see a cube moving and some text about connecting and installing dependencies. Once that stops moving, type `(+ 1 1)` into the window. It should look like the following image: -![Testing LightTable - running in the instarepl](img/os_x/testing-step4.png) +![Testing Light Table - running in the instarepl](img/os_x/testing-step4.png) -If that worked, great! Close LightTable. We only have one more thing to test, Heroku. +If that worked, great! Close Light Table. We only have one more thing to test, Heroku. Go back to your terminal. You should still be in the `clojure-sample` directory. @@ -136,11 +145,10 @@ Enter "yes" if you are asked if you are sure you want to connect, like in the fo ![Connecting via SSH](img/os_x/testing-step6.png) -Your browser should open (and take a long time to load) and you should see a website like the following: +Your browser should open (and take a long time to load), and you should see a website like the following: ![Testing heroku working](img/os_x/testing-step7.png) -Congratulations! That website is running code you have on your computer that you have uploaded. You have actually made a very simple Clojure app, and your computer is all set up to make more. - - +If your browser does not open after running `heroku open`, start a browser and go to the URL displayed after you ran `heroku create`. +Congratulations! That website is running code you have on your computer that you have uploaded. You have actually made a very simple Clojure app, and your computer is all set up to make more. diff --git a/outline/setup_win7.md b/outline/setup_win7.md index d7abf00f..49368ce8 100644 --- a/outline/setup_win7.md +++ b/outline/setup_win7.md @@ -4,7 +4,7 @@ Windows 7 Setup * Start a command prompt * Get Java installed * Get Leiningen installed -* Get LightTable installed +* Get Light Table installed * Get Heroku installed (includes Git) * Test installation @@ -48,15 +48,15 @@ Leiningen is a tool used on the command line to manage Clojure projects. Next, go back to [the Leiningen Windows installer site](http://leiningen-win-installer.djpowell.net/) and download the file linked as "leiningen-win-installer." Run this executable and follow the "Detailed installation" section at the Leiningen Windows Installer site. At the end of the installation, leave "Run a Clojure REPL" checked before you click "Finish." If a terminal window opens that looks like the one on the Leiningen Windows installer site, then you are good to go. -## Installing LightTable +## Installing Light Table -Go to the [LightTable site](http://www.lighttable.com/). On the page there, you should see a set of buttons that have download links for LightTable. Click the "Win" button and you will download a .zip file. +Go to the [Light Table site](http://www.lighttable.com/). On the page there, you should see a set of buttons that have download links for Light Table. Click the "Win" button and you will download a .zip file. -![LightTable downloads](img/win/light-table-download.png) +![Light Table downloads](img/win/light-table-download.png) -Unzip this file (either by finding it in your Downloads folder and double-clicking it, or by choosing "Open" when downloading.) Inside the .zip file, there is a a directory called "LightTable". Drag this to your desktop. (If you know what you are doing and want this somewhere else, that is fine.) +Unzip this file (either by finding it in your Downloads folder and double-clicking it, or by choosing "Open" when downloading.) Inside the .zip file, there is a a directory called "Light Table". Drag this to your desktop. (If you know what you are doing and want this somewhere else, that is fine.) -Inside the LightTable directory, there is an application called LightTable. Right-click it and choose "Pin to Start Menu" so you can start it more quickly. +Inside the Light Table directory, there is an application called Light Table. Right-click it and choose "Pin to Start Menu" so you can start it more quickly. ## Get setup with Heroku @@ -97,7 +97,7 @@ After that, run the command `heroku login`. You will be prompted for your email ## Testing your setup -You have set up Java, Leiningen, LightTable, Git, and Heroku on your computer, all the tools you will need for this program. Before starting, we need to test them out. Make sure you have a terminal (OS X) or command prompt (Windows) open for testing. We will just call this a terminal from now on. +You have set up Java, Leiningen, Light Table, Git, and Heroku on your computer, all the tools you will need for this program. Before starting, we need to test them out. Make sure you have a terminal (OS X) or command prompt (Windows) open for testing. We will just call this a terminal from now on. Go to your terminal and run the following command: @@ -121,15 +121,15 @@ This could take a long time, and will download many other pieces of code it reli This is starting a REPL, which we will learn about soon. It's a special terminal for Clojure. At the REPL prompt, type `(+ 1 1)` and hit enter. Did you get the answer `2` back? You will learn more about that in the course. For now, press the Control button and D button on your keyboard together (abbreviated as Ctrl+D). This should take you out of the Clojure REPL and back to your normal terminal prompt. -Now, start LightTable. Once it is started, press the Control button and Space Bar together (abbreviated Ctrl+Space). This is how you start giving Light Table a command. Start typing the word "instarepl" and you should see a menu of options, like below. Choose "Instarepl: open a clojure instarepl." +Now, start Light Table. Once it is started, press the Control button and Space Bar together (abbreviated Ctrl+Space). This is how you start giving Light Table a command. Start typing the word "instarepl" and you should see a menu of options, like below. Choose "Instarepl: open a clojure instarepl." -![Testing LightTable - starting instarepl](img/win7/testing-step3.png) +![Testing Light Table - starting instarepl](img/win7/testing-step3.png) At the bottom of the screen, you will see a cube moving and some text about connecting and installing dependencies. Once that stops moving, type `(+ 1 1)` into the window. It should look like the following image: -![Testing LightTable - running in the instarepl](img/win7/testing-step4.png) +![Testing Light Table - running in the instarepl](img/win7/testing-step4.png) -If that worked, great! Close LightTable. We only have one more thing to test, Heroku. +If that worked, great! Close Light Table. We only have one more thing to test, Heroku. Go back to your terminal. You should still be in the `clojure-sample` directory. diff --git a/outline/setup_win8.md b/outline/setup_win8.md index 4bdb0140..244eaa3c 100644 --- a/outline/setup_win8.md +++ b/outline/setup_win8.md @@ -4,7 +4,7 @@ Windows 8 Setup * Start a command prompt * Get Java installed * Get Leiningen installed -* Get LightTable installed +* Get Light Table installed * Get Heroku installed (includes Git) * Test installation @@ -48,15 +48,15 @@ Leiningen is a tool used on the command line to manage Clojure projects. Next, go back to [the Leiningen Windows installer site](http://leiningen-win-installer.djpowell.net/) and download the file linked as "leiningen-win-installer." Run this executable and follow the "Detailed installation" section at the Leiningen Windows Installer site. At the end of the installation, leave "Run a Clojure REPL" checked before you click "Finish." If a terminal window opens that looks like the one on the Leiningen Windows installer site, then you are good to go. -## Installing LightTable +## Installing Light Table -Go to the [LightTable site](http://www.lighttable.com/). On the page there, you should see a set of buttons that have download links for LightTable. Click the "Win" button and you will download a .zip file. +Go to the [Light Table site](http://www.lighttable.com/). On the page there, you should see a set of buttons that have download links for Light Table. Click the "Win" button and you will download a .zip file. -![LightTable downloads](img/win/light-table-download.png) +![Light Table downloads](img/win/light-table-download.png) -Unzip this file (either by finding it in your Downloads folder and double-clicking it, or by choosing "Open" when downloading.) Inside the .zip file, there is a a directory called "LightTable". Drag this to your desktop. (If you know what you are doing and want this somewhere else, that is fine.) +Unzip this file (either by finding it in your Downloads folder and double-clicking it, or by choosing "Open" when downloading.) Inside the .zip file, there is a a directory called "Light Table". Drag this to your desktop. (If you know what you are doing and want this somewhere else, that is fine.) -Inside the LightTable directory, there is an application called LightTable. Right-click it and choose "Pin to Start Menu" so you can start it more quickly. +Inside the Light Table directory, there is an application called Light Table. Right-click it and choose "Pin to Start Menu" so you can start it more quickly. ## Get setup with Heroku @@ -97,7 +97,7 @@ After that, run the command `heroku login`. You will be prompted for your email ## Testing your setup -You have set up Java, Leiningen, LightTable, Git, and Heroku on your computer, all the tools you will need for this program. Before starting, we need to test them out. Make sure you have a terminal (OS X) or command prompt (Windows) open for testing. We will just call this a terminal from now on. +You have set up Java, Leiningen, Light Table, Git, and Heroku on your computer, all the tools you will need for this program. Before starting, we need to test them out. Make sure you have a terminal (OS X) or command prompt (Windows) open for testing. We will just call this a terminal from now on. Go to your terminal and run the following command: @@ -121,15 +121,15 @@ This could take a long time, and will download many other pieces of code it reli This is starting a REPL, which we will learn about soon. It's a special terminal for Clojure. At the REPL prompt, type `(+ 1 1)` and hit enter. Did you get the answer `2` back? You will learn more about that in the course. For now, press the Control button and D button on your keyboard together (abbreviated as Ctrl+D). This should take you out of the Clojure REPL and back to your normal terminal prompt. -Now, start LightTable. Once it is started, press the Control button and Space Bar together (abbreviated Ctrl+Space). This is how you start giving Light Table a command. Start typing the word "instarepl" and you should see a menu of options, like below. Choose "Instarepl: open a clojure instarepl." +Now, start Light Table. Once it is started, press the Control button and Space Bar together (abbreviated Ctrl+Space). This is how you start giving Light Table a command. Start typing the word "instarepl" and you should see a menu of options, like below. Choose "Instarepl: open a clojure instarepl." -![Testing LightTable - starting instarepl](img/win7/testing-step3.png) +![Testing Light Table - starting instarepl](img/win7/testing-step3.png) At the bottom of the screen, you will see a cube moving and some text about connecting and installing dependencies. Once that stops moving, type `(+ 1 1)` into the window. It should look like the following image: -![Testing LightTable - running in the instarepl](img/win7/testing-step4.png) +![Testing Light Table - running in the instarepl](img/win7/testing-step4.png) -If that worked, great! Close LightTable. We only have one more thing to test, Heroku. +If that worked, great! Close Light Table. We only have one more thing to test, Heroku. Go back to your terminal. You should still be in the `clojure-sample` directory. diff --git a/outline/web.md b/outline/web.md index 281f8f9f..1e71f81d 100644 --- a/outline/web.md +++ b/outline/web.md @@ -10,7 +10,7 @@ The way that the client and server communicate with each other is through a prot A web app accepts an HTTP request from the client and gives it a response. Think of the server as just like the Clojure functions we have written. They take the input of a request and give the output of a response. In fact, we can write that function: ```clj -(defn handler +(defn app [request] {:status 200}) @@ -33,39 +33,42 @@ Look at the parts that have angle brackets around them like ``. Those are ##Making the simplest web application -Let's make the simplest possible web application. It will say hello in the browser +Let's make the simplest possible web application. It will say hello in the browser. + +First, run ```lein new basic-app``` in the console. + +Create the file ```src/basic_app.clj``` and make it look like this: ```clj -(ns hello) +(ns basic-app) + +(defn app -(defn handler - "Return a status." - ;; A request comes in the handler. + ;; A request comes in the handler. [request] ;; The handler returns a response map. {:status 200 :headers {"Content-Type" "text/html"} - :body ( "Hello, world.")}) - + :body "Hello, world."}) ```` We need some supporting pieces to run this. We need the project.clj for Leiningen. ```clj -(defproject request-echo "0.1.0-SNAPSHOT" +(defproject basic-app "0.1.0-SNAPSHOT" ;; We require ring. :dependencies [[org.clojure/clojure "1.5.1"] [ring "1.2.1"]] - + ;; We use the lein-ring plugin to start ring. :plugins [[lein-ring "0.8.10"]] - + ;; We tell Ring what our handler function is and ;; what port to start on. - :ring {:handler request-echo/handler + :ring {:handler basic-app/app :port 3001}) ```` @@ -84,13 +87,13 @@ lein ring server Now let's do the same thing but with HTML so that the text displays with formatting. ```clj -(ns hello - (:require [clojure.pprint :refer [pprint]])) +(ns basic-app + (:require [clojure.pprint :refer [pprint]])) + +(defn app -(defn handler - "Return the request as HTML." - ;; A request comes in the handler. + ;; A request comes in the handler. [request] ;; The handler returns a response map. @@ -100,7 +103,7 @@ Now let's do the same thing but with HTML so that the text displays with formatt (with-out-str (pprint request)) "")}) ```` - + ##URLs and Routes The web browser gets to the right server with an address called a URL. Take a look at the following URLS: @@ -112,22 +115,38 @@ After the "http://", "www.google.com" identifies the server. Then the part after The process of coordinating which path goes to what action is called routing. The Clojure library that does this is called Compojure. Here is an example of routing with Compojure. ```clj -(require '[compojure.core :refer [routes]]) -(require '[compojure.route :as route]) - -(routes - - ;verb route parameters handler - (GET "/" [] (index-page)) - (GET "/debts/:person" [person] (person-page person)) - (GET "/add-debt" [] (add-debt-page)) - (POST "/add-debt" [from to amount] - (add-debt-post {:from from, - :to to, - :amount amount})) - +(ns basic-app + (:use compojure.core) + (:require [clojure.pprint :refer [pprint]] + [compojure.route :as route])) + + +(defn index-page [] + "index content") + +(defn person-page [person] + "person content") + +(defn add-debt-page [] + "add debt content") + +(defn add-debt-post [xfer] + "add debt post content") + +(defroutes app + + ;verb route parameters handler + (GET "/" [] (index-page)) + (GET "/debts/:person" [person] (person-page person)) + (GET "/add-debt" [] (add-debt-page)) + (POST "/add-debt" [from to amount] + (add-debt-post {:from from, + :to to, + :amount amount})) + (route/resources "/") (route/not-found "Page not found")) + ```` The verbs - GET, POST - are part of the http request and say what you want to do with this URL. GET is just fetching some data. POST is usually doing some processing on that data. The route is the path part of the URL. The handler is the Clojure function that is going to handle this particular request. The routes table maps that combination of verb and route to the handler function.