├── .gitignore ├── .notes.zk.org ├── .projectile ├── LICENSE ├── Procfile ├── Procfile.dev ├── Procfile.prod-local ├── README.md ├── bin ├── .devenv ├── build ├── clean ├── db-reset ├── dev ├── prod ├── prod-local └── ship ├── clojuredocs.sketch ├── data └── mongodb │ ├── example-histories.bson │ ├── example-histories.metadata.json │ ├── examples.bson │ ├── examples.metadata.json │ ├── legacy-var-redirects.bson │ ├── legacy-var-redirects.metadata.json │ ├── notes.bson │ ├── notes.metadata.json │ ├── see-alsos.bson │ ├── see-alsos.metadata.json │ ├── system.indexes.bson │ ├── users.bson │ └── users.metadata.json ├── dev-db └── .gitkeep ├── externs ├── fastclick.js ├── marked.js ├── morpheus.js └── react.js ├── project.clj ├── resources ├── nginx.conf └── public │ ├── css │ ├── app.css │ ├── bootstrap.min.css │ └── font-awesome.min.css │ ├── favicon.ico │ ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff │ ├── github-btn.html │ ├── img │ ├── adzerk-logo.png │ ├── amazon-logo.png │ ├── amperity-logo.jpg │ ├── amperity-logo.png │ ├── brightcove-logo.png │ ├── circleci-logo.png │ ├── clearwater-logo.png │ ├── climate-corporation-logo.png │ ├── cognician-logo.png │ ├── cognitect-logo.png │ ├── diligenceengine-logo.png │ ├── exoscale-logo.png │ ├── factual-logo.png │ ├── farmlogs-logo.png │ ├── fluent-logo.png │ ├── funding-circle-box-logo.png │ ├── funding-circle-logo.png │ ├── fy-logo.jpg │ ├── griffin-logo.png │ ├── heroku-logo.png │ ├── intentmedia-logo.png │ ├── kira-logo.png │ ├── lisp_cycles.png │ ├── living-social-logo.png │ ├── loading-button.gif │ ├── loading.gif │ ├── netflix-logo.png │ ├── nubank-logo.png │ ├── oscaro-logo.png │ ├── outpost-logo.png │ ├── pisano-logo.jpg │ ├── pitch-logo.png │ ├── prismatic-logo.png │ ├── puppet-logo.jpg │ ├── qubit-logo.png │ ├── reify-health-logo.png │ ├── rjmetrics-logo.png │ ├── room-key-logo.jpg │ ├── soundcloud-logo.png │ ├── spacious-logo.jpg │ ├── twitter-logo.png │ ├── walmart-labs.png │ ├── whimsical-logo.png │ └── witai-logo.png │ ├── js │ ├── fastclick.min.js │ ├── marked.min.js │ ├── morpheus.min.js │ └── react.js │ └── opensearch.xml ├── reup.clj ├── src ├── clj │ ├── clojuredocs │ │ ├── api │ │ │ ├── common.clj │ │ │ ├── examples.clj │ │ │ ├── notes.clj │ │ │ ├── see_alsos.clj │ │ │ └── server.clj │ │ ├── config.clj │ │ ├── css.clj │ │ ├── data.clj │ │ ├── data │ │ │ └── import.clj │ │ ├── entry.clj │ │ ├── env.clj │ │ ├── export.clj │ │ ├── github.clj │ │ ├── mail.clj │ │ ├── main.clj │ │ ├── pages.clj │ │ ├── pages │ │ │ ├── common.clj │ │ │ ├── dev.clj │ │ │ ├── gh_auth.clj │ │ │ ├── intro.clj │ │ │ ├── jobs.clj │ │ │ ├── nss.clj │ │ │ ├── quickref.clj │ │ │ ├── quickref │ │ │ │ └── static.clj │ │ │ ├── user.clj │ │ │ └── vars.clj │ │ ├── search.clj │ │ └── search │ │ │ └── static.clj │ └── nsfw │ │ └── reup.clj ├── cljc │ ├── clojuredocs │ │ ├── md5.cljc │ │ ├── syntax.cljc │ │ └── util.cljc │ └── nsfw │ │ ├── css.cljc │ │ └── util.cljc ├── cljs │ ├── clojuredocs │ │ ├── ajax.cljs │ │ ├── anim.cljs │ │ ├── examples.cljs │ │ ├── main.cljs │ │ ├── metrics.cljs │ │ ├── mods │ │ │ ├── search.cljs │ │ │ ├── styleguide.cljs │ │ │ └── var_page.cljs │ │ ├── notes.cljs │ │ ├── see_alsos.cljs │ │ └── sticky.cljs │ └── nsfw │ │ ├── ops.cljs │ │ └── page.cljs ├── examples │ └── clj │ │ └── first.clj ├── less │ ├── app.less │ ├── bootstrap.min.less │ └── font-awesome.min.less └── md │ ├── api │ └── overview.md │ ├── concepts │ ├── destructuring.md │ └── functional-programming.md │ ├── core-library.md │ ├── examples-styleguide.md │ └── namespaces │ ├── clojure.core.async.md │ ├── clojure.core.logic.md │ ├── clojure.core.md │ ├── clojure.core.server.md │ ├── clojure.edn.md │ ├── clojure.pprint.md │ ├── clojure.set.md │ ├── clojure.string.md │ ├── clojure.test.md │ └── clojure.zip.md ├── system.properties ├── test └── clojuredocs │ └── core_test.clj └── tools ├── dev_export.clj ├── old_import.clj ├── sanity_check.clj └── top_contribs.clj /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | /.idea 5 | *.iml 6 | pom.xml 7 | pom.xml.asc 8 | *.jar 9 | *.class 10 | /.lein-* 11 | /.nrepl-port 12 | 13 | .DS_Store 14 | .sass-cache 15 | .lein-errors 16 | 17 | /resources/public/cljs 18 | /resources/public/cljs-advanced 19 | 20 | resources/public/css/app.css 21 | resources/public/css/highlighting.css 22 | resources/public/clojuredocs-export.json 23 | 24 | TAGS 25 | 26 | /dev-db 27 | /data 28 | -------------------------------------------------------------------------------- /.projectile: -------------------------------------------------------------------------------- 1 | -/resources/public/css 2 | -/resources/public/js 3 | -/resources/public/cljs 4 | -/resources/public/fonts -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: lein run -m clojuredocs.main -------------------------------------------------------------------------------- /Procfile.dev: -------------------------------------------------------------------------------- 1 | web: lein repl :headless 2 | cljs: lein figwheel 3 | mongo: mongod --dbpath ./dev-db 4 | -------------------------------------------------------------------------------- /Procfile.prod-local: -------------------------------------------------------------------------------- 1 | web: env PORT=4000 lein run -m clojuredocs.main 2 | mongo: mongod --dbpath ./data/proddb 3 | 4 | cljs: lein cljsbuild auto dev-advanced 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clojuredocs 2 | 3 | The clojuredocs.org webapp 4 | 5 |  6 | 7 | 8 | ## Contributing 9 | 10 | A few ways to contribute: 11 | 12 | * Find & report bugs: https://github.com/zk/clojuredocs/issues 13 | * Suggestions on how to make development on the site more friendly 14 | (docs, codebase organization). 15 | 16 | Let's use GH issues for discussion for now 17 | 18 | If you're looking for a project: 19 | 20 | * Content for namespaces (see `src/md/namespaces`) needs to be added / 21 | edited. Example of 22 | [clojure.core.async](http://next.clojuredocs.org/clojure.core.async) 23 | * Listing of clojure training / classes / events on home page 24 | * Stand-alone example page, maybe have the var info (signature, doc 25 | string, etc) at the top. 26 | * Source-linking on libs not included in the standard library 27 | e.g. core.async. 28 | 29 | ## Deploy 30 | 31 | Production is deployed on an AWS t2.micro instance. There's an nginx 32 | process running on the box, balancing to two JVMs managed by Upstart 33 | to support zero-downtime deploys. 34 | 35 | To regenerate the upstart scripts: 36 | 37 | ``` 38 | cd $REPO 39 | sudo foreman export -a clojuredocs -e ./.env -u ubuntu -c "web=2" upstart /etc/init/ 40 | ``` 41 | 42 | To start the app processes: 43 | 44 | ``` 45 | sudo service clojuredocs-web-1 start 46 | sudo service clojuredocs-web-2 start 47 | ``` 48 | 49 | To redeploy: 50 | 51 | ``` 52 | # in $REPO 53 | sudo service clojuredocs-web-1 stop 54 | git pull origin master 55 | # This will compile assets & run tests 56 | bin/build 57 | sudo service clojuredocs-web-1 start 58 | # Wait for proc 1 to start serving requests 59 | sudo service clojuredocs-web-2 restart 60 | ``` 61 | 62 | 63 | ## Reqs 64 | 65 | * [> JDK 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) 66 | * [JCE Unlimited Strength Jurisdiction Policy Files](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html) 67 | * [lein](http://leiningen.org) 68 | * [foreman](https://github.com/ddollar/foreman) (see `Procfile`, `bin/dev`) 69 | * [less](http://lesscss.org/#using-less-installation) 70 | * [entr](http://entrproject.org/) (available in homebrew) 71 | * MongoDB 72 | 73 | 74 | 75 | ## Dev 76 | 77 | Run `bin/dev`, which will start all the things (repl, web process, 78 | scss compiler, etc). See `Procfile` for more info. 79 | 80 | Connect to the repl and / or visit http://localhost:4000 81 | 82 | You'll notice that var information is already populated. In an effort to not make the same mistakes again, all core-related var info is loaded from the runtime version of Clojure on start up. 83 | 84 | OTOH, examples, see-alsos, and notes (and any other user-generated content) are stored in the database. 85 | 86 | 87 | ### Local Data 88 | 89 | The app uses a MongoDB database named `clojuredocs` to store data. Run `bin/db-reset` to seed the database with a recent production export (you must be running `mongod` for this to work). 90 | 91 | ### Prod Local 92 | 93 | Occasionally you'll need to compile and run things as they would be in production (checking advanced cljs compilation, for example): `bin/prod-local`. 94 | 95 | 96 | ### CLJS Source Maps 97 | 98 | The ClojureDocs project is set-up to emit source-maps for compiled javascript. To enable in Chrome, check the 'Enable JS source maps' option in the Developer Tools settings pane. 99 | 100 | 101 | ### Clojure Version 102 | 103 | Clojure vars are pulled directly from the runtime, and are not stored in the database. When new versions of Clojure are released: 104 | 105 | * Change the Clojure dep in `project.clj` 106 | * Update the version string, source base url, and gh tag url in 107 | `clojuredocs.search/clojure-lib` 108 | * Update the version for the mobile nav in `clojuredocs.pages.common` 109 | * Update the github URL in `clojuredocs.pages.vars/source-url`. 110 | 111 | 112 | ### App Structure 113 | 114 | Interesting files: 115 | 116 | * `src/clj/clojuredocs/main.clj` -- Main entry-point into the app, starts the jetty server 117 | * `src/clj/clojuredocs/entry.clj` -- Root routes and middleware 118 | * `src/clj/clojuredocs/pages.clj` -- User-facing HTML pages 119 | * `src/clj/clojuredocs/api.clj` -- API endpoints for ajax calls from the frontend. 120 | * `src/cljs/clojuredocs/main.cljs` -- Main js entry-point into the app 121 | 122 | 123 | ### Conventions 124 | 125 | * Functions that return hiccup structures should be prefixed with a `$`, like `$layout`. 126 | * Mutable state should be prefixed with a `!`, ex: `!my-atom`. 127 | 128 | 129 | ### Adding Functions, Macros, Special Forms, Namespaces & Other Vars 130 | 131 | Most vars are picked up from Clojure at runtime, using core namespace 132 | and var introspection utilities. Special forms and namespaces to 133 | include on the site are specified explicitly in the 134 | `clojuredocs.search.static` namespace. 135 | 136 | Vars are picked up automatically based on the namespaces specified in 137 | `clojuredocs.search.static/clojure-namespaces` vector. Any namespace 138 | in this vector will be queried for public vars to be made searchable 139 | and displayable on the site. 140 | 141 | Special forms are specified in the 142 | `clojuredocs.search.static/special-forms` list, and require a server 143 | restart to be picked up in a dev environment. 144 | 145 | 146 | ### Adding Core Libraries 147 | 148 | Sometimes we'd like to add core libraries that are not part of the 149 | standard Clojure distribution (like core.async) to the site. Here's 150 | how to do that: 151 | 152 | 1. Add dependency to `project.clj` 153 | 1. Add ns sym to `clojure-namespaces` in `clojuredocs.search.static` 154 | 1. Add a short description + links to community articles / videos / 155 | other resources to `src/md/namespaces/` 156 | 157 | 158 | ## Dev-Prod differences 159 | 160 | * Dev starts the environment using `lein repl :headless`, prod uses `lein run -m clojuredocs.main`. See `:repl-options` in `project.clj` for initialization options. 161 | 162 | ## Data Exports 163 | 164 | * [See also relations](https://clojuredocs.org/api/exports/see-alsos-relations) (ns/name -> [ns/name]), results cached for 1 minute. 165 | 166 | 167 | ## Contributors 168 | 169 | [Zachary Kim](https://github.com/zk), [Lee Hinman](https://github.com/dakrone), and [more](https://github.com/zk/clojuredocs/graphs/contributors). 170 | 171 | 172 | ## License 173 | 174 | Copyright © 2010-present Zachary Kim 175 | 176 | Distributed under the Eclipse Public License either version 1.0 or (at 177 | your option) any later version. 178 | -------------------------------------------------------------------------------- /bin/.devenv: -------------------------------------------------------------------------------- 1 | # Dummy credentials for use in dev 2 | 3 | export SESSION_KEY=Uy9V4nWSL2g92OGe 4 | 5 | export BASE_URL=http://localhost:5000 6 | 7 | export CLJS_DEV=true 8 | 9 | export MONGO_URL="mongodb://localhost:27017/clojuredocs" 10 | 11 | export GH_CLIENT_ID=00c7338906c4ac29315b 12 | export GH_CLIENT_SECRET=1af3fca29ce3fb36075ca28bb7513e6070847d71 13 | 14 | export ALLOW_ROBOTS=true 15 | 16 | export LOG_EXCEPTIONS=false 17 | export DEBUG_EXCEPTIONS=true 18 | 19 | export STAGING_BANNER=false 20 | 21 | export MAILGUN_API_KEY=key-2006f8148abdc36fcf192c60d9e59329 22 | export MAILGUN_API_ENDPOINT="https://api.mailgun.net/v2/sandbox424576b6653e4c64a6882868b08c3858.mailgun.org/messages" 23 | -------------------------------------------------------------------------------- /bin/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | env JVM_OPTS="-Xmx256m -Xms256m -server" lein cljsbuild once prod 6 | 7 | lein test 8 | 9 | lein with-profile production compile :all 10 | -------------------------------------------------------------------------------- /bin/clean: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | rm -rf ./resources/public/cljs 4 | rm -rf ./resources/public/cljs-advanced 5 | lein clean 6 | -------------------------------------------------------------------------------- /bin/db-reset: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | mongorestore -d clojuredocs --drop $SCRIPT_DIR/../data/mongodb 6 | -------------------------------------------------------------------------------- /bin/dev: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | source $SCRIPT_DIR/.devenv 6 | 7 | # Test account used to verify data's making it to New Relic 8 | 9 | # export NEW_RELIC_APP_NAME=cd-dev 10 | # export NEW_RELIC_LICENSE_KEY=d239f729cebbb2f0742fadcf9a6616dfb9bbcf73 11 | # export NEW_RELIC_BROWSER_ID=4996968 12 | # export NEW_RELIC_BROWSER_KEY=da19d87a54 13 | 14 | export PORT=4000 15 | 16 | cd $SCRIPT_DIR && lein clean 17 | cd $SCRIPT_DIR/.. && foreman start -f Procfile.dev 18 | -------------------------------------------------------------------------------- /bin/prod: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script Dir 4 | pushd `dirname $0` > /dev/null 5 | SP=`pwd` 6 | popd > /dev/null 7 | 8 | 9 | pushd $SP/.. > /dev/null 10 | 11 | env IN_PROD=true lein run -m clojuredocs.main 12 | 13 | popd > /dev/null 14 | -------------------------------------------------------------------------------- /bin/prod-local: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | export SESSION_KEY="b46ca2a152173e68" 6 | 7 | export BASE_URL=http://localhost:4000 8 | 9 | export DEBUG_EXCEPTIONS=true 10 | export REPL_PORT=7888 11 | 12 | export CLJS_DEV=false 13 | 14 | export APP_ID="dev-$USER-`uname -n`" 15 | 16 | # export EXCEPTIONAL_KEY=4de15b3207d63564e95f712ed69a80e053504f6f 17 | 18 | export MONGO_URL="mongodb://localhost:27017/clojuredocs" 19 | 20 | export GH_CLIENT_ID=00c7338906c4ac29315b 21 | export GH_CLIENT_SECRET=1af3fca29ce3fb36075ca28bb7513e6070847d71 22 | 23 | export STAGING_BANNER=false 24 | export ALLOW_ROBOTS=true 25 | export MAILGUN_API_KEY=nokey 26 | export MAILGUN_API_ENDPOINT=noendpoint 27 | 28 | set -e 29 | 30 | lein clean 31 | 32 | bin/build 33 | 34 | foreman start -f Procfile.prod-local 35 | -------------------------------------------------------------------------------- /bin/ship: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ $# -eq 0 ]] ; then 6 | echo "Usage: ship ENVIRONMENT" 7 | exit 0 8 | fi 9 | 10 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 11 | 12 | # $SCRIPT_DIR/test 13 | 14 | cd $SCRIPT_DIR/.. && git push git@heroku.com:clojuredocs-$1.git clj-rewrite:master 15 | -------------------------------------------------------------------------------- /clojuredocs.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/clojuredocs.sketch -------------------------------------------------------------------------------- /data/mongodb/example-histories.bson: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/data/mongodb/example-histories.bson -------------------------------------------------------------------------------- /data/mongodb/example-histories.metadata.json: -------------------------------------------------------------------------------- 1 | { "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "clojuredocs.example-histories", "name" : "_id_" } ] } -------------------------------------------------------------------------------- /data/mongodb/examples.bson: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/data/mongodb/examples.bson -------------------------------------------------------------------------------- /data/mongodb/examples.metadata.json: -------------------------------------------------------------------------------- 1 | { "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "clojuredocs.examples", "name" : "_id_" }, { "v" : 1, "key" : { "var" : 1 }, "ns" : "clojuredocs.examples", "name" : "var_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "deleted-at" : 1 }, "ns" : "clojuredocs.examples", "name" : "deleted-at_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "author.login" : 1 }, "ns" : "clojuredocs.examples", "name" : "author.login_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "author.account-source" : 1 }, "ns" : "clojuredocs.examples", "name" : "author.account-source_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "editors.login" : 1 }, "ns" : "clojuredocs.examples", "name" : "editors.login_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "editors.account-source" : 1 }, "ns" : "clojuredocs.examples", "name" : "editors.account-source_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "name" : 1 }, "ns" : "clojuredocs.examples", "name" : "name_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "from-var.name" : 1 }, "ns" : "clojuredocs.examples", "name" : "from-var.name_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "from-var.ns" : 1 }, "ns" : "clojuredocs.examples", "name" : "from-var.ns_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "from-var.library-url" : 1 }, "ns" : "clojuredocs.examples", "name" : "from-var.library-url_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "to-var.ns" : 1 }, "ns" : "clojuredocs.examples", "name" : "to-var.ns_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "to-var.name" : 1 }, "ns" : "clojuredocs.examples", "name" : "to-var.name_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "to-var.library-url" : 1 }, "ns" : "clojuredocs.examples", "name" : "to-var.library-url_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "account.login" : 1 }, "ns" : "clojuredocs.examples", "name" : "account.login_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "account.account-source" : 1 }, "ns" : "clojuredocs.examples", "name" : "account.account-source_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "namespaces" : 1 }, "ns" : "clojuredocs.examples", "name" : "namespaces_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "var.ns" : 1 }, "ns" : "clojuredocs.examples", "name" : "var.ns_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "var.name" : 1 }, "ns" : "clojuredocs.examples", "name" : "var.name_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "var.library-url" : 1 }, "ns" : "clojuredocs.examples", "name" : "var.library-url_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "function-id" : 1 }, "ns" : "clojuredocs.examples", "name" : "function-id_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "editor.login" : 1 }, "ns" : "clojuredocs.examples", "name" : "editor.login_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "editor.account-source" : 1 }, "ns" : "clojuredocs.examples", "name" : "editor.account-source_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "login" : 1 }, "ns" : "clojuredocs.examples", "name" : "login_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "account-source" : 1 }, "ns" : "clojuredocs.examples", "name" : "account-source_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "email" : 1 }, "ns" : "clojuredocs.examples", "name" : "email_1", "sparse" : false, "background" : false }, { "v" : 1, "key" : { "migraion-key" : 1 }, "ns" : "clojuredocs.examples", "name" : "migraion-key_1", "sparse" : false, "background" : false } ] } -------------------------------------------------------------------------------- /data/mongodb/legacy-var-redirects.bson: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/data/mongodb/legacy-var-redirects.bson -------------------------------------------------------------------------------- /data/mongodb/legacy-var-redirects.metadata.json: -------------------------------------------------------------------------------- 1 | { "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "clojuredocs.legacy-var-redirects", "name" : "_id_" } ] } -------------------------------------------------------------------------------- /data/mongodb/notes.bson: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/data/mongodb/notes.bson -------------------------------------------------------------------------------- /data/mongodb/notes.metadata.json: -------------------------------------------------------------------------------- 1 | { "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "clojuredocs.notes", "name" : "_id_" } ] } -------------------------------------------------------------------------------- /data/mongodb/see-alsos.bson: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/data/mongodb/see-alsos.bson -------------------------------------------------------------------------------- /data/mongodb/see-alsos.metadata.json: -------------------------------------------------------------------------------- 1 | { "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "clojuredocs.see-alsos", "name" : "_id_" } ] } -------------------------------------------------------------------------------- /data/mongodb/system.indexes.bson: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/data/mongodb/system.indexes.bson -------------------------------------------------------------------------------- /data/mongodb/users.bson: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/data/mongodb/users.bson -------------------------------------------------------------------------------- /data/mongodb/users.metadata.json: -------------------------------------------------------------------------------- 1 | { "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "clojuredocs.users", "name" : "_id_" } ] } -------------------------------------------------------------------------------- /dev-db/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/dev-db/.gitkeep -------------------------------------------------------------------------------- /externs/fastclick.js: -------------------------------------------------------------------------------- 1 | var FastClick = {}; 2 | FastClick.attach = function(target){}; 3 | -------------------------------------------------------------------------------- /externs/marked.js: -------------------------------------------------------------------------------- 1 | var marked = function(){}; 2 | marked.setOptions = function(options){}; 3 | -------------------------------------------------------------------------------- /externs/morpheus.js: -------------------------------------------------------------------------------- 1 | var morpheus = function(elements, options) {} 2 | 3 | morpheus.tween = function(duration, callback, complete, ease) {} 4 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject clojuredocs "0.1.0-SNAPSHOT" 2 | :description "FIXME: write description" 3 | :url "http://example.com/FIXME" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :min-lein-version "2.0.0" 7 | :source-paths ["src/clj" "src/cljc"] 8 | :test-paths ["test/clj"] 9 | :dependencies [[org.clojure/clojure "1.11.1"] 10 | [org.clojure/clojurescript "1.9.946"] 11 | [ring "1.5.1"] 12 | [compojure "1.1.6"] 13 | [aleph "0.4.2-alpha12"] 14 | [clucy "0.4.0"] 15 | [watchtower "0.1.1"] 16 | [org.clojure/java.jdbc "0.3.0-beta2"] 17 | [mysql/mysql-connector-java "5.1.25"] 18 | [unk "0.9.1"] 19 | [org.clojure/core.async "1.6.681"] 20 | [org.clojure/core.logic "0.8.11"] 21 | [com.vladsch.flexmark/flexmark-all "0.64.8"] 22 | [clj-fuzzy "0.1.8"] 23 | [prone "0.6.0"] 24 | [nrepl "0.6.0"] 25 | [javax.xml.bind/jaxb-api "2.4.0-b180830.0359"] 26 | [org.clojure/data.csv "1.0.1"] 27 | [clojure-interop/java.security "1.0.5"] 28 | [garden "1.2.5" :exclusions [org.clojure/clojure]] 29 | [com.cognitect/transit-clj "1.0.333"] 30 | [com.cognitect/transit-cljs "0.8.280"] 31 | [bidi "1.23.1" :exclusions [org.clojure/clojure]] 32 | [slingshot "0.12.2"] 33 | [cheshire "5.5.0"] 34 | [clj-http "3.6.0"] 35 | [camel-snake-kebab "0.3.2"] 36 | [prismatic/dommy "1.1.0"] 37 | [reagent "0.6.0"] 38 | [congomongo "2.6.0"]] 39 | :repl-options {:init (load-file "reup.clj")} 40 | :plugins [[lein-cljsbuild "1.1.5"] 41 | [lein-figwheel "0.5.18"] 42 | [cider/cider-nrepl "0.22.3"]] 43 | :cljsbuild {:builds 44 | {:dev {:source-paths ["src/cljs" "src/cljc"] 45 | :compiler {:output-to "resources/public/cljs/clojuredocs.js" 46 | :output-dir "resources/public/cljs" 47 | :main "clojuredocs.main" 48 | :optimizations :none 49 | :source-map true 50 | :asset-path "/cljs" 51 | :externs ["externs/morpheus.js"]} 52 | :figwheel {:on-jsload "clojuredocs.main/reload-hook"}} 53 | 54 | ;; for debugging advanced compilation problems 55 | :dev-advanced {:source-paths ["src/cljs" "src/cljc"] 56 | :compiler {:output-to "resources/public/cljs/clojuredocs.js" 57 | :output-dir "resources/public/cljs-advanced" 58 | :source-map "resources/public/cljs/clojuredocs.js.map" 59 | :optimizations :advanced 60 | :preamble ["public/js/morpheus.min.js" 61 | "public/js/marked.min.js" 62 | "public/js/fastclick.min.js"] 63 | :externs ["externs/morpheus.js" 64 | "externs/marked.js" 65 | "externs/fastclick.js"]}} 66 | 67 | :prod {:source-paths ["src/cljs" "src/cljc"] 68 | :compiler {:output-to "resources/public/cljs/clojuredocs.js" 69 | :optimizations :advanced 70 | :main "clojuredocs.main" 71 | :pretty-print false 72 | :preamble ["public/js/morpheus.min.js" 73 | "public/js/marked.min.js" 74 | "public/js/fastclick.min.js"] 75 | :externs ["externs/morpheus.js" 76 | "externs/marked.js" 77 | "externs/fastclick.js"]} 78 | :jar true}}} 79 | :figwheel {:http-server-root "resources/public" 80 | :css-dirs ["resources/public/css"] 81 | :repl false}) 82 | -------------------------------------------------------------------------------- /resources/nginx.conf: -------------------------------------------------------------------------------- 1 | user www-data; 2 | worker_processes 4; 3 | pid /run/nginx.pid; 4 | 5 | events { 6 | worker_connections 768; 7 | # multi_accept on; 8 | } 9 | 10 | http { 11 | 12 | upstream backend { 13 | server 127.0.0.1:5000; 14 | server 127.0.0.1:5001; 15 | } 16 | 17 | server { 18 | listen 80; 19 | 20 | location / { 21 | proxy_pass http://backend; 22 | } 23 | } 24 | 25 | ## 26 | # Basic Settings 27 | ## 28 | 29 | sendfile on; 30 | tcp_nopush on; 31 | tcp_nodelay on; 32 | keepalive_timeout 65; 33 | types_hash_max_size 2048; 34 | # server_tokens off; 35 | 36 | # server_names_hash_bucket_size 64; 37 | # server_name_in_redirect off; 38 | 39 | include /etc/nginx/mime.types; 40 | default_type application/octet-stream; 41 | 42 | ## 43 | # Logging Settings 44 | ## 45 | 46 | access_log /var/log/nginx/access.log; 47 | error_log /var/log/nginx/error.log; 48 | 49 | ## 50 | # Gzip Settings 51 | ## 52 | 53 | gzip on; 54 | gzip_disable "msie6"; 55 | 56 | # gzip_vary on; 57 | # gzip_proxied any; 58 | # gzip_comp_level 6; 59 | # gzip_buffers 16 8k; 60 | # gzip_http_version 1.1; 61 | # gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 62 | 63 | ## 64 | # nginx-naxsi config 65 | ## 66 | # Uncomment it if you installed nginx-naxsi 67 | ## 68 | 69 | #include /etc/nginx/naxsi_core.rules; 70 | 71 | ## 72 | # Virtual Host Configs 73 | ## 74 | 75 | #include /etc/nginx/conf.d/*.conf; 76 | #include /etc/nginx/sites-enabled/*; 77 | } 78 | -------------------------------------------------------------------------------- /resources/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/favicon.ico -------------------------------------------------------------------------------- /resources/public/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /resources/public/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /resources/public/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /resources/public/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /resources/public/github-btn.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /resources/public/img/adzerk-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/adzerk-logo.png -------------------------------------------------------------------------------- /resources/public/img/amazon-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/amazon-logo.png -------------------------------------------------------------------------------- /resources/public/img/amperity-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/amperity-logo.jpg -------------------------------------------------------------------------------- /resources/public/img/amperity-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/amperity-logo.png -------------------------------------------------------------------------------- /resources/public/img/brightcove-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/brightcove-logo.png -------------------------------------------------------------------------------- /resources/public/img/circleci-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/circleci-logo.png -------------------------------------------------------------------------------- /resources/public/img/clearwater-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/clearwater-logo.png -------------------------------------------------------------------------------- /resources/public/img/climate-corporation-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/climate-corporation-logo.png -------------------------------------------------------------------------------- /resources/public/img/cognician-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/cognician-logo.png -------------------------------------------------------------------------------- /resources/public/img/cognitect-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/cognitect-logo.png -------------------------------------------------------------------------------- /resources/public/img/diligenceengine-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/diligenceengine-logo.png -------------------------------------------------------------------------------- /resources/public/img/exoscale-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/exoscale-logo.png -------------------------------------------------------------------------------- /resources/public/img/factual-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/factual-logo.png -------------------------------------------------------------------------------- /resources/public/img/farmlogs-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/farmlogs-logo.png -------------------------------------------------------------------------------- /resources/public/img/fluent-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/fluent-logo.png -------------------------------------------------------------------------------- /resources/public/img/funding-circle-box-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/funding-circle-box-logo.png -------------------------------------------------------------------------------- /resources/public/img/funding-circle-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/funding-circle-logo.png -------------------------------------------------------------------------------- /resources/public/img/fy-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/fy-logo.jpg -------------------------------------------------------------------------------- /resources/public/img/griffin-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/griffin-logo.png -------------------------------------------------------------------------------- /resources/public/img/heroku-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/heroku-logo.png -------------------------------------------------------------------------------- /resources/public/img/intentmedia-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/intentmedia-logo.png -------------------------------------------------------------------------------- /resources/public/img/kira-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/kira-logo.png -------------------------------------------------------------------------------- /resources/public/img/lisp_cycles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/lisp_cycles.png -------------------------------------------------------------------------------- /resources/public/img/living-social-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/living-social-logo.png -------------------------------------------------------------------------------- /resources/public/img/loading-button.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/loading-button.gif -------------------------------------------------------------------------------- /resources/public/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/loading.gif -------------------------------------------------------------------------------- /resources/public/img/netflix-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/netflix-logo.png -------------------------------------------------------------------------------- /resources/public/img/nubank-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/nubank-logo.png -------------------------------------------------------------------------------- /resources/public/img/oscaro-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/oscaro-logo.png -------------------------------------------------------------------------------- /resources/public/img/outpost-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/outpost-logo.png -------------------------------------------------------------------------------- /resources/public/img/pisano-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/pisano-logo.jpg -------------------------------------------------------------------------------- /resources/public/img/pitch-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/pitch-logo.png -------------------------------------------------------------------------------- /resources/public/img/prismatic-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/prismatic-logo.png -------------------------------------------------------------------------------- /resources/public/img/puppet-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/puppet-logo.jpg -------------------------------------------------------------------------------- /resources/public/img/qubit-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/qubit-logo.png -------------------------------------------------------------------------------- /resources/public/img/reify-health-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/reify-health-logo.png -------------------------------------------------------------------------------- /resources/public/img/rjmetrics-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/rjmetrics-logo.png -------------------------------------------------------------------------------- /resources/public/img/room-key-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/room-key-logo.jpg -------------------------------------------------------------------------------- /resources/public/img/soundcloud-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/soundcloud-logo.png -------------------------------------------------------------------------------- /resources/public/img/spacious-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/spacious-logo.jpg -------------------------------------------------------------------------------- /resources/public/img/twitter-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/twitter-logo.png -------------------------------------------------------------------------------- /resources/public/img/walmart-labs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/walmart-labs.png -------------------------------------------------------------------------------- /resources/public/img/whimsical-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/whimsical-logo.png -------------------------------------------------------------------------------- /resources/public/img/witai-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk/clojuredocs/31d4bd2dc7b1d5d1950e2b5e5f204735331d885e/resources/public/img/witai-logo.png -------------------------------------------------------------------------------- /resources/public/js/fastclick.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | FastClick: polyfill to remove click delays on browsers with touch UIs. 3 | 4 | @version 1.0.2 5 | @codingstandard ftlabs-jsv2 6 | @copyright The Financial Times Limited [All Rights Reserved] 7 | @license MIT License (see LICENSE.txt) 8 | */ 9 | function FastClick(a,b){function c(a,b){return function(){return a.apply(b,arguments)}}var d;b=b||{};this.trackingClick=!1;this.trackingClickStart=0;this.targetElement=null;this.lastTouchIdentifier=this.touchStartY=this.touchStartX=0;this.touchBoundary=b.touchBoundary||10;this.layer=a;this.tapDelay=b.tapDelay||200;if(!FastClick.notNeeded(a)){for(var g="onMouse onClick onTouchStart onTouchMove onTouchEnd onTouchCancel".split(" "),f=0,h=g.length;f" "")
66 | (str/replace #"
" ""))]])
67 |
68 | (defn $notes [notes name]
69 | [:div.var-notes
70 | [:h5 (util/pluralize (count notes) "Note" "Notes")]
71 | [:div
72 | (if (empty? notes)
73 | [:div.null-state "No notes for " [:code name]]
74 | [:ul
75 | (for [n notes]
76 | ($note n))])]
77 | [:div.add-note-widget]])
78 |
79 |
80 | (defn clean-id [{:keys [_id] :as m}]
81 | (assoc m :_id (str _id)))
82 |
83 | (defn clean-example [{:keys [_id user history] :as m}]
84 | (-> m
85 | (update-in [:user] dissoc :email)
86 | (update-in [:_id] str)))
87 |
88 | (defn clean-see-also [m]
89 | (-> m
90 | (update-in [:user] dissoc :email)
91 | (update-in [:_id] str)))
92 |
93 | (defn $number-badge [num]
94 | [:span.badge num])
95 |
96 | (defn $var-header [{:keys [ns name added arglists forms] :as v}]
97 | [:div.row.var-header
98 | [:div.col-sm-8
99 | [:h1.var-name (util/html-encode name)]]
100 | [:div.col-sm-4
101 | [:div.var-meta
102 | [:h4 [:a {:href (str "/" ns)} ns]]
103 | (when added
104 | [:span "Available since " added])
105 | (when-let [su (source-url v)]
106 | [:span.source-link
107 | " ("
108 | [:a {:href su} "source"]
109 | ") "])]]
110 | [:div.col-sm-12
111 | [:section
112 | [:ul.arglists
113 | (if forms
114 | (map #($argform %) forms)
115 | (map #($arglist name %) arglists))]]]])
116 |
117 | (defn var-page-handler [ns name]
118 | (let [name (util/cd-decode (codec/url-decode name))
119 | {:keys [arglists name ns doc runtimes added file] :as v} (lookup-var ns name)]
120 | (fn [{:keys [user session uri]}]
121 | (when v
122 | (let [examples (data/find-examples-for v)
123 | see-alsos (->> v
124 | see-alsos-for
125 | (map #(assoc % :can-delete? (util/is-author? user %))))
126 | library (library-for v)
127 | recent (:recent session)
128 | notes (->> v
129 | data/find-notes-for
130 | (map #(let [author? (util/is-author? user %)]
131 | (-> %
132 | (assoc :can-delete? author?)
133 | (assoc :can-edit? author?)))))]
134 | {:session (update-in session [:recent]
135 | #(->> %
136 | (concat [{:text name
137 | :href (str "/" ns "/" (util/cd-encode name))}])
138 | distinct
139 | (filter :text)
140 | (take 4)))
141 | :body
142 | (common/$main
143 | {:body-class "var-page"
144 | :title (util/html-encode (str name " - " ns " | ClojureDocs - Community-Powered Clojure Documentation and Examples"))
145 | :page-data {:examples (mapv clean-example examples)
146 | :var v
147 | :notes (vec (map clean-id notes))
148 | :see-alsos (vec (map clean-see-also see-alsos))
149 | :user (when user (select-keys user [:login :avatar-url :account-source]))}
150 | :page-uri uri
151 | :user user
152 | :mobile-nav [{:title "Nav"
153 | :links [[:a {:href "#"
154 | :data-animate-scroll "true"
155 | :data-animate-buffer "70"}
156 | "Top"]
157 | [:a {:href "#examples"
158 | :data-animate-scroll "true"
159 | :data-animate-buffer "70"}
160 | "Examples "
161 | [:span.examples-count
162 | ($number-badge (count examples))]]
163 | [:a {:href "#see-also"
164 | :data-animate-scroll "true"
165 | :data-animate-buffer "70"}
166 | "See Also " ($number-badge (count see-alsos))]
167 | (when (> (count notes) 0)
168 | [:a {:href "#notes"
169 | :data-animate-scroll "true"
170 | :data-animate-buffer "70"}
171 | "Notes " ($number-badge (count notes))])]}
172 | {:title "Namespaces"
173 | :links (->> library
174 | :namespaces
175 | (map (fn [{:keys [name]}]
176 | [:a {:href (str "/" name)} name])))}]
177 | :content [:div
178 | [:div.row
179 | [:div.col-sm-2.sidenav
180 | [:div.desktop-side-nav {:data-sticky-offset "10"}
181 | [:div.var-page-nav]
182 | (common/$library-nav library ns)]]
183 | [:div.col-sm-10
184 | ($var-header v)
185 | [:section
186 | [:div.docstring
187 | (if doc
188 | [:pre (-> doc
189 | (str/replace #"\n\s\s" "\n")
190 | util/html-encode)]
191 | [:div.null-state "No Doc"])
192 | (when doc
193 | [:div.copyright
194 | "© Rich Hickey. All rights reserved."
195 | " "
196 | [:a {:href "http://www.eclipse.org/legal/epl-v10.html"}
197 | "Eclipse Public License 1.0"]])]]
198 | [:section
199 | [:div.examples-widget {:id "examples"}]]
200 | [:section
201 | [:div.see-alsos-widget {:id "see-also"}]]
202 | [:section
203 | [:div.notes-widget {:id "notes"}]]]]]})})))))
204 |
205 | (defn $example-body [{:keys [body]}]
206 | [:div.example-body
207 | [:pre.raw-example {:class "brush: clojure"} body]])
208 |
209 | (defn $example-history-point [{:keys [user body created-at updated-at] :as ex}]
210 | [:div.var-example
211 | [:div
212 | (let [num-to-show 7]
213 | [:div.example-meta
214 | [:div.contributors
215 | "Created by "
216 | (util/$avatar user)
217 | ""
218 | (util/timeago created-at) " ago."]
219 | [:div.links
220 | ]])]
221 | [:div ($example-body ex)]])
222 |
223 | (defn example-handler [id]
224 | (fn [{:keys [user session uri]}]
225 | (let [{:keys [history name ns] :as ex}
226 | (mon/fetch-one :examples :where {:_id (util/bson-id id)})]
227 | (common/$main
228 | {:body-class "example-page"
229 | :user user
230 | :page-uri uri
231 | :content [:div.row
232 | [:div.col-md-12
233 | [:p
234 | "Example history for "
235 | (util/$var-link ns name (str ns "/" name))
236 | ", in order from newest to oldest. "
237 | "The currrent version is outlined in yellow."]
238 | #_[:div.current-example
239 | ($example ex)]
240 | (->> history
241 | reverse
242 | (map $example-history-point))]]}))))
243 |
--------------------------------------------------------------------------------
/src/clj/clojuredocs/search.clj:
--------------------------------------------------------------------------------
1 | (ns clojuredocs.search
2 | (:require [clucy.core :as clucy]
3 | [clojure.string :as str]
4 | [clojuredocs.util :as util]
5 | [clojure.pprint :refer [pprint]]
6 | [clojuredocs.search.static :as static]))
7 |
8 | (def search-index (clucy/memory-index))
9 |
10 | (defn tokenize-name [s]
11 | (when s
12 | (str
13 | s
14 | " "
15 | (->> (str/split s #"-")
16 | (interpose " ")
17 | (apply str)))))
18 |
19 | (def var-keys
20 | [:ns
21 | :name
22 | :file
23 | :column
24 | :line
25 | :added
26 | :arglists
27 | :doc
28 | :static
29 | :tag ; convert to string
30 | :macro
31 | :dynamic
32 | :special-form
33 | :forms ; -> list of strings
34 | :deprecated
35 | :url
36 | :no-doc])
37 |
38 | (defn cond-update-in [m keys & rest]
39 | (if (get-in m keys)
40 | (apply update-in m keys rest)
41 | m))
42 |
43 | (defn type-of [{:keys [type macro arglists special-form]}]
44 | (cond
45 | type type
46 | macro "macro"
47 | (> (count arglists) 0) "function"
48 | special-form "special-form"
49 | :else "var"))
50 |
51 | (defn transform-var-meta [m]
52 | (-> m
53 | (select-keys var-keys)
54 | (cond-update-in [:tag] #(if (class? %)
55 | (.getName %)
56 | (str %)))
57 | (cond-update-in [:forms] #(map str %))
58 | (update-in [:ns] str)
59 | (update-in [:arglists] #(map
60 | (fn [arg-list-coll]
61 | (->> arg-list-coll
62 | (map str)
63 | (interpose " ")
64 | (apply str)))
65 | %))
66 | (update-in [:name] str)))
67 |
68 | (defn gather-var [ns-obj]
69 | (->> ns-obj
70 | ns-publics
71 | (map second)
72 | (map meta)))
73 |
74 | (defn gather-vars [{:keys [namespaces library-url] :as lib}]
75 | (assoc lib :vars (->> namespaces
76 | (map :name)
77 | (map symbol)
78 | (map find-ns)
79 | (mapcat gather-var)
80 | (concat static/special-forms)
81 | (map transform-var-meta)
82 | (map #(assoc % :library-url library-url))
83 | (map #(assoc % :type (type-of %)))
84 | (map #(assoc % :href (str "/" (:ns %) "/" (util/cd-encode (:name %))))))))
85 |
86 | (defn gather-namespace [ns-name]
87 | (require (symbol ns-name))
88 | (let [sym (symbol ns-name)
89 | namespace (find-ns sym)
90 | meta (meta namespace)]
91 | (merge
92 | (select-keys meta [:doc :no-doc :added])
93 | {:name (str ns-name)})))
94 |
95 | (defn gather-namespaces [{:keys [namespaces] :as lib}]
96 | (assoc lib
97 | :namespaces
98 | (->> namespaces
99 | (map gather-namespace)
100 | (remove :no-doc))))
101 |
102 | (def clojure-lib
103 | (-> {:library-url "https://github.com/clojure/clojure"
104 | :version "1.11.1"
105 | :source-base-url "https://github.com/clojure/clojure/1.11.1/blob"
106 | :gh-tag-url "https://github.com/clojure/clojure/tree/clojure-1.11.1"
107 | :namespaces static/clojure-namespaces}
108 | gather-namespaces
109 | gather-vars))
110 |
111 | (def searchable-vars
112 | (->> clojure-lib
113 | :vars
114 | (map #(assoc % :keywords (tokenize-name (:name %))))))
115 |
116 | (def searchable-nss
117 | (->> static/clojure-namespaces
118 | (map (fn [sym]
119 | {:name (str sym)
120 | :keywords (str
121 | (str sym)
122 | " "
123 | (->> (str/split (str sym) #"\.")
124 | (interpose " ")
125 | (apply str)))
126 | :type "namespace"}))
127 | (map (fn [{:keys [name] :as ns}]
128 | (assoc ns :href (str "/" name))))))
129 |
130 | (binding [clucy/*analyzer* (org.apache.lucene.analysis.core.WhitespaceAnalyzer. clucy/*version*)]
131 | (doseq [nm searchable-vars]
132 | (clucy/add search-index nm))
133 | (doseq [ns searchable-nss]
134 | (clucy/add search-index ns))
135 | (doseq [page static/searchable-pages]
136 | (clucy/add search-index page)))
137 |
138 | (def lookup-vars
139 | (->> searchable-vars
140 | (reduce #(assoc %1 (str (:ns %2) "/" (:name %2)) %2) {})))
141 |
142 | (defn lookup [ns-name]
143 | (get lookup-vars ns-name))
144 |
145 | (defn lucene-escape [s]
146 | (str/replace s #"[\+\-\!\(\)\{\}\[\]\^\"\~\*\?\:\\\/]" "\\\\$0"))
147 |
148 | ;; https://gist.github.com/ck/960716
149 | (defn- compute-next-row
150 | "computes the next row using the prev-row current-element and the other seq"
151 | [prev-row current-element other-seq pred]
152 | (reduce
153 | (fn [row [diagonal above other-element]]
154 | (let [update-val
155 | (if (pred other-element current-element)
156 | diagonal
157 | (inc (min diagonal above (peek row)))
158 | )]
159 | (conj row update-val)))
160 | [(inc (first prev-row))]
161 | (map vector prev-row (next prev-row) other-seq)))
162 |
163 | (defn levenshtein-distance
164 | "Levenshtein Distance - http://en.wikipedia.org/wiki/Levenshtein_distance
165 | In information theory and computer science, the Levenshtein distance is a metric for measuring the amount of difference between two sequences. This is a functional implementation of the levenshtein edit
166 | distance with as little mutability as possible.
167 |
168 | Still maintains the O(n*m) guarantee.
169 | "
170 | [a b & {p :predicate :or {p =}}]
171 | (peek
172 | (reduce
173 | (fn [prev-row current-element]
174 | (compute-next-row prev-row current-element b p))
175 | (map #(identity %2) (cons nil b) (range))
176 | a)))
177 |
178 | (defn drop-leading-stars [q]
179 | (when q
180 | (let [stripped (if (.startsWith q "*")
181 | (->> (str/replace q #"\**" "")
182 | (apply str))
183 | q)]
184 | (when-not (empty? stripped)
185 | stripped))))
186 |
187 | (defn escape-query [q]
188 | (when-not (empty? q)
189 | (org.apache.lucene.queryparser.classic.QueryParser/escape q)))
190 |
191 | (defn format-query [q]
192 | (some-> q
193 | str/trim
194 | drop-leading-stars
195 | lucene-escape
196 | (str "*")))
197 |
198 | (defn query [q]
199 | (cond
200 | (= "*" q) [(lookup "clojure.core/*")]
201 |
202 | :else
203 | (when-let [q (format-query q)]
204 | (->> (clucy/search search-index q 1000 :default-field "keywords")
205 | (map #(assoc % :edit-distance (levenshtein-distance (str (:name %)) q)))
206 | (sort-by :edit-distance)))))
207 |
--------------------------------------------------------------------------------
/src/clj/clojuredocs/search/static.clj:
--------------------------------------------------------------------------------
1 | (ns clojuredocs.search.static)
2 |
3 | (def clojure-namespaces
4 | '[clojure.core
5 | clojure.core.async
6 | clojure.core.logic
7 | clojure.core.logic.fd
8 | clojure.core.logic.pldb
9 | clojure.core.protocols
10 | clojure.core.reducers
11 | clojure.core.server
12 | clojure.data
13 | clojure.data.csv
14 | clojure.datafy
15 | clojure.edn
16 | clojure.inspector
17 | clojure.instant
18 | clojure.java.browse
19 | clojure.java.io
20 | clojure.java.javadoc
21 | clojure.java.shell
22 | clojure.main
23 | clojure.math
24 | clojure.pprint
25 | clojure.reflect
26 | clojure.repl
27 | clojure.set
28 | clojure.spec.alpha
29 | clojure.stacktrace
30 | clojure.string
31 | clojure.template
32 | clojure.test
33 | clojure.test.junit
34 | clojure.test.tap
35 | clojure.walk
36 | clojure.xml
37 | clojure.zip])
38 |
39 | (def special-forms
40 | (->> [{:name 'def
41 | :ns "clojure.core"
42 | :doc "Creates and interns or locates a global var with the name of symbol and a
43 | namespace of the value of the current namespace (*ns*). See
44 | http://clojure.org/special_forms for more information."}
45 | {:name 'if
46 | :ns "clojure.core"
47 | :doc "Evaluates test."}
48 | {:name 'do
49 | :ns "clojure.core"
50 | :doc "Evaluates the expressions in order and returns the value of the last. If no
51 | expressions are supplied, returns nil. See http://clojure.org/special_forms
52 | for more information."}
53 | {:name 'quote
54 | :ns "clojure.core"
55 | :doc "Yields the unevaluated form. See http://clojure.org/special_forms for more
56 | information."}
57 | {:name 'var
58 | :ns "clojure.core"
59 | :doc "The symbol must resolve to a var, and the Var object itself (not its value)
60 | is returned. The reader macro #'x expands to (var x). See
61 | http://clojure.org/special_forms for more information."}
62 | {:name 'recur
63 | :ns "clojure.core"
64 | :doc "Evaluates the exprs in order, then, in parallel, rebinds the bindings of
65 | the recursion point to the values of the exprs. See
66 | http://clojure.org/special_forms for more information."}
67 | {:name 'throw
68 | :ns "clojure.core"
69 | :doc "The expr is evaluated and thrown, therefore it should yield an instance of
70 | some derivee of Throwable. Please see http://clojure.org/special_forms#throw"}
71 | {:name 'try
72 | :ns "clojure.core"
73 | :doc "The exprs are evaluated and, if no exceptions occur, the value of the last
74 | is returned. If an exception occurs and catch clauses are provided, each is
75 | examined in turn and the first for which the thrown exception is an instance
76 | of the named class is considered a matching catch clause. If there is a
77 | matching catch clause, its exprs are evaluated in a context in which name is
78 | bound to the thrown exception, and the value of the last is the return value
79 | of the function. If there is no matching catch clause, the exception
80 | propagates out of the function. Before returning, normally or abnormally,
81 | any finally exprs will be evaluated for their side effects. See
82 | http://clojure.org/special_forms for more information."}
83 | {:name 'catch
84 | :ns "clojure.core"
85 | :doc "The exprs are evaluated and, if no exceptions occur, the value of the last
86 | is returned. If an exception occurs and catch clauses are provided, each is
87 | examined in turn and the first for which the thrown exception is an instance
88 | of the named class is considered a matching catch clause. If there is a
89 | matching catch clause, its exprs are evaluated in a context in which name is
90 | bound to the thrown exception, and the value of the last is the return value
91 | of the function. If there is no matching catch clause, the exception
92 | propagates out of the function. Before returning, normally or abnormally,
93 | any finally exprs will be evaluated for their side effects. See
94 | http://clojure.org/special_forms for more information."}
95 | {:name 'finally
96 | :ns "clojure.core"
97 | :doc "The exprs are evaluated and, if no exceptions occur, the value of the last
98 | is returned. If an exception occurs and catch clauses are provided, each is
99 | examined in turn and the first for which the thrown exception is an instance
100 | of the named class is considered a matching catch clause. If there is a
101 | matching catch clause, its exprs are evaluated in a context in which name is
102 | bound to the thrown exception, and the value of the last is the return value
103 | of the function. If there is no matching catch clause, the exception
104 | propagates out of the function. Before returning, normally or abnormally,
105 | any finally exprs will be evaluated for their side effects. See
106 | http://clojure.org/special_forms for more information."}
107 | {:name '.
108 | :ns "clojure.core"
109 | :doc "The '.' special form is the basis for access to Java. It can be considered
110 | a member-access operator, and/or read as 'in the scope of'. See
111 | http://clojure.org/special_forms for more information."}
112 | {:name 'set!
113 | :ns "clojure.core"
114 | :doc "Assignment special form. When the first operand is a field member access
115 | form, the assignment is to the corresponding field. If it is an instance
116 | field, the instance expr will be evaluated, then the expr. In all cases
117 | the value of expr is returned. Note - you cannot assign to function params
118 | or local bindings. Only Java fields, Vars, Refs and Agents are mutable in
119 | Clojure. See http://clojure.org/special_forms for more information."}
120 | {:name 'monitor-enter
121 | :ns "clojure.core"
122 | :doc "A synchronization primitive that should be avoided in user code. Use the
123 | locking macro. See http://clojure.org/special_forms for more information."}
124 | {:name 'monitor-exit
125 | :ns "clojure.core"
126 | :doc "A synchronization primitive that should be avoided in user code. Use the
127 | locking macro. See http://clojure.org/special_forms for more information."}
128 | {:name 'new
129 | :ns "clojure.core"
130 | :doc "Instantiate a class. See http://clojure.org/java_interop#new for
131 | more information."}]
132 | (map #(assoc % :type "special-form"))))
133 |
134 | (def concept-pages
135 | [{:name "Destructuring"
136 | :keywords "destructuring destructure destruct"
137 | :href "/concepts/destructuring"
138 | :desc "Destructuring allows you to assign names to values based on the structure of a parameter."}
139 | {:name "Functional Programming"
140 | :keywords "functional programming"
141 | :href "/concepts/functional-programming"
142 | :desc "Rooted in lambda calculus, functional programming is a the style of building programs in a declarative way favoring composition of first-class, pure, and higher-order functions, immutable data structures, laziness, and the elimination of side effects. "}])
143 |
144 | (def searchable-pages
145 | (->> [{:name "Quick Reference"
146 | :keywords "help, getting started, quickref, quick reference"
147 | :href "/quickref"
148 | :desc "Clojure functions broken down by conceptual area (string manipulation, collections, etc)."}
149 | {:name "Laziness in Clojure"
150 | :keywords "lazy laziness lazyness sequences seq lazy evaluation"
151 | :href "/concepts/lazyness"
152 | :desc "Laziness is the deferred or delayed execution of some bit of code, opposite of eager or immediate evaluation. Laziness is used Clojure to enable execution composition and solutions to problems that involve infinite sequences. FIX THIS"}
153 | {:name "Read-Eval-Print Loop (REPL)"
154 | :keywords "repl read eval print loop"
155 | :href "/concepts/repl"
156 | :desc "A read–eval–print loop (REPL), also known as an interactive toplevel or language shell, is a simple, interactive computer programming environment that takes single user inputs (i.e. single expressions), evaluates them, and returns the result to the user; a program written in a REPL environment is executed piecewise. The term is most usually used to refer to programming interfaces similar to the classic Lisp interactive environment. Common examples include command line shells and similar environments for programming languages."}
157 | {:name "Thrush Operators (->, ->>)"
158 | :keywords "thrush operators -> ->> as->"
159 | :href "/concepts/thrush"
160 | :desc "http://thecomputersarewinning.com/post/Clojure-Thrush-Operator/"}
161 | {:name "Recursion"
162 | :keywords "recursion loop recur trampoline"
163 | :href "https://www.google.com/search?q=recursion"
164 | :desc "Recursion is the process of repeating items in a self-similar way. For instance, when the surfaces of two mirrors are exactly parallel with each other the nested images that occur are a form of infinite recursion."}]
165 | (concat concept-pages)
166 | (map #(assoc % :type "page"))))
167 |
--------------------------------------------------------------------------------
/src/clj/nsfw/reup.clj:
--------------------------------------------------------------------------------
1 | (ns nsfw.reup
2 | "Utilities for supporting a clojure.tools.namespace reloading dev
3 | lifecycle.
4 |
5 | Add the following to your project.clj
6 |
7 | `:repl-options {:init (load-file \"reup.clj\")}`"
8 | (:require [clojure.tools.namespace.repl :as repl]
9 | [clojure.tools.namespace.find :as ns-find]
10 | [clojure.java.classpath :as cp]
11 | [clojure.string :as str]))
12 |
13 | (defn exception? [e]
14 | (isa? (type e) Exception))
15 |
16 | (defn ns-for-sym [sym]
17 | (when (.contains (str sym) "/")
18 | (-> sym
19 | str
20 | (str/split #"/")
21 | first
22 | symbol)))
23 |
24 | (defn setup
25 | "Helper for initializing a clojure.tools.namespace dev
26 | lifecycle. See
27 | http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded
28 | for more info.
29 |
30 | This will return a function that, when called, will stop the
31 | current environment, reload all namespaces, and start a new
32 | environment.
33 |
34 | Params:
35 | * `start-app-sym` -- FQ symbol of a no-arg function which
36 | starts the environment
37 | * `stop-app-sym` -- FQ symbol of a 1-arg
38 | function which stops the environment. The result of calling the
39 | start app function is passed in as it's first parameter
40 | * `tests-regex` -- Run tests after reload for all namespaces matching"
41 |
42 | [{:keys [start-app-sym stop-app-sym tests-regex]}]
43 | (when start-app-sym
44 | (when-not (resolve 'user/reup-app)
45 | (intern 'user 'reup-app nil))
46 | (when-not (resolve 'user/after-reup)
47 | (intern 'user 'after-reup
48 | (fn []
49 | (when start-app-sym
50 | (binding [*ns* (find-ns 'user)]
51 | (alter-var-root (resolve 'user/reup-app)
52 | (constantly (when-let [a (resolve start-app-sym)]
53 | (let [f (deref a)]
54 | (f))))))))))
55 |
56 | (require (ns-for-sym start-app-sym) :reload)
57 | (require (ns-for-sym stop-app-sym) :reload)
58 |
59 | (when-not (resolve start-app-sym)
60 | (throw (Exception. (str "Can't resolve start-app-sym: " start-app-sym))))
61 |
62 | (when-not (resolve stop-app-sym)
63 | (throw (Exception. (str "Can't resolve stop-app-sym: " stop-app-sym)))))
64 |
65 | (fn []
66 | (time
67 | (do
68 | (when start-app-sym
69 | (binding [*ns* (find-ns 'user)]
70 | (do
71 | (try
72 | (@(resolve stop-app-sym) @(resolve 'user/reup-app))
73 | (catch Exception e
74 | (println "Exception stopping app:" e)))))
75 | (alter-var-root (resolve 'user/reup-app) (constantly nil)))
76 | (let [res (if start-app-sym
77 | (repl/refresh :after 'user/after-reup)
78 | (repl/refresh))]
79 | (when (exception? res)
80 | (throw res)))
81 |
82 | (when tests-regex
83 | (doseq [ns-sym (->> (cp/classpath-directories)
84 | ns-find/find-namespaces
85 | (filter #(re-find tests-regex (str %))))]
86 | (require ns-sym))
87 | (clojure.test/run-all-tests tests-regex))))))
88 |
--------------------------------------------------------------------------------
/src/cljc/clojuredocs/md5.cljc:
--------------------------------------------------------------------------------
1 | (ns clojuredocs.md5
2 | #?(:clj
3 | (:require [clojure.string :as str])
4 | :cljs
5 | (:require [clojure.string :as str]
6 | [goog.crypt :as gcrypt]
7 | [goog.crypt.Md5 :as Md5]
8 | [goog.crypt.Sha1 :as Sha1]
9 | [goog.string :as gstring]
10 | [goog.string.format])))
11 |
12 |
13 |
14 | #?(:cljs
15 | (do
16 | (defn string->bytes [s]
17 | (gcrypt/stringToUtf8ByteArray s)) ;; must be utf8 byte array
18 |
19 | (defn bytes->hex
20 | "convert bytes to hex"
21 | [bytes-in]
22 | (gcrypt/byteArrayToHex bytes-in))
23 |
24 | (defn hash-bytes [digester bytes-in]
25 | (do
26 | (.update digester bytes-in)
27 | (.digest digester)))
28 |
29 | (defn md5-
30 | "convert bytes to md5 bytes"
31 | [bytes-in]
32 | (hash-bytes (goog.crypt.Md5.) bytes-in))
33 |
34 | (defn md5-bytes
35 | "convert utf8 string to md5 byte array"
36 | [string]
37 | (md5- (string->bytes string)))
38 |
39 | (defn md5-hex
40 | "convert utf8 string to md5 hex string"
41 | [string]
42 | (when string
43 | (bytes->hex (md5-bytes string))))))
44 |
45 |
46 |
47 | #? (:clj
48 | (defn md5-hex
49 | "Compute the hex MD5 sum of a string."
50 | [#^String str]
51 | (when str
52 | (let [alg (doto (java.security.MessageDigest/getInstance "MD5")
53 | (.reset)
54 | (.update (.getBytes str)))]
55 | (try
56 | (.toString (new BigInteger 1 (.digest alg)) 16)
57 | (catch java.security.NoSuchAlgorithmException e
58 | (throw (new RuntimeException e))))))))
59 |
--------------------------------------------------------------------------------
/src/cljc/clojuredocs/syntax.cljc:
--------------------------------------------------------------------------------
1 | ;; From https://github.com/holmsand/reagent
2 |
3 | (ns clojuredocs.syntax
4 | (:require [clojure.string :as string]))
5 |
6 | (def builtins #{"def" "defn" "ns" "atom" "let" "if" "when"
7 | "cond" "merge" "assoc" "swap!" "reset!" "for"
8 | "range" "nil?" "int" "or" "->" "->>" "%" "fn" "if-not"
9 | "empty?" "case" "str" "pos?" "zero?" "map" "remove"
10 | "empty" "into" "assoc-in" "dissoc" "get-in" "when-not"
11 | "filter" "vals" "count" "complement" "identity" "dotimes"
12 | "update-in" "sorted-map" "inc" "dec" "false" "true" "not"
13 | "=" "partial" "first" "second" "rest" "list" "conj"
14 | "drop" "when-let" "if-let" "add-watch" "mod" "quot"
15 | "bit-test" "vector"})
16 |
17 | (def styles {:comment {:style {:color "#008200"}}
18 | :str-litt {:style {:color "#2D2DFE"}}
19 | :keyw {:style {:color "#77f"}}
20 | :builtin {:style {:font-weight "normal"
21 | :color "#687868"}}
22 | :def {:style {:color "#55c"
23 | :font-weight "normal"}}})
24 |
25 | (def paren-styles [{:style {:color "#272"}}
26 | {:style {:color "#940"}}
27 | {:style {:color "#44a"}}])
28 |
29 | (defn tokenize [src]
30 | (let [ws " \\t\\n"
31 | open "\\[\\(\\{"
32 | close "\\)\\]\\}"
33 | sep (str ws open close)
34 | comment-p ";.*"
35 | str-p "\"[^\"]*\""
36 | open-p (str "[" open "]")
37 | close-p (str "[" close "]")
38 | iden-p (str "[^" sep "]+")
39 | meta-p (str "\\^" iden-p)
40 | any-p (str "[" ws "]+" "|\\^[^" sep "]+|.")
41 | patt (re-pattern (str "("
42 | (string/join ")|(" [
43 | comment-p
44 | str-p open-p
45 | close-p meta-p iden-p any-p
46 | ])
47 | ")"))
48 | keyw-re #"^:"]
49 | (for [[s comment str-litt open close met iden any] (re-seq patt src)]
50 | (cond
51 | comment [:comment s]
52 | str-litt [:str-litt s]
53 | open [:open s]
54 | close [:close s]
55 | met [:other s]
56 | iden (cond
57 | (re-find keyw-re s) [:keyw s]
58 | (builtins s) [:builtin s]
59 | :else [:iden s])
60 | any [:other s]))))
61 |
62 | (defn format-style-clj [s]
63 | (->> s
64 | (map (fn [[k v]]
65 | (str (name k) ":" v)))
66 | (interpose ";")
67 | (apply str)))
68 |
69 | (defn format-style [{:keys [style] :as opts}]
70 | (assoc opts :style (format-style-clj style)))
71 |
72 | (defn syntaxify [src & opts]
73 | (let [{:keys [stringify-style?]} (apply hash-map opts)
74 | def-re #"^def|^ns\b"
75 | ncol (count paren-styles)
76 | paren-style (fn [level]
77 | (nth paren-styles (mod level ncol)))]
78 | (loop [tokens (tokenize src)
79 | prev nil
80 | level 0
81 | res []]
82 | (let [[kind val] (first tokens)
83 | level' (case kind
84 | :open (inc level)
85 | :close (dec level)
86 | level)
87 | style (case kind
88 | :iden (when (and prev (re-find def-re prev))
89 | (:def styles))
90 | :open (paren-style level)
91 | :close (paren-style level')
92 | (styles kind))
93 | remain (rest tokens)]
94 | (if-not (empty? remain)
95 | (recur remain
96 | (if (= kind :other) prev val)
97 | level'
98 | (conj res [:span
99 | (if stringify-style?
100 | (format-style style)
101 | style)
102 | val]))
103 | (apply vector :pre.syntaxify (conj res [:span style val])))))))
104 |
--------------------------------------------------------------------------------
/src/cljc/clojuredocs/util.cljc:
--------------------------------------------------------------------------------
1 | (ns clojuredocs.util
2 | (:require [clojure.string :as str]
3 | [clojuredocs.md5 :as md5]
4 | #? (:clj [cheshire.core :as json])
5 | #? (:clj [clojure.pprint :refer [pprint]])
6 | #? (:cljs [goog.string :as gstring])
7 | #? (:cljs [cljs.reader :as reader]))
8 |
9 |
10 | #? (:clj
11 | (:import [java.net URLEncoder]
12 | [org.bson.types ObjectId]
13 | [com.vladsch.flexmark.html HtmlRenderer]
14 | [com.vladsch.flexmark.parser Parser]
15 | [com.vladsch.flexmark.profile.pegdown Extensions]
16 | [com.vladsch.flexmark.profile.pegdown PegdownOptionsAdapter]
17 | [com.vladsch.flexmark.util.data DataHolder])))
18 |
19 | #? (:clj
20 | (do
21 | (defn url-encode [s]
22 | (when s
23 | (URLEncoder/encode s)))
24 |
25 |
26 | (defn url-decode [s]
27 | (when s
28 | (java.net.URLDecoder/decode s)))))
29 |
30 | #? (:cljs
31 | (do
32 | (defn url-encode
33 | [string]
34 | (some-> string
35 | str
36 | (js/encodeURIComponent)
37 | (.replace "+" "%20")))
38 |
39 | (defn url-decode [s]
40 | (some-> s
41 | str
42 | js/decodeURIComponent))))
43 |
44 | #? (:clj
45 | (do
46 | (defn html-encode [s]
47 | (when s
48 | (-> s
49 | (str/replace #"&" "&")
50 | (str/replace #"<" "<")
51 | (str/replace #">" ">"))))
52 |
53 | (defn cd-decode [s]
54 | (when s
55 | (cond
56 | (= "_dot" s) "."
57 | (= "_." s) "."
58 | (= "_.." s) ".."
59 | :else (-> s
60 | (str/replace #"_fs" "/")
61 | (str/replace #"_bs" "\\\\")
62 | (str/replace #"_q" "?")
63 |
64 | ;; legacy
65 | (str/replace #"_dot" ".")))))))
66 |
67 | (defn cd-encode [s]
68 | (when s
69 | (cond
70 | (= "." s) "_."
71 | (= ".." s) "_.."
72 | :else (-> s
73 | (str/replace #"/" "_fs")
74 | (str/replace #"\\" "_bs")
75 | (str/replace #"\?" "_q")))))
76 |
77 | (defn var-path [ns name]
78 | (str "/" ns "/" (cd-encode name)))
79 |
80 | (defn $var-link [ns name & contents]
81 | (vec
82 | (concat
83 | [:a {:href (var-path ns name)}]
84 | contents)))
85 |
86 | #? (:cljs
87 | (defn navigate-to [url]
88 | (aset (.-location js/window) "href" url)))
89 |
90 | (def md5 md5/md5-hex)
91 |
92 | #? (:cljs
93 | (defn markdown [s]
94 | (when s
95 | (js/marked s))))
96 |
97 |
98 | #? (:clj
99 | (defn markdown [s]
100 | (when s
101 | (let [OPTIONS (PegdownOptionsAdapter/flexmarkOptions Extensions/ALL
102 | (make-array com.vladsch.flexmark.util.misc.Extension 0))
103 | PARSER (-> (Parser/builder OPTIONS) .build)
104 | RENDERER (-> (HtmlRenderer/builder OPTIONS) .build)]
105 | (->> s (str) (.parse PARSER) (.render RENDERER))))))
106 |
107 | (defn pluralize [n single plural]
108 | (str n " " (if (= 1 n) single plural)))
109 |
110 | (defn now []
111 | #? (:clj
112 | (System/currentTimeMillis)
113 | :cljs
114 | (.now js/Date)))
115 |
116 | (defn profile-url [{:keys [login account-source]}]
117 | (str (if (= "github" account-source)
118 | "/u/"
119 | "/uc/")
120 | login))
121 |
122 | (defn $avatar [{:keys [email login avatar-url account-source] :as user} & [{:keys [size]}]]
123 | (let [size (str (or size 32))]
124 | ^{:key (or avatar-url email)}
125 | [:a.avatar-link
126 | {:href (profile-url user)}
127 | [:img.avatar
128 | {:src (or (str avatar-url "&s=" size)
129 | (str "https://www.gravatar.com/avatar/"
130 | (md5 email)
131 | "?r=PG&s=" size "&default=identicon")) }]]))
132 |
133 | (defn sformat [& args]
134 | #?(:cljs
135 | (apply gstring/format args)
136 | :clj
137 | (apply format args)))
138 |
139 | (defn timeago [millis]
140 | (when millis
141 | (let [ms (- (now) millis)
142 | s (/ ms 1000)
143 | m (/ s 60)
144 | h (/ m 60)
145 | d (/ h 24)
146 | y (/ d 365.0)]
147 | (cond
148 | (< s 60) "less than a minute"
149 | (< m 2) "1 minute"
150 | (< h 1) (str (int m) " minutes")
151 | (< h 2) "1 hour"
152 | (< d 1) (str (int h) " hours")
153 | (< d 2) "1 day"
154 | (< y 1) (str (int d) " days")
155 | :else (str (sformat "%.1f" y) " years")))))
156 |
157 | (defn to-json [o]
158 | #? (:clj
159 | (json/generate-string o)
160 | :cljs
161 | (.stringify js/JSON o)))
162 |
163 | (defn from-json [s]
164 | #? (:clj
165 | (json/parse-string s true)
166 | :cljs
167 | (.parse js/JSON s)))
168 |
169 |
170 | #? (:clj
171 | (defn bson-id
172 | ([]
173 | (ObjectId.))
174 | ([id-or-str]
175 | (ObjectId. (str id-or-str)))))
176 |
177 | #? (:clj
178 | (defn uuid []
179 | (-> (java.util.UUID/randomUUID)
180 | str
181 | (str/replace #"-" ""))))
182 |
183 | #? (:clj
184 | (defn pp-str [o]
185 | (let [w (java.io.StringWriter.)]
186 | (pprint o w)
187 | (str/trim (.toString w)))))
188 |
189 | #? (:cljs
190 | (defn page-data! []
191 | (reader/read-string (aget js/window "PAGE_DATA"))))
192 |
193 |
194 | (defn is-author? [user o]
195 | (= (select-keys user [:login :account-source])
196 | (select-keys (:author o) [:login :account-source])))
197 |
198 |
199 | #? (:cljs
200 | (defn location-hash []
201 | (let [hash-str (.. js/window -location -hash)]
202 | (->> hash-str
203 | (drop 1)
204 | (apply str)
205 | url-decode))))
206 |
207 | (defn ellipsis [n s]
208 | (when s
209 | (let [len (count s)]
210 | (if (> len n)
211 | (str (->> s
212 | (take n)
213 | (apply str)
214 | str/trim)
215 | "...")
216 | s))))
217 |
--------------------------------------------------------------------------------
/src/cljc/nsfw/util.cljc:
--------------------------------------------------------------------------------
1 | (ns nsfw.util
2 | #?(:clj
3 | (:require [clojure.string :as str]
4 | [cheshire.custom :as json]
5 | [clojure.pprint :as pprint]
6 | [camel-snake-kebab.core :as csk]
7 | [cognitect.transit :as transit]
8 | [camel-snake-kebab.core :as csk])
9 | :cljs
10 | (:require [clojure.string :as str]
11 | [cognitect.transit :as transit]
12 | [cljs.pprint :as pprint]
13 | [camel-snake-kebab.core :as csk]))
14 |
15 | #?(:clj
16 | (:import
17 | [java.io ByteArrayInputStream ByteArrayOutputStream StringWriter]
18 | [java.security SecureRandom]
19 | [java.util Date UUID]
20 | [java.text SimpleDateFormat]
21 | [java.net URLDecoder URLEncoder]
22 | [org.bson.types ObjectId]
23 | [org.joda.time DateTime]
24 | [org.joda.time.format ISODateTimeFormat]))
25 | #?(:cljs
26 | (:import [goog.string StringBuffer]))
27 |
28 | (:refer-clojure :exclude [uuid]))
29 |
30 |
31 | (defn now []
32 | #?(:clj
33 | (System/currentTimeMillis)
34 | :cljs
35 | (.now js/Date)))
36 |
37 | (defn pp-str [o]
38 | #?(:clj
39 | (let [w (StringWriter.)]
40 | (pprint/pprint o w)
41 | (.toString w))
42 | :cljs
43 | (let [sb (StringBuffer.)
44 | sbw (StringBufferWriter. sb)]
45 | (pprint/pprint o sbw)
46 | (str sb))))
47 |
48 | #?(:clj (json/add-encoder ObjectId json/encode-str))
49 |
50 | (defn to-json [o & [opts-or-replacer space]]
51 | #?(:clj
52 | (json/generate-string o opts-or-replacer)
53 | :cljs
54 | (.stringify js/JSON (clj->js o) opts-or-replacer space)))
55 |
56 |
57 | #?(:clj
58 | (defn to-transit [o & [opts]]
59 | (let [bs (ByteArrayOutputStream.)]
60 | (transit/write
61 | (transit/writer bs :json opts)
62 | o)
63 | (.toString bs)))
64 | :cljs
65 | (defn to-transit [o & [opts]]
66 | (transit/write
67 | (transit/writer :json opts)
68 | o)))
69 |
70 | #?(:clj
71 | (defn from-transit [s & [opts]]
72 | (when s
73 | (transit/read
74 | (transit/reader
75 | (if (string? s)
76 | (ByteArrayInputStream. (.getBytes s "UTF-8"))
77 | s)
78 | :json
79 | opts))))
80 | :cljs
81 | (defn from-transit [s & [opts]]
82 | (when s
83 | (transit/read
84 | (transit/reader :json opts)
85 | s))))
86 |
87 |
88 | #?(:clj
89 | (defn uuid []
90 | (-> (UUID/randomUUID)
91 | str
92 | (str/replace #"-" ""))))
93 |
94 | #?(:cljs
95 | (defn uuid []
96 | (let [d (now)
97 | uuid-str "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx"]
98 | (str/replace uuid-str
99 | #"[xy]"
100 | (fn [c]
101 | (let [r (bit-or (mod (+ d (* (.random js/Math) 16)) 16) 0)
102 | d (.floor js/Math (/ d 16.0))]
103 | (.toString
104 | (if (= "x" c)
105 | r
106 | (bit-or
107 | (bit-and 0x3 r)
108 | 0x8))
109 | 16)
110 | ))))))
111 |
112 | (defn env-val [o]
113 | (csk/->SCREAMING_SNAKE_CASE o))
114 |
115 | (defn env-case [o]
116 | (env-val o))
117 |
118 | (defn lookup-map [key coll]
119 | (->> coll
120 | (map (fn [o]
121 | [(get o key)
122 | o]))
123 | (into {})))
124 |
125 | (defn throw-str [& args]
126 | #?(:clj
127 | (throw (Exception. (str (apply str args))))
128 | :cljs
129 | (throw (js/Error. (apply str args)))))
130 |
--------------------------------------------------------------------------------
/src/cljs/clojuredocs/ajax.cljs:
--------------------------------------------------------------------------------
1 | (ns clojuredocs.ajax
2 | (:require [goog.net.XhrIo]
3 | [goog.net.EventType :as EventType]
4 | [clojure.string :as str]
5 | [cljs.reader :as reader]))
6 |
7 | (defn validate-ajax-args [{:keys [method]}]
8 | (let [valid-http-methods #{:get
9 | :post
10 | :put
11 | :patch
12 | :delete
13 | :options
14 | :head
15 | :trace
16 | :connect}]
17 | (when-not (get valid-http-methods method)
18 | (throw (str "nsfw.dom/ajax: "
19 | method
20 | " is not a valid ajax method ("
21 | (->> valid-http-methods
22 | (map pr-str)
23 | (interpose ", ")
24 | (apply str))
25 | ")")))))
26 |
27 | (defn safe-name [o]
28 | (when o
29 | (name o)))
30 |
31 | (defn safe-upper-case [s]
32 | (when s
33 | (str/upper-case s)))
34 |
35 | (def ajax-defaults
36 | {:path "/"
37 | :method "GET"
38 | :data {}
39 | :success (fn []
40 | (throw "nsfw.dom/ajax: Unhandled :success callback from AJAX call."))
41 | :error (fn []
42 | (throw "nsfw.dom/ajax: Unhandled :error callback from AJAX call."))})
43 |
44 | (defn parse-headers [s]
45 | (when s
46 | (->> (str/split s #"\n")
47 | (mapcat (fn [header]
48 | (->> (str/split header #":" 2)
49 | (map str/trim))))
50 | (apply hash-map))))
51 |
52 | (defn req->resp [req]
53 | {:headers (parse-headers (.getAllResponseHeaders req))
54 | :status (.getStatus req)
55 | :body (.getResponseText req)
56 | :success (.isSuccess req)})
57 |
58 | (defn json-parse [s]
59 | (.parse js/JSON s))
60 |
61 | (defn json-stringify [s]
62 | (.stringify js/JSON s))
63 |
64 | (defn format-body [{:keys [headers body] :as r}]
65 | (let [content-type (or (-> headers
66 | (get "content-type"))
67 | (-> headers
68 | (get "Content-Type"))
69 | "")
70 | body (condp #(re-find %1 %2) content-type
71 | #"application/json" (-> body
72 | json-parse
73 | (js->clj :keywordize-keys true))
74 | #"application/edn" (reader/read-string body)
75 | body)]
76 | (assoc r :body body)))
77 |
78 | ;; To get around https://code.google.com/p/closure-library/issues/detail?id=642
79 | (defn xhrio-send [url callback method content headers & [timeout-interval with-creds]]
80 | (let [x (goog.net.XhrIo.)]
81 | (when callback
82 | (.listen x EventType/COMPLETE callback))
83 | (.listenOnce x EventType/READY (fn [] (.-dispose x)))
84 | (when timeout-interval
85 | (.setTimeoutInterval x timeout-interval))
86 | (when with-creds
87 | (.setWithCredentials x with-creds))
88 | (.send x url method content headers)))
89 |
90 | (defn ajax [opts]
91 | (let [opts (merge ajax-defaults opts)
92 | opts (if-not (:headers opts)
93 | (assoc opts
94 | :headers (condp = (:data-type opts)
95 | :json {"Content-Type" "application/json;charset=utf-8"}
96 | :edn {"Content-Type" "application/edn;charset=utf-8"}
97 | {"Content-Type" "application/edn;charset=utf-8"}))
98 | opts)
99 | opts (cond
100 | (= :json (:data-type opts))
101 | (assoc opts :data (-> (:data opts)
102 | clj->js
103 | json-stringify))
104 |
105 | (= :edn (:data-type opts))
106 | (assoc opts :data (pr-str (:data opts)))
107 |
108 | :else opts)
109 | {:keys [path method data headers success error data-type]} opts]
110 | (validate-ajax-args opts)
111 | (xhrio-send
112 | path
113 | (fn [e]
114 | (try
115 | (let [req (.-target e)
116 | resp (-> req
117 | req->resp
118 | format-body)]
119 | (if (:success resp)
120 | (success resp)
121 | (error resp)))
122 | (catch js/Object e
123 | (.error js/console (.-stack e))
124 | (throw e))))
125 | (-> method
126 | name
127 | safe-upper-case)
128 | data
129 | (clj->js headers))))
130 |
--------------------------------------------------------------------------------
/src/cljs/clojuredocs/anim.cljs:
--------------------------------------------------------------------------------
1 | (ns clojuredocs.anim
2 | (:require [dommy.core :as dom :refer-macros [sel1]]))
3 |
4 | (defn offset-parents
5 | "a lazy seq of offset parents of `node`"
6 | [elem]
7 | (->> elem
8 | (iterate #(.-offsetParent %))
9 | (take-while identity)))
10 |
11 | (defn offset-top [el]
12 | (->> el
13 | offset-parents
14 | (map #(.-offsetTop %))
15 | (reduce +)))
16 |
17 | (defn tween [el opts]
18 | (js/morpheus el (clj->js opts)))
19 |
20 | (defn scroll-to
21 | [elem & [{:keys [pad]}]]
22 | (let [body (sel1 :body)
23 | html (sel1 :html)
24 | start (max (.-scrollTop body) (.-scrollTop html))
25 | end (- (offset-top elem) pad)]
26 | (.tween js/morpheus
27 | 250
28 | (fn [pos]
29 | (aset body "scrollTop" pos)
30 | (aset html "scrollTop" pos))
31 | nil
32 | nil
33 | start
34 | end)))
35 |
36 | (defn scroll-to-top []
37 | (scroll-to (sel1 :body)))
38 |
39 | ;; From dommy.attrs
40 | (defn bounding-client-rect
41 | "Returns a map of the bounding client rect of `elem`
42 | as a map with [:top :left :right :bottom :width :height]"
43 | [elem]
44 | (let [r (.getBoundingClientRect elem)]
45 | {:top (.-top r)
46 | :bottom (.-bottom r)
47 | :left (.-left r)
48 | :right (.-right r)
49 | :width (.-width r)
50 | :height (.-height r)}))
51 |
52 | (defn scroll-into-view
53 | [elem & [opts]]
54 | (let [{:keys [top bottom] :as res} (bounding-client-rect elem)]
55 | (when (or (< js/window.innerHeight
56 | (+ top (.-offsetHeight elem)))
57 | (< top 0))
58 | (scroll-to elem opts))))
59 |
--------------------------------------------------------------------------------
/src/cljs/clojuredocs/examples.cljs:
--------------------------------------------------------------------------------
1 | (ns clojuredocs.examples
2 | (:require [dommy.core :as dommy :refer-macros [sel1]]
3 | [reagent.core :as rea]
4 | [nsfw.ops :as ops]
5 | [cljs.core.async :as async
6 | :refer [! chan close! sliding-buffer put!
7 | alts! timeout pipe mult tap]]
8 | [clojuredocs.util :as util]
9 | [nsfw.util :as nu]
10 | [clojuredocs.ajax :refer [ajax]]
11 | [clojuredocs.anim :as anim]
12 | [clojuredocs.syntax :as syntax]
13 | [clojure.string :as str]
14 | [cljs.reader :as reader]
15 | [clojure.data :refer [diff]])
16 | (:require-macros [cljs.core.async.macros :refer [go go-loop]]))
17 |
18 | (defn $expando-ta
19 | "A textarea the expands downward with the content (no scroll)"
20 | [text opts]
21 | (let [rows (Math/max
22 | (+ (->> text
23 | (filter #(= "\n" %))
24 | count)
25 | 3)
26 | 10)]
27 | [:textarea
28 | (merge
29 | {:class "form-control"
30 | :autoFocus "autofocus"
31 | :cols 80
32 | :rows rows
33 | :value text}
34 | opts)]))
35 |
36 | (defn eighty-columns []
37 | (let [text " 80 columns "
38 | char "-"
39 | pre-text ";;"
40 | post-text ">"
41 | n (- 80 (count pre-text) (count text) (count post-text))
42 | pre-n (Math/ceil (/ n 2))
43 | post-n (Math/floor (/ n 2))]
44 | (str
45 | pre-text
46 | (apply str (repeat pre-n char))
47 | text
48 | (apply str (repeat post-n char))
49 | post-text)))
50 |
51 | (defn $tabbed-clojure-editor
52 | [!editor bus]
53 | (let [{:keys [text body error create-success? loading? active]
54 | :or {active :editor}} @!editor
55 | text (or text body)]
56 | [:div.tabbed-editor
57 | [:ul.nav.nav-tabs
58 | [:li
59 | {:class (when (= :editor active) "active")}
60 | [:a {:href "#"
61 | :on-click (fn [e]
62 | (.preventDefault e)
63 | (swap! !editor assoc :active :editor)
64 | nil)}
65 | [:i.fa.fa-code] " Editor"]]
66 | [:li
67 | {:class (when (= :preview active) "active")}
68 | [:a {:href "#"
69 | :on-click (fn [e]
70 | (.preventDefault e)
71 | (swap! !editor assoc :active :preview)
72 | nil)}
73 | [:i.fa.fa-eye] " Preview"]]]
74 | [:div {:class (when (= :preview active) "hidden")}
75 | [:div.example-editor
76 | {:class (when loading? "disabled")}
77 | ($expando-ta
78 | text
79 | {:on-change (fn [e]
80 | (let [v (.. e -target -value)]
81 | (.preventDefault e)
82 | (swap! !editor assoc :text v)
83 | false))
84 | :value text
85 | :disabled (when loading? "disabled")
86 | :placeholder "Code Here"})
87 | [:pre.columns-guide (eighty-columns)]]]
88 | [:div.live-preview {:class (when (= :editor active) "hidden")}
89 | (if-not (empty? text)
90 | (syntax/syntaxify text)
91 | [:div.null-state "Live Preview"])]]))
92 |
93 | (defn user-can-delete? [user {:keys [author]}]
94 | (= (select-keys user [:login :account-source])
95 | (select-keys author [:login :account-source])))
96 |
97 | (defn $example-meta [{:keys [can-delete? can-edit?]}
98 | !state
99 | bus]
100 | (let [{:keys [preview-text delete-state editing? _id author editors]} @!state
101 | authors (distinct
102 | (concat
103 | [author]
104 | editors))
105 | num-to-show 7]
106 | [:div.example-meta
107 | [:div.contributors
108 | (->> authors
109 | (take num-to-show)
110 | (map util/$avatar))
111 | (when (> (count authors) num-to-show)
112 | [:div.contributors
113 | "+ "
114 | (- (count authors) num-to-show)
115 | " more"])]
116 | [:div.links
117 | [:a {:href (str "#example-" _id)}
118 | "link"]
119 | #_" / "
120 | #_[:a {:href (str "/ex/" _id)}
121 | "history"]
122 | (when can-edit?
123 | [:span
124 | " / "
125 | (if editing?
126 | [:a {:href "#"
127 | :on-click (fn [e]
128 | (.preventDefault e)
129 | (swap! !state assoc :editing? false)
130 | nil)}
131 | "cancel edit"]
132 | [:a {:href "#"
133 | :on-click (fn [e]
134 | (.preventDefault e)
135 | (swap! !state assoc :editing? true :text nil)
136 | nil)}
137 | "edit"])])
138 | (when (and can-delete? (not editing?))
139 | [:span
140 | " / "
141 | (if (get #{:confirm :loading} delete-state)
142 | (if (= :loading delete-state)
143 | [:img.loading {:src "/img/loading.gif"}]
144 | [:span
145 | [:a {:href "#"
146 | :on-click (fn [e]
147 | (.preventDefault e)
148 | (swap! !state assoc :delete-state :none)
149 | nil)}
150 | "cancel"]
151 | " | "
152 | [:a {:href "#"
153 | :on-click (fn [e]
154 | (.preventDefault e)
155 | (ops/send bus ::delete _id)
156 | nil)}
157 | "confirm delete?"]])
158 | [:span
159 | {:class (when (= :error delete-state) "error-deleting bg-danger")}
160 | [:a {:href "#"
161 | :on-click (fn [e]
162 | (.preventDefault e)
163 | (swap! !state assoc :delete-state :confirm)
164 | nil)}
165 | "delete"]])])
166 | [:span.edit-example-widget]]]))
167 |
168 | (def $example-instructions
169 | [:p.example-instructions
170 | "See our "
171 | [:a {:href "/examples-styleguide"} "examples style guide"]
172 | " for content and formatting guidelines. "
173 | "Examples submitted to ClojureDocs are licensed under the "
174 | [:a {:href "https://creativecommons.org/publicdomain/zero/1.0/"}
175 | "Creative Commons CC0 license"]
176 | "."])
177 |
178 | (defn $example-editor [{:keys [submit-button-text]}
179 | !state
180 | bus]
181 | (let [{:keys [editing? loading? error var body text _id] :as ex} @!state
182 | text (or text body)]
183 | [:div
184 | [$tabbed-clojure-editor !state bus]
185 | $example-instructions
186 | (when error
187 | [:div.form-group
188 | [:div.error-message.text-danger
189 | [:i.fa.fa-exclamation-circle]
190 | error]])
191 | [:div.add-example-controls.form-group.clearfix
192 | [:button.btn.btn-default
193 | {:disabled (when loading? "disabled")
194 | :on-click (fn [e]
195 | (.preventDefault e)
196 | (swap! !state assoc :editing? false :text nil)
197 | nil)}
198 | "Cancel"]
199 | [:button.btn.btn-success.pull-right
200 | {:disabled (when loading? "disabled")
201 | :on-click (fn [e]
202 | (.preventDefault e)
203 | (ops/send bus ::save {:text text
204 | :_id _id})
205 | nil)}
206 | (or submit-button-text "Submit")]
207 | [:img.loading.pull-right
208 | {:class (when-not loading? " hidden")
209 | :src "/img/loading.gif"}]]]))
210 |
211 |
212 | ;; Example API
213 | ;; + [$example opts bus]
214 |
215 | (defn $example [{:keys [can-delete? can-edit?] :as ex}
216 | !state
217 | bus]
218 | (let [{:keys [body editing? _id] :as ex} @!state]
219 | [:div.var-example
220 | {:class (if (= (str "example-" _id) (util/location-hash))
221 | "highlighted")}
222 | [:a {:id (str "example-" _id)}]
223 | [:div
224 | [$example-meta
225 | {:editing? editing?
226 | :can-delete? can-delete?
227 | :can-edit? can-edit?}
228 | !state
229 | bus]]
230 | (if editing?
231 | [:div
232 | [:h5 "Edit Example"]
233 | [$example-editor
234 | {:submit-button-text "Update Example"}
235 | !state
236 | bus]]
237 | (when body
238 | [:div.example-body
239 | (syntax/syntaxify body)]))]))
240 |
241 | (defn $create-example [!state bus]
242 | (let [{:keys [editing? should-focus? var] :as app} @!state]
243 | [:div.add-example {:ref "wrapper"}
244 | [:div.toggle-controls
245 | [:a.toggle-link
246 | {:href "#"
247 | :on-click (fn [e]
248 | (.preventDefault e)
249 | (swap! !state update-in [:editing?] not)
250 | nil)}
251 | (if-not editing? "Add an Example" "Collapse")]]
252 | [:div.add-example-content {:class (when-not editing? " hidden")}
253 | [$example-editor
254 | {:submit-button-text "Add Example"}
255 | !state
256 | bus]]]))
257 |
258 | (defn $examples [!state bus]
259 | (let [{:keys [user examples var] :as app} @!state]
260 | [:div.var-examples
261 | [:h5 (util/pluralize (count examples) "Example" "Examples")]
262 | (if (empty? examples)
263 | [:div.null-state
264 | "No examples for " (:ns var) "/" (:name var) "."]
265 | (->> examples
266 | (map-indexed
267 | (fn [i example]
268 | (with-meta
269 | [$example
270 | {:can-delete? (user-can-delete? user example)
271 | :can-edit? (not (nil? user))}
272 | (rea/cursor !state [:examples i]) bus]
273 | {:key (:_id example)})))))
274 | (if user
275 | [$create-example
276 | (rea/cursor !state [:add-example])
277 | bus]
278 | [:div.login-required-message
279 | "Log in to add an example"])]))
280 |
281 | (defn $examples-widget [!state bus]
282 | [$examples !state bus])
283 |
--------------------------------------------------------------------------------
/src/cljs/clojuredocs/metrics.cljs:
--------------------------------------------------------------------------------
1 | (ns clojuredocs.metrics)
2 |
3 | (defn ga-event [category action label value]
4 | (js/ga "send" "event" category action label value))
5 |
6 | (defn track-search [query]
7 | (ga-event "search" query "count" 1))
8 |
9 | (defn track-search-choose [query choice]
10 | (ga-event "search-choose" query choice 1))
11 |
--------------------------------------------------------------------------------
/src/cljs/clojuredocs/see_alsos.cljs:
--------------------------------------------------------------------------------
1 | (ns clojuredocs.see-alsos
2 | (:require [dommy.core :as dommy :refer-macros [sel1]]
3 | [nsfw.ops :as ops]
4 | [nsfw.page :as page]
5 | [reagent.core :as rea]
6 | [cljs.core.async :as async
7 | :refer [! chan close! sliding-buffer put! alts! timeout pipe mult tap]]
8 | [clojuredocs.ajax :refer [ajax]]
9 | [clojuredocs.anim :as anim]
10 | [clojure.string :as str]
11 | [cljs.reader :as reader]
12 | [clojuredocs.util :as util])
13 | (:require-macros [cljs.core.async.macros :refer [go]]))
14 |
15 | (defn $see-also [opts !sa bus]
16 | (let [{:keys [from-var to-var
17 | created-at
18 | doc
19 | author
20 | can-delete?
21 | delete-state
22 | _id] :as sa} @!sa]
23 | [:div.col-sm-6.see-also
24 | [:div.var-title
25 | (util/$var-link (:ns to-var) (:name to-var)
26 | [:span.ns (:ns to-var) "/"]
27 | [:span.name (:name to-var)])]
28 | [:p
29 | (->> doc
30 | (take 100)
31 | (apply str))
32 | (when (> (count doc) 100)
33 | "...")]
34 | [:div.meta
35 | "Added by "
36 | [:a {:href (util/profile-url author)} (:login author)]
37 | (when can-delete?
38 | [:span.delete-controls
39 | " / "
40 | (condp = delete-state
41 | :loading [:img.loading {:src "/img/loading.gif"}]
42 | :confirm [:span.delete-confirmation
43 | [:a {:href "#"
44 | :on-click (fn [e]
45 | (.preventDefault e)
46 | (swap! !sa assoc :delete-state :none)
47 | nil)}
48 | "cancel"]
49 | " | "
50 | [:a {:href "#"
51 | :on-click (fn [e]
52 | (.preventDefault e)
53 | (ops/send bus ::delete sa)
54 | nil)}
55 | "confirm delete"]]
56 |
57 | [:span
58 | {:class (when (= :error delete-state) "error-deleting bg-danger")}
59 | [:a {:href "#"
60 | :on-click (fn [e]
61 | (.preventDefault e)
62 | (swap! !sa assoc :delete-state :confirm)
63 | nil)}
64 | "delete"]])])]]))
65 |
66 | (defn $add-sa [{:keys [throttle debounce]} !app bus]
67 | (let [handle-ac-text (page/throttle-debounce
68 | (fn [text]
69 | (ops/send bus ::ac-text (or text "")))
70 | {:throttle throttle
71 | :debounce debounce})]
72 | (fn []
73 | (let [{:keys [expanded? loading? completing?
74 | error ac-results ac-text] :as app} @!app]
75 | [:div.add-see-also
76 | [:div.toggle-controls
77 | [:a.toggle-link {:href "#"
78 | :on-click (fn [e]
79 | (.preventDefault e)
80 | (swap! !app update-in [:expanded?] not)
81 | nil)}
82 | (if-not expanded?
83 | "Add See Also"
84 | "Collapse")]]
85 | [:div.add-see-also-content {:class (when-not expanded? "hidden")}
86 | [:form {:autoComplete "off"}
87 | [:input.form-control
88 | {:class (when (or loading? completing?) "loading")
89 | :name "see-also-name"
90 | :ref "input"
91 | :placeholder "Var Name"
92 | :disabled (when loading? "disabled")
93 | :value ac-text
94 | :on-change (fn [e]
95 | (let [text (.. e -target -value)]
96 | (handle-ac-text text)
97 | (swap! !app assoc :ac-text text)))}]
98 | (when error
99 | [:div.error-message.text-danger
100 | [:i.fa.fa-exclamation-circle]
101 | error])]
102 | [:div.ac-results
103 | [:ul
104 | (for [{:keys [ns name disabled? disabled-text] :as res} ac-results]
105 | ^{:key (str ns name)}
106 | [:li.flex-apart
107 | [:div ns "/" name]
108 | (if disabled?
109 | [:button.btn.btn-default.btn-xs
110 | {:disabled "disabled"}
111 | (or disabled-text "Can't Add")]
112 | [:button.btn.btn-success.btn-xs
113 | {:disabled (when loading? "disabled")
114 | :on-click (fn [e]
115 | (.preventDefault e)
116 | (ops/send bus ::create res)
117 | nil)}
118 | "Add"])])]]]]))))
119 |
120 | (defn $see-alsos [!app bus]
121 | (let [{:keys [see-alsos var user add-see-also] :as app} @!app]
122 | [:div
123 | [:h5 "See Also"]
124 | (if (empty? see-alsos)
125 | [:div.null-state
126 | "No see-alsos for " [:code (:ns var) "/" (:name var)]]
127 | (->> see-alsos
128 | (map-indexed
129 | (fn [i sa]
130 | [$see-also {:key i} (rea/cursor !app [:see-alsos i]) bus]))
131 | (partition-all 2)
132 | (map-indexed (fn [i cs] [:div.row
133 | {:key i}
134 | cs]))))
135 | (if user
136 | [$add-sa
137 | {:debounce 100
138 | :throttle 200}
139 | (rea/cursor !app [:add-see-also])
140 | bus]
141 | [:div.login-required-message
142 | "Log in to add a see-also"])]))
143 |
--------------------------------------------------------------------------------
/src/cljs/clojuredocs/sticky.cljs:
--------------------------------------------------------------------------------
1 | (ns clojuredocs.sticky
2 | (:require [dommy.utils :as utils]
3 | [dommy.core :as dom :refer-macros [sel sel1]]
4 | [clojure.string :as str]))
5 |
6 | (defn clog [& args]
7 | (.log js/console (pr-str args)))
8 |
9 | (defn parse-int [s & [default]]
10 | (try
11 | (js/parseInt s)
12 | (catch js/Error e
13 | (if default
14 | default
15 | (throw e)))))
16 |
17 | (defn offset-top [$el]
18 | (loop [y 0
19 | $el $el]
20 | (let [parent (.-offsetParent $el)]
21 | (if-not parent
22 | y
23 | (recur
24 | (+ y (.-offsetTop $el))
25 | parent)))))
26 |
27 | (defn computed-style [$el style-attr]
28 | (let [attr (name style-attr)
29 | v (.getPropertyValue
30 | (.getComputedStyle js/window $el nil)
31 | attr)]
32 | (when (and v (string? v))
33 | (js/parseInt (str/replace v #"px" "")))))
34 |
35 | (defn init [$el]
36 | (let [px-offset (-> $el
37 | (dom/attr :data-sticky-offset)
38 | (parse-int 100))
39 | $parent (-> $el dom/ancestor-nodes second)
40 | starting-offset (atom nil)
41 | f (fn [_]
42 | (if (> (.-pageYOffset js/window) (max @starting-offset (- (offset-top $el) px-offset)))
43 | (let [{:keys [width]} (-> $el
44 | dom/ancestor-nodes
45 | second
46 | dom/bounding-client-rect)
47 | left-padding (computed-style $parent :padding-left)
48 | right-padding (computed-style $parent :padding-right)
49 | left-margin (computed-style $parent :margin-left)
50 | right-margin (computed-style $parent :margin-right)
51 | width (- width left-padding right-padding left-margin right-margin)]
52 | (swap! starting-offset (fn [v]
53 | (if v
54 | v
55 | (- (offset-top $el) px-offset))))
56 | (dom/add-class! $el :sticky)
57 | (dom/set-style! $el
58 | :width (str width "px")
59 | :maxHeight (str js/window.innerHeight "px")
60 | :top (str px-offset "px")))
61 | (do
62 | (reset! starting-offset nil)
63 | (dom/remove-class! $el :sticky))))]
64 | (dom/listen! js/window :scroll f)
65 | (dom/listen! js/window :resize f)
66 | (f nil)
67 | (fn []
68 | (dom/unlisten! js/window :scroll f)
69 | (dom/unlisten! js/window :resize f))))
70 |
--------------------------------------------------------------------------------
/src/cljs/nsfw/ops.cljs:
--------------------------------------------------------------------------------
1 | (ns nsfw.ops
2 | "Provides message-based dispatching and context sharing. This helps
3 | with decoupling disparate parts of an app while sharing a common
4 | context (e.g. app state, windows, connections) between those parts."
5 | (:require [nsfw.util :as util]
6 | [cljs.core.async :as async
7 | :refer [! chan close! sliding-buffer put! take!
8 | alts! timeout pipe mult tap]]
9 | [cljs.core.async.impl.protocols])
10 | (:require-macros [cljs.core.async.macros :refer [go go-loop]]))
11 |
12 | (defprotocol Dispatcher
13 | (send [this op] [this op data])
14 | (bind! [this kw->f])
15 | (unbind! [this kws])
16 | (set-ctx! [this ctx])
17 | (set-debug! [this id f])
18 | (clear-debug! [this id]))
19 |
20 | (defn bus [context handlers & [{:keys [debug?]}]]
21 | (let [!handlers (atom handlers)
22 | !ctx (atom context)
23 | !debug-fns (atom {})
24 | bus (reify
25 | Dispatcher
26 | (send [this op]
27 | (send this op nil))
28 | (send [this op data]
29 | (when-let [msg {::op op ::data data}]
30 | (let [op (or (::op msg) (:op msg))]
31 | (when debug?
32 | (println "[nsfw.ops] Dispatching " op))
33 | (if-let [f (get @!handlers op)]
34 | (do
35 | (f
36 | (merge {:bus this}
37 | @!ctx)
38 | (::data msg)))
39 | (println "[nsfw.ops] No handler for op" msg))
40 | (when-not (empty? @!debug-fns)
41 | (doseq [f (vals @!debug-fns)]
42 | (f op))))))
43 | (bind! [_ kw->f]
44 | (swap! !handlers merge kw->f))
45 | (unbind! [_ kws]
46 | (swap! !handlers
47 | #(apply dissoc % kws)))
48 | (set-ctx! [_ ctx]
49 | (reset! !ctx ctx))
50 | (set-debug! [_ id f]
51 | (swap! !debug-fns assoc id f))
52 | (clear-debug! [_ id]
53 | (swap! !debug-fns dissoc id)))]
54 | bus))
55 |
56 | (defn data [op]
57 | (::data op))
58 |
59 | (defn op [{:keys [op op-id data on-ack on-error auth]}]
60 | {::op op
61 | ::data data
62 | ::op-id (or op-id (util/uuid))
63 | ::on-ack on-ack
64 | ::auth auth
65 | ::on-error on-error})
66 |
67 | (defn wrap-with-state
68 | ([with-state]
69 | (fn [h]
70 | (wrap-with-state h with-state)))
71 | ([h with-state & args]
72 | (fn [state params ctx]
73 | (let [res (h state params ctx)]
74 | (cond
75 | (map? res) (do (with-state res) res)
76 | (vector? res) (let [[state ch] res]
77 | (with-state state)
78 | [state
79 | (async/map
80 | (fn [state]
81 | (with-state state)
82 | state)
83 | [ch])]))))))
84 |
85 |
86 | (defn apply-state [!state state params]
87 | (let [state' (cond
88 | (fn? state) (state @!state)
89 | :else state)]
90 | (reset! !state state')))
91 |
92 | (defn chan? [c]
93 | (satisfies?
94 | cljs.core.async.impl.protocols/Channel
95 | c))
96 |
97 | (defn handle-step [res params !state ctx]
98 | (cond
99 | (chan? res) (go-loop []
100 | (when-let [res (> handlers
138 | (map (fn [[k v]]
139 | [k (gen-lock-step v)]))
140 | (into {})))
141 |
142 | (defn kit [!state ctx handlers & [opts]]
143 | (bus
144 | (assoc ctx :!state !state)
145 | (wrap-kit-handlers handlers)
146 | opts))
147 |
--------------------------------------------------------------------------------
/src/examples/clj/first.clj:
--------------------------------------------------------------------------------
1 | ;; Let's define some data using list / map
2 | ;; literals:
3 |
4 | (def scenes [{:subject "Frankie"
5 | :action "say"
6 | :object "relax"}
7 |
8 | {:subject "Lucy"
9 | :action "❤s"
10 | :object "Clojure"}
11 |
12 | {:subject "Rich"
13 | :action "tries"
14 | :object "a new conditioner"}])
15 |
16 | ;; Define a function
17 | (defn people-in-scenes [scenes]
18 | (->> scenes
19 | (map :subject)
20 | (interpose ", ")
21 | (reduce str)))
22 |
23 |
24 | ;; Who's in our scenes?
25 |
26 | (println "People:" (people-in-scenes scenes))
27 |
28 | ;;=> People: Frankie, Lucy, Rich
29 |
--------------------------------------------------------------------------------
/src/md/api/overview.md:
--------------------------------------------------------------------------------
1 | The ClojureDocs API is used (mainly) to support dynamic content on the site.
2 |
3 | ## Requests
4 |
5 | ### Authentication
6 |
7 | Most POSTs, PUTs, and DELETEs require authentication, where most GETs
8 | don't. See specific endpoint documentation for requirements.
9 |
10 | ### Parameters
11 |
12 | Parameters for GET and DELETE requests are sent as either part of the
13 | request path (`GET /api/examples/:id`), or as query parameters (`GET
14 | /api/examples?sort=desc`).
15 |
16 | ### Request Bodies
17 |
18 | POST and PATCH requests bodies are [EDN](https://github.com/edn-format/edn) encoded.
19 |
20 |
21 | ## Responses
22 |
23 | ClojureDocs responds with EDN encoded bodies.
24 |
25 |
26 | ### Errors
27 |
28 | Here are some common errors you'll encounter using the ClojureDocs API:
29 |
30 | Failure to send an EDN encoded body:
31 |
32 | ```
33 | ;; HTTP/1.1 415 Unsupported Media Type
34 |
35 | {:message "Request must be Content-Type application/edn"}
36 | ```
37 |
38 |
39 | Sending invalid EDN
40 |
41 | ```
42 | HTTP/1.1 400 Bad Request
43 |
44 | {:message "Error parsing request body as EDN"}
45 | ```
46 |
47 | Trying to POST / DELETE while unauthenticated
48 |
49 | ```
50 | HTTP/1.1 401 Unauthorized
51 |
52 | {:message "Unauthorized"}
53 | ```
54 |
55 | Payload validation errors
56 |
57 | ```
58 | HTTP/1.1 422 Unprocessable Entity
59 |
60 | {:errors [{:field "body" :message "Body can't be empty"}
61 | {:field "var" :message "That var doesn't exist"}]}
62 | ```
63 |
64 | Occasionally, you might run into a server error
65 |
66 | ```
67 | HTTP/1.1 500 Internal Server Error
68 |
69 | {:message "There was a problem processing your request"}
70 | ```
71 |
--------------------------------------------------------------------------------
/src/md/concepts/destructuring.md:
--------------------------------------------------------------------------------
1 | # Destructuring in Clojure
2 |
3 | In Clojure, destructuring is a shorthand for assigning names to parts
4 | of data structures based on their forms. Don't worry if that's
5 | confusing at first, it becomes very clear with a few examples.
6 |
7 | Suppose we have a function that prints a greeting based on a user's
8 | name, title, and location.
9 |
10 | Here we'll manually pull out the name, title, and location from the
11 | `user` parameter (a Map), and create bindings named `name`, `title`,
12 | and `location` via [`let`](/clojure.core/let).
13 |
14 | ```
15 | (defn greet [user]
16 | (let [name (:name user)
17 | location (:location user)]
18 | (println "Hey there" name ", how's the weather in" location "?")))
19 |
20 | (greet {:name "Josie" :location "San Francisco"})
21 | ;; Hey there Josie, how's the weather in San Francisco?
22 | ;;=> nil
23 |
24 | (greet {:name "Ivan" :location "Moscow"})
25 | ;; Hey there Ivan, how's the weather in Moscow?
26 | ;;=> nil
27 |
28 | ```
29 |
30 | Destructuring lets us specify naming of the parameters directly from the
31 | structure of the passed map:
32 |
33 | ```
34 | (defn greet2 [{:keys [name location]}]
35 | (println "Hey there" name ", how's the weather in" location "?"))
36 |
37 | (greet2 {:name "Josie" :location "San Francisco"})
38 | ;; Hey there Josie, how's the weather in San Francisco?
39 | ;;=> nil
40 |
41 |
42 | ```
43 |
44 | * For more detailed take on destructuring see Daniel Gregoire's [blog post](https://danielgregoire.dev/posts/2021-06-13-code-observation-clojure-destructuring/).
45 | * Bruno Bonacci's [guide on destructuring](https://blog.brunobonacci.com/2014/11/16/clojure-complete-guide-to-destructuring/) is worth a look.
46 | * Jay Field's [introductory blog post](http://blog.jayfields.com/2010/07/clojure-destructuring.html) provides a good starting point.
47 | * See John Del Rosario's [destructuring cheat sheet](https://gist.github.com/john2x/e1dca953548bfdfb9844) for a more comprehensive overview.
48 | * Also there is [the official Clojure guide on destructuring](https://clojure.org/guides/destructuring).
49 |
--------------------------------------------------------------------------------
/src/md/concepts/functional-programming.md:
--------------------------------------------------------------------------------
1 | ##### Community Links
2 | * [A beginners guide to functional programming](http://mooc.cs.helsinki.fi/clojure)
3 |
--------------------------------------------------------------------------------
/src/md/core-library.md:
--------------------------------------------------------------------------------
1 | # Clojure's Core Library
2 |
3 | Clojure's standard library, i.e. the `clojure.*` namespaces, provide a
4 | ton of general-purpose functionality for writing robust, maintainable
5 | applications.
6 |
7 | Getting a handle on all the functionality you'll want to use can be a
8 | little daunting at first, especially if you're coming from
9 | object-oriented languages like Java, Ruby, or Python, where behavior
10 | is grouped using classes. In Clojure, namespaces are used to group
11 | similar behavior and state, and we've outlined a few of the core
12 | namespaces to help you find what you're looking for.
13 |
14 | We have a
15 | [page listing all functions, macros, and other vars in Clojure's core library](/core-library/vars)
16 | as well.
17 |
--------------------------------------------------------------------------------
/src/md/examples-styleguide.md:
--------------------------------------------------------------------------------
1 | # ClojureDocs Example Submission Guidelines
2 |
3 | The example sections on each var page are there to provide simple, isolated examples of var usage. In a nutshell, the examples you add to Clojuredocs should be easy to understand, and to help you with that we've outlined a few guidelines below.
4 |
5 | ## General Guidelines
6 |
7 | Examples should be short, unique, self-contained snippets of code that illustrate var usage in the simplest possible way.
8 |
9 | * Try to imagine clear conceptual boundaries of your example before submitting it.
10 | * Assume the reader has a background in software development, with little Clojure experience.
11 | * Short, sweet, and complete is the name of the game.
12 |
13 | If the target var is not part of the core ns (or otherwise not use
d by default) please include the use
/ require
statement.
14 |
15 | Bad:
16 |
17 | 18 | 19 | (sh "ls" "-aul") 20 | 21 | ;; {:exit 0, 22 | ;; :out "total 64 23 | ;; drwxr-xr-x 11 zkim staff 374 Jul 5 13:21 ." 24 | ;; ... 25 |26 | 27 | Good: 28 | 29 |
30 | (use '[clojure.java.shell :only [sh]]) 31 | 32 | (sh "ls" "-aul") 33 | 34 | ;; {:exit 0, 35 | ;; :out "total 64 36 | ;; drwxr-xr-x 11 zkim staff 374 Jul 5 13:21 ." 37 | ... 38 |39 | 40 | Each example should be either broad, or deep, not both. For example, the following example for
not=
shows the broad range of inputs allowed.
41 |
42 | 43 | (not= 1 1) ;;=> false 44 | 45 | (not= 1 2) ;;=> true 46 | 47 | (not= true true) ;;=> false 48 | 49 | (not= true false) ;;=> true 50 | 51 | (not= true true true true) ;;=> false 52 | 53 | (not= true true false true) ;;=> true 54 |55 | 56 | Where this example for
future
has depth.
57 |
58 | 59 | ;; A future is calculated in another thread 60 | (def f (future (Thread/sleep 10000) 100)) 61 | ;;=> #'user/f 62 | 63 | ;; When you dereference it you will block until the result is available. 64 | @f 65 | ;;=> 100 66 | 67 | ;; Dereferencing again will return the already calculated value immediately. 68 | @f 69 | ;;=> 100 70 |71 | 72 | Also, please mention any gotchas you feel are associated with your example (specifically) or the var (in general). 73 | 74 | ## Comments 75 | 76 | Comments should be used to describe the following code block or blocks and/or point out bits of information that may not be obvious to new Clojure devs. 77 | 78 | Bad: 79 | 80 |
81 | (with-precision 10 (/ 1M 3)) 82 | ;;=> 0.3333333333M 83 | 84 | user=> (.floatValue 0.3333333333M) 85 | ;;=> 0.33333334 86 |87 | 88 | Good: 89 | 90 |
91 | ;; The "M" suffix denotes a BigDecimal instance 92 | ;; http://download.oracle.com/javase/6/docs/api/java/math/BigDecimal.html 93 | 94 | (with-precision 10 (/ 1M 3)) 95 | ;;=> 0.3333333333M 96 | 97 | (.floatValue 0.3333333333M) 98 | ;;=> 0.33333334 99 |100 | 101 |
;;
should be for a general comment about a block of code, ;
should be used to add a comment to the end of a line of code.
102 |
103 | Bad:
104 |
105 | 106 | ; This function will print 'hello world' to the console 107 | (defn hello-world [] 108 | (println "hello world")) ;; Does the actual printing 109 |110 | 111 | Good: 112 | 113 |
114 | ;; This function will print 'hello world' to the console 115 | (defn hello-world [] 116 | (println "hello world")) ; Does the actual printing 117 |118 | 119 | Differentiating code from context in your example will help 120 | 121 | Using comments to differentiate code from context and output will help new Clojure devs match up the executable parts of your example in their REPLs. 122 | 123 | Good: 124 | 125 |
126 | ;; You can use destructuring to have keyword arguments. This would be a pretty 127 | ;; verbose version of map (in an example a bit more verbose than the first above): 128 | 129 | (defn keyworded-map [& {function :function sequence :sequence}] 130 | (map function seq)) 131 | 132 | 133 | ;; You call it like this: 134 | 135 | (keyworded-map :sequence [1 2 3] :function #(+ % 2)) 136 | ;;=> (3 4 5) 137 | 138 | 139 | ;; The declaration can be shortened with ":keys" if your local variables should be 140 | ;; named in the same way as your keys in the map: 141 | 142 | (defn keyworded-map [& {:keys [function sequence]}] 143 | (map function sequence)) 144 |145 | 146 | Feel free to omit comments for very simple examples. 147 | 148 | ## Indentation / Formatting 149 | 150 | Please follow the conventions outlined in this [Scheme style guide](http://mumble.net/~campbell/scheme/style.txt), which follows Emacs' (among others) indentation and formatting conventions. We realize that code style can often be largely dictated by personal preference, however, uniformity across examples on ClojureDocs is important. 151 | 152 | Lines should have a maximum width of 80 characters to prevent wrapping when displayed on ClojureDocs pages, and please indent with spaces, not tabs. 153 | 154 | Consider leaving one line of whitespace after output from the repl to make your examples easier to visually scan. 155 | 156 | Bad: 157 | 158 |
159 | (println "foo") 160 | ;; foo 161 | ;;=> nil 162 | (println "bar") 163 | ;; bar 164 | ;;=> nil 165 | (println "baz") 166 | ;; baz 167 | ;;=> nil 168 |169 | 170 | 171 | Good: 172 | 173 |
174 | (println "foo") 175 | ;; foo 176 | ;;=> nil 177 | 178 | (println "bar") 179 | ;; bar 180 | ;;=> nil 181 | 182 | (println "baz") 183 | ;; baz 184 | ;;=> nil 185 |186 | 187 | 188 | ## Linking 189 | 190 | Urls in examples source are automatically converted to links. Feel free to use them where appropriate to link to external resources. 191 | -------------------------------------------------------------------------------- /src/md/namespaces/clojure.core.async.md: -------------------------------------------------------------------------------- 1 | A Clojure library providing facilities for async programming and communication. 2 | 3 | **Core.async is not provided as part of Clojure's standard distribution, and must be included as a [dependency](https://github.com/clojure/core.async#releases-and-dependency-information)**. 4 | 5 | 6 | ##### Community Links 7 | 8 | * [Blog post announcing core.async](https://clojure.org/news/2013/06/28/clojure-clore-async-channels) 9 | * [Source repo](https://github.com/clojure/core.async) 10 | * [Rich Hickey on core.async](http://www.infoq.com/presentations/clojure-core-async) (video) 11 | * [Communicating Sequential Processes](http://swannodette.github.io/2013/07/12/communicating-sequential-processes) by David Nolen 12 | * [Brave Clojure: Mastering Concurrent Processes with core.async](http://www.braveclojure.com/core-async/) 13 | * [Go Block Best Practices](https://github.com/clojure/core.async/wiki/Go-Block-Best-Practices) 14 | -------------------------------------------------------------------------------- /src/md/namespaces/clojure.core.logic.md: -------------------------------------------------------------------------------- 1 | **Core.logic is not provided as part of Clojure's standard distribution, and must be included as a [dependency](https://github.com/clojure/core.logic#releases-and-dependency-information)**. 2 | -------------------------------------------------------------------------------- /src/md/namespaces/clojure.core.md: -------------------------------------------------------------------------------- 1 | The largest of the core namespaces, `clojure.core` provides the bulk of the functionality 2 | you'll be using to build Clojure programs. 3 | 4 | There are too many core functions to feature here, but take a look at the 5 | [quickref](/quickref) to get a breakdown by conceptual arena. 6 | -------------------------------------------------------------------------------- /src/md/namespaces/clojure.core.server.md: -------------------------------------------------------------------------------- 1 | clojure.core.server contains functions to expose the Clojure environment through a socket connection and across network boundaries. If the property `-Dclojure.server.repl="{:port 8881 :accept clojure.core.server/repl}"` is present when the JDK starts, Clojure will start the related socket server (or more than one) on the specified port. The API in the namespace allows to do this programmatically. 2 | -------------------------------------------------------------------------------- /src/md/namespaces/clojure.edn.md: -------------------------------------------------------------------------------- 1 | Extensible Data Notation is a subset of the Clojure language used as a 2 | data transfer format, designed to be used in a similar way to JSON or 3 | XML. 4 | 5 | At some point in your adventures in Clojure land, you'll want to 6 | deserialize some clojure data structures from a string, and you'll 7 | want to use [clojure.edn/read](/clojure.edn/read) or 8 | [clojure.edn/read-string](/clojure.edn/read-string) for that. **Do not 9 | use** the `read-*` functions in `clojure.core` to deserialize untrusted Clojure code, as [they can be unsafe](http://www.learningclojure.com/2013/02/clojures-reader-is-unsafe.html). 10 | 11 | ##### Community Links 12 | 13 | * [Official EDN Spec](http://edn-format.org) 14 | * [Official documentation for clojure.edn](https://clojure.github.io/clojure/clojure.edn-api.html) 15 | * [EDN walkthrough by Mark Mandel](http://www.compoundtheory.com/clojure-edn-walkthrough) 16 | -------------------------------------------------------------------------------- /src/md/namespaces/clojure.pprint.md: -------------------------------------------------------------------------------- 1 | Pretty printing utility, really nice for looking at larger-ish data structures. See [pprint](/clojure.pprint/pprint). 2 | -------------------------------------------------------------------------------- /src/md/namespaces/clojure.set.md: -------------------------------------------------------------------------------- 1 | Functions for working on sets (`#{1 2 3 4}`) in all the ways you'd expect, e.g. calculating the [intersection](/clojure.set/intersection) of two sets, and testing if one set is a [subset](/clojure.set/subset_q) of another. 2 | -------------------------------------------------------------------------------- /src/md/namespaces/clojure.string.md: -------------------------------------------------------------------------------- 1 | Provides most standard string manipulation and processing function 2 | that you'd expect in any general-purpose programming language. 3 | 4 | In Clojure and ClojureScript strings are represented using the native 5 | platform implementation, and can be directly manipulated, 6 | e.g. `(.toLowerCase "FOO") ;=> "foo"`. The `clojure.string` namespace 7 | gives you the ability to manipulate strings in an idiomatic way: 8 | `(clojure.string/lower-case "FOO") ;=> "foo"`. 9 | 10 | Something to keep in mind is most (all?) of these functions take the 11 | string to act on as the first parameter, lending themselves well for 12 | use with the single-thrush operator (->) 13 | , as in this contrived example: 14 | 15 |
16 | (require '[clojure.string :as str]) 17 | 18 | (-> " .LIRpa ni yAD dloc thgIrb a sAw Ti " 19 | str/reverse 20 | str/trim 21 | str/lower-case 22 | (str/replace #"\s+" " ") 23 | str/capitalize) 24 | 25 | ;;=> "It was a bright cold day in april" 26 |27 | -------------------------------------------------------------------------------- /src/md/namespaces/clojure.test.md: -------------------------------------------------------------------------------- 1 | Provides basic facilities for unit testing Clojure code. 2 | 3 | * [Official Docs](http://clojure.github.io/clojure/clojure.test-api.html) 4 | * [Introduction to clojure.test by Jay Fields](http://blog.jayfields.com/2010/08/clojuretest-introduction.html) 5 | -------------------------------------------------------------------------------- /src/md/namespaces/clojure.zip.md: -------------------------------------------------------------------------------- 1 | Functional tree editing and manipulation. One of the core benefits of using Clojure is that you mostly work with immutable data structures. This, in turn, seems to make your programs easier to build and maintain. 2 | 3 | 4 | ##### Community Links 5 | 6 | * ["Editing" Trees in Clojure](http://www.exampler.com/blog/2010/09/01/editing-trees-in-clojure-with-clojurezip) 7 | * [Tim Baldrage's video walkthrough of Zippers](https://tbaldridge.pivotshare.com/media/zippers-episode-1/11348/feature) 8 | * ["The Art of Tree Shaping with Zippers" a talk by Arne Brasseur, at the Den of Clojure meetup in Denver](https://www.youtube.com/watch?v=5Nm56YvTKZY) 9 | * ["Clojure Zippers" blog post by Ivan Grishaev](https://grishaev.me/en/clojure-zippers/) 10 | -------------------------------------------------------------------------------- /system.properties: -------------------------------------------------------------------------------- 1 | java.runtime.version=1.7 -------------------------------------------------------------------------------- /test/clojuredocs/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojuredocs.core-test 2 | (:require [clojure.test :refer :all] 3 | [clojuredocs.core :refer :all])) 4 | 5 | (deftest a-test 6 | (testing "FIXME, I fail." 7 | (is (= 0 1)))) 8 | -------------------------------------------------------------------------------- /tools/dev_export.clj: -------------------------------------------------------------------------------- 1 | (ns tools.dev-export 2 | (:require [somnium.congomongo :as mon] 3 | [clojure.java.shell :as sh])) 4 | -------------------------------------------------------------------------------- /tools/sanity_check.clj: -------------------------------------------------------------------------------- 1 | (ns tools.sanity-check 2 | (:require [clojure.java.jdbc :as j] 3 | [clojure.pprint :refer (pprint)] 4 | [clojure.string :as str] 5 | [somnium.congomongo :as mon] 6 | [clojuredocs.data :as data] 7 | [clojuredocs.util :as util] 8 | [clojure.set :as set])) 9 | 10 | (def mysql-db {:subprotocol "mysql" 11 | :subname "//127.0.0.1:3306/clojuredocs" 12 | :user "root" 13 | :password ""}) 14 | 15 | (defn all-users [] 16 | (j/query mysql-db ["SELECT * FROM users"])) 17 | 18 | (defn clojure-core-lib [] 19 | (first (j/query mysql-db ["SELECT * FROM libraries WHERE id=3"]))) 20 | 21 | (defn clojure-core-lib [] 22 | (first (j/query mysql-db ["SELECT * FROM libraries WHERE id=3"]))) 23 | 24 | (defn core-nss [] 25 | (j/query mysql-db ["SELECT * FROM namespaces WHERE library_id=3 OR library_id=15"])) 26 | 27 | (defn core-functions [] 28 | (let [ns-ids (map :id (core-nss))] 29 | (j/query mysql-db [(format "SELECT * FROM functions WHERE namespace_id IN (%s)" 30 | (->> ns-ids 31 | (interpose ",") 32 | (apply str)))]))) 33 | 34 | (defn core-examples [] 35 | (let [fids (map :id (core-functions))] 36 | (j/query mysql-db [(format "SELECT * FROM examples WHERE function_id IN (%s)" 37 | (->> fids 38 | (interpose ",") 39 | (apply str)))]))) 40 | 41 | (defn core-see-alsos [] 42 | (let [fs (core-functions) 43 | fids (map :id fs) 44 | comma-sep (->> fids 45 | (interpose ",") 46 | (apply str)) 47 | sas (j/query mysql-db 48 | [(format "SELECT * FROM see_alsos WHERE from_id IN (%s)" 49 | comma-sep 50 | comma-sep)])] 51 | sas)) 52 | 53 | (defn core-notes [] 54 | (let [fs (core-functions) 55 | fids (map :id fs) 56 | comma-sep (->> fids 57 | (interpose ",") 58 | (apply str)) 59 | notes (j/query mysql-db 60 | [(format "SELECT * FROM comments WHERE commentable_id IN (%s)" 61 | comma-sep)])] 62 | notes)) 63 | 64 | #_(->> (core-functions) 65 | (map :id) 66 | (mapcat #(j/query mysql-db 67 | [(format "SELECT * FROM comments WHERE commentable_id=%s" 68 | %)])) 69 | (remove empty?) 70 | count) 71 | 72 | (defn all-functions [] 73 | (j/query mysql-db ["SELECT * FROM functions"])) 74 | 75 | (defn all-notes [] 76 | (j/query mysql-db ["SELECT * FROM comments"])) 77 | 78 | (defn process-notes [lookup ns] 79 | (->> ns 80 | (map (fn [{:keys [id body commentable_id]}] 81 | (let [{:keys [name file] :as l} (lookup commentable_id)] 82 | (when l 83 | {:id id 84 | :body body 85 | :name name 86 | :file file})))) 87 | (sort-by :file) 88 | (remove nil?))) 89 | 90 | 91 | (defn render-note-overview [{:keys [file name body]}] 92 | (format "%s -- %s %s" 93 | file 94 | name 95 | (->> body 96 | (take 50) 97 | (apply str) 98 | pr-str))) 99 | 100 | #_(let [cfs (core-functions) 101 | afs (all-functions) 102 | lookup (reduce #(assoc %1 (:id %2) %2) {} afs) 103 | cnotes (core-notes) 104 | anotes (all-notes) 105 | cnotes-prime (process-notes lookup cnotes) 106 | anotes-prime (process-notes lookup anotes)] 107 | (doseq [n (set/difference (set anotes-prime) (set cnotes-prime))] 108 | (println (render-note-overview n))) 109 | (println "CORE NOTES:" (count cnotes-prime)) 110 | (println "ALL NOTES:" (count anotes-prime))) 111 | 112 | 113 | (do 114 | (println "-- Core Examples") 115 | (println "MySQL:" (count (core-examples))) 116 | (println "Mongo:" (count (mon/fetch :examples)))) 117 | 118 | 119 | (do 120 | (println "-- Users") 121 | (println "MySQL:" (count (all-users))) 122 | (println "Mongo:" (count (mon/fetch :users))) 123 | (println "Duplicate usernames:" (->> (all-users) 124 | (map :login) 125 | (reduce #(assoc %1 %2 (inc (%1 %2 0))) {}) 126 | (sort-by second) 127 | (filter #(> (second %) 1))))) 128 | 129 | (do 130 | (println "-- See Alsos") 131 | (println "MySQL:" (count (core-see-alsos))) 132 | (println "Mongo:" (count (mon/fetch :see-alsos)))) 133 | 134 | (do 135 | (println "-- Notes") 136 | (println "MySQL:" (count (core-notes))) 137 | (println "Mongo:" (count (mon/fetch :notes)))) 138 | -------------------------------------------------------------------------------- /tools/top_contribs.clj: -------------------------------------------------------------------------------- 1 | (ns tools.top-contribs 2 | (:require [somnium.congomongo :as mon] 3 | [clojure.pprint :refer (pprint)])) 4 | 5 | 6 | (def scores (atom {})) 7 | 8 | (time (doseq [{:keys [history]} (mon/fetch :examples)] 9 | (let [history (reverse history) 10 | first-user (-> history first :user)] 11 | (swap! scores update-in [first-user] #(+ 4 (or % 0))) 12 | (doseq [user (->> history rest (map :user))] 13 | (swap! scores update-in [user] #(inc (or % 0))))))) 14 | 15 | 16 | (->> @scores 17 | (sort-by second) 18 | reverse 19 | (take 24) 20 | (map #(assoc (first %) :score (second %))) 21 | pprint) 22 | --------------------------------------------------------------------------------