Permalink
Browse files

added documentation and a couple tweaks

  • Loading branch information...
slagyr committed Jan 18, 2011
1 parent 9ebc969 commit ec30f8b8fa50d520d87cde1e6e29e712a5e65f48
Showing with 301 additions and 48 deletions.
  1. +1 −1 .idea/vcs.xml
  2. +138 −31 .idea/workspace.xml
  3. +0 −13 README
  4. +106 −0 README.md
  5. +30 −0 example/console.clj
  6. +21 −0 example/timed.clj
  7. +1 −1 project.clj
  8. +4 −2 src/fresh/core.clj
View
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
- <mapping directory="" vcs="" />
+ <mapping directory="" vcs="Git" />
</component>
</project>
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
13 README
@@ -1,13 +0,0 @@
-# fresh
-
-FIXME: write description
-
-## Usage
-
-FIXME: write
-
-## License
-
-Copyright (C) 2010 FIXME
-
-Distributed under the Eclipse Public License, the same as Clojure.
View
106 README.md
@@ -0,0 +1,106 @@
+# fresh
+### A library to keep your clojure runtime 'Fresh' ###
+
+## About
+
+Clojure's dynamic nature allows you to add definitions or even change existing definition in a live runtime.
+It's brilliant and powerful. Yet, to do so you typically have to run in the REPL and it can become a tedious task
+to reload files with every change you make, not to mention the dependencies of changes you make.
+
+Fresh simplifies it all. The source code was extracted from [Speclj's][https://github.com/slagyr/speclj] vigilant runner
+(autotest) because of it's usefulness. Simply tell Fresh which source code you want to keep fresh and it'll take care
+of the rest for you.
+
+## Usage
+
+The primary function is `freshener`.
+
+ user=> (doc freshener)
+ -------------------------
+ fresh.core/freshener
+ ([provider] [provider auditor])
+ Returns a freshener function that, when invoked, will ensure
+ the freshness of all files provided by the provider function.
+ The provider must be a no-arg function that returns a seq of java.io.File
+ objects. If any of the files have been modified, they (and all
+ thier dependent files), will be reloaded. New files will be loaded and
+ tracked. Deleted files will be unloaded along with any dependant files
+ that are no longer referenced. The freshener function returns a report map
+ of seqs containings File objects: {:new :modified :deleted :reloaded}.
+ The optional auditor function is called, passing in the report map,
+ before the state of the runtime has been modified. Only when the auditor
+ returns a truthy value will the runtime be modified.
+
+## Examples
+
+### Example #1
+
+Below is a script that will reload all the Clojure source files in the src and spec directories. It sits in an infinite
+loop on the console waiting for you to press Enter. Each time you press Enter, it printes a report and reloads. Simple!
+
+ (ns console
+ (:use
+ [fresh.core :only (clj-files-in freshener)]
+ [clojure.java.io :only (file)]))
+
+ (defn files-to-keep-fresh []
+ (clj-files-in (file "src") (file "spec")))
+
+ (defn report-refresh [report]
+ (println "Refreshing...")
+ (println "(:new report): " (:new report))
+ (println "(:modified report): " (:modified report))
+ (println "(:deleted report): " (:deleted report))
+ (println "(:reloaded report): " (:reloaded report))
+ (println "")
+ true)
+
+ (def refresh-src (freshener files-to-keep-fresh report-refresh))
+
+ (loop [key nil]
+ (refresh-src)
+ (println "Press any RETURN to reload, CTR-C to quit.")
+ (recur (.read System/in)))
+
+Assuming you have the Fresh source code checked out on your filesystem you can execute this command like so:
+
+ $ java -cp src:spec:lib/clojure-1.2.0.jar:lib/dev/speclj-1.2.0.jar:path/to/fresh/src clojure.main path/to/fresh/example/console.clj
+
+### Example #2
+
+This example show two new techniques. First notice how it produces a list of all the Clojure source files currently
+loaded in the runtime. Second, it uses the `ScheduledThreadPoolExecutor` to refresh every second. Reloaded files
+are printed.
+
+ (ns timed
+ (:use
+ [fresh.core :only (ns-to-file freshener)])
+ (:import
+ [java.util.concurrent ScheduledThreadPoolExecutor TimeUnit]))
+
+ (defn files-to-keep-fresh []
+ (filter identity (map #(ns-to-file (.name %)) (all-ns))))
+
+ (defn report-refresh [report]
+ (when-let [reloaded (seq (:reloaded report))]
+ (println "Refreshing...")
+ (doseq [file reloaded] (println file))
+ (println ""))
+ true)
+
+ (def refresh! (freshener files-to-keep-fresh report-refresh))
+ (refresh!)
+ (def scheduler (ScheduledThreadPoolExecutor. 1))
+ (.scheduleWithFixedDelay scheduler refresh! 0 1000 TimeUnit/MILLISECONDS)
+ (.awaitTermination scheduler Long/MAX_VALUE TimeUnit/SECONDS)
+
+Now typically, you might include similar code in your dev environment. This script, nor Example #1, are very useful
+by them selves. But to make this script interesting we'll have to load some of our code using the -i option.
+
+ java -cp src:spec:lib/clojure-1.2.0.jar:lib/dev/speclj-1.2.0.jar:path/to/fresh/src clojure.main -i spec/your_package/core.clj path/to/fresh/example/timed.clj
+
+## License
+
+Copyright (C) 2011 Micah Martin All Rights Reserved.
+
+Distributed under the The MIT License.
View
@@ -0,0 +1,30 @@
+(ns console
+ (:use
+ [fresh.core :only (clj-files-in freshener)]
+ [clojure.java.io :only (file)]))
+
+(defn files-to-keep-fresh []
+ (clj-files-in (file "src") (file "spec")))
+
+(defn report-refresh [report]
+ (println "Refreshing...")
+ (println "(:new report): " (:new report))
+ (println "(:modified report): " (:modified report))
+ (println "(:deleted report): " (:deleted report))
+ (println "(:reloaded report): " (:reloaded report))
+ (println "")
+ true)
+
+(def refresh-src (freshener files-to-keep-fresh report-refresh))
+
+(loop [key nil]
+ (refresh-src)
+ (println "Press any RETURN to reload, CTR-C to quit.")
+ (recur (.read System/in)))
+
+
+
+
+
+
+
View
@@ -0,0 +1,21 @@
+(ns timed
+ (:use
+ [fresh.core :only (ns-to-file freshener)])
+ (:import
+ [java.util.concurrent ScheduledThreadPoolExecutor TimeUnit]))
+
+(defn files-to-keep-fresh []
+ (filter identity (map #(ns-to-file (.name %)) (all-ns))))
+
+(defn report-refresh [report]
+ (when-let [reloaded (seq (:reloaded report))]
+ (println "Refreshing...")
+ (doseq [file reloaded] (println file))
+ (println ""))
+ true)
+
+(def refresh! (freshener files-to-keep-fresh report-refresh))
+(refresh!)
+(def scheduler (ScheduledThreadPoolExecutor. 1))
+(.scheduleWithFixedDelay scheduler refresh! 0 1000 TimeUnit/MILLISECONDS)
+(.awaitTermination scheduler Long/MAX_VALUE TimeUnit/SECONDS)
View
@@ -1,4 +1,4 @@
-(defproject fresh "1.0.0"
+(defproject fresh "1.0.1"
:description "A library to keep your clojure runtime 'Fresh'."
:dependencies [[org.clojure/clojure "1.2.0"]]
:dev-dependencies [[speclj "1.2.0"]
View
@@ -10,8 +10,10 @@
(defn clj-files-in
"Returns a seq of all clojure source files contained in the given directories."
[& dirs]
- (let [files (reduce #(into %1 (file-seq (file %2))) [] dirs)]
- (filter #(re-matches clj-file-regex (.getName %)) files)))
+ (let [dirs (map #(.getCanonicalFile %) dirs)
+ files (reduce #(into %1 (file-seq (file %2))) [] dirs)
+ clj-files (filter #(re-matches clj-file-regex (.getName %)) files)]
+ clj-files))
;; Resolving ns names ---------------------------------------------------------------------------------------------------
;

0 comments on commit ec30f8b

Please sign in to comment.