Skip to content

Commit

Permalink
One more pass through names and places to make sure everything works
Browse files Browse the repository at this point in the history
  • Loading branch information
abedra committed May 4, 2011
1 parent 4769d62 commit 19cb38d
Showing 1 changed file with 46 additions and 52 deletions.
98 changes: 46 additions & 52 deletions src/labs/names_and_places.clj
Expand Up @@ -19,33 +19,28 @@
(defn require-section []
[[:h3 "Require"]
[:ol
[:li "You can load the code for any clojure library with "
(c "(require libname)")
". Try it with " (c clojure.java.io) ":"
(code (require 'clojure.java.io))]
[:li "You can load the code for any clojure library with " (c "(require libname)")
". Try it with " (c clojure.java.io) ":" (code (require 'clojure.java.io))]
[:li "Then print the directory of names available in the namespace"
(code (dir clojure.java.io))]
(code (dir clojure.java.io))]
[:li "Show using " [:code "file"] " to create a new file:"
(repl-code (clojure.java.io/file "foo"))]
[:li "Writing out the namespace prefix on every function call is a pain, so you can specify a shorter alias using "
[:code "as"] ":"
(code (require '[clojure.java.io :as io]))]
[:li "Calling the shorter form is much easier:"
(repl-code (io/file "foo"))]
[:li "You can see all the loaded namespaces with"
(code (all-ns))]]])
(repl-code (clojure.java.io/file "foo"))]
[:li "Writing out the namespace prefix on every function call is a pain, so you
can specify a shorter alias using " [:code "as"] ":"
(code (require '[clojure.java.io :as io]))]
[:li "Calling the shorter form is much easier:" (repl-code (io/file "foo"))]
[:li "You can see all the loaded namespaces with" (code (all-ns))]]])

(defn refer-and-use []
[[:h3 "Refer and Use"]
[:ol
[:li "It would be even easier to use a function with no namespace prefix at all. You
can do this by " [:i "referring"] " to the name, which makes a
reference to the name in the current namespace:"
(code (refer 'clojure.java.io))]
[:li "Now you can call " [:code "file"] " directly:"
(repl-code (file "foo"))]
(code (refer 'clojure.java.io))]
[:li "Now you can call " [:code "file"] " directly:" (repl-code (file "foo"))]
[:li "If you want to load and refer all in one step, call " [:code "use"] ": "
(code (use 'clojure.java.io))]
(code (use 'clojure.java.io))]
[:li "Referring a library refers all of its names. This is often undesirable, because"
[:ul
[:li "it does not clearly document intent to readers"]
Expand All @@ -60,18 +55,18 @@
(code (ns-refers *ns*))]]
[:li "The refers map is often pretty big. If you are only interested in one symbol,
pass that symbol to the result of calling " [:code "ns-refers"] ": "
(repl-code ((ns-refers 'labs.names-and-places) 'dir))]])
(repl-code ((ns-refers 'labs.names-and-places) 'file))]])

(defn import-section []
[[:h3 "Import"]
[:ol
[:li "Importing is like referring, but for Java classes instead of Clojure
namespaces. Instead of " (code (java.io.File. "woozle")) " you can say "
(code (import java.io.File) (File. "woozle"))]
(code (import java.io.File) (File. "woozle"))]
[:li "You can import multiple classes in a Java package with the form "
(code (import [package Class Class])) "For example: "
(code (import [java.util Date Random])
(Date. (long (.nextInt (Random.)))))]
(code (import [package Class Class])) "For example: "
(code (import [java.util Date Random])
(Date. (long (.nextInt (Random.)))))]
[:li "Programmers new to Lisp are often put off by the \"inside-out\" reading
of forms like the date creation above. Starting from the inside, you "
[:ul
Expand All @@ -94,24 +89,24 @@
[:li "Clojure namespaces (a.k.a. libraries) are equivalent to Java packages."]
[:li "Clojure respects Java naming conventions for directories and files, but
Lisp naming conventions for namespace names. So a Clojure namespace "
[:code "com.my-app.utils"] " would live in a path named "
[:code "com/my_app/utils.clj"] ". Note especially the underscore/hyphen
[:code "com.my-app.utils"] " would live in a path named "
[:code "com/my_app/utils.clj"] ". Note especially the underscore/hyphen
distinction."]
[:li "Clojure files normally begin with a namespace declaration, e.g."
(code (ns com.my-app.utils))]
(code (ns com.my-app.utils))]
[:li "The syntax for import/use/refer/require presented in the previous sections
is for REPL use. Namespace declarations allow similar forms--similar
enough to aid memory, but also different enough to confuse. The following
forms at the REPL:"
(code (use 'foo.bar)
(require 'baz.quux)
(import '[java.util Date Random]))
" would look like this in a source code file:"
(code (ns com.my-app.utils
(:use foo.bar)
(:require baz.quux)
(:import [java.util Date Random])))
" Symbols become keywords, and quoting is no longer required."]
(code (use 'foo.bar)
(require 'baz.quux)
(import '[java.util Date Random]))
" would look like this in a source code file:"
(code (ns com.my-app.utils
(:use foo.bar)
(:require baz.quux)
(:import [java.util Date Random])))
" Symbols become keywords, and quoting is no longer required."]
[:li "At the time of this writing, the error messages for doing it wrong with
namespaces are, well, opaque. Be careful."]]]
[:p "Now let's try creating a source code file. We aren't going to bother with
Expand All @@ -121,35 +116,34 @@
[:ol
[:li "Create a file named " [:code "student/dialect.clj"] " in the " [:code "src"] "
directory, with the appropriate namespace declaration:"
(code (ns student.dialect))]
(code (ns student.dialect))]
[:li "Now, implement a simple " [:code "canadianize"] " function that takes a
string, and appends "
[:code ", eh?"]
(code (defn canadianize
[sentence]
(str sentence ", eh")))]
[:li "From your REPL, use the new namespace:"
(code (use 'student.dialect))]
[:code ", eh?"]
(code (defn canadianize
[sentence]
(str sentence ", eh")))]
[:li "From your REPL, use the new namespace:" (code (use 'student.dialect))]
[:li "Now try it out."
(let [canadianize #(str % ", eh")]
(repl-code (canadianize "Hello, world.")))]
(let [canadianize #(str % ", eh")]
(repl-code (canadianize "Hello, world.")))]
[:li "Oops! We need to trim the period off the end of the input. Fortunately, "
[:code "clojure.string."] " provides " [:code "replace"] ".
[:code "clojure.string."] " provides " [:code "replace"] ".
Go back to " [:code "student/dialect.clj"] " and add require in "
[:code "[clojure.string :as str]"] ": "
(code (ns student.dialect
(:require [clojure.string :as str])))]
[:code "[clojure.string :as str]"] ": "
(code (ns student.dialect
(:require [clojure.string :as str])))]
[:li "Now, update " [:code "canadianize"] " to use " [:code "replace"] ": "
(code (defn canadianize
[sentence]
(str/replace "hello." #"\.?$" ", eh?")))]
(code (defn canadianize
[sentence]
(str/replace sentence #"\.$" ", eh?")))]
[:li "If you simply retry calling " [:code "canadianize"] " from the repl,
you will not see your new change, because the code was already loaded.
However, you can use namespace forms with " [:code "reload"] "
( or " [:code "reload-all"] ") to reload a namespace (and its dependencies)."
(code (use :reload 'student.dialect))]
(code (use :reload 'student.dialect))]
[:li "Now you should see the new version of " (c canadianize) ": "
(repl-code (canadianize "Hello, world."))]]]])
(repl-code (canadianize "Hello, world."))]]]])

(defn bonus []
[[:h3 "Bonus"]
Expand Down

0 comments on commit 19cb38d

Please sign in to comment.