├── .github └── workflows │ ├── deploy.yaml │ └── release-pdf.yaml ├── .gitignore ├── Boot ├── boot.adoc ├── build.boot ├── build.boot.sample ├── docinfo.html └── script ├── Collections-and-Sequences ├── collections-and-sequences.adoc ├── docinfo.html └── subs │ └── zipper.adoc ├── Design-Patterns ├── coderay-asciidoctor.css ├── design-patterns.adoc ├── docinfo.html └── sub │ ├── clojure-and-gof-design-patterns.adoc │ └── translation.txt ├── Destructuring ├── destructuring.adoc └── docinfo.html ├── Development-Environments ├── atom.adoc ├── development-environments.adoc ├── docinfo.html ├── emacs.adoc ├── img │ ├── atom-ink-install.png │ ├── atom-proto-repl-install.png │ ├── emacs-clojure-mode.png │ ├── intellij-cursive-install.png │ ├── intellij-eval-in-edit.png │ ├── intellij-eval-in-repl.png │ ├── intellij-ns-change.png │ ├── intellij-ns-eval.png │ ├── intellij-open-new-jdk.png │ ├── intellij-open-project.png │ ├── intellij-plugins.png │ ├── intellij-repl-register-1.png │ ├── intellij-repl-register-2.png │ ├── intellij-repl-run.png │ ├── intellij-select-jdk.png │ ├── lighttable.png │ ├── vscode-calva-install.png │ ├── vscode-eval-in-edit.png │ ├── vscode-eval-in-repl.png │ ├── vscode-file-eval.png │ ├── vscode-repl-connect.png │ ├── vscode-repl-namespace.png │ ├── vscode-repl-start.png │ ├── vscode-start.png │ ├── windows-appdata-no-show.png │ └── windows-appdata-show.png ├── intellij.adoc └── vscode.adoc ├── Flow-Controls ├── docinfo.html └── flow-controls.adoc ├── Functional-Programming ├── docinfo.html └── functional-programming.adoc ├── Java-Interoperability ├── docinfo.html └── java-interoperability.adoc ├── Namespaces-and-Libraries ├── docinfo.html └── namespaces-and-libraries.adoc ├── Preface ├── docinfo.html └── preface.adoc ├── README.adoc ├── Simple-Values ├── docinfo.html ├── simple-values.adoc └── sub │ ├── numbers.adoc │ └── strings.adoc ├── Start ├── docinfo.html └── start.adoc ├── Testing ├── docinfo.html └── testing.adoc ├── asciidoctor-theme └── notosansmono-cjk-kr │ ├── .DS_Store │ ├── fonts │ ├── LICENSE │ ├── notosansmono-cjk-kr-bold.ttf │ ├── notosansmono-cjk-kr-bold_italic.ttf │ ├── notosansmono-cjk-kr-italic.ttf │ └── notosansmono-cjk-kr-normal.ttf │ └── themes │ ├── LICENSE │ ├── LICENSE-asciidoctor-pdf │ ├── LICENSE-asciidoctor-pdf-cjk-kai_gen_gothic │ ├── default-ext-notosansmono-cjk-kr-pdf-1-theme.yml │ ├── default-ext-notosansmono-cjk-kr-theme.yml │ ├── default-notosansmono-cjk-kr-pdf-1-theme.yml │ ├── default-notosansmono-cjk-kr-theme.yml │ ├── notosansmono-cjk-kr-pdf-1-theme.yml │ └── notosansmono-cjk-kr-theme.yml ├── asciidoctor.css ├── clojure-complete-html.adoc ├── clojure-complete-pdf.adoc ├── coderay-asciidoctor.css ├── docinfo.html ├── guide ├── asciidoctor.adoc ├── asciidoctor.css ├── asciidoctor.pdf ├── asciidoctor.pdfmarks ├── chores.rb ├── coderay-asciidoctor.css ├── demo.adoc ├── docinfo.html └── to-html.sh ├── my-asciidoctor.css ├── src └── java-interop │ ├── .gitignore │ ├── .idea │ ├── .name │ ├── compiler.xml │ ├── copyright │ │ └── profiles_settings.xml │ ├── encodings.xml │ ├── libraries │ │ ├── Leiningen__args4j_2_0_26.xml │ │ ├── Leiningen__cider_cider_nrepl_0_10_0.xml │ │ ├── Leiningen__clojure_complete_0_2_3.xml │ │ ├── Leiningen__com_cemerick_piggieback_0_2_1.xml │ │ ├── Leiningen__com_google_code_findbugs_jsr305_1_3_9.xml │ │ ├── Leiningen__com_google_code_gson_gson_2_2_4.xml │ │ ├── Leiningen__com_google_guava_guava_18_0.xml │ │ ├── Leiningen__com_google_javascript_closure_compiler_externs_v20150126.xml │ │ ├── Leiningen__com_google_javascript_closure_compiler_v20150126.xml │ │ ├── Leiningen__com_google_protobuf_protobuf_java_2_5_0.xml │ │ ├── Leiningen__com_google_truth_truth_0_24.xml │ │ ├── Leiningen__criterium_0_4_3.xml │ │ ├── Leiningen__http_kit_2_1_18.xml │ │ ├── Leiningen__junit_4_10.xml │ │ ├── Leiningen__org_clojure_clojure_1_7_0.xml │ │ ├── Leiningen__org_clojure_clojurescript_0_0_3165.xml │ │ ├── Leiningen__org_clojure_data_json_0_2_6.xml │ │ ├── Leiningen__org_clojure_google_closure_library_0_0_20140718_946a7d39.xml │ │ ├── Leiningen__org_clojure_google_closure_library_third_party_0_0_20140718_946a7d39.xml │ │ ├── Leiningen__org_clojure_tools_nrepl_0_2_12.xml │ │ ├── Leiningen__org_clojure_tools_reader_0_8_16.xml │ │ ├── Leiningen__org_hamcrest_hamcrest_core_1_1.xml │ │ ├── Leiningen__org_mozilla_rhino_1_7R5.xml │ │ ├── Leiningen__org_tcrawley_dynapath_0_2_3.xml │ │ ├── Leiningen__prismatic_schema_1_0_3.xml │ │ └── Leiningen__weasel_0_7_0.xml │ ├── misc.xml │ ├── modules.xml │ └── workspace.xml │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── doc │ └── intro.md │ ├── java-interop.iml │ ├── project.clj │ ├── src │ └── java_interop │ │ ├── Example3.clj │ │ ├── Example4.clj │ │ ├── Example5.clj │ │ ├── Example6.clj │ │ ├── example1.clj │ │ ├── example2.clj │ │ ├── test1.clj │ │ ├── test2.clj │ │ ├── test3.clj │ │ ├── test4.clj │ │ ├── test5.clj │ │ └── test6.clj │ └── test │ └── java_interop │ └── core_test.clj ├── to-html.sh └── to-pdf.sh /.github/workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | name: Build and deploy GH Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | name: Publish site 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: checkout 14 | uses: actions/checkout@v4 15 | 16 | - name: build_and_deploy 17 | env: 18 | GITHUB_TOKEN: ${{ github.token }} 19 | run: | 20 | GITHUB_HOSTNAME="github.com" 21 | TARGET_REPOSITORY=${GITHUB_REPOSITORY} 22 | remote_repo="https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@${GITHUB_HOSTNAME}/${TARGET_REPOSITORY}.git" 23 | remote_branch="gh-pages" 24 | 25 | sudo apt-get install -y asciidoctor 26 | sudo gem install coderay 27 | ./to-html.sh 28 | 29 | echo "Pushing artifacts to ${TARGET_REPOSITORY}:$remote_branch" 30 | 31 | cd public 32 | git init 33 | git config user.name "GitHub Actions" 34 | git config user.email "github-actions-bot@users.noreply.${GITHUB_HOSTNAME}" 35 | git add . 36 | 37 | git commit -m "Deploy ${TARGET_REPOSITORY} to ${TARGET_REPOSITORY}:$remote_branch" 38 | git push --force "${remote_repo}" master:"${remote_branch}" 39 | 40 | echo "Deploy complete" 41 | -------------------------------------------------------------------------------- /.github/workflows/release-pdf.yaml: -------------------------------------------------------------------------------- 1 | name: Release PDF 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | release: 10 | name: Write Release Page 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v3 15 | 16 | - name: Get Tagname 17 | ## ref: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ 18 | ## echo "::set-output name={name}::{value}" (deprecated) 19 | ## echo "{name}={value}" >> $GITHUB_OUTPUT (updated) 20 | id: tag_name 21 | run: | 22 | echo "current_version"="${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT 23 | shell: bash 24 | 25 | - name: Release 26 | id: create_release 27 | uses: actions/create-release@v1 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | with: 31 | draft: false 32 | prerelease: false 33 | release_name: ${{ github.ref }} 34 | tag_name: ${{ github.ref }} 35 | body: "" 36 | 37 | outputs: 38 | upload_url: ${{ steps.create_release.outputs.upload_url }} 39 | 40 | build: 41 | needs: release 42 | name: Build and upload pdf 43 | runs-on: ubuntu-latest 44 | steps: 45 | - name: checkout 46 | uses: actions/checkout@v4 47 | 48 | - name: generate pdf 49 | env: 50 | GITHUB_TOKEN: ${{ github.token }} 51 | run: | 52 | echo "=== install dependencies" 53 | sudo apt-get install -y asciidoctor 54 | sudo gem install asciidoctor-pdf 55 | sudo gem install coderay 56 | ./to-pdf.sh 57 | 58 | - name: Upload Asset 59 | uses: actions/upload-release-asset@v1 60 | env: 61 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 62 | with: 63 | upload_url: ${{ needs.release.outputs.upload_url }} 64 | asset_path: ./clojure-complete.pdf 65 | asset_name: clojure-complete.pdf 66 | asset_content_type: application/octet-stream 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | prj/target 2 | prj/classes 3 | prj/checkouts 4 | prj/pom.xml 5 | prj/pom.xml.asc 6 | *.jar 7 | *.class 8 | *.pdf 9 | *.pdfmarks 10 | 11 | prj/.lein-* 12 | prj/.nrepl-port 13 | 14 | *~ 15 | *# 16 | .#* 17 | 18 | ## asciidoctor 19 | /public/ 20 | 21 | ## temp 22 | 23 | /.clj-kondo/ 24 | /.lsp/ 25 | -------------------------------------------------------------------------------- /Boot/build.boot: -------------------------------------------------------------------------------- 1 | ;; source 2 | ;; github.com/magomimmo/modern-cljs/blob/master/doc/second-edition/tutorial-16.md 3 | 4 | (set-env! 5 | :source-paths #{"src/clj" "src/cljs" "src/cljc"} 6 | :resource-paths #{"html"} 7 | :target-path "target" 8 | 9 | :dependencies '[ 10 | [org.clojure/clojure "1.7.0"] ;; add CLJ 11 | [org.clojure/clojurescript "1.7.170"] ;; add CLJS 12 | [adzerk/boot-cljs "1.7.170-3"] 13 | [pandeiro/boot-http "0.7.0"] 14 | [adzerk/boot-reload "0.4.2"] 15 | [adzerk/boot-cljs-repl "0.3.0"] ;; add bREPL 16 | [com.cemerick/piggieback "0.2.1"] ;; needed by bREPL 17 | [weasel "0.7.0"] ;; needed by bREPL 18 | [org.clojure/tools.nrepl "0.2.12"] ;; needed by bREPL 19 | [org.clojars.magomimmo/domina "2.0.0-SNAPSHOT"] 20 | [hiccups "0.3.0"] 21 | [compojure "1.4.0"] ;; for routing 22 | [org.clojars.magomimmo/shoreleave-remote-ring "0.3.1"] 23 | [org.clojars.magomimmo/shoreleave-remote "0.3.1"] 24 | [javax.servlet/servlet-api "2.5"] 25 | [org.clojars.magomimmo/valip "0.4.0-SNAPSHOT"] 26 | [enlive "1.1.6"] 27 | [adzerk/boot-test "1.0.7"] 28 | [crisptrutski/boot-cljs-test "0.2.1-SNAPSHOT"] 29 | ]) 30 | 31 | (require '[adzerk.boot-cljs :refer [cljs]] 32 | '[pandeiro.boot-http :refer [serve]] 33 | '[adzerk.boot-reload :refer [reload]] 34 | '[adzerk.boot-cljs-repl :refer [cljs-repl start-repl]] 35 | '[adzerk.boot-test :refer [test]] 36 | '[crisptrutski.boot-cljs-test :refer [test-cljs]] 37 | ) 38 | 39 | (def defaults {:test-dirs #{"test/cljc" "test/clj" "test/cljs"} 40 | :output-to "main.js" 41 | :testbed :phantom 42 | :target "target" 43 | :namespaces '#{modern-cljs.shopping.validators-test 44 | modern-cljs.login.validators-test}}) 45 | 46 | (deftask add-source-paths 47 | "Add paths to :source-paths environment variable" 48 | [t dirs PATH #{str} ":source-paths"] 49 | (merge-env! :source-paths dirs) 50 | identity) 51 | 52 | (deftask tdd 53 | "Launch a customizable TDD Environment" 54 | [e testbed ENGINE kw "the JS testbed engine (default phantom)" 55 | k httpkit bool "Use http-kit web server (default jetty)" 56 | n namespaces NS #{sym} "the set of namespace symbols to run tests in" 57 | o output-to NAME str "the JS output file name for test (default main.js)" 58 | O optimizations LEVEL kw "the optimization level (default none)" 59 | p port PORT int "the web server port to listen on (default 3000)" 60 | t dirs PATH #{str} "test paths (default test/clj test/cljs test/cljc)" 61 | v verbose bool "Print which files have changed (default false)"] 62 | (let [dirs (or (:test-dirs defaults)) 63 | output-to (or output-to (:output-to defaults)) 64 | testbed (or testbed (:testbed defaults)) 65 | namespaces (or namespaces (:namespaces defaults))] 66 | (comp 67 | (serve ;:dir "target" 68 | :handler 'modern-cljs.core/app 69 | :resource-root (:target defaults) 70 | :reload true 71 | :httpkit httpkit 72 | :port port) 73 | (add-source-paths :dirs dirs) 74 | (watch :verbose verbose) 75 | (reload) 76 | (cljs-repl) 77 | (test-cljs :out-file output-to 78 | :js-env testbed 79 | :namespaces namespaces 80 | :optimizations optimizations) 81 | (test :namespaces namespaces)))) 82 | 83 | (deftask dev 84 | "Launch immediate feedback dev environment" 85 | [] 86 | (comp 87 | (serve :handler 'modern-cljs.core/app ;; ring hanlder 88 | :resource-root (:target defaults) ;; root classpath 89 | :reload true) ;; reload ns 90 | (watch) 91 | (reload) 92 | (cljs-repl) ;; before cljs 93 | (cljs))) 94 | -------------------------------------------------------------------------------- /Boot/build.boot.sample: -------------------------------------------------------------------------------- 1 | (set-env! 2 | :source-paths #{"src"} ;; compiled by cljs task 3 | :resource-paths #{"resources"} ;; copied to the target dir by target task 4 | :dependencies '[[org.clojure/clojure "1.8.0"] 5 | [org.clojure/clojurescript "1.9.229"] 6 | [adzerk/boot-cljs "2.0.0" :scope "test"] ;; cljs source complie 7 | [adzerk/boot-cljs-repl "0.3.3" :scope "test"] ;; add bREPL 8 | [org.clojure/tools.nrepl "0.2.13" :scope "test"] ;; needed by bREPL 9 | [com.cemerick/piggieback "0.2.1" :scope "test"] ;; needed by bREPL 10 | [weasel "0.7.0" :scope "test"] ;; needed by bREPL 11 | [adzerk/boot-reload "0.5.1" :scope "test"] ;; live reload for browser 12 | [philoskim/debux "0.2.1"] ]) 13 | 14 | (require 15 | '[adzerk.boot-cljs :refer [cljs]] 16 | '[adzerk.boot-cljs-repl :refer [cljs-repl start-repl]] 17 | '[adzerk.boot-reload :refer [reload]]) 18 | 19 | (deftask prod [] 20 | (comp (cljs :ids #{"main"} 21 | :optimizations :simple) 22 | (cljs :ids #{"renderer"} 23 | :optimizations :advanced))) 24 | 25 | (deftask dev [] 26 | (comp ;; Audio feedback about warnings etc. ======================= 27 | (speak) 28 | (watch) 29 | ;; Inject REPL and reloading code into renderer build ======= 30 | (cljs-repl :ids #{"renderer"}) 31 | (reload :ids #{"renderer"} 32 | :ws-host "localhost" 33 | :on-jsload 'app.renderer/init 34 | :target-path "target") 35 | ;; Compile renderer ========================================= 36 | (cljs :ids #{"renderer"}) 37 | ;; Compile JS for main process ============================== 38 | ;; path.resolve(".") which is used in CLJS's node shim 39 | ;; returns the directory `electron` was invoked in and 40 | ;; not the directory our main.js file is in. 41 | ;; Because of this we need to override the compilers `:asset-path option` 42 | ;; See http://dev.clojure.org/jira/browse/CLJS-1444 for details. 43 | (cljs :ids #{"main"} 44 | :compiler-options {:asset-path "target/main.out" 45 | :closure-defines {'app.main/dev? true}}) 46 | (target))) 47 | -------------------------------------------------------------------------------- /Boot/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Boot/script: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env boot 2 | 3 | (set-env! :dependencies '[[clj-time "0.11.0"]]) 4 | 5 | (require '[clojure.string :as str] 6 | '[clj-time.core :as time]) 7 | 8 | (defn -main [& args] 9 | (println (str/upper-case "hello, world! The time is") (time/now)) 10 | (System/exit 0)) 11 | -------------------------------------------------------------------------------- /Collections-and-Sequences/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Collections-and-Sequences/subs/zipper.adoc: -------------------------------------------------------------------------------- 1 | = 지퍼(Zipper) 2 | :source-highlighter: coderay 3 | :source-language: clojure 4 | :sectnums: 5 | :icons: font 6 | 7 | == 트리 8 | 9 | 내용을 채워넣을 것. 10 | 11 | -------------------------------------------------------------------------------- /Design-Patterns/coderay-asciidoctor.css: -------------------------------------------------------------------------------- 1 | /* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */ 2 | /*pre.CodeRay {background-color:#f7f7f8;}*/ 3 | .CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em} 4 | .CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)} 5 | .CodeRay .line-numbers strong{color:rgba(0,0,0,.4)} 6 | table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none} 7 | table.CodeRay td{vertical-align: top;line-height:1.45} 8 | table.CodeRay td.line-numbers{text-align:right} 9 | table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)} 10 | table.CodeRay td.code{padding:0 0 0 .5em} 11 | table.CodeRay td.code>pre{padding:0} 12 | .CodeRay .debug{color:#fff !important;background:#000080 !important} 13 | .CodeRay .annotation{color:#007} 14 | .CodeRay .attribute-name{color:#000080} 15 | .CodeRay .attribute-value{color:#700} 16 | .CodeRay .binary{color:#509} 17 | .CodeRay .comment{color:#998;font-style:italic} 18 | .CodeRay .char{color:#04d} 19 | .CodeRay .char .content{color:#04d} 20 | .CodeRay .char .delimiter{color:#039} 21 | .CodeRay .class{color:#458;font-weight:bold} 22 | .CodeRay .complex{color:#a08} 23 | .CodeRay .constant,.CodeRay .predefined-constant{color:#008080} 24 | .CodeRay .color{color:#099} 25 | .CodeRay .class-variable{color:#369} 26 | .CodeRay .decorator{color:#b0b} 27 | .CodeRay .definition{color:#099} 28 | .CodeRay .delimiter{color:#000} 29 | .CodeRay .doc{color:#970} 30 | .CodeRay .doctype{color:#34b} 31 | .CodeRay .doc-string{color:#d42} 32 | .CodeRay .escape{color:#666} 33 | .CodeRay .entity{color:#800} 34 | .CodeRay .error{color:#808} 35 | .CodeRay .exception{color:inherit} 36 | .CodeRay .filename{color:#099} 37 | .CodeRay .function{color:#900;font-weight:bold} 38 | .CodeRay .global-variable{color:#008080} 39 | .CodeRay .hex{color:#058} 40 | .CodeRay .integer,.CodeRay .float{color:#099} 41 | .CodeRay .include{color:#555} 42 | .CodeRay .inline{color:#000} 43 | .CodeRay .inline .inline{background:#ccc} 44 | .CodeRay .inline .inline .inline{background:#bbb} 45 | .CodeRay .inline .inline-delimiter{color:#d14} 46 | .CodeRay .inline-delimiter{color:#d14} 47 | .CodeRay .important{color:#555;font-weight:bold} 48 | .CodeRay .interpreted{color:#b2b} 49 | .CodeRay .instance-variable{color:#008080} 50 | .CodeRay .label{color:#970} 51 | .CodeRay .local-variable{color:#963} 52 | .CodeRay .octal{color:#40e} 53 | .CodeRay .predefined{color:#369} 54 | .CodeRay .preprocessor{color:#579} 55 | .CodeRay .pseudo-class{color:#555} 56 | .CodeRay .directive{font-weight:bold} 57 | .CodeRay .type{font-weight:bold} 58 | .CodeRay .predefined-type{color:inherit} 59 | .CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold} 60 | .CodeRay .key{color:#808} 61 | .CodeRay .key .delimiter{color:#606} 62 | .CodeRay .key .char{color:#80f} 63 | .CodeRay .value{color:#088} 64 | .CodeRay .regexp .delimiter{color:#808} 65 | .CodeRay .regexp .content{color:#808} 66 | .CodeRay .regexp .modifier{color:#808} 67 | .CodeRay .regexp .char{color:#d14} 68 | .CodeRay .regexp .function{color:#404;font-weight:bold} 69 | .CodeRay .string{color:#d20} 70 | .CodeRay .string .string .string{background:#ffd0d0} 71 | .CodeRay .string .content{color:#d14} 72 | .CodeRay .string .char{color:#d14} 73 | .CodeRay .string .delimiter{color:#d14} 74 | .CodeRay .shell{color:#d14} 75 | .CodeRay .shell .delimiter{color:#d14} 76 | .CodeRay .symbol{color:#990073} 77 | .CodeRay .symbol .content{color:#a60} 78 | .CodeRay .symbol .delimiter{color:#630} 79 | .CodeRay .tag{color:#008080} 80 | .CodeRay .tag-special{color:#d70} 81 | .CodeRay .variable{color:#036} 82 | .CodeRay .insert{background:#afa} 83 | .CodeRay .delete{background:#faa} 84 | .CodeRay .change{color:#aaf;background:#007} 85 | .CodeRay .head{color:#f8f;background:#505} 86 | .CodeRay .insert .insert{color:#080} 87 | .CodeRay .delete .delete{color:#800} 88 | .CodeRay .change .change{color:#66f} 89 | .CodeRay .head .head{color:#f4f} -------------------------------------------------------------------------------- /Design-Patterns/design-patterns.adoc: -------------------------------------------------------------------------------- 1 | = Design Patterns 2 | :source-highlighter: coderay 3 | :source-language: clojure 4 | :sectnums: 5 | :icons: font 6 | :imagesdir: ../img 7 | :linkcss: 8 | :stylesdir: ../ 9 | :stylesheet: my-asciidoctor.css 10 | :docinfo1: 11 | :toc: right 12 | 13 | 14 | == Pattern and Functional Programming 15 | -------------------------------------------------------------------------------- /Design-Patterns/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Destructuring/destructuring.adoc: -------------------------------------------------------------------------------- 1 | = 구조분해(Destructuring) 2 | :source-language: clojure 3 | :source-highlighter: coderay 4 | :sectnums: 5 | :imagesdir: ../img 6 | :linkcss: 7 | :stylesdir: ../ 8 | :stylesheet: my-asciidoctor.css 9 | :docinfo1: 10 | :toc: right 11 | 12 | 클로저는 데이터를 직접 다룬다. 데이터들은 주로 맵이나 벡터같은 컬렉션으로 구조화되어 13 | 사용되는데, 컬렉션들은 추상 인터페이스를 통해서 개별 데이터에 접근하는 방법을 14 | 제공한다. 예를 들어, 벡터의 경우 값을 가져올 때 다음과 같이 한다. 15 | 16 | [source] 17 | .... 18 | (def v [42 "foo" 99.2 [5 12]]) 19 | 20 | (first v) ;=> 42 21 | (second v) ;=> "foo" 22 | (last v) ;=> [5 12] 23 | (nth v 2) ;=> 99.2 ;; 1 24 | (v 2) ;=> 99.2 ;; 2 25 | (.get v 2) ;=> 99.2 ;; 3 26 | .... 27 | 28 | `first`, `second`, `last`, `nth` 같은 이러한 함수들은 벡터나 맵같은 컬렉션들이 제공하는 29 | 추상 인터페이스이다. 개개의 컬렉션들의 구체적인 구현에 상관없이 이러한 추상 인터페이스를 30 | 기반으로 해서 컬렉션에 접근하는 것이 가능하기 때문에, 컬렉션을 처리하는 클로저의 모든 코어 31 | 함수들은 그 구현이 단순해지며, 또한 서로 레고 블럭처럼 조립 가능하게 된다. 32 | 33 | 하지만 컬렉션의 여러 요소에 접근할 때는 추상 인터페이스가 제공하는 이러한 함수들을 34 | 이용하는 것이 상당히 번거로워진다. 35 | 36 | [source] 37 | .... 38 | (+ (first v) (v 2)) ;=> (+ 42 99.2) => 141.2 39 | (+ (first v) (first (last v))) ;=> (+ 42 (first [5 12])) => (+ 42 5) => 47 40 | .... 41 | 42 | 43 | 클로저는 이러한 문제를 해결하기 위해 구조분해라는 매우 유용한 기능을 제공한다. 구조분해는 44 | 컬렉션과 같은 추상 데이터 구조에서 원하는 값만 손쉽게 뽑아서 바인딩하는 기법이다. 45 | 46 | 구조분해는 기본적으로 `let` 바인딩 리스트에서 사용되지만, `let` 바인딩을 내부적으로 47 | 사용하는 `fn`, `defn`, `loop` 등에서도 사용될 수 있다. 구조분해에는 벡터 구조분해와 맵 48 | 구조분해가 있다. 49 | 50 | 51 | == 벡터 구조분해 52 | 53 | 벡터 구조분해는 ``nth`를 지원하는 모든 시퀀스들에 대해 적용된다. 54 | 55 | 이러한 컬렉션은 아래와 같다. 56 | 57 | * 클로저의 리스트, 벡터, seqs 58 | * java.util.List 인터페이스를 구현한 컬렉션들. 즉 ArrayList, LinkedList 등 59 | * java.util.RandomAccess 인터페이스를 구현한 클래스 60 | * 자바 CharSequence 61 | * 자바 java.util.regex.Matcher 62 | * 자바 String 63 | 64 | 65 | === 기본 시퀀스 구조분해 66 | 67 | 다음은 간단한 시퀀스 구조분해이다. 68 | 69 | [source] 70 | .... 71 | (def v [42 "foo" 99.2 [5 12]]) 72 | 73 | (let [[x y z] v] 74 | (+ x z)) 75 | ;=> 141.2 76 | .... 77 | 78 | `let` 바인딩 벡터는 이름-값 쌍의 나열이다. 위 코드에서는 이름이 ``[x y z]``이고, 값은 79 | ``v``인 쌍 하나만 있다. 값 ``v``는 하나의 심볼이 아닌 ``[x y z]``라는 심볼 시퀀스로 80 | 바인딩되기 위해 구조분해 되어야 한다. 물론 ``v``가 시퀀스 구조분해되기 위해서는 `v` 자체가 81 | 시퀀스여야 한다. 시퀀스 구조분해는 자리별로 바인딩된다. 즉 ``v``의 첫 요소는 `x`, 둘째 82 | 요소는 `y`, 세째 요소는 ``z``로 바인딩된다. 83 | 84 | 사실 위의 코드는 아래 코드와 같은 일을 하는 것이다. 85 | 86 | [source] 87 | .... 88 | (let [x (nth v 0) 89 | y (nth v 1) 90 | z (nth v 2)] 91 | (+ x z)) 92 | ;=> 141.2 93 | .... 94 | 95 | 96 | === 내부 시퀀스 구조분해 97 | 98 | 다음은 구조분해가 내부 벡터에 적용되는 예이다. 99 | 100 | [source] 101 | .... 102 | (let [[x _ _ [y z]] v] 103 | (+ x y z)) 104 | ;=> 59 105 | .... 106 | 107 | 108 | ==== 시퀀스 구조분해는 자리별 분해 109 | 110 | 구조분해는 자리별로 서로 매칭되어 분해되서 바인딩되는 것이다. 111 | 112 | [source] 113 | .... 114 | [x y z] 115 | [42 "foo" 99.2 [5 12]] 116 | .... 117 | 118 | 위의 내부 시퀀스 구조분해는 다음과 같이 자리별 매칭이 된다. 119 | 120 | [source] 121 | .... 122 | [x _ _ [y z ]] 123 | [42 "foo" 99.2 [5 12]] 124 | .... 125 | 126 | 127 | === 나머지 구조분해 128 | 129 | ``&``를 사용하면 나머지 요소들을 시퀀스로 구조분해 할 수 있다. 130 | 131 | [source] 132 | .... 133 | (let [[x & rest] v] 134 | rest) 135 | ;=> ("foo" 99.2 [5 12]) 136 | .... 137 | 138 | 이것은 전형적인 시퀀스 구조분해이다. 이런 구조분해는 특히 ``loop``등 재귀 호출에서 많이 139 | 사용된다. 한가지 주의할 점은 ``rest``가 벡터가 아니라 시퀀스라는 점이다. 140 | 141 | 142 | === 원본 구조분해 143 | 144 | 때로는 원래의 값을 그대로 유지하고 싶을 수도 있다. 그럴 때는 `:as` 키워드를 사용한다. 145 | 146 | [source] 147 | .... 148 | (let [[x _ z :as org] v] 149 | (conj org (+ x z))) 150 | ;=> [42 "foo" 99.2 [5 12] 141.2] 151 | .... 152 | 153 | 이것이 유용할 때는 ``v``가 함수일 경우이다. 함수의 결과값을 구조분해했지만 결과값 전체를 154 | 지시하는 심볼이 없어 함수를 다시 호출하지 않기 위해서이다. 다음 코드를 보자. 155 | 156 | 157 | [source] 158 | .... 159 | (defn f [] 160 | [1 2 3]) 161 | 162 | (let [[x y] (f)] 163 | (conj (f) (+ x y))) ;; f 함수가 2번 호출된다. 164 | ;=> [1 2 3 3] 165 | 166 | (let [[x y :as all] (f)] 167 | (conj all (+ x y))) ;; f 함수의 결과값을 심볼 all로 받아 사용한다. 168 | ;=> [1 2 3 3] 169 | .... 170 | 171 | 다음은 나머지 구조분해와 원본 구조분해를 같이 사용하는 예이다. 172 | 173 | [source] 174 | .... 175 | (let [[a b c & more :as all] (range 10)] 176 | (println "a b c are: " a b c) 177 | (println "more is: " more) 178 | (println "all is: " all)) 179 | ;>> a b c are: 0 1 2 180 | ;>> more is: (3 4 5 6 7 8 9) 181 | ;>> all is: (0 1 2 3 4 5 6 7 8 9) 182 | ;=> nil 183 | .... 184 | 185 | 186 | == 맵 구조분해 187 | 188 | === 맵 구조분해의 대상 189 | 190 | 맵 구조분해의 대상은 다음과 같다. 191 | 192 | * 클로저 hash-map, array-map, record 193 | * java.util.Map 인터페이스를 구현한 컬렉션 194 | * 인덱스를 키로하는 get 함수를 지원하는 클래스 195 | * 클로저 벡터 196 | * 스트링 197 | * Array 198 | 199 | 200 | === 기본 맵 구조분해 201 | 202 | 다음은 기본적인 맵 구조분해이다. 203 | 204 | [source] 205 | .... 206 | (def m {:a 5 :b 6 207 | :c [7 8 9] 208 | :d {:e 10 :f 11} 209 | "foo" 88 210 | 42 false}) 211 | 212 | (let [{a :a b :b} m] 213 | (+ a b)) 214 | ;=> 11 215 | .... 216 | 217 | 위 코드에서 `let` 바인딩 벡터는 구조분해를 위해 맵을 사용하여, ``m``의 `:a` 값인 ``5``를 218 | ``a``에, ``m``의 `:b` 값인 ``6``을 ``b``에 바인딩한다. 219 | 220 | 221 | === 맵 구조분해는 키별 분해 222 | 223 | 맵은 키-값 쌍을 요소로 하기 때문에 다음과 같이 키에 따른 분해가 된다고 생각할 수 있다. 224 | 225 | [source] 226 | .... 227 | {a :a b :b} 228 | {:a 5 :b 6} 229 | .... 230 | 231 | 맵의 키는 키워드 외에 다른 것이 올 수도 있기 때문에 다음 코드도 가능하다. 232 | 233 | [source] 234 | .... 235 | (let [{f "foo"} m] 236 | (+ f 12)) 237 | ;=> 100 238 | .... 239 | 240 | [source] 241 | .... 242 | (let [{v 42} m] 243 | (if v 1 0)) 244 | ;=> 0 245 | .... 246 | 247 | 248 | === 벡터에 대한 맵 구조분해 249 | 250 | 맵 구조분해에서 벡터나 스트링의 인덱스는 키로 사용될 수 있다. 다음은 벡터를 맵 251 | 구조분해하는 예이다. 252 | 253 | [source] 254 | .... 255 | (let [{x 3 y 8} [12 0 0 -18 44 6 0 0 1]] 256 | (+ x y)) 257 | ;=> -17 258 | .... 259 | 260 | 벡터를 맵 구조분해하는 장점은 특정 자리만을 골라서 구조분해할 수 있다는 점이다. 261 | 262 | 벡터는 위치 인덱스를 키로 하는 맵이다. 263 | 264 | 265 | === 내부 맵 구조분해 266 | 267 | 다음은 내부 맵에 대한 구조분해이다. 268 | 269 | [source] 270 | .... 271 | (let [{{e :e} :d} m] 272 | (* 2 e)) 273 | ;=> 20 274 | .... 275 | 276 | 277 | ``:d``에 의해 ``m``의 내부 맵 ``{:e 10 :f 11}``이 선택되고, 다시 ``:e``에 의해 ``10``이 278 | 선택된다. 279 | 280 | 281 | === 시퀀스 구조분해와 맵 구조분해 같이 사용하기 282 | 283 | 맵 구조분해와 시퀀스 구조분해가 같이 사용되면 우아한 코드가 된다. 284 | 285 | [source] 286 | .... 287 | (let [{[x _ y] :c} m] 288 | (+ x y)) 289 | ;=> 16 290 | .... 291 | 292 | [source] 293 | .... 294 | (def map-in-vector ["James" {:birthday (java.util.Date. 73 1 6)}]) 295 | 296 | (let [[name {bd :birthday}] map-in-vector] 297 | (str name " was born on " bd)) 298 | ;=> "James was born on Thu Feb 06 00:00:00 EST 1973" 299 | .... 300 | 301 | 302 | === 원본 구조분해 303 | 304 | 시퀀스 구조분해에서처럼 ``:as``를 사용하면 구조분해되는 맵 자체를 바인딩할 수 있다. 305 | 306 | [source] 307 | .... 308 | (let [{r1 :x r2 :y :as randoms} 309 | (zipmap [:x :y :z] (repeatedly (partial rand-int 10)))] 310 | (assoc randoms :sum (+ r1 r2))) 311 | ;=> {:sum 17, :z 3, :y 8, :x 9} 312 | .... 313 | 314 | === 기본값 설정 315 | 316 | 구조분해 문구에서 피구조분해 맵에는 없는 키를 사용했을 때, 기본 맵을 제공하여 해당 키의 317 | 값을 설정할 수 있다. 318 | 319 | [source] 320 | .... 321 | (let [{k :unknown x :a :or {k 50}} m] 322 | (+ k x)) 323 | ;=> 55 324 | .... 325 | 326 | 아래 코드는 같은 결과를 낸다. 327 | 328 | [source] 329 | .... 330 | (let [{k :unknown x :a} m 331 | k (or k 50)] 332 | (+ k x)) 333 | ;=> 55 334 | .... 335 | 336 | 하지만 ``:or``는 피구조분해의 해당 키 값이 ``false``이거나 ``nil``일 때도 동작한다. 337 | 338 | [source] 339 | .... 340 | (let [{opt1 :option} {:option false} 341 | opt1 (or opt1 true) 342 | {opt2 :option :or {opt2 true}} {:option false}] 343 | {:opt1 opt1 :opt2 opt2}) 344 | ;=> {:opt1 true, :opt2 false} 345 | .... 346 | 347 | 348 | === 맵키 이름 구조분해 349 | 350 | 맵의 키는 그 자체로 데이터의 성격을 드러내는 경우, 맵 구조분해 이후에도 그 키의 이름을 351 | 그대로 사용하는 것이 좋은데, 다음과 같이 같은 이름들이 반복되게 된다. 352 | 353 | [source] 354 | .... 355 | (def kildong {:name "KilDong" :age 24 :location "west"}) 356 | 357 | (let [{name :name age :age location :location} kildong] 358 | (format "%s is %s years old and lives in %s." name age location)) 359 | ;=> "KilDong is 24 old years and lives in west." 360 | .... 361 | 362 | 이런 반복을 하지 않기 위해 ``:keys``를 사용하여 피구조분해 맵의 각 키의 이름으로 363 | 바인딩한다. 364 | 365 | [source] 366 | .... 367 | (def kildong {:name "KilDong" :age 24 :location "west"}) 368 | 369 | (let [{:keys [name age location]} kildong] 370 | (format "%s is %s years old and lives in %s." name age location)) 371 | ;=> "KilDong is 24 old years and lives in west." 372 | .... 373 | 374 | 피구조분해 맵이 키로 스트링이나 심볼을 사용하는 경우는 ``:strs``과 ``:syms``를 사용한다. 375 | 376 | 377 | [source] 378 | .... 379 | (def kildong {"name" "KilDong" "age" 24 "location" "west"}) 380 | 381 | (let [{:strs [name age location]} kildong] 382 | (format "%s is %s years old and lives in %s." name age location)) 383 | ;=> "KilDong is 24 old years and lives in west." 384 | .... 385 | 386 | [source] 387 | .... 388 | (def kildong {'name "KilDong" 'age 24 'location "west"}) 389 | 390 | (let [{:syms [name age location]} kildong] 391 | (format "%s is %s years old and lives in %s." name age location)) 392 | ;=> "KilDong is 24 old years and lives in west." 393 | .... 394 | 395 | 396 | === 나머지 시퀀스를 키-값 쌍으로 구조분해 397 | 398 | 시퀀스 구조분해서는 ``&``를 사용하여 나머지 요소를 시퀀스로 바인딩할 수 있었다. 키-값 쌍이 399 | 튜플로 있는 벡터에 대해서는 튜플들을 맵으로 구조분해할 수 있다. 400 | 401 | [source] 402 | .... 403 | (def movie ["Les Miserables" 2012 :director "Tom Hooper" :rating 8.0]) 404 | 405 | (let [[movie-name year & rest] movie 406 | {:keys [director rating]} (apply hash-map rest)] 407 | (format "%s is made by %s in %s, rating %.1f" movie-name year director rating)) 408 | .... 409 | 410 | 이 코드에서는 시퀀스 구조분해에서 받은 ``rest``를 맵 구조분해하기 위해 ``hash-map``을 411 | 적용하고 있다. 이것은 다음과 같이 간단하게 처리될 수 있다. 412 | 413 | [source] 414 | .... 415 | (let [[movie-name year & {:keys [director rating]}] movie] 416 | (format "%s is made by %s in %s, rating %s" movie-name year director rating)) 417 | .... 418 | 419 | `rest` 자리에 직접 맵 구조분해 문구를 바로 적용할 수 있다. 420 | 421 | === 맵을 시퀀스 구조분해할 수는 없다 422 | 423 | 위에서 시퀀스를 맵 구조분해 할 수 있음을 보았다. 그것은 시퀀스도 맵 구조분해가 요구하는 424 | `get` 메소드를 지원하기 때문이다. 하지만 반대로 맵을 시퀀스 구조분해할 수는 없는데, 맵은 425 | 시퀀스 구조분해가 요구하는 ``nth``를 지원하지 않기 때문이다. 426 | 427 | 특히 주의할 점은 집합은 값(Value)를 키(Key)로 하는 맵이기 때문에 시퀀스 구조분해가 되지 428 | 않는다. 429 | 430 | [source] 431 | .... 432 | (let [[a & r] #{1 2 3}] 433 | a) 434 | ;>> UnsupportedOperationException nth not supported on this type: PersistentHashSet... 435 | .... 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | -------------------------------------------------------------------------------- /Destructuring/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Development-Environments/atom.adoc: -------------------------------------------------------------------------------- 1 | = Atom editor + proto-repl 설치 2 | :source-language: clojure 3 | :source-highlighter: coderay 4 | :sectnums: 5 | :imagesdir: img 6 | :linkcss: 7 | :stylesdir: ../ 8 | :stylesheet: my-asciidoctor.css 9 | :docinfo1: 10 | :toc: right 11 | 12 | == Atom editor 설치 13 | 14 | . link:https://atom.io/[]를 방문해 아톰 윈도우즈 최신 버전(여기서는 `AtomSetup-x64.exe` 15 | 파일)을 다운로드 받는다. 16 | 17 | . 다운받은 `AtomSetup-x64.exe` 파일을 실행해. 아톰 편집기 설치를 마친다. 18 | 19 | 20 | == ink 플러그인 설치 21 | 22 | 먼저 ink 플러그인을 설치한다. 이 플러그인에 대한 자세한 설명은 23 | link:https://github.com/JunoLab/atom-ink[]를 참조한다. 24 | 25 | * [Files -- Settings -- Install] 버튼을 클릭한 후, 텍스트 입력 상자에 `ink` 라고 입력한 후 26 | `install` 버튼을 클릭한다. 27 | + 28 | image:atom-ink-install.png[] 29 | 30 | 31 | == proto-repl 플러그인 설치 32 | 33 | * 위와 같은 요령으로 [Files -- Settings -- Install] 버튼을 클릭한 후, 텍스트 입력 상자에 `proto-repl` 이라고 입력한 후 `install` 버튼을 클릭한다. 34 | + 35 | image:atom-proto-repl-install.png[] 36 | 37 | 38 | -------------------------------------------------------------------------------- /Development-Environments/development-environments.adoc: -------------------------------------------------------------------------------- 1 | = 개발 환경 설정 2 | :source-language: clojure 3 | :source-highlighter: coderay 4 | :sectnums: 5 | :imagesdir: img 6 | :linkcss: 7 | :stylesdir: ../ 8 | :stylesheet: my-asciidoctor.css 9 | :docinfo1: 10 | :toc: right 11 | 12 | 13 | 이 장에서는 `Windows 10` (64비트 버전)에 클로저 개발 환경을 설치하는 예를 보여준다. 다른 14 | OS의 경우에는 이 장의 내용을 참고해서 약간 변용하면 설치가 가능할 것이다. 15 | 16 | 17 | == Java JDK 설치 18 | 19 | . 클로저는 JVM(Java Virtual Machine) 상에서 실행되는 언어이므로, 먼저 JDK(Java 20 | Development Kit)를 설치해야 한다. 클로저는 JDK 1.6.0 이상의 버전에서 돌아가지만, 21 | 특별한 요구 사항이 없다면 최신 버전의 JDK를 설치하도록 한다. 22 | 23 | . http://www.oracle.com/technetwork/java/javase/downloads/index.html[]를 방문해 'Java SE 24 | 11 (LTS)'의 'Oracle JDK DOWNLOAD' 버튼을 클릭한 후, 자신의 OS에 맞는 최신 버전의 JDK을 내려 25 | 받는다. 여기에서는 `Windows` (64비트 버전) 상에서 JDK를 설치하는 예를 보이겠다. 따라서 26 | Java SE Development Kit 11 중에서 Windows x64 버전의 jdk-11_windows-x64_bin.exe 파일을 27 | 다운로드 받는다. 28 | + 29 | CAUTION: JRE(Java Runtime Environment)가 아니라 JDK를 다운로드 받아야 한다. 30 | 31 | . 내려 받은 파일을 실행해, JDK 설치를 시작한다. 기본 설정 값대로 진행해 설치를 마친다. 32 | 33 | . Windows 'Path' 환경 변수 설정하기 [[environment-variables]] 34 | ** 화면 좌측 최하단의 ['시작' 버튼 -- 'Windows 시스템' -- '제어판'] 을 선택한다. 35 | ** ['시스템 및 보안' -- '시스템' -- '고급 시스템 설정' -- '고급' -- '환경변수' -- '시스템 36 | 변수' -- 'Path'] 항목을 클릭한다. 37 | ** ['편집' -- '새로 만들기'] 클릭 후, 입력 상자에 `C:\Program Files\java\jdk-11\bin` 를 입력 38 | 후, '확인' 버튼을 누른다. 39 | 40 | . Java SDK 설치 확인 41 | ** 화면 좌측 최하단의 ['시작' 버튼 -- 'Windows 시스템' -- '명령 프람프트'] 를 선택한다. 42 | ** 명령창에서 다음과 같이 실행해 메시지가 출력되면, Java JDK 버전 설치에 성공한 것이다. 43 | + 44 | [listing] 45 | ---- 46 | C:\> java -version 47 | java version "11" 2018-09-25 48 | Java(TM) SE Runtime Environment 18.9 (build 11+28) 49 | Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11+28, mixed mode) 50 | 51 | C:\> 52 | ---- 53 | 54 | == wget 설치 55 | 56 | 클로저 프로젝트 관리 도구인 Leiningen이 라이브러리를 내려받을 때 wget 프로그램을 필요로 57 | 하므로, 이 프로그램을 미리 설치해 두어야 한다. 58 | 59 | . https://eternallybored.org/misc/wget[]을 방문해, 최신 버전을 다운로드 받는다. 여기에서는 60 | 64비트 버전인 wget-1.19.4-win64.zip 파일을 다운로드 받는 것으로 한다. 61 | 62 | . 압축을 푼 후에, `wget.exe` 파일을 자신이 원하는 폴더로 복사한다. 여기에서는 63 | `C:\dev\bin\` 폴더에 복사하는 것으로 한다. 64 | 65 | . 환경 변수 ``Path``에 `wget.exe` 파일이 위치한 폴더의 경로를 추가한다: 66 | (<>) 67 | ** [시스템 변수]에서 [Path] 변수 선택 후, ['편집' -- '새로 만들기'] 클릭 후, 입력 상자에 68 | `C:\dev\bin` 경로를 추가한 후, '확인' 버튼을 클릭한다. 69 | 70 | . wget 설치 확인 71 | ** 화면 좌측 최하단의 ['시작' 버튼 -- 'Windows 시스템' -- '명령 프람프트'] 를 선택한다. 72 | ** 명령창에서 다음과 같이 실행해 메시지가 출력되면, wget 설치에 성공한 것이다. 73 | + 74 | [listing] 75 | ---- 76 | C:\> wget 77 | wget: Missing URL 78 | Usage: wget [OPTION]... [URL]... 79 | 80 | Try `wget --help' for more options. 81 | 82 | C:\> 83 | ---- 84 | 85 | == Leiningen 설치 86 | 87 | Leiningen(라이닝언)은 클로저 프로젝트 관리를 위한 기본 도구이다. 88 | 89 | . 다음과 같이 wget을 이용해 leiningen을 다운로드한다. 여기서는 leiningen을 `C:\dev\bin\` 90 | 폴더 아래에 설치하는 것으로 한다. 91 | + 92 | [listing] 93 | ---- 94 | C:\> cd dev\bin 95 | 96 | C:\dev\bin> wget --no-check-certificate https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein.bat 97 | ---- 98 | 99 | . 환경 변수 ``LEIN_HOME`` 추가 (<>) 100 | + 101 | 환경 변수 ``LEIN_HOME``을 새로 만들고, ``lein.bat``을 포함하고 있는 폴더의 경로를 102 | 입력한다. 103 | 104 | * [시스템 변수 -- 새로 만들기] 선택 후, [변수 이름] 란에 LEIN_HOME으로, [변수 값] 란에는 105 | ``C:\dev\bin``을 입력한다. 106 | 107 | . 이후 같은 명령창에서 다음과 같이 입력해 leiningen 본체를 설치하려 하면, 다음과 같은 에러가 날 것이다. 108 | 109 | + 110 | [listing] 111 | ---- 112 | C:\dev\bin> lein self-install 113 | Downloading Leiningen now... 114 | "2"개의 인수가 있는 "DownloadFile"을(를) 호출하는 동안 예외가 발생했습니다. 115 | "요청이 중단되었습니다. SSL/TLS 보안 채널을 만들 수 없습니다." ...... 116 | ---- 117 | + 118 | 이 에러는 link:https://github.com/technomancy/leiningen/issues/2412[]에 이미 보고되어 119 | 있다. lein 다음 버전에는 이 문제가 해결될 것으로 보인다. 하지만 당장은 임시방편으로 120 | 위의 사이트에 나와 있는 대로, 다운 받은 `lein.bat` 파일의 내용 중 다음 라인을 121 | + 122 | [listing] 123 | ---- 124 | powershell -Command "& {param($a,$f) $client = New-Object System.Net.WebClient; $client.Proxy.Credentials =[System.Net.CredentialCache]::DefaultNetworkCredentials; $client.DownloadFile($a, $f)}" ""%2"" ""%1"" 125 | ---- 126 | + 127 | 다음 라인으로 직접 대체해서 해결하도록 한다. 128 | + 129 | [listing] 130 | ---- 131 | powershell -Command "& {param($a,$f) $client = New-Object System.Net.WebClient; [Net.ServicePointManager]::SecurityProtocol = 'tls12' ; $client.Proxy.Credentials =[System.Net.CredentialCache]::DefaultNetworkCredentials; $client.DownloadFile($a, $f)}" ""%2"" ""%1"" 132 | ---- 133 | + 134 | `lein.bat` 파일을 위와 같이 수정한 후, 다음 명령을 재실행해 leiningen 본체의 설치를 마친다. 135 | + 136 | [listing] 137 | ---- 138 | C:\dev\bin> lein self-install 139 | ---- 140 | + 141 | 위 명령이 실행된 후에, ``LEIN_HOME``에 지정되어 있는 폴더에 `self-installs` 폴더가 생성되고 그 142 | 아래에 ``leiningen-2.8.1-standalone.jar``가 설치된 것을 확인할 수 있다. 143 | + 144 | [listing] 145 | ---- 146 | C:\dev\bin> tree /a /f 147 | | lein.bat 148 | | wget.exe 149 | | 150 | \---self-installs 151 | leiningen-2.8.1-standalone.jar 152 | ---- 153 | 154 | . Leiningen 설치 확인 155 | + 156 | 다음과 같이 실행해 메시지가 출력되면, Leiningen이 제대로 설지된 것이다. 157 | + 158 | [listing] 159 | ---- 160 | C:\> lein version 161 | Leiningen 2.8.1 on Java 11 Java HotSpot(TM) 64-Bit Server VM 162 | ---- 163 | 164 | == 예제 프로젝트 만들기 165 | 166 | 여기서는 ``sample``이라는 이름의 프로젝트를 만들 것이다. 이 프로젝트를 아래의 `IDE 설치` 167 | 절에서 읽어 들여 실행해 볼 것이다. 168 | 169 | . 먼저 명령창에서 다음의 명령을 실행해 `C:\dev\projects` 폴더를 만들어 놓는다. 170 | + 171 | [listing] 172 | ---- 173 | C:\> cd dev 174 | 175 | C:\dev> mkdir projects 176 | 177 | C:\dev> cd projects 178 | 179 | C:\dev\projects> 180 | ---- 181 | 182 | . 다음을 실행해 ``sample``이라는 이름의 프로젝트를 만든다. 그러면 `sample` 183 | 폴더 아래에 이 프로젝트에 기본적으로 필요한 여러 개의 폴더와 파일이 만들어질 것이다. 184 | + 185 | [listing] 186 | ---- 187 | C:\dev\projects> lein new sample 188 | Generating a project called sample based on the 'default' template. 189 | The default template is intended for library projects, not applications. 190 | To see other templates (app, plugin, etc), try `lein help new`. 191 | 192 | C:\dev\projects> cd sample 193 | 194 | C:\dev\projects\sample> dir 195 | 196 | C:\dev\projects\sample 디렉터리 197 | 198 | 2018-10-10 오후 08:12 . 199 | 2018-10-10 오후 08:12 .. 200 | 2018-10-10 오후 08:12 110 .gitignore 201 | 2018-10-10 오후 08:12 134 .hgignore 202 | 2018-10-10 오후 08:12 790 CHANGELOG.md 203 | 2018-10-10 오후 08:12 doc 204 | 2018-10-10 오후 08:12 11,433 LICENSE 205 | 2018-10-10 오후 08:12 272 project.clj 206 | 2018-10-10 오후 08:12 246 README.md 207 | 2018-10-10 오후 08:12 resources 208 | 2018-10-10 오후 08:12 src 209 | 2018-10-10 오후 08:12 test 210 | 6개 파일 12,985 바이트 211 | 6개 디렉터리 11,568,414,720 바이트 남음 212 | ---- 213 | 214 | . 만들어진 파일들 중에서 `project.clj` 파일을 편집기로 열어, 다음과 같이 수정한다. 215 | + 216 | [source] 217 | .project.clj 218 | .... 219 | (defproject sample "0.1.0-SNAPSHOT" 220 | :dependencies [[org.clojure/clojure "1.10.0-RC1"]]) 221 | .... 222 | 223 | . 다음과 같이 실행해, 의존 라이브러리들을 미리 다운로드 받아 놓는다. 224 | + 225 | [listing] 226 | ---- 227 | C:\dev\projects\sample> lein deps 228 | Retrieving org/clojure/clojure/1.10.0-beta2/clojure-1.10.0-RC1.pom from central 229 | Retrieving org/clojure/spec.alpha/0.2.176/spec.alpha-0.2.176.pom from central 230 | Retrieving org/clojure/pom.contrib/0.2.2/pom.contrib-0.2.2.pom from central 231 | ...... 232 | 233 | C:\dev\projects\sample> 234 | ---- 235 | 236 | 237 | == IDE 설치 238 | 239 | 클로저 프로그래밍을 위한 IDE(Intergrated Development Environment)는 여러가지가 240 | 있다. 다음에는 설치와 사용이 수월한 것에서 어려운 순서대로 나열하였다. 자신에게 익숙하고 241 | 편리한 IDE를 골라 설치하도록 한다. 242 | 243 | 244 | * link:vscode.adoc[Visual Studio Code + Calva 설치] 245 | * link:intellij.adoc[IntelliJ + Cursive 설치] 246 | // * link:emacs.adoc[Emacs + Cider 설치] -------------------------------------------------------------------------------- /Development-Environments/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Development-Environments/emacs.adoc: -------------------------------------------------------------------------------- 1 | = Emacs + Cider 설치 2 | :source-language: clojure 3 | :source-highlighter: coderay 4 | :sectnums: 5 | :imagesdir: img 6 | :linkcss: 7 | :stylesdir: ../ 8 | :stylesheet: my-asciidoctor.css 9 | :docinfo1: 10 | :toc: right 11 | 12 | == Emacs 설치 13 | 14 | * link:http://ftp.gnu.org/gnu/emacs/windows[] 페이지를 방문해, 64 비트 Windows용 최신 15 | emacs 버전을 내려 받는다. 여기서는 `emacs-26/emacs-26.1-x86_64.zip` 파일을 내려 받는 16 | 것으로 한다. 17 | 18 | * 내려 받는 압축 파일을 푼 후, 자신이 원하는 폴더로 통쨰로 옮긴다. 여기서는 19 | `C:\dev\bin\emacs` 폴더로 옮기는 것으로 한다. 20 | + 21 | [listing] 22 | ---- 23 | C:\> cd dev\bin\emacs 24 | 25 | C:\dev\bin\emacs> dir 26 | C 드라이브의 볼륨에는 이름이 없습니다. 27 | 볼륨 일련 번호: 8059-3BAA 28 | 29 | C:\dev\bin\emacs 디렉터리 30 | 31 | 2018-10-18 오후 06:38 . 32 | 2018-10-18 오후 06:38 .. 33 | 2018-10-18 오후 06:37 bin 34 | 2018-10-18 오후 06:37 etc 35 | 2018-10-18 오후 06:37 include 36 | 2018-10-18 오후 06:38 lib 37 | 2018-10-18 오후 06:38 libexec 38 | 2018-10-18 오후 06:38 share 39 | 2018-10-18 오후 06:38 ssl 40 | 0개 파일 0 바이트 41 | 9개 디렉터리 9,383,415,808 바이트 남음 42 | 43 | C:\dev\bin\emacs> 44 | ---- 45 | 46 | * `bin` 폴더 아래에 있는 `runemacs.exe` 파일을 더블 클릭하면 emacs가 실행된다. 47 | 48 | 49 | == `init.el` 파일 만들기 50 | 51 | * emacs가 실행되면, 먼저 ``init.el``이라는 파일을 읽어 들여, 실행에 필요한 초기화 작업을 52 | 수행한다. 53 | 54 | * 이 `init.el` 파일은 일반적으로 `사용자\<자신의 사용자 아이디>\AppData\Roaming\.emacs.d\` 55 | 폴더에 위치한다. 56 | 57 | * 그런데 `사용자\<자신의 사용자 아이디>` 폴더에 들어가 보아도 ``AppData``라는 폴더는 58 | 아래의 화면에서처럼 일반적으로 보이지 않게 설정되어 있다. 59 | + 60 | image:windows-appdata-no-show.png[] 61 | 62 | * 이 ``AppData`` 폴더를 보이게 하려면, '파일 탐색기'를 실행한 후, [파일 -- 폴더 및 검색 63 | 옵션 변경 -- 보기 -- 고급 설정 -- 숨김 파일 및 폴더 -- 숨김 파일, 폴더 및 드라이브 표시] 64 | 메뉴를 선택해 주고 `확인` 버튼을 눌러 준다. 65 | 66 | * 이제 `사용자\<자신의 사용자 아이디>` 폴더를 다시 확인해 보면, 다음과 같이 `AppData` 67 | 폴더가 보일 것이다. 68 | + 69 | image:windows-appdata-show.png[] 70 | 71 | * `AppData\Roaming\.emacs.d` 폴더의 위치에 `init.el` 파일을 만들어 준 후, 다음의 내용을 72 | 입력한 후 저장한다. 73 | + 74 | [listing] 75 | ---- 76 | ;; Hangul 77 | (set-language-environment "Korean") 78 | (prefer-coding-system 'utf-8) 79 | (setq input-method-verbose-flag nil) 80 | 81 | ;; melpa 관련 설정 82 | (require 'package) 83 | (add-to-list 'package-archives 84 | '("melpa-stable" . "https://stable.melpa.org/packages/") t) 85 | ---- 86 | 87 | 88 | == Cider 설치 89 | 90 | * emacs를 실행한다. 91 | 92 | * 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Development-Environments/img/atom-ink-install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/atom-ink-install.png -------------------------------------------------------------------------------- /Development-Environments/img/atom-proto-repl-install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/atom-proto-repl-install.png -------------------------------------------------------------------------------- /Development-Environments/img/emacs-clojure-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/emacs-clojure-mode.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-cursive-install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-cursive-install.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-eval-in-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-eval-in-edit.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-eval-in-repl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-eval-in-repl.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-ns-change.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-ns-change.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-ns-eval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-ns-eval.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-open-new-jdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-open-new-jdk.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-open-project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-open-project.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-plugins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-plugins.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-repl-register-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-repl-register-1.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-repl-register-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-repl-register-2.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-repl-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-repl-run.png -------------------------------------------------------------------------------- /Development-Environments/img/intellij-select-jdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/intellij-select-jdk.png -------------------------------------------------------------------------------- /Development-Environments/img/lighttable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/lighttable.png -------------------------------------------------------------------------------- /Development-Environments/img/vscode-calva-install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/vscode-calva-install.png -------------------------------------------------------------------------------- /Development-Environments/img/vscode-eval-in-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/vscode-eval-in-edit.png -------------------------------------------------------------------------------- /Development-Environments/img/vscode-eval-in-repl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/vscode-eval-in-repl.png -------------------------------------------------------------------------------- /Development-Environments/img/vscode-file-eval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/vscode-file-eval.png -------------------------------------------------------------------------------- /Development-Environments/img/vscode-repl-connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/vscode-repl-connect.png -------------------------------------------------------------------------------- /Development-Environments/img/vscode-repl-namespace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/vscode-repl-namespace.png -------------------------------------------------------------------------------- /Development-Environments/img/vscode-repl-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/vscode-repl-start.png -------------------------------------------------------------------------------- /Development-Environments/img/vscode-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/vscode-start.png -------------------------------------------------------------------------------- /Development-Environments/img/windows-appdata-no-show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/windows-appdata-no-show.png -------------------------------------------------------------------------------- /Development-Environments/img/windows-appdata-show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/Development-Environments/img/windows-appdata-show.png -------------------------------------------------------------------------------- /Development-Environments/intellij.adoc: -------------------------------------------------------------------------------- 1 | = IntelliJ + Cursive 설치 2 | :source-language: clojure 3 | :source-highlighter: coderay 4 | :sectnums: 5 | :imagesdir: img 6 | :linkcss: 7 | :stylesdir: ../ 8 | :stylesheet: my-asciidoctor.css 9 | :docinfo1: 10 | :toc: right 11 | 12 | 13 | * IntelliJ에 Cursive 플러그인을 추가하면 소스 브라우징, 리팩토링, 디버깅 등을 디폴트로 14 | 이용할 수 있어 편리하다. 15 | 16 | * Cursive plugin에 대한 자세한 설명은 link:https://cursive-ide.com/userguide[] 페이지를 17 | 참조한다. 18 | 19 | 20 | == IntelliJ 설치 21 | 22 | * https://www.jetbrains.com/idea/download/[]에서 윈도우즈 버전의 Community Edition을 23 | 내려받아 설치한다. 24 | 25 | 26 | == Cursive 플러그인 추가 27 | 28 | * 설치한 IntelliJ를 실행한다. 29 | 30 | * 다음과 같은 화면이 나오면 ``[Configure -- Plugins]``을 선택한다. 31 | + 32 | image:intellij-plugins.png[] 33 | 34 | * ``[Browse repositories...]`` 버튼을 선택한 후, 다음 화면에서처럼 텍스트 입력상자에 35 | ``cursive``라고 입력한 후 `install` 버튼을 눌러 ``Cursive plugin`` 설치를 마친다. 36 | + 37 | image:intellij-cursive-install.png[] 38 | 39 | * IntelliJ를 재실행한다. 40 | 41 | 42 | == Project 열기 43 | 44 | * Intellij를 재실행해서 다음과 같은 화면이 나오면, ``Import project``를 선택한다. 45 | 46 | * 그후에 앞에서 미리 만들어 두었던 ``C:\dev\projects\sample\project.clj`` 파일을 선택한 47 | 후, `OK` 버튼을 눌러 진행한다. 48 | + 49 | image:intellij-open-project.png[] 50 | 51 | * 계속해서 `Next` 버튼을 눌러 나가다가, 다음과 같은 ``Please select project JDK`` 창을 52 | 만나면 바로 아래 `+` 버튼을 눌러 준 후, ``JDK``를 선택하고 `Next` 버튼을 눌러 준다. 53 | + 54 | image:intellij-open-new-jdk.png[] 55 | 56 | * 그후에 JDK가 default로 설치된 `C:\Program Files\Java\JDK-11` 경로를 다음과 같이 선택해 57 | 준 후, `OK` 버튼을 누른다. 이후 계속해서 `Next` 버튼을 눌러 프로젝트 열기를 마친다. 58 | + 59 | image:intellij-select-jdk.png[] 60 | 61 | 62 | == REPL 등록하기 63 | 64 | Cursive에서는 REPL을 따로 등록해 주어야 한다. 65 | 66 | * [`Run -- Edit configurations...`] 메뉴를 선택하면 다음과 같은 화면이 나온다. 이때 [pass:q[+ 67 | -- Clojure REPL -- Local]]을 선택한 후, `OK` 버튼을 눌러 준다. 68 | + 69 | image:intellij-repl-register-1.png[] 70 | 71 | * 다음과 같은 화면이 나오면, `Name` 란에 자신이 원하는 REPL 이름을 입력한 후 `OK` 버튼을 72 | 누른다. 여기서는 편의상 ``My REPL``로 명명하기로 한다. 73 | + 74 | image:intellij-repl-register-2.png[] 75 | 76 | 77 | == Cursive REPL 실행 예 78 | 79 | === REPL 구동하기 80 | 81 | * 다음 화면의 우측 상단의 ``우측 화살표`` 모양을 클릭하면 REPL이 구동된다. 82 | 83 | * REPL의 구동이 끝난 후, 우측 하단의 창에 `(+ 2 3)` 코드를 입력하고 `Shift-` 키를 84 | 누르면, 그 실행 결과가 우측 중앙의 REPL 창에 나타난다. 85 | + 86 | image:intellij-repl-run.png[] 87 | 88 | 89 | === namespace 전환하기 90 | 91 | * `core.clj` 편집창에 커서를 위치 시킨 후, `Alt-Shift-r` 키를 눌러 주면 REPL내의 92 | namespace를 변경할 수 있다. REPL 창에 `(in-ns 'sample.core)` 코드가 실행된 결과, 우측 93 | 상단에 ``Local sample.core``가 표시되어 namespace가 전환되었다는 사실을 확인할 수 있다. 94 | + 95 | image:intellij-ns-change.png[] 96 | 97 | 98 | === 파일 전체 평가하기 99 | 100 | * `core.clj` 편집창에 커서를 위치 시킨 후, `Alt-Shift-l` 키를 눌러 주면, `core.clj` 101 | 파일 전체가 평가된다. 그 사실이 `REPL` 창에 표시되어 있다. 102 | + 103 | image:intellij-ns-eval.png[] 104 | 105 | 106 | === REPL 창에서 코드 실행하기 107 | 108 | * 이제 우측 하단의 창에서 `(foo "Clojure")` 코드를 입력한 후 `Shift-` 키를 누르면, 109 | 그 결과가 우측 중앙의 REPL 창에 보인다. 110 | + 111 | image:intellij-eval-in-repl.png[] 112 | 113 | 114 | === 편집창에서 코드 실행하기 115 | 116 | * `core.clj` 편집창에 커서를 위치시킨 후, 아래와 같이 `(+ 10 20)` 코드를 입력해 보자. 닫는 117 | 괄호 뒤에 커서를 위치 시킨 후, `Alt-Shift-p` 키를 누르면, 그 실행 결과가 `REPL` 창에 118 | 다음과 같이 표시된다 119 | + 120 | image:intellij-eval-in-edit.png[] 121 | -------------------------------------------------------------------------------- /Development-Environments/vscode.adoc: -------------------------------------------------------------------------------- 1 | = Visual Studio Code + Calva 설치 2 | :source-language: clojure 3 | :source-highlighter: coderay 4 | :sectnums: 5 | :imagesdir: img 6 | :linkcss: 7 | :stylesdir: ../ 8 | :stylesheet: my-asciidoctor.css 9 | :docinfo1: 10 | :toc: right 11 | 12 | == Visual Studio Code 설치 13 | 14 | * link:https://code.visualstudio.com/Download[] 페이지를 방문해 Windows용 VS Code(여기서는 15 | User Installer 64 bit: VSCodeUserSetup-x64-1.28.1.exe)를 내려 받는다. 16 | 17 | * 내려 받은 파일을 실행해 설치를 마친 후, VS Code를 실행한다. 18 | 19 | 20 | == Calva extension 설치 21 | 22 | * `[File -- Preferences -- Extensions]` 메뉴를 선택한다. 23 | 24 | * 다음과 같이 텍스트 입력상자에 ``calva``를 입력한 후 `install` 버튼을 눌러 Calva 25 | extension을 설치한다. 26 | + 27 | image:vscode-calva-install.png[] 28 | 29 | * 설치를 마친 후, VS Code를 재실행한다. 30 | 31 | 32 | == Calva REPL 실행 예 33 | 34 | * Calva에 대한 자세한 내용은 link:https://github.com/BetterThanTomorrow/calva[]를 참조하기 35 | 바란다. 36 | 37 | 38 | === 프로젝트 열기 39 | 40 | * VS Code를 실행한 후, `[File -- Open Folder...]` 메뉴를 선택해, 위에서 만든 41 | `C:\dev\projects\sample` 폴더를 열고, `src\sample\core.clj` 파일을 아래와 같이 연다. 42 | + 43 | image:vscode-start.png[] 44 | 45 | 46 | === REPL 실행하기 47 | 48 | * `[Termianl -- New Terminal]` 메뉴를 선택해 새 터미널 창을 연 후, 아래와 같이 `lein repl` 49 | 명령을 실행한다. 50 | + 51 | NOTE: Calva는 아직 자동으로 repl을 실행해 주지 못해서, 수동으로 이와같이 실행해 주어야 52 | 한다. 하지만 이렇게 최초에 한 번 실행해 주면, 추후에 vscode를 재실행해 줄 때에는 이 53 | 단계를 거치지 않아도 된다. 54 | + 55 | image:vscode-repl-start.png[] 56 | 57 | 58 | === REPL 연결하기 59 | 60 | * 맨 아래 상태줄에 있는 `nREPL` 부분을 클릭하면, 다음과 같이 `localhost:<포트번호>` 61 | 형식으로 작은 창이 하나 뜰 것이다. 이 상태에서 `` 키를 눌러주면 nREPL에 62 | 연결된다. 63 | + 64 | NOTE: 이렇게 최초에 한 번 연결시켜 주면, 추후에 vscode를 재실행할 때에는 이 단계를 거치지 65 | 않아도 된다. 66 | + 67 | image:vscode-repl-connect.png[] 68 | 69 | 70 | === namespace 전환하기 71 | 72 | * `core.clj` 편집창에 커서를 위치 시킨 후, `Ctrl-Alt-v n` 키를 눌러 주면 `TERMINAL` 탭의 73 | namespace가 pass:q[`user=>`]에서 pass:q[`sample.core=>`]로 바뀐다. 74 | + 75 | image:vscode-repl-namespace.png[] 76 | 77 | 78 | === 파일 전체 평가하기 79 | 80 | * `core.clj` 편집창에 커서를 위치 시킨 후, `Ctrl-Alt-v ` 키를 눌러 주면, `core.clj` 81 | 파일 전체가 평가된다. 그 사실이 `OUTPUT` 탭에 표시되어 있다. 82 | + 83 | image:vscode-file-eval.png[] 84 | 85 | 86 | === 터미널 창에서 코드 실행하기 87 | 88 | * 이제 `TERMINAL` 탭에서 `(foo "Clojure")` 코드를 입력한 후 `` 키를 입력해 다음과 89 | 같이 실행하면 그 결과가 `TERMINAL` 탭에 보일 것이다. 90 | + 91 | image:vscode-eval-in-repl.png[] 92 | 93 | 94 | === 편집창에서 코드 실행하기 95 | 96 | * `core.clj` 편집창에 커서를 위치시킨 후, 아래와 같이 `(+ 10 20)` 코드를 입력해 보자. 닫는 97 | 괄호 뒤에 커서를 위치 시킨 후, `Ctrl-Alt-v e` 키를 누르면, 그 실행 결과가 `OUTPUT` 탭에 98 | 다음과 같이 표시된다 99 | + 100 | image:vscode-eval-in-edit.png[] 101 | -------------------------------------------------------------------------------- /Flow-Controls/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Functional-Programming/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Java-Interoperability/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Namespaces-and-Libraries/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Preface/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Preface/preface.adoc: -------------------------------------------------------------------------------- 1 | = Preface 2 | :source-language: clojure 3 | :source-highlighter: coderay 4 | :linkcss: 5 | :stylesdir: ../ 6 | :stylesheet: my-asciidoctor.css 7 | :docinfo1: 8 | :toc: right 9 | 10 | [preface] 11 | 12 | == 소스코드 예제 표기법 13 | 14 | 소스 코드를 실행한 결과를 표시할 때, 다음의 표기법을 사용했다. 참고로 아래에서 `;` 기호는 15 | 클로저의 주석 처리 기호로, 소스 코드를 Copy & Paste해서 실행할 때 불편이 없게 했다. 16 | 17 | [source] 18 | .... 19 | (defn get-name [] 20 | (println "Enter Your Name:") 21 | (let [name (read-line)] 22 | (println "Hello," name) 23 | name)) 24 | 25 | (get-name) 26 | ;>> Enter Your Name: ; <1> 27 | ;<< Mr. Kim ; <2> 28 | ;>> Hello, Mr. Kim 29 | ;=> "Mr. Kim" ; <3> 30 | .... 31 | <1> ;>> 화면에 출력된 내용을 표시한다. 32 | <2> ;<< 키보드로 입력한 내용을 표시한다. 33 | <3> ;pass:macros[=>] 함수의 반환값을 표시한다. 34 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Clojure Complete (클로저 완전정복) 2 | :bookseries: Clojure 3 | :doctype: book 4 | :source-language: clojure 5 | :source-highlighter: coderay 6 | //:stem: latexmath 7 | :icons: font 8 | :imagesdir: ./img 9 | :linkcss: 10 | :stylesdir: ../ 11 | :stylesheet: my-asciidoctor.css 12 | 13 | 14 | === Version:   2015-12-31 15 | 16 | [sidebar] 17 | **** 18 | commit은 수시로 이루어지지만, 버전 번호는 큰 변화가 있다고 판단될 때(예를 들어, 새로운 19 | 장을 마쳤을 때)에만 올라 갑니다. 20 | **** 21 | 22 | == [small]#문서 보기 안내# 23 | 24 | github가 asciidoc 형식의 문서 내용 중 일부를 html 형식으로 제대로 변환하지 못하는 문제가 25 | 발견되었습니다. 따라서 앞으로 이곳은 문서를 보관하는 용도로만 사용하고, 실제 이 책의 26 | 내용을 열람하실 떄에는 https://clojure-kr.github.io/clojure-complete/[]에서 보시기를 권합니다. 27 | 28 | 29 | === Table of Contents 30 | 31 | 다음의 목차에서 링크가 아직 걸려 있지 않은 장은 앞으로 채워 나갈 예정입니다. 32 | 33 | :leveloffset: 1 34 | 35 | . link:Preface/preface.adoc[서문] 36 | . 왜 클로저인가? 37 | . link:Development-Environments/development-environments.adoc[개발 환경] 38 | . link:Start/start.adoc[클로저 시작하기] 39 | . link:Simple-Values/simple-values.adoc[단순값] 40 | . link:Flow-Controls/flow-controls.adoc[제어 구조] 41 | . link:Collections-and-Sequences/collections-and-sequences.adoc[컬렉션과 시퀀스] 42 | . 함수형 프로그래밍 43 | . link:Destructuring/destructuring.adoc[구조분해(Destructuring)] 44 | . 변환자(Transducers) 45 | . link:Java-Interoperability/java-interoperability.adoc[자바 코드 가져다쓰기(Java Interoperability)] 46 | . link:Namespaces-and-Libraries/namespaces-and-libraries.adoc[이름공간과 라이브러리] 47 | . 상태 관리와 동시성 48 | . core.async 49 | . 멀티메소드와 상속 50 | . 프로토콜과 레코드 51 | . 매크로 52 | . 수학 53 | . 날짜와 시간 54 | . 입출력: 파일과 디렉토리 55 | . 프로젝트 관리 56 | . 예외 처리 57 | . link:Testing/testing.adoc[테스팅] 58 | . 타입 검사 59 | . 데이타베이스 프로그래밍 60 | . 통신 및 웹 프로그래밍 61 | . 파서 62 | . 문자 인코딩 63 | . GUI 프로그래밍 64 | . link:Boot/boot.adoc[Boot 사용하기] 65 | 66 | //. link:Why-Clojure/why-clojure.adoc[Why Clojure?] 67 | //. link:Collections-and-Sequences/collections-and-sequences.adoc[Collections and Sequences] 68 | //. link:Functional-Programming/functional-programming.adoc[함수형 프로그래밍] 69 | //. link:Transducers/transducers.adoc[Transducers] 70 | //. link:Metadata/metadata.adoc[Metadata] 71 | //. link:State-Management-and-Parallel-Programming/state-management-and-parallel-programming.adoc[State Management and Parallel Programming] 72 | //. link:Core-Async/core-async.adoc[core.async] 73 | //. link:Multimedthos-and-Hierarchies/multimedthos-and-hierarchies.adoc[Multimedthos and Hierarchies] 74 | //. link:Protocols-Records-and-Types/protocols-records-and-types.adoc[Protocols, Records and Types] 75 | //. link:Macros/macros.adoc[Macros] 76 | //. link:Numerics and Mathematics/numerics-and-mathematics.adoc[Numerics and Mathematics] 77 | //. link:Project-Management/project-management.adoc[Project Management] 78 | //. link:Testing/testing.adoc[Testing] 79 | //. link:Type-Checking/type-checking.adoc[Type Checking] 80 | //. link:Database-Programming/database-programming.adoc[Database Programming] 81 | //. link:Web-Programming/web-programming.adoc[Web Programming] 82 | //. link:index.asciidoc[Index] 83 | //. link:colo.asciidoc[Colophon] 84 | 85 | 86 | :leveloffset: 0 87 | 88 | === Copyright 89 | 90 | Copyright (C) 2015. All rights reserved. 91 | 92 | 이 책의 저작권은 https://creativecommons.org/licenses/by-nc-sa/4.0/[Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)]을 따른다. 93 | 94 | 즉, 다음의 조건을 준수하는 한 이 책의 자유로운 복제, 수정 및 배포가 가능하다. 95 | 96 | * 이 책의 내용을 기반으로 2차 저작물을 만들 경우 원작자를 표시하여야 한다. 97 | * 상업적 목적으로 이용할 수 없다. 98 | * 2차 저작물의 경우 위와 동일한 저작권을 사용해야 한다. 99 | 100 | 101 | === Contributing 102 | 103 | 이 책의 집필에 함께 참여하고자 하는 분들을 환영합니다. 참여를 원하시는 분은 104 | https://github.com/[github]에 먼저 사용자 계정을 만드신 후, 이 repository를 자신의 105 | 계정으로 fork합니다. 그리고 문서를 작성하신 후에 pull request를 보내 주십시오. 몇 차례의 106 | pull request가 받아들여지고, 문서의 집필에 기여하신 분의 이름이 Contributors 명단에 등록된 107 | 이후부터 자유로운 commit이 가능해집니다. 108 | 109 | 이 책의 문서 형식은 asciidoc이고, http://asciidoctor.org/[asciidoctor]를 이용해 110 | 관리됩니다. 문서 관리에 필요한 asciidoctor 프로그램 설치 정보는 link:guide[] 디렉토리 111 | 아래에 있는 문서를 참고하시기 바라며, asciidoc 문서 작성 요령은 112 | http://asciidoctor.org/docs/user-manual/[Asciidoctor User Manual]에 자세히 나와 있습니다. 113 | 114 | 보내 주신 문서는 문서의 통일성과 완결성을 위해 필요에 따라 내용의 첨삭/편집/재배치 과정을 115 | 거칠 수 있음을 미리 밝힙니다. 116 | 117 | 118 | === Contributors 119 | 120 | * 김영태 (philos99@gmail.com)   Main editor 121 | * 박상규 (psk810@gmail.com) 122 | * 김만명 (manmyung@gmail.com) 123 | 124 | -------------------------------------------------------------------------------- /Simple-Values/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Simple-Values/simple-values.adoc: -------------------------------------------------------------------------------- 1 | = Simple Values 2 | :source-highlighter: coderay 3 | :source-language: clojure 4 | :sectnums: 5 | :icons: font 6 | :imagesdir: ../img 7 | :linkcss: 8 | :stylesdir: ../ 9 | :stylesheet: my-asciidoctor.css 10 | :docinfo1: 11 | :toc: right 12 | 13 | 14 | == Clojure Data Type Diagram 15 | 16 | 다음의 도표는 클로저의 모든 자료형들을 한 눈에 살펴볼 수 있도록 일목요연하게 정리한 17 | 것이다. 먼저 전체적인 지도를 마음 속에 두고 각 부분을 자세하게 살펴 나가는 것이 클로저를 18 | 빠르고 정확하게 이해하는 지름길이다. 각 자료형 옆에는 실제로 구현되어 있는 자바 클래스를 19 | 병기했다. 이 장에서는 단순 자료형(Simple values)들을 중심으로 살펴보고, 다음 장에서 복합 20 | 자료형인 Collection들을 살펴 보겠다. 21 | 22 | [[clojure-data-type-diagram]] 23 | 24 | 25 | [cols="1,1,^.^2,^.^6", width="70%", options="header"] 26 | |=== 27 | | | ^| 클로저 타입 ^| 자바 클래스 28 | 29 | .13+^.^v|Immutables 30 | (= Values) 31 | 32 | .9+^.^|Simple values 33 | ^.^| Integers 34 | ^v| java.lang.Long 35 | clojure.lang.BigInt 36 | 37 | ^.^| Floats 38 | ^v| java.lang.Double + 39 | java.math.BigDecimal 40 | 41 | ^.^| Ratios ^| clojure.lang.Ratio 42 | 43 | ^.^| Strings ^| java.lang.String 44 | 45 | ^.^| Characters ^| java.lang.Character 46 | 47 | ^.^| Symbols ^| clojure.lang.Symbol 48 | 49 | ^.^| Keywords ^| clojure.lang.Keyword 50 | 51 | ^.^| Booleans ^| java.lang.Boolean 52 | 53 | ^| nil ^| null 54 | 55 | 56 | .4+^.^|Collections 57 | ^| Lists | clojure.lang.PersistentList 58 | 59 | ^| Vectors ^| clojure.lang.PersistentVector 60 | 61 | ^.^| Maps 62 | ^v| array-map: clojure.lang.PersistentArrayMap 63 | hash-map: clojure.lang.PersistentHashMap 64 | sorted-map: clojure.lang.PersistentTreeMap 65 | 66 | ^.^| Sets 67 | ^v| hash-set: clojure.lang.PersistentHashSet 68 | sorted-set: clojure.lang.PersistentTreeSet 69 | 70 | .4+^.^v|Mutables 71 | (= References) 72 | 73 | .4+^.^|Identities 74 | ^| Atoms ^| clojure.lang.Atom 75 | 76 | ^| Refs ^| clojure.lang.Ref 77 | 78 | ^| Agents ^| clojure.lang.Agent 79 | 80 | ^| Vars ^| clojure.lang.Var 81 | 82 | |=== 83 | 84 | 85 | :leveloffset: 1 86 | 87 | include::sub/numbers.adoc[] 88 | 89 | :leveloffset: 0 90 | 91 | 92 | indexterm:[nil] 93 | 94 | == nil 95 | 96 | 클로저의 ``nil``은 자기 자신으로 평가되는 값이다. 자바의 `null`, 루비의 `nil`, 파이썬의 97 | ``None``과 같이 값의 부재를 표현한다. 98 | 99 | [source] 100 | .... 101 | nil ;=> nil 102 | 103 | (type nil) ;=> nil 104 | .... 105 | 106 | ``nil``은 클로저에서 논리적인 거짓(logically false)으로 취급된다. 클로저에서는 ``false``와 107 | ``nil``만을 논리적 거짓으로 판단하고, 그 이외의 모든 값은 논리적 참(logically true)으로 108 | 판단한다. 예를 들어 ``0``이나 빈 문자열 `""`, 빈 백터 `[]` 등도 논리적 참으로 취급된다. 109 | 110 | [source] 111 | .... 112 | (if nil 10 20) ;=> 20 113 | (if false 10 20) ;=> 20 114 | 115 | (if 0 10 20) ;=> 10 116 | (if "" 10 20) ;=> 10 117 | (if [] 10 20) ;=> 10 118 | .... 119 | 120 | `nil?` 함수는 주어진 인수가 ``nil``인지 판별한다. indexterm:[nil?] 121 | 122 | [source] 123 | .... 124 | (nil? nil) ;=> true 125 | 126 | (nil? false) ;=> false 127 | (nil? 0) ;=> false 128 | (nil? "") ;=> false 129 | (nil? []) ;=> false 130 | .... 131 | 132 | `some?` 함수는 주어진 인수가 ``nil``이 아닌지 판별한다. ``(not (nil? x)`` 와 같다. 133 | 134 | CAUTION: `some?` 함수는 클로저 버전 1.6부터 도입되었다. core 함수치고 꽤 늦게 도입된 것인데, 그 아래 버전에서는 컴파일 예외 발생하니 사용시 버전 주의. 135 | 136 | [source] 137 | .... 138 | (some? nil) ;=> false 139 | 140 | (some? false) ;=> true 141 | (some? 0) ;=> true 142 | (some? "") ;=> true 143 | (some? []) ;=> true 144 | .... 145 | 146 | == 불린(Booleans) 147 | 148 | 불린값으로는 ``true``와 ``false``가 있고, 역시 자기 자신으로 평가되는 값이다. 149 | 150 | [source] 151 | .... 152 | true ;=> true 153 | false ;=> false 154 | 155 | (type true) ;=> java.lang.Boolean 156 | (type false) ;=> java.lang.Boolean 157 | .... 158 | 159 | indexterm:[true?] indexterm:[false?] 160 | 161 | `true?` 함수는 주어진 인수가 '실제로 ``true``'footnote:[논리적 참(logically true)과는 162 | 다르다는 점에 주의하자.]인지 판별한다. 즉, 주어진 인자가 ``true``로 평가될 때에만 163 | ``true``를 반환한다. 그리고 `false?` 함수는 주어진 인수가 실제로 ``false``인지 164 | 판별한다. 즉, 주어진 인자가 ``false``로 평가될 때에만 ``true``를 반환한다. 165 | 166 | [source] 167 | .... 168 | (true? true) ;=> true 169 | (true? (= 1 1)) ;=> true 170 | 171 | (true? "hello") ;=> false 172 | (true? 1) ;=> false 173 | 174 | (false? false) ;=> true 175 | (false? (= 1 2)) ;=> true 176 | 177 | (false? nil) ;=> false 178 | (false? "foo") ;=> false 179 | (false? 1) ;=> false 180 | .... 181 | 182 | 183 | == 키워드(Keywords) 184 | 185 | 키워드는 임의의 식별자 앞에 콜론(`:`) 기호를 붙여 만든다. 자기 자신으로 평가되는 값으로 186 | 클로저에서 아주 많이 사용된다. 187 | 188 | indexterm:[keyword?] indexterm:[keyword] 189 | 190 | [source] 191 | .... 192 | :city ;=> :city 193 | 194 | (type :city) ;=> clojure.lang.Keyword 195 | 196 | (keyword? :city) ;=> true 197 | 198 | ;; keyword함수는 문자열을 키워드로 바꾸어 준다. 199 | (keyword "city") ;=> :city 200 | (= :city (keyword "city")) ;=> true 201 | .... 202 | 203 | 204 | 콜론은 키워드를 만들기 위한 문법적 기능을 수행하기 위한 것이지 키워드의 이름은 아니다. 205 | 206 | [source] 207 | .... 208 | (= :seoul (keyword "seoul")) 209 | (= :seoul (keyword ":seoul")) 210 | .... 211 | 212 | 키워드는 특히 키/값 쌍으로 이루어진 맵 자료형의 키로 많이 사용된다. 213 | 214 | [source] 215 | .... 216 | (def person {:name "Sandra Cruz" 217 | :city "Portland, ME"}) 218 | .... 219 | 220 | 식별자 앞에 콜론을 두 개 붙이면 해당 이름공간을 가진 키워드로 확장된다. 예를 들어, 현재의 221 | 이름공간이 ``user``일 때 다음을 실행하면, ``user`` 이름공간이 붙은 키워드로 확장되는 것을 222 | 볼 수 있다. 223 | 224 | [source] 225 | .... 226 | ::address ;=> :user/address 227 | .... 228 | 229 | 이때 `namespace` 함수와 `name` 함수로, 이름공간과 키워드명 부분만을 알아낼 수 230 | 있다. indexterm:[namespce] indexterm:[name] 231 | 232 | [source] 233 | .... 234 | (name :user/address) ;=> "address" 235 | (name ::address) ;=> "address" 236 | 237 | (namespace ::address) ;=> "user" 238 | (namespace :user/address) ;=> "user" 239 | 240 | (namespace :address) ;=> nil 241 | .... 242 | 243 | 244 | == 심볼(Symbols) 245 | 246 | 클로저의 심볼은 다른 언어들에서의 식별자(identifiers)와 유사한 개념이다. 심볼은 숫자가 247 | 아닌 문자로 시작해야 하고, 그 뒤에 `*`, `+`, `-`, `=`, `?`, `!`, `$`, `%`, `&`, `_`, `|`, 248 | `<`, `>` 같은 기호와 문자들이 올 수 있다. 249 | 250 | [source] 251 | .... 252 | (def *+-=?!$%&_|<> "이런 심볼도 가능") ;=> "이런 심볼도 가능" 253 | .... 254 | 255 | 256 | 심볼은 유니코드를 지원한다. 257 | 258 | [source] 259 | .... 260 | (def 심볼1 "한글도 가능") ;=> "한글도 가능" 261 | .... 262 | 263 | 264 | 심볼은 일반적으로 어떤 값을 가리킨다. 그래서 심볼이 평가되면 가리키던 값을 반환하게 265 | 된다. 266 | 267 | [source] 268 | .... 269 | ;; 전역 심볼 a를 정의한다. 270 | (def a 10) 271 | 272 | ;; 전역 심볼 a를 평가하면, 가리키던 값 10을 반환한다. 273 | a ;=> 10 274 | 275 | ;; 지역 심볼 a를 정의한다. let 안에서 지역 심볼 a는 전역 심볼 a을 가린다(shadowing). 276 | (let [a 20] 277 | (+ 100 a)) 278 | ;=> 120 279 | 280 | ;; 전역 심볼 a는 여전히 10을 가리키고 있다. 281 | a ;=> 10 282 | .... 283 | 284 | 285 | `name` 함수는 심볼을 문자열로 바꾼다. indexterm:[name] 286 | 287 | [source] 288 | .... 289 | (name 'a) ;=> "a" 290 | .... 291 | 292 | 293 | `symbol` 함수는 문자열을 심볼로 만든다. indexterm:[symbol] 294 | 295 | 296 | [source] 297 | .... 298 | (symbol "a") ;=> a 299 | (symbol "my-namespace" "a") ;=> my-namespace/a 300 | .... 301 | 302 | 303 | `symbol?` 함수는 심볼인지 여부를 확인한다. indexterm:[symbol?] 304 | 305 | 306 | [source] 307 | .... 308 | (def a 1) ;=> 1 309 | (symbol? 'a) ;=> true 310 | (symbol? a) ;=> false 311 | 312 | (symbol? "a") ;=> false 313 | (symbol? :a) ;=> false 314 | (symbol? 1) ;=> false 315 | .... 316 | 317 | 318 | == 문자(Characters) 319 | 320 | 문자는 역슬래쉬(`\`) 기호 뒤에 한 개의 문자를 덧붙여 표현한다. 321 | 322 | [source] 323 | .... 324 | \a ;=> \a 325 | \가 ;=> \가 326 | 327 | (type \a) ;=> java.lang.Character 328 | (char? \a) ;=> true 329 | .... 330 | 331 | `\u` 뒤에 16진법 숫자 4개를 덧붙여 유니코드를 직접 표현할 수도 있다. ``\o``footnote:[숫자 332 | ``0``이 아니라 알파벳 ``o``임에 주의하자.] 뒤에 8진법 숫자를 붙여 표현할 수도 있는데, 333 | `\o0` ~ `\o377` (즉, `0` ~ `255`) 사이의 숫자만 허용한다. 334 | 335 | [source] 336 | .... 337 | \u03bb ;=> \λ 338 | \o101 ;=> \A 339 | .... 340 | 341 | 이름을 갖는 특별한 문자들이 다음과 같이 정의되어 있다. 342 | 343 | * `\space` 344 | * `\newline` 345 | * `\formfeed` 346 | * `\return` 347 | * `\backspace` 348 | * `\tab` 349 | 350 | 351 | `char`함수는 정수를 문자로 바꾼다. indexterm:[char] 352 | 353 | [source] 354 | .... 355 | (char 97) ;=> \a 356 | .... 357 | 358 | 359 | `char?`는 문자인지를 판별한다. indexterm:[char?] 360 | 361 | [source] 362 | .... 363 | (char? \a) ;=> true 364 | (char? 97) ;=> false 365 | (char? "a") ;=> false 366 | .... 367 | 368 | :leveloffset: 1 369 | 370 | include::sub/strings.adoc[] 371 | 372 | :leveloffset: 0 373 | -------------------------------------------------------------------------------- /Simple-Values/sub/strings.adoc: -------------------------------------------------------------------------------- 1 | = 문자열(Strings) 2 | :source-highlighter: coderay 3 | :source-language: clojure 4 | :sectnums: 5 | :icons: font 6 | 7 | 클로저에서 문자열 역시 자기 자신으로 평가되는 값(value)으로, 쌍따옴표(`"`)로 둘러싸 표현한다. 8 | 9 | indexterm:[string?] 10 | 11 | [source] 12 | .... 13 | "Welcome to Clojure!" ;=> "Welcome to Clojure!" 14 | 15 | (type "functional language") ;=> java.lang.String 16 | (string? "hello") ;=> true 17 | .... 18 | 19 | 자바의 `java.lang.String` 클래스를 그대로 이용하므로, `String` 클래스의 메소드도 이용할 수 20 | 있다. 21 | 22 | [source] 23 | .... 24 | (.toUpperCase "modern lisp") ;=> "MODERN LISP" 25 | .... 26 | 27 | 여러 줄의 입력도 가능하다. 28 | 29 | [source] 30 | .... 31 | "multiline strings 32 | are allowed too." 33 | ;=> "multiline strings\nare allowed too." 34 | .... 35 | 36 | `str` 함수는 주어진 인수들을 문자열로 변환한 후, 공백 없이 연결된 문자열을 반환한다. 단, 37 | ``nil``은 빈 문자열(`""`)로 변환된다. indexterm:[str] 38 | 39 | [source] 40 | .... 41 | (str) ;=> "" 42 | (str nil) ;=> "" 43 | 44 | (str 1) ;=> "1" 45 | (str 1 2 nil 3) ;=> "123" 46 | 47 | (str [1 2 3]) ;=> "[1 2 3]" 48 | 49 | (str 1 'symbol :keyword) ;=> "1symbol:keyword" 50 | (str "Hello, " "World!") ;=> "Hello, World!" 51 | .... 52 | 53 | indexterm:[format] 54 | 55 | `format` 함수는 `java.lang.String.format` 함수를 그대로 이용한다. 자세한 포맷 서식은 56 | `java.util.Formatter` 57 | http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html[관련 문서]를 58 | 참조하도록 한다. 59 | 60 | [source] 61 | .... 62 | (format "Hello there, %s" "Bob") 63 | ;=> "Hello there, Bob" 64 | 65 | (format "%5d" 3) 66 | ;=> " 3" 67 | 68 | (format "Pad with leading zeros %07d" 5432) 69 | ;=> "Pad with leading zeros 0005432" 70 | 71 | (format "Left justified :%-7d:" 5432) 72 | ;=> "Left justified :5432 :" 73 | .... 74 | 75 | indexterm:[subs] 76 | 77 | `subs` 함수는 주어진 문자열의 '시작 index(포함)'에서 '종료 index(불포함)'까지의 부분 78 | 문자열(substring)을 반환한다. index는 0부터 시작하고, '종료 index'가 주어지지 않으면, 79 | 문자열의 마지막까지 반환한다. 80 | 81 | [source] 82 | .... 83 | (subs "Clojure" 1 3) ;=> "lo" 84 | (subs "Clojure" 1) ;=> "lojure" 85 | .... 86 | 87 | == println-str/print-str/prn-str/pr-str 함수 88 | 89 | indexterm:[println-str] indexterm:[print-str] indexterm:[prn-str] indexterm:[pr-str] 90 | indexterm:[println] indexterm:[print] indexterm:[prn] indexterm:[pr] 91 | 92 | 이 함수들은 `println`/`print`/`prn`/`pr` 함수들과 관계가 있다. 함수명에 `-str`이 붙지 않은 93 | 이 함수들은, 문자열을 '반환'하는 함수가 아니라, 문자열을 stdout(표준 출력, 일반적으로 94 | 디스플레이 화면)에 '출력'하는 함수이다. 95 | 96 | [source] 97 | .... 98 | (println "Hello world.") 99 | ;>> Hello world. 100 | ;=> nil 101 | 102 | (println-str "Hello world.") 103 | ;=> "Hello world.\n" 104 | .... 105 | 106 | 위 두 함수의 출력 결과를 표시할 때, 표기 방식이 약간 다르다는 점에 먼저 주목할 필요가 107 | 있다. ``;>> `` 기호는 그 뒤의 문자열이 '화면'에 출력되었다는 것을 나타내고, `pass:c[;=>]` 108 | 기호는 이 함수의 반환값이 ``nil``이라는 것을 표시하고 있다. 즉, `println` 함수는 side 109 | effect(부수 효과)를 수행하는 함수이다. 그리고 클로저에서 부수 효과를 실행하는 함수들은 110 | 대개 `nil` 값을 반환한다. 111 | 112 | 반면에 `println-str` 함수는, ``println``을 사용했다면 화면에 출력되었어야 할 문자열을, 113 | 화면에 출력하지 않고 함수의 반환값으로 리턴한다. ``-str``이 붙고 붙지 않은 나머지 함수들의 114 | 관계도 마찬가지이다. 115 | 116 | `println` 함수는 개행 문자(newline)를 맨마지막에 추가하는 반면, `print` 함수는 개행 문자를 117 | 추가하지 않는다. 118 | 119 | [source] 120 | .... 121 | (println "foo") (println "foo") 122 | ;>> foo 123 | ;>> foo 124 | ;=> nil 125 | 126 | (print "foo") (print "foo") 127 | ;>> foofoo 128 | ;=> nil 129 | .... 130 | 131 | `prn` 함수와 `pr` 함수의 관계도 `println` 함수와 `print` 함수의 관계와 같다. 즉, 132 | 개행문자를 추가하는지 여부의 차이이다. 133 | 134 | [source] 135 | .... 136 | (prn "foo") (prn "foo") 137 | ;>> "foo" 138 | ;>> "foo" 139 | ;=> nil 140 | 141 | (pr "foo") (pr "foo") 142 | ;>> "foo""foo" 143 | ;=> nil 144 | .... 145 | 146 | 이번에는 ``println``과 ``prn``의 차이를 알아보자. 이 두 함수는 '문자열'과 '문자'를 출력할 147 | 때에만 차이가 있다. 148 | 149 | [source] 150 | .... 151 | (println 10 "foo\nbar" \A :keyword [1 2 3]) 152 | ;>> 10 foo 153 | ;>> bar A :keyword [1 2 3] 154 | ;=> nil 155 | 156 | (prn 10 "foo\nbar" \A :keyword [1 2 3]) 157 | ;>> 10 "foo\nbar" \A :keyword [1 2 3] 158 | ;=> nil 159 | .... 160 | 161 | 즉, 문자열 자료형을 출력할 때, `println` 함수는 '사람이 읽기 쉬운' 형태로 출력한다. 그래서 162 | 출력할 때, 겹따옴표(`"`)를 제거하고 개행 문자 ``\n``도 실제 개행을 한 결과를 163 | 보여준다. 그리고 문자 자료형인 경우에는 역슬래시(`\`) 기호를 제거한 상태로 출력해 준다. 164 | 이 두 자료형을 제외한 나머지 자료형들의 경우에는, 두 함수 모두 출력한 결과에 차이가 없다. 165 | 166 | 반면에 ``prn`` 함수는 클로저의 리더(reader) 함수인 ``read``나 `read-string` 함수가 167 | 다시 읽어 들일 수 있는 형태로 출력해 준다. 168 | 169 | [source] 170 | .... 171 | (prn "hello") 172 | ;>> "hello" 173 | ;=> nil 174 | 175 | (println "hello") 176 | ;>> hello 177 | ;=> nil 178 | 179 | (prn-str "hello") 180 | ;>> "\"hello\"\n" 181 | 182 | (println-str "hello") 183 | ;>> "hello\n" 184 | .... 185 | 186 | 다음에서 `"hello"` 문자열이 인수로 주어졌지만, 첫 번째 줄은 문자열 ``"hello"``를 반환한 187 | 반면에, 두 번째 줄은 심볼 ``hello``를 반환했다. 그래서 출력한 문자열을 문자열 그대로 클로저 188 | 리더 함수로 다시 읽어 들이고 싶다면 `prn-str` 또는 `pr-str` 함수를 사용해야 한다. 189 | 190 | [source] 191 | .... 192 | (read-string (prn-str "hello")) ;=> "hello" 193 | (read-string (println-str "hello")) ;=> hello 194 | .... 195 | 196 | 197 | == `clojure.string` 이름 공간의 문자열 처리 함수들 198 | 199 | `clojure.string` 이름 공간에는 문자열 처리시 유용한 함수들이 많다. 그 중 몇 개만 200 | 소개한다. 201 | 202 | indexterm:[upper-case] indexterm:[lower-case] 203 | 204 | ``upper-case``와 `lower-case` 함수는 각각 주어진 문자열을 대문자와 소문자로 바꾼다. 205 | 206 | [source] 207 | .... 208 | (require '[clojure.string :as str]) 209 | 210 | (str/upper-case "Clojure User Groups") 211 | ;=> "CLOJURE USER GROUPS" 212 | 213 | (str/lower-case "Clojure User Groups") 214 | ;=> "clojure user groups" 215 | .... 216 | 217 | indexterm:[split] 218 | 219 | `split` 함수는 문자열과 정규식 패턴을 받아, 분할된 문자열의 벡터를 반환한다. 클로저에서 220 | 정규식은 문자열 앞에 `#` 기호를 붙여 표시하는데, 자바의 정규식 표현을 따른다. 221 | 222 | [source] 223 | .... 224 | (str/split "Clojure is awesome!" #" ") 225 | ;=> ["Clojure" "is" "awesome!"] 226 | 227 | (str/split "q1w2e3r4t5y6u7i8o9p0" #"\d+") 228 | ;=> ["q" "w" "e" "r" "t" "y" "u" "i" "o" "p"] 229 | .... 230 | 231 | 정규식 인수 뒤에 숫자를 지정하면, 해당하는 숫자만큼의 문자열들을 반환한다. 232 | 233 | [source] 234 | .... 235 | (str/split "q1w2e3r4t5y6u7i8o9p0" #"\d+" 5) 236 | ;=> ["q" "w" "e" "r" "t5y6u7i8o9p0"] 237 | .... 238 | 239 | indexterm:[join] 240 | 241 | ``join`` 함수는 인수로 주어진 컬렉션을, 문자열로 변환환 후 연결해 반환한다. 242 | 243 | [source] 244 | .... 245 | (str/join [1 2 3]) 246 | ;=> "123" 247 | .... 248 | 249 | 연결할 떄 사용할 문자열을 컬렉션 앞에 지정해 주는 것이 일반적이다. 250 | 251 | [source] 252 | .... 253 | (str/join ", " ["spam" "eggs" "spam"]) 254 | ;=> "spam, eggs, spam" 255 | 256 | (str/join ", " ["spam" "" "eggs" nil "spam"]) 257 | ;=> "spam, , eggs, , spam" 258 | 259 | (str/join "\n" (str/split "The Quick Brown Fox" #"\s")) 260 | ;=> "The\nQuick\nBrown\nFox" 261 | .... 262 | 263 | indexterm:[trim] indexterm:[triml] indexterm:[trimr] 264 | 265 | `trim` 함수는 주어진 문자열의 좌우 끝에 있는 공백 문자들을 모두 제거한 문자열을 266 | 반환한다. ``triml``과 `trimr` 함수는 각각 주어진 문자열의 좌측과 우측 끝에 있는 공백 267 | 문자들을 제거한 문자열을 반환한다. 268 | 269 | 이 세 함수 모두 문자열 중간에 있는 공백 문자들은 제거하지 않는다. 270 | 271 | [source] 272 | .... 273 | (str/trim " my string ") 274 | ;=> "my string" 275 | 276 | (str/triml " my string ") 277 | ;=> "my string " 278 | 279 | (str/trimr " my string ") 280 | ;=> " my string" 281 | .... 282 | 283 | 284 | 285 | -------------------------------------------------------------------------------- /Start/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Start/start.adoc: -------------------------------------------------------------------------------- 1 | = 클로저 시작하기 2 | :sectnums: 3 | :source-language: clojure 4 | :source-highlighter: coderay 5 | :linkcss: 6 | :stylesdir: ../ 7 | :stylesheet: my-asciidoctor.css 8 | :docinfo1: 9 | :toc: right 10 | 11 | 12 | == 클로저 코드의 특징들 13 | 14 | 컴퓨터 언어의 역사에서 Lisp 계열 언어들(Common Lisp, Scheme, Racket, Clojure, ...)은 Algol 15 | 계열 언어들과는 다른 계보를 형성해 왔다. 오늘날의 주류 언어들(C, C++, C#, Java, 16 | JavaScript, Python, Ruby, Perl, ...)이 모두 알골계 언어들인데 반해, 클로저는 리습 계열 17 | 언어여서 실제 코드를 본 후 아마도 생소한 느낌을 갖는 사람들이 많았을 것이다. 따라서 클로저 18 | 언어를 본격적으로 익히기에 앞서, 다른 언어들과의 두드러진 차이점 몇 가지를 먼저 소개한다. 19 | 20 | 21 | === 괄호의 사용 22 | 23 | 클로저 코드를 처음 접한 사람들은 아마도 그 많은 괄호에 강한 거부감을 느꼈을 것이다. 그런 24 | 느낌은 이 글을 쓰고 있는 필자들의 경우도 예외는 아니었다. 하지만 그 형태가 아니라, 괄호가 25 | 있음으로 인해 가지게 되는 막강한 효용에 눈뜨기 시작할 때부터, 거부감의 대상이던 그 26 | 괄호들이 아름답게 보이기 시작한다. 이것은 단순한 주관적인 느낌이 아니라, 리습 언어를 27 | 알아가는 사람들의 공통된 심리적 패턴이다. 28 | 29 | 괄호가 있어서 얻을 수 있는 첫 번째 이점은, 코드의 의미가 명확해져 연산자 우선 순위를 따로 30 | 외울 필요가 없다는 점이다. 다음의 두 코드를 보면 어느 것의 의미가 명확한지는 자명하다. 31 | 32 | .C 33 | [source,c] 34 | .... 35 | a > b + c * d && e 36 | .... 37 | 38 | .Clojure 39 | [source] 40 | .... 41 | (and (> a (+ b (* c d))) e) 42 | .... 43 | 44 | 하지만, 괄호를 사용하는 진정한 위력은 매크로를 작성할 때 나온다. 리습 언어가 Programmable 45 | Programming Language라고 불리는 이유는 매크로를 통해 코드를 조작할 수 있기 때문인데, 이 46 | 괄호가 있음으로 해서 코드 조작이 수월해진다. 위의 클로저 코드를 잘 살펴보면, 이미 코드 47 | 형태 자체가 구문 트리(Syntax Tree)의 형식이어서, 이 코드를 변형하기 위해 별도의 48 | 파싱(parsing) 과정을 거칠 필요가 없기 때문이다. 지금 당장은 잘 이해가 안되더라도 매크로를 49 | 작성하다 보면 그 가치를 깨닫게 된다. 그리고 바로 그 순간부터 괄호가 아름답게 보이기 50 | 시작한다. 사실 괄호가 있음으로 해서 좀더 강력하면서도 간결한 프로그래밍이 가능해진다면, 51 | 괄호가 많다는 것이 무슨 그리 큰 대수이겠는가? 52 | 53 | 54 | === 전위 표기법(Prefix Notation) 55 | 56 | 리습 언어들에서는 연산자와 함수명이 괄호 내의 맨 앞 자리(전위 표기법: Prefix Notation)에 57 | 온다. 사실 함수명의 경우에는 C 언어나 클로저나 큰 차이가 없다. 단지 함수 이름이 괄호 밖에 58 | 있는가 안에 있는가의 차이와, 함수의 인수들 사이에 콤마를 찍느냐 마느냐의 차이밖에는 59 | 없다. 함수명의 경우에는, 약간의 차이만 있을 뿐 C 언어도 이미 전위 표기법을 사용하고 있다는 60 | 말이다. 61 | 62 | .C 63 | [source,c] 64 | .... 65 | printf("ASCII value = %d, Character = %c\n", ch , ch); 66 | .... 67 | 68 | .Clojure 69 | [source] 70 | .... 71 | (printf "ASCII value = %d, Character = %c%n" ch ch) 72 | .... 73 | 74 | 차이가 있다면 연산자의 경우인데, C 언어에서는 중위 표기법(Infix Notation)을 사용하고 75 | 클로저에서는 함수명과 마찬가지로 전위 표기법을 사용한다. 76 | 77 | .C 78 | [source,c] 79 | .... 80 | a + b + c + d + e; 81 | .... 82 | 83 | .Clojure 84 | [source] 85 | .... 86 | (+ a b c d e) 87 | .... 88 | 89 | 클로저의 경우에는 전위 표기법을 사용함으로써, 연산항이 많을 때 `+` 기호를 반복할 필요가 90 | 없다는 장점이 있다. 91 | 92 | 리습 계열 언어에서는 연산자와 함수가 다른 취급을 받지 않는다. 연산자의 경우, 수학에서 이미 93 | 중위 표기법을 사용하고 있어 대부분의 언어가 그것을 답습하고 있을 뿐, 프로그래밍에서는 굳이 94 | 그것을 구분해 처리하지 않는 것이 오히려 일관되고 편리하다. 연산자가 중간에 위치하게 되면 95 | 컴파일러에서는 이를 따로 파싱해야하는 수고를 한 번 더 거쳐야 하기 때문이다. 96 | 97 | 예를 들어, C 언어에서 `**` 연산자를 거듭제곱 연산자로 여러분이 언어에 추가하고 싶다고 98 | 가정해 보자. 그러자면 우선 C 표준을 다루는 위원회에 제안을 해야 할 것이다. 물론 이 제안이 99 | 받아들여진다는 보장도 없지만, 이 위원회가 그 타당성을 인정해 새로운 C 언어 표준에 100 | 반영하기로 했다고 가정해 보자. 그러면 그 후에 모든 C 컴파일러를 이 새로운 표준에 맞춰 다시 101 | 작성해야 할 것이고, 이 연산자를 이용해 작성한 C 소스는 구 버전의 컴파일러에서는 제대로 102 | 컴파일이 되지도 않을 것이다. 이 상황을 클로저에 적용해 보면 일은 너무도 간단해진다. 클로저 103 | 프로그래머는 다음과 같이 코드를 작성하면 된다. 104 | 105 | [source] 106 | .... 107 | (defn ** [a b] 108 | (Math/pow a b)) 109 | 110 | (** 2 8) ; => 256.0 111 | .... 112 | 113 | 얼마나 간단한가? 연산자와 함수를 구별할 필요가 없는 데서 오는 편리함이다. 함수 추가하듯이 114 | 연산자를 추가하면 된다. 엄밀하게 말하자면, 클로저에는 다른 언어들에서의 연산자라는 개념이 115 | 따로 없다. 함수의 이름으로 기호를 사용할 수 있어서 오직 함수만이 존재할 뿐이다. 연산자의 중위 116 | 표기법을 과감하게 버림으로써, 다른 언어에서 언어의 표준 위원회에서나 결정할 수 있는 일을 117 | 개발자가 직접 할 수 있게 된 것이다. 118 | 119 | 120 | === 모든 것이 식(expression)이다. 121 | 122 | 클로저는 리습 계열의 언어이다. 따라서 클로저가 갖는 리습 언어로서의 특징을 먼저 이해해야 123 | 한다. 클로저에서는 모든 것이 식이다. 즉, 어떤 코드의 일부를 실행하든 전체를 실행하든 124 | 반드시 어떤 값(value)을 반환한다. 다른 언어들에서의 문(statement)이라는 개념이 클로저에는 125 | 없다. 126 | 127 | 이해를 돕기 위해, C 언어에서의 삼항 연산자(`? :`)와 `if` 문을 예로 들어 보자. 128 | 129 | 아래의 삼항 연산자는 식(expression)이어서, 이 연산자 자체가 ``10``이나 ``20``을 반환한 후 130 | 그 결과값이 ``result``에 저장된다. 131 | 132 | [source,c] 133 | .... 134 | result = a > b ? 10 : 20; 135 | .... 136 | 137 | 하지만 아래의 `if` 문은 식(expression)이 아니라 문(statement)이어서, `if` 문 자체가 138 | ``10``이나 ``20``을 반환하는 것이 아니라, `if` 문의 내부에서 `result` 변수의 상태를 139 | 변경하고 있다. 140 | 141 | [source,c] 142 | .... 143 | if (a > b) { 144 | result = 10; 145 | } else { 146 | result = 20; 147 | } 148 | .... 149 | 150 | 만약 C의 ``if``가 식이였다면 다음의 코드가 작동해야 한다(물론, 다음의 코드는 적법한 C 151 | 코드가 아니다). 152 | 153 | [source,c] 154 | .... 155 | result = if (a > b) 10 else 20; 156 | .... 157 | 158 | 159 | 이와 같이 문(statement)은 주로 어떤 명령을 수행해서 부수 효과(side effect)를 내기 위한 160 | 용도로 주로 쓰인다. 반면에 식(expression)은 코드가 어떤 값을 반환하느냐 하는 것에 관심이 161 | 있을 때 쓰인다. 162 | 163 | 그러면 이것이 왜 중요한가? 모든 코드가 식으로 구성되면, 코드의 표현력이 늘어나고 아울러 164 | 코드의 조합력이 증가한다. 왜냐하면 코드가 부수 효과 없이 어떤 값만을 반환하다면, 코드는 165 | 참조 투명성(referential transparency)이 보장되며, 또한 일급 객체(first citizen)로 다루어질 166 | 수 있어서 함수의 파라미터로 사용될 수 있기 때문이다. 167 | 168 | ``if``가 문이 아니라 식일 때, 코드의 표현력이 어떻게 증가하는지 다음의 실제 예제를 통해 169 | 살펴보자. 170 | 171 | 다음의 버전 1은, 우리가 흔히 사용하는 `if` 문의 예이다. ``n``이 참이면, ``-n``만큼 172 | 이동하고, 거짓이면 ``-1``만큼 이동한다. 173 | 174 | .Version 1 175 | [source] 176 | .... 177 | (if n ; condition 178 | (move (- n)) ; then-part 179 | (move -1)) ; else-part 180 | .... 181 | 182 | ``if``가 식이 아니라 문인 언어에 익숙해져 있는 사람들에게는 위의 코드를 별도의 함수를 183 | 사용하지 않고 더 간결하게 표현할 수 있다는 생각 자체가 떠오르지 않을 것이다. 하지만 리습 184 | 언어로 사고하는 사람들은 문제점을 발견한다. 즉, 위 코드의 문제점은 `move` 호출이 두 185 | 번씩이나 중복되어 있다는 것이다. ``if``가 식인 언어에서는, 이를 수학에서 인수분해할 때 186 | 공통 인수 뽑아내듯이 더 간단하게 다음과 같이 줄일 수 있다. 187 | 188 | .Version 2 189 | [source] 190 | .... 191 | (move (if n (- n) -1)) 192 | .... 193 | 194 | 위의 코드가 C 언어에서 동작할 수 없는 이유는, `move` 함수의 첫 번째 인수 자리에 놓인 `if` 195 | 문이 어떤 값도 반환할 수 없기 때문이다. 하지만 리습 계열 언어에서는 모든 것이 식이이서, 196 | ``if``조차도 값을 반환할 수 있어 위와 같은 표현이 가능해진다. 197 | 198 | 한 걸음 더 나아가 ``-``도 한 번 더 공통 인수로 뽑아낼 수 있다. 199 | 200 | .Version 3 201 | [source] 202 | .... 203 | (move (- (if n n 1))) 204 | .... 205 | 206 | ``if``를 ``or`` 로 대치하면 더 간결해 진다. 207 | 208 | .Version 4 209 | [source] 210 | .... 211 | (move (- (or n 1))) 212 | .... 213 | 214 | 215 | 클로저에서는 반복문조차도 값을 반환한다. 216 | 217 | [source] 218 | .... 219 | (for [n [1 2 3 4 5]] 220 | (* 2 n)) 221 | ; => (2 4 6 8 10) 222 | .... 223 | 224 | stdout에 결과를 출력(이것도 일종의 부수 효과이다)하기 위한 함수 ``println``조자도 225 | ``nil``이라는 값을 반환한다footnote:[참고로, 클로저에서 부수 효과를 수행하는 함수들은 226 | 대체로 ``nil``을 반환한다.]. 아래에서 `;>>` 기호는 stdout 출력 결과를, pass:q[`;=>`] 227 | 기호는 함수의 반환 결과를 표시한다. 228 | 229 | [source] 230 | .... 231 | (println "Hello" "world!") 232 | ;>> Hello world! 233 | ;=> nil 234 | 235 | .... 236 | 237 | 위와 같이 클로저와 같은 리습 계열 언어에서는 코드의 일부 또는 전체가 모두 식으로 구성되어 238 | 있다. 그래서 모든 리습 계열 언어에서는 코드를 '실행(execution)'한다고 하지 않고 239 | '평가(evaluation)'한다고 표현하는데, 그 이유는 evaluation이라는 말 자체가 접두어 e-(out)와 240 | value(값)의 합성어로, 어떤 값을 내놓는다, 즉 평가한다는 의미를 갖고 있기 때문이다. 다시 241 | 말해, 비리습 계열 언어에서의 실행한다는 말 속에는 실행 결과가 어떤 값을 내놓지 않을 수도 242 | 있다는 의미가 함축되어 있기 때문에, 리습 계열 언어에서는 평가한다는 말을 주로 사용한다. 243 | 244 | 아울러 모든 코드가 식이라는 사실은, 나중에 배우게 될 매크로(Macros)의 구현에도 대단히 245 | 중요한 의미를 지닌다. 246 | 247 | 248 | === return 문이 없다 249 | 250 | 클로저에는 값을 반환하기 위한 `return` 문이 별도로 존재하지 않는다. 마지막에 위치해 있는 251 | 식이 평가된 결과가 곧 반환값이 된다. 252 | 253 | [source] 254 | .... 255 | (defn my-add [a b] 256 | (println "LOG: Computing...") 257 | (+ a b)) 258 | 259 | (my-add 1 2) 260 | ;>> LOG: Computing... 261 | ;=> 3 262 | .... 263 | 264 | 아울러 `return` 문이 아예 존재하지 않으므로, 함수 실행 도중에 함수의 실행을 종료할 수 265 | 없다. 일단 함수가 실행되면 함수의 끝에 도달해야 함수가 종료된다. 이것은 함수형 언어의 266 | 일반적인 특징이기도 하다. 267 | 268 | 269 | == 주석(Comment) 270 | 271 | 클로저에서 주석을 표현하는 방식에는 세 가지가 있다. 272 | 273 | * `;` reader macro 274 | * `comment` macro 275 | * `#_` reader macro 276 | 277 | 278 | === `;` 주석 문자 279 | 280 | 클로저에서 라인 단위 주석 문자는 ``;``이다. 이 주석 문자가 나온 부분부터 라인의 끝까지 281 | 주석으로 처리된다. 참고로, 리습 계열 언어들은 일반적으로 ``;`` 문자를 라인 주석 문자로 282 | 사용한다. 283 | 284 | 리습 계열 언어에서는 주석을 달 때 일반적으로 다음과 같은 관행을 따른다. 반드시 따라야 하는 285 | 것은 아니지만, 참고로 알아 두자. 286 | 287 | * 패키지 또는 이름공간 수준의 주석은 `;` 기호 4개를 사용한다. 288 | * 여러 개의 함수에 공통적으로 해당되는 주석은 `;` 기호 3개를 사용한다. 289 | * 함수 한 개에 대한 설명(예를 들면, 구현 알고리즘)이나, 함수 내 코드 블럭에 대한 주석은 290 | `;` 기호 2개를 사용한다. 함수 내 코드 블럭에 대한 주석인 경우에는, 주석을 코드 블럭 앞에 291 | 두고, 코드 블럭에 맞게 들여쓰기를 맞춘다. 292 | * 코드 뒤에 주석을 달 때는 `;` 기호 1개를 사용한다. 293 | 294 | 다음은 위의 관행을 따른 예제이다. 295 | 296 | [source] 297 | .... 298 | ;;;; frob namespace 299 | (ns my-project.frob) 300 | 301 | ;;; The next 20 functions do various sorts of frobbing 302 | 303 | ;; frob1 function 304 | (defn frob1 [num] 305 | ;; return double frob of num 306 | (let [tmp (ran-int num)] ; breaks if 0, fix! 307 | (double-frob tmp num :with-good-luck true))) 308 | 309 | ;; frob2 function 310 | (defn frob2 [lst] 311 | (frob-aux (first lst))) 312 | .... 313 | 314 | 315 | === `comment` 매크로 316 | 317 | `comment` 매크로는 여러 개의 최상위(top level) 코드들을 한꺼번에 모두 주석 처리하고 싶을 318 | 때 주로 사용한다. 319 | 320 | [source] 321 | .... 322 | (comment 323 | (def greeting "Hello, World!") 324 | 325 | ;; The first version of main function. 326 | ;; TODO: delete if a new version completes. 327 | (defn -main [] 328 | "I can say 'Hello World'." 329 | (println greeting)) 330 | ) 331 | 332 | (defn hello-world [] (println "Hello, World!")) 333 | 334 | (defn -main [] 335 | "I can call a function, which prints 'Hello World'." 336 | (hello-world)) 337 | .... 338 | 339 | `comment` 매크로는 괄호로 둘러 싸인 부분을 주석으로 처리한 후, 반환값으로 항상 ``nil``을 340 | 반환한다. 따라서 다음과 같은 곳에서 이 매크로를 사용하면 안된다. 341 | 342 | [source] 343 | .... 344 | ;; 다음의 코드는 결과적으로 (+ 10 20 nil 30)을 계산하게 된다. 345 | ;; 이때 + 함수는 nil을 대상으로 연산을 수행할 수 없으므로 예외가 발생한다. 346 | (+ 10 20 (comment (* 2 3)) 30) 347 | ;>> NullPointerException clojure.lang.Numbers.ops 348 | .... 349 | 350 | 아울러 `comment` 매크로로 둘러싸인 코드는, 클로저 문법에 맞는 코드이어야 한다. 다음의 351 | 코드는 클로저가 읽어 들일 수 없는 코드이므로 예외가 발생했다. 352 | 353 | [source] 354 | .... 355 | (comment 356 | a : b 357 | ) 358 | ;>> RuntimeException Invalid token: : 359 | .... 360 | 361 | 362 | === `#_` reader 매크로 363 | 364 | `#_` reader 매크로는 그 뒤에 나오는 형식(form) 한 개만을 주석 처리한다. 365 | 366 | CAUTION: `pass:[#_]` reader 매크로는 그 다음에 나오는 형식(form)의 소스 코드를 클로저 367 | 자료형으로 아예 읽어 들이지 않고 무시한다. 반면에 `comment` 일반 매크로는 괄호로 둘러 싸인 368 | 소스 코드를 클로저 자료형으로 일단 읽어 들인 후 무시한다는 점에서 `#_` reader 매크로와 369 | 다르다. 그래서 ``comment``의 경우에는 소스 코드를 읽어 들이는 과정에서 오류가 없어야 한다. 370 | 371 | [source] 372 | .... 373 | ;; 아래의 코드는 (+ 10 20 30)과 동일하다. 374 | (+ 10 20 #_ (* 2 3) 30) ;=> 60 375 | 376 | ;; 아래의 코드는 (+ 20 30)과 동일하다. 377 | (+ #_ 10 20 #_ (* 2 3) 30) ;=> 50 378 | .... 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | -------------------------------------------------------------------------------- /Testing/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /Testing/testing.adoc: -------------------------------------------------------------------------------- 1 | = Testing 2 | :source-language: clojure 3 | :source-highlighter: coderay 4 | :sectnums: 5 | :imagesdir: ../img 6 | :linkcss: 7 | :stylesdir: ../ 8 | :stylesheet: my-asciidoctor.css 9 | :docinfo1: 10 | :toc: right 11 | 12 | 프로그램을 개발하는데 있어, TDD(Test Driven Development) 방법론은, 테스트와 프로그램 13 | 개발을 병행함으로써, 이미 작성된 모든 프로그램 코드의 무결성을 그때 그때 확인해 가며 14 | 개발을 진행할 수 있기 때문에, 나중에 발견될 수도 있는 버그 처리 과정을 미리 방지하게 해 15 | 준다. 아울러 테스트 코드 자체가 프로그램 코드의 훌륭한 실행 예제를 제공하므로, 해당 API의 16 | 문서화의 효과도 볼 수 있다. 17 | 18 | 언뜻 생각하기에는, 프로그램 코드와 테스트 코드를 둘 다 작성하다 보면, 시간이 더 걸리는 것 19 | 아니냐는 생각을 할 수도 있는데, 실제의 경험상으로는 그 반대다. 테스트 코드를 작성하며 20 | 코딩을 진행하면, 본 코드를 작성할 때 테스트를 염두에 두고 코드를 짜게 된다. 그 결과 21 | 테스트에 용이한 보다 단순하고 논리적인 코드를 작성하게 되어, 프로그램의 유지/보수에 더 22 | 용이한 생산적인 코드를 낳게 된다. 아울러 코드를 개선할 때마다 테스트 코드를 실행함으로써, 23 | 이전에 작성한 모든 코드들과의 호환성을 미리 검증하는 과정을 매번 거치치 되므로, 버그를 24 | 미연에 방지해 주는 효과까지 곁들어지게 되어, 결과적으로는 프로젝트를 더 짧은 시간 안에 25 | 완료할 수 있게 해 즌다. 코딩하는 시간보다 디버깅하는 시간이 훨씬 더 많이 든다는 것을 이미 26 | 경험해 본 프로그래머라면 위의 주장이 쉽게 납득되리라 본다. 27 | 28 | 클로저는 `clojure.test` 패키지에 TDD를 지원하는 기능이 준비되어 있다. 29 | 30 | == deftest & is 31 | 32 | 대부분의 테스트 코드는 `deftest` 매크로와 `is` 매크로를 이용해 작성한다. 33 | 34 | .deftest 매크로 35 | [listing] 36 | ---- 37 | (deftest name expr+) 38 | name := test name을 지정한다. 39 | expr := 실제 test 코드가 작성되는 자리. 40 | ---- 41 | 42 | .is 매크로 43 | [listing] 44 | ---- 45 | (is predicate message?) 46 | predicate := 참 또는 거짓을 반환하는 form. 47 | message := predicate이 거짓을 반환할 경우, 출력할 메시지. 48 | ---- 49 | 50 | `is` 매크로는, 테스트 실패시 출력할 메시지를, 두 번째 인수에 지정할 수도 있다. 51 | 52 | [source] 53 | .... 54 | ;; file: myproject/test/myproject/core_test.clj 55 | (ns myproject.core-test 56 | (:use [clojure.test])) 57 | 58 | (deftest add 59 | (is (= 4 (+ 2 2))) 60 | (is (= 2 (+ 2 0)) "adding zero doesn't change value")) 61 | .... 62 | 63 | `lein test` 명령을 내리면, `myproject/test` 폴더 아래의 모든 테스트 파일들을 읽어 들여 64 | 실행한다. 각 테스트 파일 안의 모든 `deftest` 문을 실행한 후, 그 결과를 보고한다. 65 | 66 | [listing] 67 | ---- 68 | $ lein test 69 | 70 | lein test myproject.core-test 71 | 72 | Ran 1 tests containing 2 assertions. 73 | 0 failures, 0 errors. 74 | ---- 75 | 76 | 위에서는 test 1건, assertion 2건을 처리해 실패 0건, 에러 0건이 발생했음을 보고하고 있다. 77 | 78 | 이번에는 의도적으로 테스트 실패를 유도해 보자. 79 | 80 | [source] 81 | .... 82 | (ns myproject.core-test 83 | (:use [clojure.test])) 84 | 85 | (deftest add 86 | (is (= 4 (+ 2 2))) 87 | (is (= 2 (+ 2 0)) "adding zero doesn't change value") 88 | (is (= 9 (+ 4 4))) ; error here 89 | (is (= 7 (+ 2 4)) "2 + 4 should return 6")) ; error here 90 | .... 91 | 92 | [listing] 93 | ---- 94 | $ lein test 95 | 96 | lein test myproject.core-test 97 | 98 | lein test :only myproject.core-test/add 99 | 100 | FAIL in (add) (core_test.clj:7) 101 | expected: (= 9 (+ 4 4)) 102 | actual: (not (= 9 8)) 103 | 104 | lein test :only myproject.core-test/add 105 | 106 | FAIL in (add) (core_test.clj:8) 107 | 2 + 4 should return 6 108 | expected: (= 7 (+ 2 4)) 109 | actual: (not (= 7 6)) 110 | 111 | Ran 1 tests containing 4 assertions. 112 | 2 failures, 0 errors. 113 | Tests failed. 114 | ---- 115 | 116 | 117 | == are 118 | 119 | .are 매크로 120 | [listing] 121 | ---- 122 | (are argv expr arg*) 123 | ---- 124 | 125 | ``clojure.test``는 `is` 매크로 외에도 `are` 매크로를 제공한다. 이름을 통해 예상할 수 126 | 있겠지만, 하나의 `are` 매크로는 여러 개의 `is` 매크로를 대신할 수 있다. 127 | 128 | 방금 전에 든 예를, `are` 매크로를 사용해 재작성해 보면 다음과 같다. 129 | 130 | [source] 131 | .... 132 | (ns myproject.core-test 133 | (:use [clojure.test])) 134 | 135 | (deftest add 136 | (are [sum x y] (= sum (+ x y)) 137 | 4 2 2 138 | 2 2 0 139 | 9 4 4 140 | 7 2 4)) 141 | .... 142 | 143 | 즉, ``sum``에 4, ``x``에 2, ``y``에 2가 각각 대입된 후, ``(= sum (+ x y))``가 수행됨을 알 144 | 수 있다. 145 | 146 | [listing] 147 | ---- 148 | $ lein test 149 | 150 | lein test myproject.core-test 151 | 152 | lein test :only myproject.core-test/add 153 | 154 | FAIL in (add) (core_test.clj:5) 155 | expected: (= 9 (+ 4 4)) 156 | actual: (not (= 9 8)) 157 | 158 | lein test :only myproject.core-test/add 159 | 160 | FAIL in (add) (core_test.clj:5) 161 | expected: (= 7 (+ 2 4)) 162 | actual: (not (= 7 6)) 163 | 164 | Ran 1 tests containing 4 assertions. 165 | 2 failures, 0 errors. 166 | Tests failed. 167 | ---- 168 | 169 | `are` 매크로는, 실제로는 여러 개의 `is` 매크로로 확장된다. 확장된 모습을 살펴보자. 170 | 171 | [source] 172 | .... 173 | (macroexpand '(are [sum x y] (= sum (+ x y)) 174 | 4 2 2 175 | 2 2 0 176 | 9 4 4 177 | 7 2 4)) 178 | ; => (do 179 | ; (clojure.test/is (= 4 (+ 2 2))) 180 | ; (clojure.test/is (= 2 (+ 2 0))) 181 | ; (clojure.test/is (= 9 (+ 4 4))) 182 | ; (clojure.test/is (= 7 (+ 2 4)))) 183 | .... 184 | 185 | `is` 매크로로 모두 확장된 것을 직접 확인할 수 있다. 186 | 187 | 188 | == testing 189 | 190 | .testing 매크로 191 | [listing] 192 | ---- 193 | (testing string expr+) 194 | ---- 195 | 196 | `testing` 매크로는, 테스트를 그룹화하기 위한 용도로 사용되고, 테스트가 실패할 경우 출력할 197 | 메시지를 지정할 수 있다. `deftest` 매크로 안에서 사용되어야 하며, 중첩될 수 있다. 198 | 199 | [source] 200 | .... 201 | (ns myproject.core-test 202 | (:use [clojure.test])) 203 | 204 | (deftest arithmetic 205 | (testing "Addition" 206 | (testing "with positive integers" 207 | (is (= 4 (+ 2 2))) 208 | (is (= 7 (+ 3 4)))) 209 | (testing "with negative integers" 210 | (is (= -5 (+ -2 -2))) ; error here 211 | (is (= -1 (+ 3 -4))) ))) 212 | .... 213 | 214 | [listing] 215 | ---- 216 | $ lein test 217 | 218 | lein test myproject.core-test 219 | 220 | lein test :only myproject.core-test/arithmetic 221 | 222 | FAIL in (arithmetic) (core_test.clj:10) 223 | Addition with negative integers 224 | expected: (= -5 (+ -2 -2)) 225 | actual: (not (= -5 -4)) 226 | 227 | Ran 1 tests containing 4 assertions. 228 | 1 failures, 0 errors. 229 | Tests failed. 230 | ---- 231 | 232 | 233 | == exception 테스트 234 | 235 | ``form``에서 던진 예외가, ``exception-class``와 일치하고, 함께 전달된 메시지가 236 | ``message``와 일치하면 테스트를 통과하고, 그렇지 않으면 테스트가 실패한다. 237 | 238 | [listing] 239 | ---- 240 | (thrown? exception-class form) 241 | (thrown? exception-class message form) 242 | 243 | exception-class := form에서 발생이 예상되는 예외 클래스명 244 | message := 예외가 발생할 떄, 함께 전달되는 메시지, 정규식 문자열로 표시 245 | form := 예외를 발생하는 form 246 | ---- 247 | 248 | `is` 매크로 내에서, 예외가 실제로 발생하는 지를 테스트할 수 있다. 249 | 250 | [source] 251 | .... 252 | (ns myproject.core-test 253 | (:use [clojure.test])) 254 | 255 | (deftest divide-by-zero 256 | ;; ArithmeticException 예외를 발생하므로, 테스트 통과 257 | (is (thrown? ArithmeticException (/ 1 0))) 258 | 259 | ;; ArithmeticException 예외를 발생하지 않으므로, 테스트 실패 260 | (is (thrown? ArithmeticException (/ 1 2))) 261 | 262 | ;; ArithmeticException 예외를 발생하고, 이때 전달되는 메시지가 일치하므로 263 | ;; 테스트 통과 264 | (is (thrown-with-msg? ArithmeticException #"Divide by zero" 265 | (/ 2 0) )) 266 | 267 | ;; ArithmeticException 예외가 발생하지만, 이때 전달되는 메시지가 일치 안하므로 268 | ;; 테스트 실패 269 | (is (thrown-with-msg? ArithmeticException #"Incorrect message" 270 | (/ 2 0) )) 271 | 272 | ;; ArithmeticException 예외를 발생하지 않으므로, 테스트 실패 273 | (is (thrown-with-msg? ArithmeticException #"Divide by zero" 274 | (/ 1 3) ))) 275 | .... 276 | 277 | [listing] 278 | ---- 279 | $ lein test 280 | 281 | lein test myproject.core-test 282 | 283 | lein test :only myproject.core-test/divide-by-zero 284 | 285 | FAIL in (divide-by-zero) (core_test.clj:9) 286 | expected: (thrown? ArithmeticException (/ 1 2)) 287 | actual: nil 288 | 289 | lein test :only myproject.core-test/divide-by-zero 290 | 291 | FAIL in (divide-by-zero) (core_test.clj:18) 292 | expected: (thrown-with-msg? ArithmeticException #"Incorrect message" (/ 2 0)) 293 | actual: #error { 294 | :cause "Divide by zero" 295 | :via 296 | [{:type java.lang.ArithmeticException 297 | :message "Divide by zero" 298 | :at [clojure.lang.Numbers divide "Numbers.java" 158]}] 299 | :trace 300 | [[clojure.lang.Numbers divide "Numbers.java" 158] 301 | [clojure.lang.Numbers divide "Numbers.java" 3808] 302 | [myproject.core_test$fn__194$fn__202 invoke "core_test.clj" 19] 303 | [myproject.core_test$fn__194 invoke "core_test.clj" 18] 304 | [clojure.test$test_var$fn__7670 invoke "test.clj" 704] 305 | ......]} 306 | 307 | lein test :only myproject.core-test/divide-by-zero 308 | 309 | FAIL in (divide-by-zero) (core_test.clj:22) 310 | expected: (thrown-with-msg? ArithmeticException #"Divide by zero" (/ 1 3)) 311 | actual: nil 312 | 313 | Ran 1 tests containing 5 assertions. 314 | 3 failures, 0 errors. 315 | Tests failed. 316 | ---- 317 | 318 | 319 | == fixture 사용하기 320 | 321 | 테스트 코드를 작성하다 보면, 테스트 실행 직전 또는 직후에 실행되어야 하는 코드가 322 | 있을 수 있다. 이때 필요한 것이 바로 fixture이다. 323 | 324 | [listing] 325 | ---- 326 | (use-fixtures :once fixture+) 327 | (use-fixtures :each fixture+) 328 | 329 | :once := 테스트 파일 전체에 걸쳐, fixture들을 지정된 순서대로 딱 한번만 수행한다. 330 | :each := deftest 문을 실행할 떄마다, fixture들을 지정된 순서대로 메번 수행한다. 331 | ---- 332 | 333 | `:once` 옵션의 경우를 먼저 살펴보자. 334 | 335 | [source] 336 | .... 337 | (ns myproject.core-test 338 | (:use [clojure.test])) 339 | 340 | (defn fixture-1 [f] 341 | (println ":once fixutre-1 started.") 342 | ; other codes here ... 343 | (f) 344 | (println ":once fixutre-1 ended.") 345 | ; another codes here ... 346 | ) 347 | 348 | (defn fixture-2 [f] 349 | (println ":once fixture-2 started.") 350 | ; other codes here ... 351 | (f) 352 | (println ":once fixture-2 ended.") 353 | ; another codes here ... 354 | ) 355 | 356 | (use-fixtures :once fixture-1 fixture-2) 357 | 358 | (deftest add 359 | (is (= 3 (+ 1 2))) 360 | (is (= 8 (+ 3 5)))) 361 | 362 | (deftest subtract 363 | (is (= 5 (- 10 5))) 364 | (is (= 2 (- 7 5)))) 365 | .... 366 | 367 | [listing] 368 | ---- 369 | $ lein test 370 | 371 | lein test myproject.core-test 372 | :once fixutre-1 started. 373 | :once fixture-2 started. 374 | :once fixture-2 ended. 375 | :once fixutre-1 ended. 376 | 377 | Ran 2 tests containing 4 assertions. 378 | 0 failures, 0 errors. 379 | ---- 380 | 381 | 테스트 종료시, 지정한 fixture 함수의 순서가 역순으로 실행되는 것에 주의하라. 382 | 383 | 이번에는 `:each` 옵션의 경우를 살펴보자. 384 | 385 | [source] 386 | .... 387 | (ns myproject.core-test 388 | (:use [clojure.test])) 389 | 390 | (defn fixture-1 [f] 391 | (println ":each fixutre-1 started.") 392 | ; other codes here ... 393 | (f) 394 | (println ":each fixutre-1 ended.") 395 | ; another codes here ... 396 | ) 397 | 398 | (defn fixture-2 [f] 399 | (println ":each fixture-2 started.") 400 | ; other codes here ... 401 | (f) 402 | (println ":each fixture-2 ended.") 403 | ; another codes here ... 404 | ) 405 | 406 | (use-fixtures :each fixture-1 fixture-2) 407 | 408 | (deftest add 409 | (is (= 3 (+ 1 2))) 410 | (is (= 8 (+ 3 5)))) 411 | 412 | (deftest subtract 413 | (is (= 5 (- 10 5))) 414 | (is (= 2 (- 7 5)))) 415 | .... 416 | 417 | [listing] 418 | ---- 419 | $ lein test 420 | 421 | lein test myproject.core-test 422 | :each fixutre-1 started. 423 | :each fixture-2 started. 424 | :each fixture-2 ended. 425 | :each fixutre-1 ended. 426 | :each fixutre-1 started. 427 | :each fixture-2 started. 428 | :each fixture-2 ended. 429 | :each fixutre-1 ended. 430 | 431 | Ran 2 tests containing 4 assertions. 432 | 0 failures, 0 errors. 433 | ---- 434 | 435 | `deftest` 문이 실행될 때마다, `:each` 옵션 뒤에 지정한 fixture들이 지정된 순서대로 436 | 실행되는 것을 확인할 수 있다. 437 | -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/asciidoctor-theme/notosansmono-cjk-kr/.DS_Store -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/fonts/LICENSE: -------------------------------------------------------------------------------- 1 | This Font Software is licensed under the SIL Open Font License, 2 | Version 1.1. 3 | 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | ----------------------------------------------------------- 8 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 9 | ----------------------------------------------------------- 10 | 11 | PREAMBLE 12 | The goals of the Open Font License (OFL) are to stimulate worldwide 13 | development of collaborative font projects, to support the font 14 | creation efforts of academic and linguistic communities, and to 15 | provide a free and open framework in which fonts may be shared and 16 | improved in partnership with others. 17 | 18 | The OFL allows the licensed fonts to be used, studied, modified and 19 | redistributed freely as long as they are not sold by themselves. The 20 | fonts, including any derivative works, can be bundled, embedded, 21 | redistributed and/or sold with any software provided that any reserved 22 | names are not used by derivative works. The fonts and derivatives, 23 | however, cannot be released under any other type of license. The 24 | requirement for fonts to remain under this license does not apply to 25 | any document created using the fonts or their derivatives. 26 | 27 | DEFINITIONS 28 | "Font Software" refers to the set of files released by the Copyright 29 | Holder(s) under this license and clearly marked as such. This may 30 | include source files, build scripts and documentation. 31 | 32 | "Reserved Font Name" refers to any names specified as such after the 33 | copyright statement(s). 34 | 35 | "Original Version" refers to the collection of Font Software 36 | components as distributed by the Copyright Holder(s). 37 | 38 | "Modified Version" refers to any derivative made by adding to, 39 | deleting, or substituting -- in part or in whole -- any of the 40 | components of the Original Version, by changing formats or by porting 41 | the Font Software to a new environment. 42 | 43 | "Author" refers to any designer, engineer, programmer, technical 44 | writer or other person who contributed to the Font Software. 45 | 46 | PERMISSION & CONDITIONS 47 | Permission is hereby granted, free of charge, to any person obtaining 48 | a copy of the Font Software, to use, study, copy, merge, embed, 49 | modify, redistribute, and sell modified and unmodified copies of the 50 | Font Software, subject to the following conditions: 51 | 52 | 1) Neither the Font Software nor any of its individual components, in 53 | Original or Modified Versions, may be sold by itself. 54 | 55 | 2) Original or Modified Versions of the Font Software may be bundled, 56 | redistributed and/or sold with any software, provided that each copy 57 | contains the above copyright notice and this license. These can be 58 | included either as stand-alone text files, human-readable headers or 59 | in the appropriate machine-readable metadata fields within text or 60 | binary files as long as those fields can be easily viewed by the user. 61 | 62 | 3) No Modified Version of the Font Software may use the Reserved Font 63 | Name(s) unless explicit written permission is granted by the 64 | corresponding Copyright Holder. This restriction only applies to the 65 | primary font name as presented to the users. 66 | 67 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 68 | Software shall not be used to promote, endorse or advertise any 69 | Modified Version, except to acknowledge the contribution(s) of the 70 | Copyright Holder(s) and the Author(s) or with their explicit written 71 | permission. 72 | 73 | 5) The Font Software, modified or unmodified, in part or in whole, 74 | must be distributed entirely under this license, and must not be 75 | distributed under any other license. The requirement for fonts to 76 | remain under this license does not apply to any document created using 77 | the Font Software. 78 | 79 | TERMINATION 80 | This license becomes null and void if any of the above conditions are 81 | not met. 82 | 83 | DISCLAIMER 84 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 85 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 86 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 87 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 88 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 89 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 90 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 91 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 92 | OTHER DEALINGS IN THE FONT SOFTWARE. 93 | -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/fonts/notosansmono-cjk-kr-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/asciidoctor-theme/notosansmono-cjk-kr/fonts/notosansmono-cjk-kr-bold.ttf -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/fonts/notosansmono-cjk-kr-bold_italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/asciidoctor-theme/notosansmono-cjk-kr/fonts/notosansmono-cjk-kr-bold_italic.ttf -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/fonts/notosansmono-cjk-kr-italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/asciidoctor-theme/notosansmono-cjk-kr/fonts/notosansmono-cjk-kr-italic.ttf -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/fonts/notosansmono-cjk-kr-normal.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/asciidoctor-theme/notosansmono-cjk-kr/fonts/notosansmono-cjk-kr-normal.ttf -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/themes/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 life888888 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/themes/LICENSE-asciidoctor-pdf: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2014-present OpenDevise Inc. and the Asciidoctor Project 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/themes/LICENSE-asciidoctor-pdf-cjk-kai_gen_gothic: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Rei 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/themes/default-ext-notosansmono-cjk-kr-pdf-1-theme.yml: -------------------------------------------------------------------------------- 1 | # FOR Asciidoctor-PDF 1.x 2 | extends: default-with-fallback-font 3 | font: 4 | catalog: 5 | merge: true 6 | Noto Sans Mono CJK KR: 7 | normal: notosansmono-cjk-kr-normal.ttf 8 | bold: notosansmono-cjk-kr-bold.ttf 9 | italic: notosansmono-cjk-kr-italic.ttf 10 | bold_italic: notosansmono-cjk-kr-bold_italic.ttf 11 | fallbacks: [M+ 1p Fallback, Noto Emoji, Noto Sans Mono CJK KR] 12 | base_font_family: Noto Sans Mono CJK KR 13 | base_align: left 14 | 15 | -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/themes/default-ext-notosansmono-cjk-kr-theme.yml: -------------------------------------------------------------------------------- 1 | # FOR Asciidoctor-PDF 2.x 2 | extends: default-with-font-fallbacks 3 | font: 4 | catalog: 5 | merge: true 6 | Noto Sans Mono CJK KR: 7 | normal: notosansmono-cjk-kr-normal.ttf 8 | bold: notosansmono-cjk-kr-bold.ttf 9 | italic: notosansmono-cjk-kr-italic.ttf 10 | bold_italic: notosansmono-cjk-kr-bold_italic.ttf 11 | fallbacks: [M+ 1p Fallback, Noto Emoji, Noto Sans Mono CJK KR] 12 | base_font_family: Noto Sans Mono CJK KR 13 | base_align: left 14 | 15 | -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/themes/default-notosansmono-cjk-kr-pdf-1-theme.yml: -------------------------------------------------------------------------------- 1 | # FOR Asciidoctor-PDF 1.x 2 | # Modify from Asciidoctor-PDF 1.6.2 (default + default-with-fallback-font) - Copyright (C) 2014-present OpenDevise Inc. and the Asciidoctor Project - MIT License 3 | # merge KaiGenGothicTW-theme.yml - Copyright (c) 2015 Rei - MIT License (https://github.com/chloerei/asciidoctor-pdf-cjk-kai_gen_gothic) 4 | font: 5 | catalog: 6 | # notosansmono-cjk-kr-normal.ttf Fonts supports languages in Taiwan, Hong Kong and Macau that use the Traditional Chinese variant of the Han ideograms. It also supports Hiragana, Katakana, Latin, Cyrillic, Greek and Hangul. 7 | Noto Sans Mono CJK KR: 8 | normal: notosansmono-cjk-kr-normal.ttf 9 | bold: notosansmono-cjk-kr-bold.ttf 10 | italic: notosansmono-cjk-kr-italic.ttf 11 | bold_italic: notosansmono-cjk-kr-bold_italic.ttf 12 | # M+ 1mn supports ASCII and the circled numbers used for conums 13 | M+ 1mn: 14 | normal: mplus1mn-regular-subset.ttf 15 | bold: mplus1mn-bold-subset.ttf 16 | italic: mplus1mn-italic-subset.ttf 17 | bold_italic: mplus1mn-bold_italic-subset.ttf 18 | # Add Fallback 19 | M+ 1p Fallback: mplus1p-regular-fallback.ttf 20 | Noto Emoji: notoemoji-subset.ttf 21 | fallbacks: [M+ 1p Fallback, Noto Emoji, Noto Sans Mono CJK KR] 22 | page: 23 | background_color: FFFFFF 24 | layout: portrait 25 | initial_zoom: FitH 26 | margin: [0.5in, 0.67in, 0.67in, 0.67in] 27 | # margin_inner and margin_outer keys are used for recto/verso print margins when media=prepress 28 | margin_inner: 0.75in 29 | margin_outer: 0.59in 30 | size: A4 31 | base: 32 | # ORG 33 | # align: justify 34 | # 20221012 KaiGenGothicTW ADD 35 | align: left 36 | # color as hex string (leading # is optional) 37 | font_color: 333333 38 | # color as RGB array 39 | #font_color: [51, 51, 51] 40 | # color as CMYK array (approximated) 41 | #font_color: [0, 0, 0, 0.92] 42 | #font_color: [0, 0, 0, 92%] 43 | font_family: Noto Sans Mono CJK KR 44 | # choose one of these font_size/line_height_length combinations 45 | #font_size: 14 46 | #line_height_length: 20 47 | #font_size: 11.25 48 | #line_height_length: 18 49 | #font_size: 11.2 50 | #line_height_length: 16 51 | font_size: 10.5 52 | #line_height_length: 15 53 | # correct line height for Noto Serif metrics 54 | # ORG 55 | #line_height_length: 12 56 | # 20221012 KaiGenGothicTW ADD 57 | line_height_length: 15 58 | #font_size: 11.25 59 | #line_height_length: 18 60 | line_height: $base_line_height_length / $base_font_size 61 | font_size_large: round($base_font_size * 1.25) 62 | font_size_small: round($base_font_size * 0.85) 63 | font_size_min: $base_font_size * 0.75 64 | font_style: normal 65 | border_color: EEEEEE 66 | border_radius: 4 67 | border_width: 0.5 68 | role: 69 | line-through: 70 | text_decoration: line-through 71 | underline: 72 | text_decoration: underline 73 | big: 74 | font_size: $base_font_size_large 75 | small: 76 | font_size: $base_font_size_small 77 | subtitle: 78 | font_size: 0.8em 79 | font_color: 999999 80 | # FIXME vertical_rhythm is weird; we should think in terms of ems 81 | #vertical_rhythm: $base_line_height_length * 2 / 3 82 | # correct line height for Noto Serif metrics (comes with built-in line height) 83 | vertical_rhythm: $base_line_height_length 84 | horizontal_rhythm: $base_line_height_length 85 | # QUESTION should vertical_spacing be block_spacing instead? 86 | vertical_spacing: $vertical_rhythm 87 | link: 88 | font_color: 428BCA 89 | # literal is currently used for inline monospaced in prose and table cells 90 | literal: 91 | font_color: B12146 92 | font_family: M+ 1mn 93 | button: 94 | content: "[\u2009%s\u2009]" 95 | font_style: bold 96 | key: 97 | background_color: F5F5F5 98 | border_color: CCCCCC 99 | border_offset: 2 100 | border_radius: 2 101 | border_width: 0.5 102 | font_family: $literal_font_family 103 | separator: "\u202f+\u202f" 104 | mark: 105 | background_color: FFFF00 106 | border_offset: 1 107 | menu: 108 | caret_content: " \u203a " 109 | heading: 110 | align: left 111 | font_color: $base_font_color 112 | # 20221012 KaiGenGothicTW ADD 113 | font_family: $base_font_family 114 | font_style: bold 115 | # h1 is used for part titles (book doctype) or the doctitle (article doctype) 116 | h1_font_size: floor($base_font_size * 2.6) 117 | # h2 is used for chapter titles (book doctype only) 118 | h2_font_size: floor($base_font_size * 2.15) 119 | h3_font_size: round($base_font_size * 1.7) 120 | h4_font_size: $base_font_size_large 121 | h5_font_size: $base_font_size 122 | h6_font_size: $base_font_size_small 123 | #line_height: 1.4 124 | # correct line height for Noto Serif metrics (comes with built-in line height) 125 | # ORG 126 | # line_height: 1 127 | # 20221012 KaiGenGothicTW ADD 128 | line_height: 1.2 129 | # ORG 130 | # margin_top: $vertical_rhythm * 0.4 131 | # 20221012 KaiGenGothicTW ADD 132 | margin_top: $vertical_rhythm * 0.2 133 | # ORG 134 | # margin_bottom: $vertical_rhythm * 0.9 135 | # 20221012 KaiGenGothicTW ADD 136 | margin_bottom: $vertical_rhythm * 0.8 137 | min_height_after: $base_line_height_length * 1.5 138 | title_page: 139 | align: right 140 | logo: 141 | top: 10% 142 | title: 143 | top: 55% 144 | font_size: $heading_h1_font_size 145 | font_color: 999999 146 | line_height: 0.9 147 | subtitle: 148 | font_size: $heading_h3_font_size 149 | font_style: bold_italic 150 | line_height: 1 151 | authors: 152 | margin_top: $base_font_size * 1.25 153 | font_size: $base_font_size_large 154 | font_color: 181818 155 | revision: 156 | margin_top: $base_font_size * 1.25 157 | block: 158 | # ORG 159 | # margin_top: 0 160 | # ORG 161 | # margin_bottom: $vertical_rhythm 162 | # 20221012 KaiGenGothicTW ADD 163 | padding: [$vertical_rhythm, $vertical_rhythm * 1.25, $vertical_rhythm, $vertical_rhythm * 1.25] 164 | caption: 165 | align: left 166 | font_size: $base_font_size * 0.95 167 | font_style: italic 168 | # FIXME perhaps set line_height instead of / in addition to margins? 169 | # ORG 170 | # margin_inside: $vertical_rhythm / 3 171 | # 20221012 KaiGenGothicTW ADD 172 | margin_inside: $vertical_rhythm * 0.25 173 | # margin_inside: $vertical_rhythm / 4 174 | margin_outside: 0 175 | lead: 176 | font_size: $base_font_size_large 177 | line_height: 1.4 178 | abstract: 179 | font_color: 5C6266 180 | font_size: $lead_font_size 181 | line_height: $lead_line_height 182 | font_style: italic 183 | first_line_font_style: bold 184 | title: 185 | align: center 186 | font_color: $heading_font_color 187 | font_size: $heading_h4_font_size 188 | font_style: $heading_font_style 189 | admonition: 190 | # 20221012 KaiGenGothicTW ADD 191 | border_color: $base_border_color 192 | # 20221012 KaiGenGothicTW ADD 193 | border_width: $base_border_width 194 | column_rule_color: $base_border_color 195 | column_rule_width: $base_border_width 196 | padding: [0, $horizontal_rhythm, 0, $horizontal_rhythm] 197 | #icon: 198 | # tip: 199 | # name: far-lightbulb 200 | # stroke_color: 111111 201 | # size: 24 202 | label: 203 | text_transform: uppercase 204 | font_style: bold 205 | blockquote: 206 | # 20221012 KaiGenGothicTW ADD 207 | font_color: $base_font_color 208 | font_size: $base_font_size_large 209 | border_color: $base_border_color 210 | # ORG 211 | # border_width: 0 212 | # 20221012 KaiGenGothicTW ADD 213 | border_width: 5 214 | border_left_width: 5 215 | # FIXME disable negative padding bottom once margin collapsing is implemented 216 | padding: [0, $horizontal_rhythm, $block_margin_bottom * -0.75, $horizontal_rhythm + $blockquote_border_left_width / 2] 217 | cite_font_size: $base_font_size_small 218 | cite_font_color: 999999 219 | verse: 220 | font_size: $blockquote_font_size 221 | border_color: $blockquote_border_color 222 | border_width: $blockquote_border_width 223 | border_left_width: $blockquote_border_left_width 224 | padding: $blockquote_padding 225 | cite_font_size: $blockquote_cite_font_size 226 | cite_font_color: $blockquote_cite_font_color 227 | # code is used for source blocks (perhaps change to source or listing?) 228 | code: 229 | font_color: $base_font_color 230 | font_family: $literal_font_family 231 | font_size: ceil($base_font_size) 232 | padding: $code_font_size 233 | line_height: 1.25 234 | # line_gap is an experimental property to control how a background color is applied to an inline block element 235 | line_gap: 3.8 236 | background_color: F5F5F5 237 | border_color: CCCCCC 238 | border_radius: $base_border_radius 239 | border_width: 0.75 240 | conum: 241 | font_family: $literal_font_family 242 | font_color: $literal_font_color 243 | font_size: $base_font_size 244 | line_height: 4 / 3 245 | glyphs: circled 246 | example: 247 | border_color: $base_border_color 248 | border_radius: $base_border_radius 249 | border_width: 0.75 250 | # ORG 251 | # background_color: $page_background_color 252 | # 20221012 KaiGenGothicTW ADD 253 | background_color: transparent 254 | # FIXME reenable padding bottom once margin collapsing is implemented 255 | padding: [$vertical_rhythm, $horizontal_rhythm, 0, $horizontal_rhythm] 256 | image: 257 | align: left 258 | # 20221012 KaiGenGothicTW ADD 259 | scaled_width_default: 0.5 260 | prose: 261 | margin_top: $block_margin_top 262 | margin_bottom: $block_margin_bottom 263 | sidebar: 264 | background_color: EEEEEE 265 | # ORG 266 | # border_color: E1E1E1 267 | # 20221012 KaiGenGothicTW ADD 268 | border_color: FFFFFF 269 | border_radius: $base_border_radius 270 | border_width: $base_border_width 271 | # FIXME reenable padding bottom once margin collapsing is implemented 272 | padding: [$vertical_rhythm, $vertical_rhythm * 1.25, 0, $vertical_rhythm * 1.25] 273 | title: 274 | align: center 275 | font_color: $heading_font_color 276 | font_size: $heading_h4_font_size 277 | font_style: $heading_font_style 278 | # 20221012 KaiGenGothicTW ADD 279 | font_family: $heading_font_family 280 | thematic_break: 281 | border_color: $base_border_color 282 | border_style: solid 283 | border_width: $base_border_width 284 | margin_top: $vertical_rhythm * 0.5 285 | margin_bottom: $vertical_rhythm * 1.5 286 | description_list: 287 | # ORG 288 | # term_font_style: bold 289 | # 20221012 KaiGenGothicTW ADD 290 | term_font_style: italic 291 | term_spacing: $vertical_rhythm / 4 292 | description_indent: $horizontal_rhythm * 1.25 293 | outline_list: 294 | indent: $horizontal_rhythm * 1.5 295 | #marker_font_color: 404040 296 | # NOTE outline_list_item_spacing applies to list items that do not have complex content 297 | item_spacing: $vertical_rhythm / 2 298 | table: 299 | background_color: $page_background_color 300 | border_color: DDDDDD 301 | border_width: $base_border_width 302 | # ORG 303 | # cell_padding: 3 304 | # 20221012 KaiGenGothicTW ADD 305 | # HACK accounting for line-height 306 | # 20221012 KaiGenGothicTW ADD 307 | cell_padding: [3, 3, 6, 3] 308 | head: 309 | font_style: bold 310 | border_bottom_width: $base_border_width * 2.5 311 | body: 312 | stripe_background_color: F9F9F9 313 | # 20221012 KaiGenGothicTW ADD 314 | even_row_background_color: F9F9F9 315 | #odd_row_background_color: 316 | foot: 317 | background_color: F0F0F0 318 | toc: 319 | indent: $horizontal_rhythm 320 | line_height: 1.4 321 | dot_leader: 322 | #content: ". " 323 | # ORG 324 | # font_color: A9A9A9 325 | # 20221012 KaiGenGothicTW ADD 326 | font_color: DDDDDD 327 | #levels: 2 3 328 | footnotes: 329 | font_size: round($base_font_size * 0.75) 330 | item_spacing: $outline_list_item_spacing / 2 331 | header: 332 | font_size: $base_font_size_small 333 | line_height: 1 334 | vertical_align: middle 335 | footer: 336 | font_size: $base_font_size_small 337 | # 20221012 KaiGenGothicTW ADD 338 | font_color: $base_font_color 339 | # NOTE if background_color is set, background and border will span width of page 340 | border_color: DDDDDD 341 | border_width: 0.25 342 | height: $base_line_height_length * 2.5 343 | line_height: 1 344 | padding: [$base_line_height_length / 2, 1, 0, 1] 345 | vertical_align: top 346 | recto: 347 | #columns: "<50% =0% >50%" 348 | right: 349 | content: '{page-number}' 350 | verso: 351 | #columns: $footer_recto_columns 352 | left: 353 | # OTG 354 | # content: $footer_recto_right_content 355 | # 20221012 KaiGenGothicTW ADD 356 | content: '{page-number}' 357 | -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/themes/default-notosansmono-cjk-kr-theme.yml: -------------------------------------------------------------------------------- 1 | # FOR Asciidoctor-PDF 2.x 2 | # Modify from Asciidoctor-PDF 2.1.6 (default + default-with-font-fallbacks ) - Copyright (C) 2014-present OpenDevise Inc. and the Asciidoctor Project - MIT License 3 | # merge KaiGenGothicTW-theme.yml - Copyright (c) 2015 Rei - MIT License (https://github.com/chloerei/asciidoctor-pdf-cjk-kai_gen_gothic) 4 | font: 5 | catalog: 6 | # notosansmono-cjk-kr-normal.ttf Fonts supports languages in Taiwan, Hong Kong and Macau that use the Traditional Chinese variant of the Han ideograms. It also supports Hiragana, Katakana, Latin, Cyrillic, Greek and Hangul. 7 | Noto Sans Mono CJK KR: 8 | normal: notosansmono-cjk-kr-normal.ttf 9 | bold: notosansmono-cjk-kr-bold.ttf 10 | italic: notosansmono-cjk-kr-italic.ttf 11 | bold_italic: notosansmono-cjk-kr-bold_italic.ttf 12 | # M+ 1mn supports ASCII and the circled numbers used for conums 13 | M+ 1mn: 14 | normal: mplus1mn-regular-subset.ttf 15 | bold: mplus1mn-bold-subset.ttf 16 | italic: mplus1mn-italic-subset.ttf 17 | bold_italic: mplus1mn-bold_italic-subset.ttf 18 | # Add Fallback 19 | M+ 1p Fallback: mplus1p-regular-fallback.ttf 20 | Noto Emoji: notoemoji-subset.ttf 21 | fallbacks: [M+ 1p Fallback, Noto Emoji, Noto Sans Mono CJK KR] 22 | page: 23 | background_color: FFFFFF 24 | layout: portrait 25 | initial_zoom: FitH 26 | margin: [0.5in, 0.67in, 0.67in, 0.67in] 27 | # margin_inner and margin_outer keys are used for recto/verso print margins when media=prepress 28 | margin_inner: 0.75in 29 | margin_outer: 0.59in 30 | size: A4 31 | base: 32 | text_align: left 33 | # color as hex string (leading # is optional) 34 | font_color: 333333 35 | # color as RGB array 36 | #font_color: [51, 51, 51] 37 | # color as CMYK array (approximated) 38 | #font_color: [0, 0, 0, 0.92] 39 | #font_color: [0, 0, 0, 92%] 40 | font_family: Noto Sans Mono CJK KR 41 | # choose one of these font_size/line_height_length combinations 42 | #font_size: 14 43 | #line_height_length: 20 44 | #font_size: 11.25 45 | #line_height_length: 18 46 | #font_size: 11.2 47 | #line_height_length: 16 48 | font_size: 10.5 49 | #line_height_length: 15 50 | # correct line height for Noto Serif metrics 51 | # ORIG 52 | # line_height_length: 12 53 | # 20221002 KaiGenGothicTW ADD 54 | line_height_length: 15 55 | #font_size: 11.25 56 | #line_height_length: 18 57 | line_height: $base_line_height_length / $base_font_size 58 | font_size_large: round($base_font_size * 1.25) 59 | font_size_small: round($base_font_size * 0.85) 60 | font_size_min: $base_font_size * 0.75 61 | font_style: normal 62 | border_color: EEEEEE 63 | border_radius: 4 64 | border_width: 0.5 65 | # 20221002 KaiGenGothicTW ADD 66 | align: left 67 | role: 68 | lead: 69 | font_size: $base_font_size_large 70 | line-through: 71 | text_decoration: line-through 72 | underline: 73 | text_decoration: underline 74 | big: 75 | font_size: $base_font_size_large 76 | small: 77 | font_size: $base_font_size_small 78 | subtitle: 79 | font_color: 999999 80 | font_size: 0.8em 81 | font_style: normal_italic 82 | # FIXME vertical_rhythm is weird; we should think in terms of ems 83 | #vertical_rhythm: $base_line_height_length * 2 / 3 84 | # correct line height for Noto Serif metrics (comes with built-in line height) 85 | vertical_rhythm: $base_line_height_length 86 | horizontal_rhythm: $base_line_height_length 87 | link: 88 | font_color: 428BCA 89 | # codespan is currently used for monospaced phrases and table cells 90 | codespan: 91 | font_color: B12146 92 | font_family: M+ 1mn 93 | # 20221002 KaiGenGothicTW NOT USE THIS 94 | # TODO: Use SansMono ??? 95 | # font_family: Roboto Mono 96 | button: 97 | content: "[\u2009%s\u2009]" 98 | font_style: bold 99 | kbd: 100 | background_color: F5F5F5 101 | border_color: CCCCCC 102 | border_offset: 2 103 | border_radius: 2 104 | border_width: 0.5 105 | font_family: $codespan_font_family 106 | separator: "\u202f+\u202f" 107 | mark: 108 | background_color: FFFF00 109 | border_offset: 1 110 | menu: 111 | caret_content: " \u203a " 112 | font_style: bold 113 | heading: 114 | text_align: left 115 | font_color: $base_font_color 116 | font_style: bold 117 | # 20221002 KaiGenGothicTW ADD 118 | font_family: $base_font_family 119 | # h1 is used for part titles (book doctype) or the doctitle (article doctype) 120 | h1_font_size: floor($base_font_size * 2.6) 121 | # h2 is used for chapter titles (book doctype only) 122 | h2_font_size: floor($base_font_size * 2.15) 123 | h3_font_size: round($base_font_size * 1.7) 124 | h4_font_size: $base_font_size_large 125 | h5_font_size: $base_font_size 126 | h6_font_size: $base_font_size_small 127 | #line_height: 1.4 128 | # correct line height for Noto Serif metrics (comes with built-in line height) 129 | # ORIGIN 130 | # line_height: 1 131 | # 20221002 KaiGenGothicTW ADD 132 | line_height: 1.2 133 | # ORIGIN 134 | # margin_top: $vertical_rhythm * 0.4 135 | # 20221002 KaiGenGothicTW ADD 136 | margin_top: $vertical_rhythm * 0.2 137 | # ORIGIN 138 | # margin_bottom: $vertical_rhythm * 0.9 139 | # 20221002 KaiGenGothicTW ADD 140 | margin_bottom: $vertical_rhythm * 0.8 141 | min_height_after: $base_line_height_length * 1.5 142 | title_page: 143 | text_align: right 144 | logo: 145 | top: 10% 146 | title: 147 | top: 55% 148 | font_size: $heading_h1_font_size 149 | font_color: $role_subtitle_font_color 150 | line_height: 0.9 151 | subtitle: 152 | font_size: $heading_h3_font_size 153 | font_style: bold_italic 154 | line_height: 1 155 | authors: 156 | margin_top: $base_font_size * 1.25 157 | font_size: $base_font_size_large 158 | font_color: 181818 159 | revision: 160 | margin_top: $base_font_size * 1.25 161 | block: 162 | margin_bottom: $vertical_rhythm 163 | # 20221002 KaiGenGothicTW ADD 164 | padding: [$vertical_rhythm, $vertical_rhythm * 1.25, $vertical_rhythm, $vertical_rhythm * 1.25] 165 | caption: 166 | align: left 167 | font_size: $base_font_size * 0.95 168 | font_style: italic 169 | # FIXME perhaps set line_height instead of / in addition to margins? 170 | # ORIGIN 171 | # margin_inside: $vertical_rhythm / 3 172 | # 20221002 KaiGenGothicTW ADD 173 | margin_inside: $vertical_rhythm * 0.25 174 | margin_outside: 0 175 | abstract: 176 | font_color: 5C6266 177 | font_size: $role_lead_font_size 178 | line_height: 1.4 179 | font_style: italic 180 | first_line_font_style: bold 181 | title: 182 | text_align: center 183 | font_color: $heading_font_color 184 | font_size: $heading_h4_font_size 185 | font_style: $heading_font_style 186 | admonition: 187 | column_rule_color: $base_border_color 188 | column_rule_width: $base_border_width 189 | padding: [$vertical_rhythm / 3.0, $horizontal_rhythm, $vertical_rhythm / 3.0, $horizontal_rhythm] 190 | #icon: 191 | # tip: 192 | # name: far-lightbulb 193 | # stroke_color: 111111 194 | # size: 24 195 | label: 196 | text_transform: uppercase 197 | font_style: bold 198 | quote: 199 | font_size: $base_font_size_large 200 | # 20221002 KaiGenGothicTW ADD 201 | font_color: $base_font_color 202 | border_color: $base_border_color 203 | # ORIGIN 204 | # border_width: 0 205 | border_width: 5 206 | border_left_width: $horizontal_rhythm / 3 207 | padding: [$vertical_rhythm / 4, $horizontal_rhythm, $vertical_rhythm / 4, $horizontal_rhythm + $quote_border_left_width / 2] 208 | cite: 209 | font_size: $base_font_size_small 210 | font_color: $role_subtitle_font_color 211 | verse: 212 | font_size: $quote_font_size 213 | border_color: $quote_border_color 214 | border_width: $quote_border_width 215 | border_left_width: $quote_border_left_width 216 | padding: $quote_padding 217 | cite: 218 | font_size: $quote_cite_font_size 219 | font_color: $quote_cite_font_color 220 | # code is used for literal, listing, and source blocks and literal table cells 221 | code: 222 | font_color: $base_font_color 223 | font_family: $codespan_font_family 224 | font_size: ceil($base_font_size) 225 | padding: $code_font_size 226 | line_height: 1.25 227 | # line_gap is an experimental property to control how a background color is applied to an inline block element 228 | line_gap: 3.8 229 | background_color: F5F5F5 230 | border_color: CCCCCC 231 | border_radius: $base_border_radius 232 | border_width: 0.75 233 | conum: 234 | font_family: $codespan_font_family 235 | font_color: $codespan_font_color 236 | font_size: $base_font_size 237 | line_height: 4 / 3 238 | glyphs: circled 239 | example: 240 | border_color: $base_border_color 241 | border_radius: $base_border_radius 242 | border_width: 0.75 243 | # ORIGIN 244 | # background_color: $page_background_color 245 | # 20221002 KaiGenGothicTW ADD 246 | background_color: transparent 247 | padding: [$vertical_rhythm, $horizontal_rhythm, $vertical_rhythm, $horizontal_rhythm] 248 | image: 249 | align: left 250 | # 20221002 KaiGenGothicTW ADD 251 | align_default: left 252 | # 20221002 KaiGenGothicTW ADD 253 | scaled_width_default: 0.5 254 | prose: 255 | margin_bottom: $block_margin_bottom 256 | sidebar: 257 | background_color: EEEEEE 258 | border_color: E1E1E1 259 | border_radius: $base_border_radius 260 | border_width: $base_border_width 261 | padding: [$vertical_rhythm, $vertical_rhythm * 1.25, $vertical_rhythm, $vertical_rhythm * 1.25] 262 | title: 263 | text_align: center 264 | font_color: $heading_font_color 265 | font_size: $heading_h4_font_size 266 | font_style: $heading_font_style 267 | # 20221002 KaiGenGothicTW ADD 268 | font_family: $heading_font_family 269 | thematic_break: 270 | border_color: $base_border_color 271 | border_style: solid 272 | border_width: $base_border_width 273 | padding: [$vertical_rhythm * 0.5, 0] 274 | # 20221002 KaiGenGothicTW ADD 275 | margin_top: $vertical_rhythm * 0.5 276 | # 20221002 KaiGenGothicTW ADD 277 | margin_bottom: $vertical_rhythm * 1.5 278 | list: 279 | indent: $horizontal_rhythm * 1.5 280 | #marker_font_color: 404040 281 | # NOTE list_item_spacing only applies to list items that do not have complex content 282 | item_spacing: $vertical_rhythm / 2 283 | description_list: 284 | # ORIGIN 285 | # term_font_style: bold 286 | # 20221002 KaiGenGothicTW ADD 287 | term_font_style: italic 288 | term_spacing: $vertical_rhythm / 4 289 | description_indent: $horizontal_rhythm * 1.25 290 | callout_list: 291 | margin_top_after_code: -$block_margin_bottom / 2 292 | table: 293 | background_color: $page_background_color 294 | border_color: DDDDDD 295 | border_width: $base_border_width 296 | grid_width: $base_border_width 297 | # ORIGIN 298 | # cell_padding: 3 299 | # 20221002 KaiGenGothicTW ADD 300 | # HACK accounting for line-height 301 | cell_padding: [3, 3, 6, 3] 302 | head: 303 | font_style: bold 304 | border_bottom_width: $base_border_width * 2.5 305 | body: 306 | stripe_background_color: F9F9F9 307 | # 20221002 KaiGenGothicTW ADD 308 | even_row_background_color: F9F9F9 309 | foot: 310 | background_color: F0F0F0 311 | toc: 312 | indent: $horizontal_rhythm 313 | line_height: 1.4 314 | dot_leader: 315 | #content: ". " 316 | # ORIGIN 317 | # font_color: A9A9A9 318 | # 20221002 KaiGenGothicTW ADD 319 | font_color: DDDDDD 320 | #levels: 2 3 321 | footnotes: 322 | font_size: round($base_font_size * 0.75) 323 | item_spacing: $list_item_spacing / 2 324 | index: 325 | column_gap: $vertical_rhythm 326 | header: 327 | font_size: $base_font_size_small 328 | line_height: 1 329 | vertical_align: middle 330 | footer: 331 | font_size: $base_font_size_small 332 | # 20221002 KaiGenGothicTW ADD 333 | font_color: $base_font_color 334 | # NOTE if background_color is set, background and border will span width of page 335 | border_color: DDDDDD 336 | border_width: 0.25 337 | height: $base_line_height_length * 2.5 338 | line_height: 1 339 | padding: [$base_line_height_length / 2, 1, 0, 1] 340 | vertical_align: top 341 | recto: 342 | right: 343 | content: '{page-number}' 344 | verso: 345 | left: 346 | # ORIGIN 347 | # content: $footer_recto_right_content 348 | # 20221002 KaiGenGothicTW ADD 349 | content: '{page-number}' 350 | -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/themes/notosansmono-cjk-kr-pdf-1-theme.yml: -------------------------------------------------------------------------------- 1 | # FOR Asciidoctor-PDF 1.x 2 | # Modify from KaiGenGothicTW-theme.yml - Copyright (c) 2015 Rei - MIT License (https://github.com/chloerei/asciidoctor-pdf-cjk-kai_gen_gothic) 3 | font: 4 | catalog: 5 | Noto Sans Mono CJK KR: 6 | normal: notosansmono-cjk-kr-normal.ttf 7 | bold: notosansmono-cjk-kr-bold.ttf 8 | italic: notosansmono-cjk-kr-italic.ttf 9 | bold_italic: notosansmono-cjk-kr-bold_italic.ttf 10 | # M+ 1mn supports ASCII and the circled numbers used for conums 11 | M+ 1mn: 12 | normal: mplus1mn-regular-subset.ttf 13 | bold: mplus1mn-bold-subset.ttf 14 | italic: mplus1mn-italic-subset.ttf 15 | bold_italic: mplus1mn-bold_italic-subset.ttf 16 | # Add Fallback 17 | M+ 1p Fallback: mplus1p-regular-fallback.ttf 18 | Noto Emoji: notoemoji-subset.ttf 19 | fallbacks: [M+ 1p Fallback, Noto Emoji, Noto Sans Mono CJK KR] 20 | page: 21 | background_color: ffffff 22 | layout: portrait 23 | # NOTE multiply inches by 72 to get pt values 24 | #margin: [0.5 * 72, 0.67 * 72, 0.67 * 72, 0.67 * 72] 25 | margin: [0.5in, 0.67in, 0.67in, 0.67in] 26 | # size can be a named size (e.g., A4) or custom dimensions (e.g., [8.25in, 11.69in]) 27 | size: Letter 28 | base: 29 | # color as hex string (leading # is optional) 30 | font_color: 333333 31 | # color as RGB array 32 | #font_color: [51, 51, 51] 33 | # color as CMYK array (approximated) 34 | #font_color: [0, 0, 0, 0.92] 35 | #font_color: [0, 0, 0, 92%] 36 | font_family: Noto Sans Mono CJK KR 37 | # choose one of these font_size/line_height_length combinations 38 | #font_size: 14 39 | #line_height_length: 20 40 | #font_size: 11.25 41 | #line_height_length: 18 42 | #font_size: 11.2 43 | #line_height_length: 16 44 | font_size: 10.5 45 | #line_height_length: 15 46 | # correct line height for Noto Serif metrics 47 | line_height_length: 15 48 | #font_size: 11.25 49 | #line_height_length: 18 50 | line_height: $base_line_height_length / $base_font_size 51 | font_size_large: round($base_font_size * 1.25) 52 | font_size_small: round($base_font_size * 0.85) 53 | font_size_min: $base_font_size * 0.75 54 | font_style: normal 55 | align: left 56 | border_radius: 4 57 | border_width: 0.5 58 | border_color: eeeeee 59 | # FIXME vertical_rhythm is weird; we should think in terms of ems 60 | #vertical_rhythm: $base_line_height_length * 2 / 3 61 | # correct line height for Noto Serif metrics 62 | vertical_rhythm: $base_line_height_length 63 | horizontal_rhythm: $base_line_height_length 64 | link: 65 | font_color: 428bca 66 | # literal is currently used for inline monospaced in prose and table cells 67 | literal: 68 | font_color: b12146 69 | font_family: Roboto Mono 70 | heading: 71 | #font_color: 181818 72 | font_color: $base_font_color 73 | font_family: $base_font_family 74 | # h1 is used for part titles 75 | h1_font_size: floor($base_font_size * 2.6) 76 | # h2 is used for chapter titles 77 | h2_font_size: floor($base_font_size * 2.15) 78 | h3_font_size: round($base_font_size * 1.7) 79 | h4_font_size: $base_font_size_large 80 | h5_font_size: $base_font_size 81 | h6_font_size: $base_font_size_small 82 | font_style: bold 83 | #line_height: 1.4 84 | # correct line height for Noto Serif metrics 85 | line_height: 1.2 86 | margin_top: $vertical_rhythm * 0.2 87 | margin_bottom: $vertical_rhythm * 0.8 88 | title_page: 89 | align: right 90 | title_top: 55% 91 | title_font_size: $heading_h1_font_size 92 | title_font_color: 999999 93 | title_line_height: 0.9 94 | subtitle_font_size: $heading_h3_font_size 95 | subtitle_font_style: bold_italic 96 | subtitle_line_height: 1 97 | authors_margin_top: $base_font_size * 1.25 98 | authors_font_size: $base_font_size_large 99 | authors_font_color: 181818 100 | revision_margin_top: $base_font_size * 1.25 101 | #prose: 102 | # margin_top: 0 103 | # margin_bottom: $vertical_rhythm 104 | block: 105 | #margin_top: 0 106 | #margin_bottom: $vertical_rhythm 107 | padding: [$vertical_rhythm, $vertical_rhythm * 1.25, $vertical_rhythm, $vertical_rhythm * 1.25] 108 | # code is used for source blocks (perhaps change to source or listing?) 109 | caption: 110 | font_style: italic 111 | align: left 112 | # FIXME perhaps set line_height instead of / in addition to margins? 113 | margin_inside: $vertical_rhythm * 0.25 114 | margin_outside: 0 115 | code: 116 | font_color: $base_font_color 117 | #font_family: Liberation Mono 118 | #font_size: floor($base_font_size * 0.9) 119 | #font_size: 10 120 | #padding: [9.5, 9.5, 9.5, 9.5] 121 | # LiberationMono carries extra gap below line 122 | #padding: [10, 10, 7.5, 10] 123 | #line_height: 1.45 124 | font_family: $literal_font_family 125 | font_size: ceil($base_font_size) 126 | #padding: [$base_font_size, $code_font_size, $base_font_size, $code_font_size] 127 | padding: $code_font_size 128 | line_height: 1.25 129 | background_color: f5f5f5 130 | border_color: cccccc 131 | border_radius: $base_border_radius 132 | border_width: 0.75 133 | blockquote: 134 | font_color: $base_font_color 135 | font_size: $base_font_size_large 136 | border_width: 5 137 | border_color: $base_border_color 138 | cite_font_size: $base_font_size_small 139 | cite_font_color: 999999 140 | sidebar: 141 | border_color: $page_background_color 142 | border_radius: $base_border_radius 143 | border_width: $base_border_width 144 | background_color: eeeeee 145 | title_font_color: $heading_font_color 146 | title_font_family: $heading_font_family 147 | title_font_size: $heading_h4_font_size 148 | title_font_style: $heading_font_style 149 | title_align: center 150 | example: 151 | border_color: $base_border_color 152 | border_radius: $base_border_radius 153 | border_width: 0.75 154 | background_color: transparent 155 | admonition: 156 | border_color: $base_border_color 157 | border_width: $base_border_width 158 | conum: 159 | font_family: $literal_font_family 160 | font_color: $literal_font_color 161 | font_size: $base_font_size 162 | line_height: 4 / 3 163 | image: 164 | align_default: left 165 | scaled_width_default: 0.5 166 | lead: 167 | # QUESTION what about $base_font_size_large? 168 | #font_size: floor($base_line_height_length * 0.8) 169 | #font_size: floor($base_font_size * 1.15) 170 | #line_height: 1.3 171 | font_size: $base_font_size_large 172 | line_height: 1.4 173 | abstract: 174 | #font_color: 404040 175 | font_color: 5c6266 176 | font_size: $lead_font_size 177 | line_height: $lead_line_height 178 | font_style: italic 179 | thematic_break: 180 | border_color: $base_border_color 181 | margin_top: $vertical_rhythm * 0.5 182 | margin_bottom: $vertical_rhythm * 1.5 183 | description_list: 184 | term_font_style: italic 185 | description_indent: $horizontal_rhythm * 1.25 186 | outline_list: 187 | indent: $horizontal_rhythm * 1.5 188 | # NOTE item_spacing applies to list items that do not have complex content 189 | item_spacing: $vertical_rhythm / 2 190 | #marker_font_color: 404040 191 | table: 192 | background_color: $page_background_color 193 | #head_background_color: 194 | #head_font_color: $base_font_color 195 | even_row_background_color: f9f9f9 196 | #odd_row_background_color: 197 | foot_background_color: f0f0f0 198 | border_color: dddddd 199 | border_width: $base_border_width 200 | # HACK accounting for line-height 201 | cell_padding: [3, 3, 6, 3] 202 | toc: 203 | indent: $horizontal_rhythm 204 | dot_leader_color: dddddd 205 | #dot_leader_content: ". " 206 | line_height: 1.4 207 | # NOTE In addition to footer, header is also supported 208 | footer: 209 | font_size: $base_font_size_small 210 | font_color: $base_font_color 211 | # NOTE if background_color is set, background and border will span width of page 212 | border_color: dddddd 213 | border_width: 0.25 214 | height: $base_line_height_length * 2.5 215 | padding: [$base_line_height_length / 2, 1, 0, 1] 216 | valign: top 217 | #image_valign: or 218 | # additional attributes for content: 219 | # * {page-count} 220 | # * {page-number} 221 | # * {document-title} 222 | # * {document-subtitle} 223 | # * {chapter-title} 224 | # * {section-title} 225 | # * {section-or-chapter-title} 226 | recto_content: 227 | #right: '{section-or-chapter-title} | {page-number}' 228 | #right: '{document-title} | {page-number}' 229 | right: '{page-number}' 230 | #center: '{page-number}' 231 | verso_content: 232 | #left: '{page-number} | {chapter-title}' 233 | left: '{page-number}' 234 | #center: '{page-number}' 235 | -------------------------------------------------------------------------------- /asciidoctor-theme/notosansmono-cjk-kr/themes/notosansmono-cjk-kr-theme.yml: -------------------------------------------------------------------------------- 1 | # FOR Asciidoctor-PDF 2.x 2 | # Modify from KaiGenGothicTW-theme.yml - Copyright (c) 2015 Rei - MIT License (https://github.com/chloerei/asciidoctor-pdf-cjk-kai_gen_gothic) 3 | font: 4 | catalog: 5 | Noto Sans Mono CJK KR: 6 | normal: notosansmono-cjk-kr-normal.ttf 7 | bold: notosansmono-cjk-kr-bold.ttf 8 | italic: notosansmono-cjk-kr-italic.ttf 9 | bold_italic: notosansmono-cjk-kr-bold_italic.ttf 10 | # M+ 1mn supports ASCII and the circled numbers used for conums 11 | M+ 1mn: 12 | normal: mplus1mn-regular-subset.ttf 13 | bold: mplus1mn-bold-subset.ttf 14 | italic: mplus1mn-italic-subset.ttf 15 | bold_italic: mplus1mn-bold_italic-subset.ttf 16 | # Add Fallback 17 | M+ 1p Fallback: mplus1p-regular-fallback.ttf 18 | Noto Emoji: notoemoji-subset.ttf 19 | fallbacks: [M+ 1p Fallback, Noto Emoji, Noto Sans Mono CJK KR] 20 | page: 21 | background_color: ffffff 22 | layout: portrait 23 | # NOTE multiply inches by 72 to get pt values 24 | #margin: [0.5 * 72, 0.67 * 72, 0.67 * 72, 0.67 * 72] 25 | margin: [0.5in, 0.67in, 0.67in, 0.67in] 26 | # size can be a named size (e.g., A4) or custom dimensions (e.g., [8.25in, 11.69in]) 27 | size: A4 28 | base: 29 | # color as hex string (leading # is optional) 30 | font_color: 333333 31 | # color as RGB array 32 | #font_color: [51, 51, 51] 33 | # color as CMYK array (approximated) 34 | #font_color: [0, 0, 0, 0.92] 35 | #font_color: [0, 0, 0, 92%] 36 | font_family: Noto Sans Mono CJK KR 37 | # choose one of these font_size/line_height_length combinations 38 | #font_size: 14 39 | #line_height_length: 20 40 | #font_size: 11.25 41 | #line_height_length: 18 42 | #font_size: 11.2 43 | #line_height_length: 16 44 | font_size: 10.5 45 | #line_height_length: 15 46 | # correct line height for Noto Serif metrics 47 | line_height_length: 15 48 | #font_size: 11.25 49 | #line_height_length: 18 50 | line_height: $base_line_height_length / $base_font_size 51 | font_size_large: round($base_font_size * 1.25) 52 | font_size_small: round($base_font_size * 0.85) 53 | font_size_min: $base_font_size * 0.75 54 | font_style: normal 55 | align: left 56 | border_radius: 4 57 | border_width: 0.5 58 | border_color: eeeeee 59 | # FIXME vertical_rhythm is weird; we should think in terms of ems 60 | #vertical_rhythm: $base_line_height_length * 2 / 3 61 | # correct line height for Noto Serif metrics 62 | vertical_rhythm: $base_line_height_length 63 | horizontal_rhythm: $base_line_height_length 64 | link: 65 | font_color: 428bca 66 | # literal is currently used for inline monospaced in prose and table cells 67 | # [INFO] asciidoctor: WARN: the literal theme category is deprecated; use the codespan category instead 68 | # literal: 69 | # 20221002 FIX 70 | codespan: 71 | font_color: b12146 72 | font_family: M+ 1mn 73 | heading: 74 | #font_color: 181818 75 | font_color: $base_font_color 76 | font_family: $base_font_family 77 | # h1 is used for part titles 78 | h1_font_size: floor($base_font_size * 2.6) 79 | # h2 is used for chapter titles 80 | h2_font_size: floor($base_font_size * 2.15) 81 | h3_font_size: round($base_font_size * 1.7) 82 | h4_font_size: $base_font_size_large 83 | h5_font_size: $base_font_size 84 | h6_font_size: $base_font_size_small 85 | font_style: bold 86 | #line_height: 1.4 87 | # correct line height for Noto Serif metrics 88 | line_height: 1.2 89 | margin_top: $vertical_rhythm * 0.2 90 | margin_bottom: $vertical_rhythm * 0.8 91 | title_page: 92 | align: right 93 | title_top: 55% 94 | title_font_size: $heading_h1_font_size 95 | title_font_color: 999999 96 | title_line_height: 0.9 97 | subtitle_font_size: $heading_h3_font_size 98 | subtitle_font_style: bold_italic 99 | subtitle_line_height: 1 100 | authors_margin_top: $base_font_size * 1.25 101 | authors_font_size: $base_font_size_large 102 | authors_font_color: 181818 103 | revision_margin_top: $base_font_size * 1.25 104 | #prose: 105 | # margin_top: 0 106 | # margin_bottom: $vertical_rhythm 107 | block: 108 | #margin_top: 0 109 | #margin_bottom: $vertical_rhythm 110 | padding: [$vertical_rhythm, $vertical_rhythm * 1.25, $vertical_rhythm, $vertical_rhythm * 1.25] 111 | # code is used for source blocks (perhaps change to source or listing?) 112 | caption: 113 | font_style: italic 114 | align: left 115 | # FIXME perhaps set line_height instead of / in addition to margins? 116 | margin_inside: $vertical_rhythm * 0.25 117 | margin_outside: 0 118 | code: 119 | font_color: $base_font_color 120 | #font_family: Liberation Mono 121 | #font_size: floor($base_font_size * 0.9) 122 | #font_size: 10 123 | #padding: [9.5, 9.5, 9.5, 9.5] 124 | # LiberationMono carries extra gap below line 125 | #padding: [10, 10, 7.5, 10] 126 | #line_height: 1.45 127 | #font_family: $literal_font_family 128 | # 20221002 FIX literal to codespan 129 | font_family: $codespan_font_family 130 | font_size: ceil($base_font_size) 131 | #padding: [$base_font_size, $code_font_size, $base_font_size, $code_font_size] 132 | padding: $code_font_size 133 | line_height: 1.25 134 | background_color: f5f5f5 135 | border_color: cccccc 136 | border_radius: $base_border_radius 137 | border_width: 0.75 138 | # # [INFO] asciidoctor: WARN: the blockquote theme category is deprecated; use the quote category instead 139 | # blockquote: 140 | # 20221002 FIX 141 | quote: 142 | font_color: $base_font_color 143 | font_size: $base_font_size_large 144 | border_width: 5 145 | border_color: $base_border_color 146 | cite_font_size: $base_font_size_small 147 | cite_font_color: 999999 148 | sidebar: 149 | border_color: $page_background_color 150 | border_radius: $base_border_radius 151 | border_width: $base_border_width 152 | background_color: eeeeee 153 | title_font_color: $heading_font_color 154 | title_font_family: $heading_font_family 155 | title_font_size: $heading_h4_font_size 156 | title_font_style: $heading_font_style 157 | title_align: center 158 | example: 159 | border_color: $base_border_color 160 | border_radius: $base_border_radius 161 | border_width: 0.75 162 | background_color: transparent 163 | admonition: 164 | border_color: $base_border_color 165 | border_width: $base_border_width 166 | conum: 167 | #font_family: $literal_font_family 168 | # 20221002 FIX literal to codespan 169 | font_family: $codespan_font_family 170 | # 20221002 FIX literal to codespan 171 | #font_color: $literal_font_color 172 | font_color: $codespan_font_color 173 | font_size: $base_font_size 174 | line_height: 4 / 3 175 | image: 176 | align_default: left 177 | scaled_width_default: 0.5 178 | lead: 179 | # QUESTION what about $base_font_size_large? 180 | #font_size: floor($base_line_height_length * 0.8) 181 | #font_size: floor($base_font_size * 1.15) 182 | #line_height: 1.3 183 | font_size: $base_font_size_large 184 | line_height: 1.4 185 | abstract: 186 | #font_color: 404040 187 | font_color: 5c6266 188 | font_size: $lead_font_size 189 | line_height: $lead_line_height 190 | font_style: italic 191 | thematic_break: 192 | border_color: $base_border_color 193 | margin_top: $vertical_rhythm * 0.5 194 | margin_bottom: $vertical_rhythm * 1.5 195 | description_list: 196 | term_font_style: italic 197 | description_indent: $horizontal_rhythm * 1.25 198 | # [INFO] asciidoctor: WARN: the outline-list theme category is deprecated; use the list category instead 199 | # outline_list: 200 | # 20221002 FIX 201 | list: 202 | indent: $horizontal_rhythm * 1.5 203 | # NOTE item_spacing applies to list items that do not have complex content 204 | item_spacing: $vertical_rhythm / 2 205 | #marker_font_color: 404040 206 | table: 207 | background_color: $page_background_color 208 | #head_background_color: 209 | #head_font_color: $base_font_color 210 | even_row_background_color: f9f9f9 211 | #odd_row_background_color: 212 | foot_background_color: f0f0f0 213 | border_color: dddddd 214 | border_width: $base_border_width 215 | # HACK accounting for line-height 216 | cell_padding: [3, 3, 6, 3] 217 | toc: 218 | indent: $horizontal_rhythm 219 | dot_leader_color: dddddd 220 | #dot_leader_content: ". " 221 | line_height: 1.4 222 | # NOTE In addition to footer, header is also supported 223 | footer: 224 | font_size: $base_font_size_small 225 | font_color: $base_font_color 226 | # NOTE if background_color is set, background and border will span width of page 227 | border_color: dddddd 228 | border_width: 0.25 229 | height: $base_line_height_length * 2.5 230 | padding: [$base_line_height_length / 2, 1, 0, 1] 231 | valign: top 232 | #image_valign: or 233 | # additional attributes for content: 234 | # * {page-count} 235 | # * {page-number} 236 | # * {document-title} 237 | # * {document-subtitle} 238 | # * {chapter-title} 239 | # * {section-title} 240 | # * {section-or-chapter-title} 241 | recto_content: 242 | #right: '{section-or-chapter-title} | {page-number}' 243 | #right: '{document-title} | {page-number}' 244 | right: '{page-number}' 245 | #center: '{page-number}' 246 | verso_content: 247 | #left: '{page-number} | {chapter-title}' 248 | left: '{page-number}' 249 | #center: '{page-number}' 250 | -------------------------------------------------------------------------------- /clojure-complete-html.adoc: -------------------------------------------------------------------------------- 1 | = Clojure Complete (클로저 완전정복) 2 | :bookseries: Clojure 3 | :doctype: book 4 | :source-language: clojure 5 | :source-highlighter: coderay 6 | //:stem: latexmath 7 | :linkcss: 8 | :icons: font 9 | :imagesdir: ./img 10 | :docinfo1: 11 | 12 | * github 저장소: https://github.com/clojure-kr/clojure-complete[] 13 | 14 | == [small]#Version:   2015-12-31# 15 | 16 | [sidebar] 17 | **** 18 | commit은 수시로 이루어지지만, 버전 번호는 큰 변화가 있다고 판단될 때(예를 들어, 새로운 19 | 장을 마쳤을 때)에만 올라 갑니다. 20 | **** 21 | 22 | :leveloffset: 1 23 | 24 | 다음의 목차에서 링크가 아직 걸려 있지 않은 장은 앞으로 채워 나갈 예정입니다. 25 | 26 | .Table of Contents 27 | [sidebar] 28 | **** 29 | . <> 30 | . 왜 클로저인가? 31 | . <> 32 | . <> 33 | . <> 34 | . <> 35 | . <> 36 | . 함수형 프로그래밍 37 | . <> 38 | . 변환자(Transducers) 39 | . <> 40 | . <> 41 | . 상태 관리와 동시성 42 | . core.async 43 | . 멀티메소드와 상속 44 | . 프로토콜과 레코드 45 | . 매크로 46 | . 수학 47 | . 날짜와 시간 48 | . 입출력: 파일과 디렉토리 49 | . 프로젝트 관리 50 | . 예외 처리 51 | . <> 52 | . 타입 검사 53 | . 데이타베이스 프로그래밍 54 | . 통신 및 웹 프로그래밍 55 | . 파서 56 | . 문자 인코딩 57 | . GUI 프로그래밍 58 | . <> 59 | **** 60 | 61 | //. <> 62 | //. <> 63 | //. <> 64 | //. <> 65 | //. <> 66 | //. <> 67 | //. <> 68 | //. <> 69 | //. <> 70 | //. <> 71 | //. <> 72 | //. <> 73 | //. <> 74 | //. <> 75 | //. <> 76 | 77 | 78 | :leveloffset: 0 79 | 80 | == [small]#Copyright# 81 | 82 | Copyright (C) 2015. All rights reserved. 83 | 84 | 이 책의 저작권은 https://creativecommons.org/licenses/by-nc-sa/4.0/[Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)]을 따른다. 85 | 86 | 즉, 다음의 조건을 준수하는 한 이 책의 자유로운 복제, 수정 및 배포가 가능하다. 87 | 88 | * 이 책의 내용을 기반으로 2차 저작물을 만들 경우 원작자를 표시하여야 한다. 89 | * 상업적 목적으로 이용할 수 없다. 90 | * 2차 저작물의 경우 위와 동일한 저작권을 사용해야 한다. 91 | 92 | 93 | == [small]#Contributing# 94 | 95 | 이 책의 집필에 함께 참여하고자 하는 분들을 환영합니다. 참여를 원하시는 분은 96 | https://github.com/[github]에 먼저 사용자 계정을 만드신 후, github의 97 | https://github.com/clojure-kr/clojure-complete[clojure-complete 저장소]를 자신의 계정으로 98 | fork합니다. 그리고 문서를 작성하신 후에 pull request를 보내 주십시오. 몇 차례의 pull 99 | request가 받아들여지고, 문서의 집필에 기여하신 분의 이름이 Contributors 명단에 등록된 100 | 이후부터 자유로운 commit이 가능해집니다. 101 | 102 | 이 책의 문서 형식은 asciidoc이고, http://asciidoctor.org/[asciidoctor]를 이용해 103 | 관리됩니다. 문서 관리에 필요한 asciidoctor 프로그램 설치 정보는 <>디렉토리 104 | 아래에 있는 문서를 참고하시기 바라며, asciidoc 문서 작성 요령은 105 | http://asciidoctor.org/docs/user-manual/[Asciidoctor User Manual]에 자세히 나와 있습니다. 106 | 107 | 보내 주신 문서는 문서의 통일성과 완결성을 위해 필요에 따라 내용의 첨삭/편집/재배치 과정을 108 | 거칠 수 있음을 미리 밝힙니다. 109 | 110 | 111 | == [small]#Contributors# 112 | 113 | * 김영태 (philos99@gmail.com)   Main editor 114 | * 박상규 (psk810@gmail.com) 115 | * 김만명 (manmyung@gmail.com) 116 | -------------------------------------------------------------------------------- /clojure-complete-pdf.adoc: -------------------------------------------------------------------------------- 1 | = Clojure Complete (클로저 완전정복) 2 | :bookseries: Clojure 3 | :doctype: book 4 | :source-language: clojure 5 | :source-highlighter: coderay 6 | //:stem: latexmath 7 | :icons: font 8 | :imagesdir: ./img 9 | :toc: 10 | :toclevels: 1 11 | 12 | [colophon] 13 | == Copyright 14 | 15 | 이 책의 저작권은 https://creativecommons.org/licenses/by-nc-sa/4.0/[Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)]을 따른다. 16 | 17 | 즉, 다음의 조건을 준수하는 한 이 책의 자유로운 복제, 수정 및 배포가 가능하다. 18 | 19 | * 이 책의 내용을 기반으로 2차 저작물을 만들 경우 원작자를 표시하여야 한다. 20 | * 상업적 목적으로 이용할 수 없다. 21 | * 2차 저작물의 경우 위와 동일한 저작권을 사용해야 한다. 22 | 23 | 24 | == Contributing 25 | 26 | 이 책의 집필에 함께 참여하고자 하는 분들을 환영합니다. 참여를 원하시는 분은 27 | https://github.com/[github]에 먼저 사용자 계정을 만드신 후, 이 repository를 자신의 28 | 계정으로 fork합니다. 그리고 문서를 작성하신 후에 pull request를 보내 주시면 됩니다. 최초 29 | pull request가 받아들여진 후에 Contributors 명단에 문서의 집필에 기여하신 분의 이름이 30 | 등재될 것입니다. 31 | 32 | 이 책의 문서 형식은 asciidoc이고, http://asciidoctor.org/[asciidoctor]를 이용해 33 | 관리됩니다. 문서 관리에 필요한 asciidoctor 프로그램 설치 정보는 internal 디렉토리 밑에 34 | 있으니 참고하기 바라며, asciidoc 문서 작성 요령은 35 | http://asciidoctor.org/docs/user-manual/[Asciidoctor User Manual]에 자세히 나와 있습니다. 36 | 37 | 보내 주신 문서는 문서의 통일성과 완결성을 위해 필요에 따라 편집과 재배치의 과정을 거칠 수 38 | 있음을 미리 밝힙니다. 39 | 40 | 41 | == Contributors 42 | 43 | * 김영태 (philos99@gmail.com) Main editor 44 | * 박상규 (psk810@gmail.com) 45 | * 김만명 (manmyung@gmail.com) 46 | 47 | 48 | :leveloffset: 1 49 | 50 | include::Preface/preface.adoc[] 51 | 52 | :sectnums: 53 | 54 | //include::Development-Environments/development-environments.adoc[] 55 | 56 | //include::Leiningen/leiningen.adoc[] 57 | 58 | //include::Start/start.adoc[] 59 | 60 | //include::Simple-Data-Types/simple-data-types.adoc[] 61 | 62 | //include::Flow-Controls/flow-controls.adoc[] 63 | 64 | //include::Collections-and-Sequences/collections-and-sequences.adoc[] 65 | 66 | //include::Functions-and-Functional-Programming/functions-and-functional-programming.adoc[] 67 | 68 | //include::Destructuring/destructuring.adoc[] 69 | 70 | //include::Recursions/recursions.adoc[] 71 | 72 | //include::Transducers/transducers.adoc[] 73 | 74 | //include::Java-Interoperability/java-interoperability.adoc[] 75 | 76 | //include::Metadata/metadata.adoc[] 77 | 78 | include::Namespaces-and-Libraries/namespaces-and-libraries.adoc[] 79 | 80 | //include::State-Management-and-Parallel-Programming/state-management-and-parallel-programming.adoc[] 81 | 82 | //include::Core-Async/core-async.adoc[] 83 | 84 | //include::Multimedthos-and-Hierarchies/multimedthos-and-hierarchies.adoc[] 85 | 86 | //include::Protocols-Records-and-Types/protocols-records-and-types.adoc[] 87 | 88 | //include::Macros/macros.adoc[] 89 | 90 | //include::Numerics and Mathematics/numerics-and-mathematics.adoc[] 91 | 92 | //include::Project-Management/project-management.adoc[] 93 | 94 | //include::Testing/testing.adoc[] 95 | 96 | //include::Type-Checking/type-checking.adoc[] 97 | 98 | //include::Database-Programming/database-programming.adoc[] 99 | 100 | //include::Web-Programming/web-programming.adoc[] 101 | 102 | //include::index.asciidoc[] 103 | 104 | //include::colo.asciidoc[] 105 | 106 | :leveloffset: 0 107 | 108 | -------------------------------------------------------------------------------- /coderay-asciidoctor.css: -------------------------------------------------------------------------------- 1 | /* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */ 2 | /*pre.CodeRay {background-color:#f7f7f8;}*/ 3 | .CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em} 4 | .CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)} 5 | .CodeRay .line-numbers strong{color:rgba(0,0,0,.4)} 6 | table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none} 7 | table.CodeRay td{vertical-align: top;line-height:1.45} 8 | table.CodeRay td.line-numbers{text-align:right} 9 | table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)} 10 | table.CodeRay td.code{padding:0 0 0 .5em} 11 | table.CodeRay td.code>pre{padding:0} 12 | .CodeRay .debug{color:#fff !important;background:#000080 !important} 13 | .CodeRay .annotation{color:#007} 14 | .CodeRay .attribute-name{color:#000080} 15 | .CodeRay .attribute-value{color:#700} 16 | .CodeRay .binary{color:#509} 17 | .CodeRay .comment{color:#998;font-style:italic} 18 | .CodeRay .char{color:#04d} 19 | .CodeRay .char .content{color:#04d} 20 | .CodeRay .char .delimiter{color:#039} 21 | .CodeRay .class{color:#458;font-weight:bold} 22 | .CodeRay .complex{color:#a08} 23 | .CodeRay .constant,.CodeRay .predefined-constant{color:#008080} 24 | .CodeRay .color{color:#099} 25 | .CodeRay .class-variable{color:#369} 26 | .CodeRay .decorator{color:#b0b} 27 | .CodeRay .definition{color:#099} 28 | .CodeRay .delimiter{color:#000} 29 | .CodeRay .doc{color:#970} 30 | .CodeRay .doctype{color:#34b} 31 | .CodeRay .doc-string{color:#d42} 32 | .CodeRay .escape{color:#666} 33 | .CodeRay .entity{color:#800} 34 | .CodeRay .error{color:#808} 35 | .CodeRay .exception{color:inherit} 36 | .CodeRay .filename{color:#099} 37 | .CodeRay .function{color:#900;font-weight:bold} 38 | .CodeRay .global-variable{color:#008080} 39 | .CodeRay .hex{color:#058} 40 | .CodeRay .integer,.CodeRay .float{color:#099} 41 | .CodeRay .include{color:#555} 42 | .CodeRay .inline{color:#000} 43 | .CodeRay .inline .inline{background:#ccc} 44 | .CodeRay .inline .inline .inline{background:#bbb} 45 | .CodeRay .inline .inline-delimiter{color:#d14} 46 | .CodeRay .inline-delimiter{color:#d14} 47 | .CodeRay .important{color:#555;font-weight:bold} 48 | .CodeRay .interpreted{color:#b2b} 49 | .CodeRay .instance-variable{color:#008080} 50 | .CodeRay .label{color:#970} 51 | .CodeRay .local-variable{color:#963} 52 | .CodeRay .octal{color:#40e} 53 | .CodeRay .predefined{color:#369} 54 | .CodeRay .preprocessor{color:#579} 55 | .CodeRay .pseudo-class{color:#555} 56 | .CodeRay .directive{font-weight:bold} 57 | .CodeRay .type{font-weight:bold} 58 | .CodeRay .predefined-type{color:inherit} 59 | .CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold} 60 | .CodeRay .key{color:#808} 61 | .CodeRay .key .delimiter{color:#606} 62 | .CodeRay .key .char{color:#80f} 63 | .CodeRay .value{color:#088} 64 | .CodeRay .regexp .delimiter{color:#808} 65 | .CodeRay .regexp .content{color:#808} 66 | .CodeRay .regexp .modifier{color:#808} 67 | .CodeRay .regexp .char{color:#d14} 68 | .CodeRay .regexp .function{color:#404;font-weight:bold} 69 | .CodeRay .string{color:#d20} 70 | .CodeRay .string .string .string{background:#ffd0d0} 71 | .CodeRay .string .content{color:#d14} 72 | .CodeRay .string .char{color:#d14} 73 | .CodeRay .string .delimiter{color:#d14} 74 | .CodeRay .shell{color:#d14} 75 | .CodeRay .shell .delimiter{color:#d14} 76 | .CodeRay .symbol{color:#990073} 77 | .CodeRay .symbol .content{color:#a60} 78 | .CodeRay .symbol .delimiter{color:#630} 79 | .CodeRay .tag{color:#008080} 80 | .CodeRay .tag-special{color:#d70} 81 | .CodeRay .variable{color:#036} 82 | .CodeRay .insert{background:#afa} 83 | .CodeRay .delete{background:#faa} 84 | .CodeRay .change{color:#aaf;background:#007} 85 | .CodeRay .head{color:#f8f;background:#505} 86 | .CodeRay .insert .insert{color:#080} 87 | .CodeRay .delete .delete{color:#800} 88 | .CodeRay .change .change{color:#66f} 89 | .CodeRay .head .head{color:#f4f} -------------------------------------------------------------------------------- /docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /guide/asciidoctor.adoc: -------------------------------------------------------------------------------- 1 | = asciidoctor 사용법 2 | :linkcss: 3 | :sectnums: 4 | :stylesdir: ../ 5 | :stylesheet: my-asciidoctor.css 6 | 7 | == ruby 설치 8 | 9 | asciidoctor는 루비 언어로 작성되어 있으므로, 먼저 ruby를 설치한다. 다음은 리눅스 10 | Ubuntu에서 설치한 예이다. 11 | 12 | $ sudo apt-get install ruby 13 | 14 | 15 | == asciidoctor 설치 16 | 17 | asciidoctor gem을 설치한다. 참고로, 루비에서는 라이브러리를 gem이라 부른다. 18 | 19 | $ sudo gem install asciidoctor 20 | 21 | 22 | == coderay 설치 23 | 24 | syntax highlighting을 위해 coderay gem을 설치한다. 25 | 26 | $ sudo gem install coderay 27 | 28 | 29 | == asciidoctor-pdf 설치 30 | 31 | pdf 변환을 위해 asciidoctor-pdf gem을 설치한다. 32 | 33 | $ sudo gem install --pre asciidoctor-pdf 34 | 35 | 36 | == asciidoctor-pdf-cjk-kai_gen_gothic 설치 37 | 38 | asciidoctor-pdf만으로 pdf를 만들면 한글이 제대로 출력되지 않는다. 따라서 39 | asciidoctor-pdf-cjk-kai_gen_gothic gem을 추가로 설치해 주어야 한다. 40 | 41 | $ sudo gem install asciidoctor-pdf-cjk-kai_gen_gothic 42 | 43 | 44 | == asciidoctor-pdf-cjk-kai_gen_gothic-install 실행 45 | 46 | 다음을 실행해 pdf 생성에 필요한 폰트 파일을 다운로드 받는다. 한 번만 실행해 주면 된다. 47 | 48 | $ sudo asciidoctor-pdf-cjk-kai_gen_gothic-install 49 | 50 | 51 | == pdf 만들기 52 | 53 | $ asciidoctor-pdf -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicKR sample.adoc 54 | 55 | WARNING: 위의 방식으로 pdf를 생성할 때, mathjax를 이용한 수식 처리는 아직 제대로 되지 않는다는 점에 56 | 주의한다. 57 | 58 | 59 | == install asciidoctor-mathematical 60 | 61 | * 참고: https://github.com/asciidoctor/asciidoctor-mathematical 62 | 63 | $ sudo apt install ruby-dev 64 | $ sudo apt install bison flex libffi-dev libxml2-dev libgdk-pixbuf2.0-dev \ 65 | libcairo2-dev libpango1.0-dev ttf-lyx 66 | 67 | $ sudo add-apt-repository ppa:george-edison55/cmake-3.x 68 | $ sudo apt-get update 69 | $ sudo apt-get install cmake 70 | 71 | $ sudo gem install asciidoctor-mathematical 72 | 73 | $ asciidoctor-pdf -r asciidoctor-pdf-cjk-kai_gen_gothic -r asciidoctor-mathematical \ 74 | -a pdf-style=KaiGenGothicKR sample.adoc 75 | 76 | 77 | == Chrome plugin asciidoctor.js 설치 78 | 79 | asciidoctor.js Chrome plugin을 설치한 후 크롬 브라우저 상에서 asciidoctor 문서를 열면, 80 | 문서를 저장할 때마다 실시간(실제로는 2초 간격)으로 변경된 내용이 반영되어 나타나므로 81 | 설치하는 것이 편리하다. 82 | 83 | -------------------------------------------------------------------------------- /guide/asciidoctor.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure-kr/clojure-complete/eb11771112b54c0b8bbe337a8718e50271a2f09a/guide/asciidoctor.pdf -------------------------------------------------------------------------------- /guide/asciidoctor.pdfmarks: -------------------------------------------------------------------------------- 1 | [ /Title 2 | /Author null 3 | /Subject null 4 | /Keywords null 5 | /ModDate (D:20150904205714) 6 | /CreationDate (D:20150904205714) 7 | /Creator (Asciidoctor PDF 1.5.0.alpha.9, based on Prawn 2.0.2) 8 | /Producer null 9 | /DOCINFO pdfmark 10 | -------------------------------------------------------------------------------- /guide/chores.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | $dirs = %w(Why-Clojure Development-Environments Leiningen Start Basic-Data-Types 4 | Flow-Controls Collections-and-Data-Structures Functions-and-Functional-Programming 5 | Destructuring Recursions Transducers Java-Interoperability Metadata 6 | Namespaces-and-Libraries State-Management-and-Parallel-Programming Core-Async 7 | Multimedthos-and-Hierarchies Protocols-Records-and-Types Macros 8 | Numerics-and-Mathematics Project-Management Testing Type-Checking 9 | Database-Programming Web-Programming) 10 | 11 | def init_dirs () 12 | $dirs.each do |dir| 13 | `rm -rf #{dir}` 14 | `mkdir #{dir}` 15 | `touch "#{dir}/#{dir.downcase}.adoc"` 16 | end 17 | end 18 | 19 | def remove_htmls () 20 | $dirs.each do |dir| 21 | `rm "#{dir}/#{dir.downcase}.html"` 22 | end 23 | end 24 | 25 | # remove_htmls 26 | 27 | 28 | -------------------------------------------------------------------------------- /guide/coderay-asciidoctor.css: -------------------------------------------------------------------------------- 1 | /* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */ 2 | /*pre.CodeRay {background-color:#f7f7f8;}*/ 3 | .CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em} 4 | .CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)} 5 | .CodeRay .line-numbers strong{color:rgba(0,0,0,.4)} 6 | table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none} 7 | table.CodeRay td{vertical-align: top;line-height:1.45} 8 | table.CodeRay td.line-numbers{text-align:right} 9 | table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)} 10 | table.CodeRay td.code{padding:0 0 0 .5em} 11 | table.CodeRay td.code>pre{padding:0} 12 | .CodeRay .debug{color:#fff !important;background:#000080 !important} 13 | .CodeRay .annotation{color:#007} 14 | .CodeRay .attribute-name{color:#000080} 15 | .CodeRay .attribute-value{color:#700} 16 | .CodeRay .binary{color:#509} 17 | .CodeRay .comment{color:#998;font-style:italic} 18 | .CodeRay .char{color:#04d} 19 | .CodeRay .char .content{color:#04d} 20 | .CodeRay .char .delimiter{color:#039} 21 | .CodeRay .class{color:#458;font-weight:bold} 22 | .CodeRay .complex{color:#a08} 23 | .CodeRay .constant,.CodeRay .predefined-constant{color:#008080} 24 | .CodeRay .color{color:#099} 25 | .CodeRay .class-variable{color:#369} 26 | .CodeRay .decorator{color:#b0b} 27 | .CodeRay .definition{color:#099} 28 | .CodeRay .delimiter{color:#000} 29 | .CodeRay .doc{color:#970} 30 | .CodeRay .doctype{color:#34b} 31 | .CodeRay .doc-string{color:#d42} 32 | .CodeRay .escape{color:#666} 33 | .CodeRay .entity{color:#800} 34 | .CodeRay .error{color:#808} 35 | .CodeRay .exception{color:inherit} 36 | .CodeRay .filename{color:#099} 37 | .CodeRay .function{color:#900;font-weight:bold} 38 | .CodeRay .global-variable{color:#008080} 39 | .CodeRay .hex{color:#058} 40 | .CodeRay .integer,.CodeRay .float{color:#099} 41 | .CodeRay .include{color:#555} 42 | .CodeRay .inline{color:#000} 43 | .CodeRay .inline .inline{background:#ccc} 44 | .CodeRay .inline .inline .inline{background:#bbb} 45 | .CodeRay .inline .inline-delimiter{color:#d14} 46 | .CodeRay .inline-delimiter{color:#d14} 47 | .CodeRay .important{color:#555;font-weight:bold} 48 | .CodeRay .interpreted{color:#b2b} 49 | .CodeRay .instance-variable{color:#008080} 50 | .CodeRay .label{color:#970} 51 | .CodeRay .local-variable{color:#963} 52 | .CodeRay .octal{color:#40e} 53 | .CodeRay .predefined{color:#369} 54 | .CodeRay .preprocessor{color:#579} 55 | .CodeRay .pseudo-class{color:#555} 56 | .CodeRay .directive{font-weight:bold} 57 | .CodeRay .type{font-weight:bold} 58 | .CodeRay .predefined-type{color:inherit} 59 | .CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold} 60 | .CodeRay .key{color:#808} 61 | .CodeRay .key .delimiter{color:#606} 62 | .CodeRay .key .char{color:#80f} 63 | .CodeRay .value{color:#088} 64 | .CodeRay .regexp .delimiter{color:#808} 65 | .CodeRay .regexp .content{color:#808} 66 | .CodeRay .regexp .modifier{color:#808} 67 | .CodeRay .regexp .char{color:#d14} 68 | .CodeRay .regexp .function{color:#404;font-weight:bold} 69 | .CodeRay .string{color:#d20} 70 | .CodeRay .string .string .string{background:#ffd0d0} 71 | .CodeRay .string .content{color:#d14} 72 | .CodeRay .string .char{color:#d14} 73 | .CodeRay .string .delimiter{color:#d14} 74 | .CodeRay .shell{color:#d14} 75 | .CodeRay .shell .delimiter{color:#d14} 76 | .CodeRay .symbol{color:#990073} 77 | .CodeRay .symbol .content{color:#a60} 78 | .CodeRay .symbol .delimiter{color:#630} 79 | .CodeRay .tag{color:#008080} 80 | .CodeRay .tag-special{color:#d70} 81 | .CodeRay .variable{color:#036} 82 | .CodeRay .insert{background:#afa} 83 | .CodeRay .delete{background:#faa} 84 | .CodeRay .change{color:#aaf;background:#007} 85 | .CodeRay .head{color:#f8f;background:#505} 86 | .CodeRay .insert .insert{color:#080} 87 | .CodeRay .delete .delete{color:#800} 88 | .CodeRay .change .change{color:#66f} 89 | .CodeRay .head .head{color:#f4f} -------------------------------------------------------------------------------- /guide/demo.adoc: -------------------------------------------------------------------------------- 1 | = 2 | :source-language: clojure 3 | :source-highlighter: coderay 4 | :sectnums: 5 | :imagesdir: ../img 6 | :linkcss: 7 | :stylesdir: ../ 8 | :stylesheet: my-asciidoctor.css 9 | :docinfo1: 10 | :toc: right 11 | 12 | -------------------------------------------------------------------------------- /guide/docinfo.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /guide/to-html.sh: -------------------------------------------------------------------------------- 1 | asciidoctor clojure-complete.adoc **/*.adoc 2 | -------------------------------------------------------------------------------- /my-asciidoctor.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/earlyaccess/nanumgothic.css); 2 | @import url("asciidoctor.css"); 3 | 4 | html{font-family: 'Nanum Gothic', serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} 5 | 6 | body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family: 'Nanum Gothic', serif;;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto} 7 | 8 | h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#000;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em} 9 | -------------------------------------------------------------------------------- /src/java-interop/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | -------------------------------------------------------------------------------- /src/java-interop/.idea/.name: -------------------------------------------------------------------------------- 1 | java-interop -------------------------------------------------------------------------------- /src/java-interop/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/java-interop/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/java-interop/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__args4j_2_0_26.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__cider_cider_nrepl_0_10_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__clojure_complete_0_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__com_cemerick_piggieback_0_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__com_google_code_findbugs_jsr305_1_3_9.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__com_google_code_gson_gson_2_2_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__com_google_guava_guava_18_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__com_google_javascript_closure_compiler_externs_v20150126.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__com_google_javascript_closure_compiler_v20150126.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__com_google_protobuf_protobuf_java_2_5_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__com_google_truth_truth_0_24.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__criterium_0_4_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__http_kit_2_1_18.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__junit_4_10.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__org_clojure_clojure_1_7_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__org_clojure_clojurescript_0_0_3165.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__org_clojure_data_json_0_2_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__org_clojure_google_closure_library_0_0_20140718_946a7d39.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__org_clojure_google_closure_library_third_party_0_0_20140718_946a7d39.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__org_clojure_tools_nrepl_0_2_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__org_clojure_tools_reader_0_8_16.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__org_hamcrest_hamcrest_core_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__org_mozilla_rhino_1_7R5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__org_tcrawley_dynapath_0_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__prismatic_schema_1_0_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/libraries/Leiningen__weasel_0_7_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/java-interop/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/java-interop/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/java-interop/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). 3 | 4 | ## [Unreleased][unreleased] 5 | ### Changed 6 | - Add a new arity to `make-widget-async` to provide a different widget shape. 7 | 8 | ## [0.1.1] - 2015-12-08 9 | ### Changed 10 | - Documentation on how to make the widgets. 11 | 12 | ### Removed 13 | - `make-widget-sync` - we're all async, all the time. 14 | 15 | ### Fixed 16 | - Fixed widget maker to keep working when daylight savings switches over. 17 | 18 | ## 0.1.0 - 2015-12-08 19 | ### Added 20 | - Files from the new template. 21 | - Widget maker public API - `make-widget-sync`. 22 | 23 | [unreleased]: https://github.com/your-name/java-interop/compare/0.1.1...HEAD 24 | [0.1.1]: https://github.com/your-name/java-interop/compare/0.1.0...0.1.1 25 | -------------------------------------------------------------------------------- /src/java-interop/LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor tocontrol, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /src/java-interop/README.md: -------------------------------------------------------------------------------- 1 | # java-interop 2 | 3 | A Clojure library designed to ... well, that part is up to you. 4 | 5 | ## Usage 6 | 7 | FIXME 8 | 9 | ## License 10 | 11 | Copyright © 2015 FIXME 12 | 13 | Distributed under the Eclipse Public License either version 1.0 or (at 14 | your option) any later version. 15 | -------------------------------------------------------------------------------- /src/java-interop/doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to java-interop 2 | 3 | TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) 4 | -------------------------------------------------------------------------------- /src/java-interop/java-interop.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/java-interop/project.clj: -------------------------------------------------------------------------------- 1 | (defproject java-interop "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 | :dependencies [[org.clojure/clojure "1.7.0"]] 7 | :aot [java-interop.example1 java-interop.example2 8 | java-interop.Example3 java-interop.Example4 9 | java-interop.Example5 java-interop.Example6]) 10 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/Example3.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.Example3 2 | (:gen-class 3 | :implements [clojure.lang.IDeref])) 4 | 5 | (defn -deref 6 | [this] 7 | "Hello, World!") 8 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/Example4.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.Example4 2 | (:gen-class 3 | :extends java_interop.Example3)) 4 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/Example5.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.Example5 2 | (:gen-class 3 | :implements [clojure.lang.IDeref] 4 | :state state 5 | :init init 6 | :constructors {[String] []})) 7 | 8 | (defn -init 9 | [message] 10 | [[] (atom message)]) 11 | 12 | (defn -deref 13 | [this] 14 | @(.state this)) 15 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/Example6.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.Example6 2 | (:gen-class 3 | :methods [^:static [greet [] String] 4 | [greetMessage [String] String]])) 5 | 6 | (defn -greet 7 | [] 8 | "Hello, World!") 9 | 10 | (defn -greetMessage 11 | [this msg] 12 | (str "Hello, " msg "!")) 13 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/example1.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.example1) 2 | 3 | (gen-class 4 | :name java_interop.example1.MyClass) 5 | 6 | (defn -toString 7 | [this] 8 | "Hello, World!") 9 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/example2.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.example2) 2 | 3 | (gen-class 4 | :name java_interop.example1.MyClassA 5 | :prefix classA-) 6 | 7 | (gen-class 8 | :name java_interop.example1.MyClassB 9 | :prefix classB-) 10 | 11 | (defn classA-toString 12 | [this] 13 | "I'm an A.") 14 | 15 | (defn classB-toString 16 | [this] 17 | "I'm a B.") 18 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/test1.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.test1 2 | (:import java_interop.example1.MyClass)) 3 | 4 | (.toString (MyClass.)) ;=> "Hello, World!" 5 | 6 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/test2.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.test2 2 | (:import (java_interop.example1 MyClassA MyClassB)) 3 | 4 | (.toString (MyClassA.)) ;=> "I'm an A." 5 | (.toString (MyClassB.)) ;=> "I'm an B." 6 | 7 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/test3.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.test3 2 | (:import java_interop.Example3)) 3 | 4 | @(Example3.) ;=> "Hello, World!" 5 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/test4.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.test4 2 | (:import java_interop.Example4)) 3 | 4 | @(Example4.) ;=> "Hello, World!" 5 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/test5.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.test5 2 | (:import java_interop.Example5)) 3 | 4 | (def o (Example5. "Hello, there!")) 5 | 6 | @o ;=> "Hallo, there!" 7 | 8 | (reset! (.state o) "Good morning, everybody!") 9 | 10 | @o ;=> "Good morning, everybody!" 11 | 12 | -------------------------------------------------------------------------------- /src/java-interop/src/java_interop/test6.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.test6 2 | (:import java_interop.Example6)) 3 | 4 | (Example6/greet) 5 | ;=> "Hello, World!" 6 | 7 | (.greetMessage (Example6.) "Rich Hickey") 8 | ;=> "Hello, Rich Hickey!" 9 | 10 | -------------------------------------------------------------------------------- /src/java-interop/test/java_interop/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns java-interop.core-test 2 | (:require [clojure.test :refer :all] 3 | [java-interop.core :refer :all])) 4 | 5 | (deftest a-test 6 | (testing "FIXME, I fail." 7 | (is (= 0 1)))) 8 | -------------------------------------------------------------------------------- /to-html.sh: -------------------------------------------------------------------------------- 1 | mkdir -p public 2 | asciidoctor -R . -D public -a stylesheet=my-asciidoctor.css clojure-complete-html.adoc **/*.adoc 3 | mv public/clojure-complete-html.html public/index.html 4 | cp asciidoctor.css public 5 | cp coderay-asciidoctor.css public 6 | cp my-asciidoctor.css public 7 | 8 | #asciidoctor clojure-complete-html.adoc **/*.adoc 9 | #mv clojure-complete-html.html index.html 10 | -------------------------------------------------------------------------------- /to-pdf.sh: -------------------------------------------------------------------------------- 1 | # asciidoctor-pdf -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicKR -o clojure-programming.pdf -o clojure-complete.pdf clojure-complete-pdf.adoc 2 | asciidoctor-pdf -a pdf-theme=asciidoctor-theme/notosansmono-cjk-kr/themes/default-ext-notosansmono-cjk-kr-theme.yml -a pdf-fontsdir=asciidoctor-theme/notosansmono-cjk-kr/fonts -o clojure-programming.pdf -o clojure-complete.pdf clojure-complete-pdf.adoc 3 | --------------------------------------------------------------------------------