clementine 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/Gemfile +4 -0
- data/README.md +52 -0
- data/Rakefile +1 -0
- data/clementine.gemspec +23 -0
- data/lib/clementine.rb +27 -0
- data/lib/clementine/clementine_rails.rb +8 -0
- data/lib/clementine/clojurescript_engine.rb +49 -0
- data/lib/clementine/clojurescript_engine_mri.rb +65 -0
- data/lib/clementine/clojurescript_template.rb +21 -0
- data/lib/clementine/options.rb +9 -0
- data/lib/clementine/version.rb +3 -0
- data/test/clojurescript_engine_test.rb +46 -0
- data/test/options_test.rb +22 -0
- data/vendor/assets/bin/cljsc.clj +21 -0
- data/vendor/assets/lib/clojure.jar +0 -0
- data/vendor/assets/lib/compiler.jar +0 -0
- data/vendor/assets/lib/goog.jar +0 -0
- data/vendor/assets/lib/js.jar +0 -0
- data/vendor/assets/src/clj/cljs/closure.clj +823 -0
- data/vendor/assets/src/clj/cljs/compiler.clj +1341 -0
- data/vendor/assets/src/clj/cljs/core.clj +702 -0
- data/vendor/assets/src/clj/cljs/repl.clj +162 -0
- data/vendor/assets/src/clj/cljs/repl/browser.clj +341 -0
- data/vendor/assets/src/clj/cljs/repl/rhino.clj +170 -0
- data/vendor/assets/src/cljs/cljs/core.cljs +3330 -0
- data/vendor/assets/src/cljs/cljs/nodejs.cljs +11 -0
- data/vendor/assets/src/cljs/cljs/nodejs_externs.js +2 -0
- data/vendor/assets/src/cljs/cljs/nodejscli.cljs +9 -0
- data/vendor/assets/src/cljs/cljs/reader.cljs +360 -0
- data/vendor/assets/src/cljs/clojure/browser/dom.cljs +106 -0
- data/vendor/assets/src/cljs/clojure/browser/event.cljs +100 -0
- data/vendor/assets/src/cljs/clojure/browser/net.cljs +182 -0
- data/vendor/assets/src/cljs/clojure/browser/repl.cljs +109 -0
- data/vendor/assets/src/cljs/clojure/set.cljs +162 -0
- data/vendor/assets/src/cljs/clojure/string.cljs +160 -0
- data/vendor/assets/src/cljs/clojure/walk.cljs +94 -0
- data/vendor/assets/src/cljs/clojure/zip.cljs +291 -0
- metadata +103 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
;; Copyright (c) Rich Hickey. All rights reserved.
|
2
|
+
;; The use and distribution terms for this software are covered by the
|
3
|
+
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
4
|
+
;; which can be found in the file epl-v10.html at the root of this distribution.
|
5
|
+
;; By using this software in any fashion, you are agreeing to be bound by
|
6
|
+
;; the terms of this license.
|
7
|
+
;; You must not remove this notice, or any other, from this software.
|
8
|
+
|
9
|
+
(ns ^{:doc "This namespace contains functions to work with browser
|
10
|
+
events. It is based on the Google Closure Library event system."
|
11
|
+
:author "Bobby Calderwood"}
|
12
|
+
clojure.browser.event
|
13
|
+
(:require [goog.events :as events]
|
14
|
+
[goog.events.EventTarget :as gevent-target]
|
15
|
+
[goog.events.EventType :as gevent-type]))
|
16
|
+
|
17
|
+
(defprotocol EventType
|
18
|
+
(event-types [this]))
|
19
|
+
|
20
|
+
(extend-protocol EventType
|
21
|
+
|
22
|
+
goog.events.EventTarget
|
23
|
+
(event-types
|
24
|
+
[this]
|
25
|
+
(into {}
|
26
|
+
(map
|
27
|
+
(fn [[k v]]
|
28
|
+
[(keyword (. k (toLowerCase)))
|
29
|
+
v])
|
30
|
+
(merge
|
31
|
+
(js->clj goog.events.EventType)))))
|
32
|
+
|
33
|
+
js/Element
|
34
|
+
(event-types
|
35
|
+
[this]
|
36
|
+
(into {}
|
37
|
+
(map
|
38
|
+
(fn [[k v]]
|
39
|
+
[(keyword (. k (toLowerCase)))
|
40
|
+
v])
|
41
|
+
(merge
|
42
|
+
(js->clj goog.events.EventType))))))
|
43
|
+
|
44
|
+
(defn listen
|
45
|
+
([src type fn]
|
46
|
+
(listen src type fn false))
|
47
|
+
([src type fn capture?]
|
48
|
+
(goog.events/listen src
|
49
|
+
(get (event-types src) type type)
|
50
|
+
fn
|
51
|
+
capture?)))
|
52
|
+
|
53
|
+
(defn listen-once
|
54
|
+
([src type fn]
|
55
|
+
(listen-once src type fn false))
|
56
|
+
([src type fn capture?]
|
57
|
+
(goog.events/listenOnce src
|
58
|
+
(get (event-types src) type type)
|
59
|
+
fn
|
60
|
+
capture?)))
|
61
|
+
|
62
|
+
(defn unlisten
|
63
|
+
([src type fn]
|
64
|
+
(unlisten src type fn false))
|
65
|
+
([src type fn capture?]
|
66
|
+
(goog.events/unlisten src
|
67
|
+
(get (event-types src) type type)
|
68
|
+
fn
|
69
|
+
capture?)))
|
70
|
+
|
71
|
+
(defn unlisten-by-key
|
72
|
+
[key]
|
73
|
+
(goog.events/unlistenByKey key))
|
74
|
+
|
75
|
+
(defn dispatch-event
|
76
|
+
[src event]
|
77
|
+
(goog.events/dispatchEvent src event))
|
78
|
+
|
79
|
+
(defn expose [e]
|
80
|
+
(goog.events/expose e))
|
81
|
+
|
82
|
+
(defn fire-listeners
|
83
|
+
[obj type capture event])
|
84
|
+
|
85
|
+
(defn total-listener-count []
|
86
|
+
(goog.events/getTotalListenerCount))
|
87
|
+
|
88
|
+
;; TODO
|
89
|
+
(defn get-listener [src type listener opt_capt opt_handler]); ⇒ ?Listener
|
90
|
+
(defn all-listeners [obj type capture]); ⇒ Array.<Listener>
|
91
|
+
|
92
|
+
(defn unique-event-id [event-type]); ⇒ string
|
93
|
+
|
94
|
+
(defn has-listener [obj opt_type opt_capture]); ⇒ boolean
|
95
|
+
;; TODO? (defn listen-with-wrapper [src wrapper listener opt_capt opt_handler])
|
96
|
+
;; TODO? (defn protect-browser-event-entry-point [errorHandler])
|
97
|
+
|
98
|
+
(defn remove-all [opt_obj opt_type opt_capt]); ⇒ number
|
99
|
+
;; TODO? (defn unlisten-with-wrapper [src wrapper listener opt_capt opt_handler])
|
100
|
+
|
@@ -0,0 +1,182 @@
|
|
1
|
+
;; Copyright (c) Rich Hickey. All rights reserved.
|
2
|
+
;; The use and distribution terms for this software are covered by the
|
3
|
+
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
4
|
+
;; which can be found in the file epl-v10.html at the root of this distribution.
|
5
|
+
;; By using this software in any fashion, you are agreeing to be bound by
|
6
|
+
;; the terms of this license.
|
7
|
+
;; You must not remove this notice, or any other, from this software.
|
8
|
+
|
9
|
+
(ns ^{:doc "Network communication library, wrapping goog.net.
|
10
|
+
Includes a common API over XhrIo, CrossPageChannel, and Websockets."
|
11
|
+
:author "Bobby Calderwood and Alex Redington"}
|
12
|
+
clojure.browser.net
|
13
|
+
(:require [clojure.browser.event :as event]
|
14
|
+
[goog.net.XhrIo :as gxhrio]
|
15
|
+
[goog.net.EventType :as gnet-event-type]
|
16
|
+
[goog.net.xpc.CfgFields :as gxpc-config-fields]
|
17
|
+
[goog.net.xpc.CrossPageChannel :as xpc]
|
18
|
+
#_[goog.net.WebSocket :as gwebsocket]
|
19
|
+
[goog.json :as gjson]))
|
20
|
+
|
21
|
+
(def *timeout* 10000)
|
22
|
+
|
23
|
+
(def event-types
|
24
|
+
(into {}
|
25
|
+
(map
|
26
|
+
(fn [[k v]]
|
27
|
+
[(keyword (. k (toLowerCase)))
|
28
|
+
v])
|
29
|
+
(merge
|
30
|
+
(js->clj goog.net.EventType)))))
|
31
|
+
|
32
|
+
(defprotocol IConnection
|
33
|
+
(connect
|
34
|
+
[this]
|
35
|
+
[this opt1]
|
36
|
+
[this opt1 opt2]
|
37
|
+
[this opt1 opt2 opt3])
|
38
|
+
(transmit
|
39
|
+
[this opt]
|
40
|
+
[this opt opt2]
|
41
|
+
[this opt opt2 opt3]
|
42
|
+
[this opt opt2 opt3 opt4]
|
43
|
+
[this opt opt2 opt3 opt4 opt5])
|
44
|
+
(close [this]))
|
45
|
+
|
46
|
+
(extend-type goog.net.XhrIo
|
47
|
+
|
48
|
+
IConnection
|
49
|
+
(transmit
|
50
|
+
([this uri]
|
51
|
+
(transmit this uri "GET" nil nil *timeout*))
|
52
|
+
([this uri method]
|
53
|
+
(transmit this uri method nil nil *timeout*))
|
54
|
+
([this uri method content]
|
55
|
+
(transmit this uri method content nil *timeout*))
|
56
|
+
([this uri method content headers]
|
57
|
+
(transmit this uri method content headers *timeout*))
|
58
|
+
([this uri method content headers timeout]
|
59
|
+
(.setTimeoutInterval this timeout)
|
60
|
+
(.send this uri method content headers)))
|
61
|
+
|
62
|
+
|
63
|
+
event/EventType
|
64
|
+
(event-types [this]
|
65
|
+
(into {}
|
66
|
+
(map
|
67
|
+
(fn [[k v]]
|
68
|
+
[(keyword (. k (toLowerCase)))
|
69
|
+
v])
|
70
|
+
(merge
|
71
|
+
(js->clj goog.net.EventType))))))
|
72
|
+
|
73
|
+
;; TODO jQuery/sinatra/RestClient style API: (get [uri]), (post [uri payload]), (put [uri payload]), (delete [uri])
|
74
|
+
|
75
|
+
(def xpc-config-fields
|
76
|
+
(into {}
|
77
|
+
(map
|
78
|
+
(fn [[k v]]
|
79
|
+
[(keyword (. k (toLowerCase)))
|
80
|
+
v])
|
81
|
+
(js->clj goog.net.xpc.CfgFields))))
|
82
|
+
|
83
|
+
(defn xhr-connection
|
84
|
+
"Returns an XhrIo connection"
|
85
|
+
[]
|
86
|
+
(goog.net.XhrIo.))
|
87
|
+
|
88
|
+
(defprotocol ICrossPageChannel
|
89
|
+
(register-service [this service-name fn] [this service-name fn encode-json?]))
|
90
|
+
|
91
|
+
(extend-type goog.net.xpc.CrossPageChannel
|
92
|
+
|
93
|
+
ICrossPageChannel
|
94
|
+
(register-service
|
95
|
+
([this service-name fn]
|
96
|
+
(register-service this service-name fn false))
|
97
|
+
([this service-name fn encode-json?]
|
98
|
+
(.registerService this (name service-name) fn encode-json?)))
|
99
|
+
|
100
|
+
IConnection
|
101
|
+
(connect
|
102
|
+
([this]
|
103
|
+
(connect this nil))
|
104
|
+
([this on-connect-fn]
|
105
|
+
(.connect this on-connect-fn))
|
106
|
+
([this on-connect-fn config-iframe-fn]
|
107
|
+
(connect this on-connect-fn config-iframe-fn (.body js/document)))
|
108
|
+
([this on-connect-fn config-iframe-fn iframe-parent]
|
109
|
+
(.createPeerIframe this iframe-parent config-iframe-fn)
|
110
|
+
(.connect this on-connect-fn)))
|
111
|
+
|
112
|
+
(transmit [this service-name payload]
|
113
|
+
(.send this (name service-name) payload))
|
114
|
+
|
115
|
+
(close [this]
|
116
|
+
(.close this ())))
|
117
|
+
|
118
|
+
(defn xpc-connection
|
119
|
+
"When passed with a config hash-map, returns a parent
|
120
|
+
CrossPageChannel object. Keys in the config hash map are downcased
|
121
|
+
versions of the goog.net.xpc.CfgFields enum keys,
|
122
|
+
e.g. goog.net.xpc.CfgFields.PEER_URI becomes :peer_uri in the config
|
123
|
+
hash.
|
124
|
+
|
125
|
+
When passed with no args, creates a child CrossPageChannel object,
|
126
|
+
and the config is automatically taken from the URL param 'xpc', as
|
127
|
+
per the CrossPageChannel API."
|
128
|
+
([]
|
129
|
+
(when-let [config (.getParameterValue
|
130
|
+
(goog.Uri. (.href (.location js/window)))
|
131
|
+
"xpc")]
|
132
|
+
(goog.net.xpc.CrossPageChannel. (gjson/parse config))))
|
133
|
+
([config]
|
134
|
+
(goog.net.xpc.CrossPageChannel.
|
135
|
+
(.strobj (reduce (fn [sum [k v]]
|
136
|
+
(when-let [field (get xpc-config-fields k)]
|
137
|
+
(assoc sum field v)))
|
138
|
+
{}
|
139
|
+
config)))))
|
140
|
+
|
141
|
+
;; WebSocket is not supported in the 3/23/11 release of Google
|
142
|
+
;; Closure, but will be included in the next release.
|
143
|
+
|
144
|
+
#_(defprotocol IWebSocket
|
145
|
+
(open? [this]))
|
146
|
+
|
147
|
+
#_(extend-type goog.net.WebSocket
|
148
|
+
|
149
|
+
IWebSocket
|
150
|
+
(open? [this]
|
151
|
+
(.isOpen this ()))
|
152
|
+
|
153
|
+
IConnection
|
154
|
+
(connect
|
155
|
+
([this url]
|
156
|
+
(connect this url nil))
|
157
|
+
([this url protocol]
|
158
|
+
(.open this url protocol)))
|
159
|
+
|
160
|
+
(transmit [this message]
|
161
|
+
(.send this message))
|
162
|
+
|
163
|
+
(close [this]
|
164
|
+
(.close this ()))
|
165
|
+
|
166
|
+
event/EventType
|
167
|
+
(event-types [this]
|
168
|
+
(into {}
|
169
|
+
(map
|
170
|
+
(fn [[k v]]
|
171
|
+
[(keyword (. k (toLowerCase)))
|
172
|
+
v])
|
173
|
+
(merge
|
174
|
+
(js->clj goog.net.WebSocket/EventType))))))
|
175
|
+
|
176
|
+
#_(defn websocket-connection
|
177
|
+
([]
|
178
|
+
(websocket-connection nil nil))
|
179
|
+
([auto-reconnect?]
|
180
|
+
(websocket-connection auto-reconnect? nil))
|
181
|
+
([auto-reconnect? next-reconnect-fn]
|
182
|
+
(goog.net.WebSocket. auto-reconnect? next-reconnect-fn)))
|
@@ -0,0 +1,109 @@
|
|
1
|
+
;; Copyright (c) Rich Hickey. All rights reserved.
|
2
|
+
;; The use and distribution terms for this software are covered by the
|
3
|
+
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
4
|
+
;; which can be found in the file epl-v10.html at the root of this distribution.
|
5
|
+
;; By using this software in any fashion, you are agreeing to be bound by
|
6
|
+
;; the terms of this license.
|
7
|
+
;; You must not remove this notice, or any other, from this software.
|
8
|
+
|
9
|
+
(ns ^{:doc "Receive - Eval - Print - Loop
|
10
|
+
|
11
|
+
Receive a block of JS (presumably generated by a ClojureScript compiler)
|
12
|
+
Evaluate it naively
|
13
|
+
Print the result of evaluation to a string
|
14
|
+
Send the resulting string back to the server Loop!"
|
15
|
+
|
16
|
+
:author "Bobby Calderwood and Alex Redington"}
|
17
|
+
clojure.browser.repl
|
18
|
+
(:require [clojure.browser.net :as net]
|
19
|
+
[clojure.browser.event :as event]))
|
20
|
+
|
21
|
+
(def xpc-connection (atom nil))
|
22
|
+
|
23
|
+
(defn repl-print [data]
|
24
|
+
(if-let [conn @xpc-connection]
|
25
|
+
(net/transmit conn :print (pr-str data))))
|
26
|
+
|
27
|
+
(defn evaluate-javascript
|
28
|
+
"Process a single block of JavaScript received from the server"
|
29
|
+
[conn block]
|
30
|
+
(let [result (try {:status :success :value (str (js* "eval(~{block})"))}
|
31
|
+
(catch js/Error e
|
32
|
+
{:status :exception :value (pr-str e)
|
33
|
+
:stacktrace (if (.hasOwnProperty e "stack")
|
34
|
+
(.stack e)
|
35
|
+
"No stacktrace available.")}))]
|
36
|
+
(pr-str result)))
|
37
|
+
|
38
|
+
(defn send-result [connection url data]
|
39
|
+
(net/transmit connection url "POST" data nil 0))
|
40
|
+
|
41
|
+
(defn send-print
|
42
|
+
"Send data to be printed in the REPL. If there is an error, try again
|
43
|
+
up to 10 times."
|
44
|
+
([url data]
|
45
|
+
(send-print url data 0))
|
46
|
+
([url data n]
|
47
|
+
(let [conn (net/xhr-connection)]
|
48
|
+
(event/listen conn :error
|
49
|
+
(fn [_]
|
50
|
+
(if (< n 10)
|
51
|
+
(send-print url data (inc n))
|
52
|
+
(.log js/console (str "Could not send " data " after " n " attempts.")))))
|
53
|
+
(net/transmit conn url "POST" data nil 0))))
|
54
|
+
|
55
|
+
(def order (atom 0))
|
56
|
+
|
57
|
+
(defn wrap-message [t data]
|
58
|
+
(pr-str {:type t :content data :order (swap! order inc)}))
|
59
|
+
|
60
|
+
(defn start-evaluator
|
61
|
+
"Start the REPL server connection."
|
62
|
+
[url]
|
63
|
+
(if-let [repl-connection (net/xpc-connection)]
|
64
|
+
(let [connection (net/xhr-connection)]
|
65
|
+
(event/listen connection
|
66
|
+
:success
|
67
|
+
(fn [e]
|
68
|
+
(net/transmit
|
69
|
+
repl-connection
|
70
|
+
:evaluate-javascript
|
71
|
+
(.getResponseText e/currentTarget
|
72
|
+
()))))
|
73
|
+
|
74
|
+
(net/register-service repl-connection
|
75
|
+
:send-result
|
76
|
+
(fn [data]
|
77
|
+
(send-result connection url (wrap-message :result data))))
|
78
|
+
|
79
|
+
(net/register-service repl-connection
|
80
|
+
:print
|
81
|
+
(fn [data]
|
82
|
+
(send-print url (wrap-message :print data))))
|
83
|
+
|
84
|
+
(net/connect repl-connection
|
85
|
+
(constantly nil))
|
86
|
+
|
87
|
+
(js/setTimeout #(send-result connection url (wrap-message :ready "ready")) 50))
|
88
|
+
(js/alert "No 'xpc' param provided to child iframe.")))
|
89
|
+
|
90
|
+
(defn connect
|
91
|
+
"Connects to a REPL server from an HTML document. After the
|
92
|
+
connection is made, the REPL will evaluate forms in the context of
|
93
|
+
the document that called this function."
|
94
|
+
[repl-server-url]
|
95
|
+
(let [repl-connection (net/xpc-connection
|
96
|
+
{:peer_uri repl-server-url})]
|
97
|
+
(swap! xpc-connection (constantly repl-connection))
|
98
|
+
(net/register-service repl-connection
|
99
|
+
:evaluate-javascript
|
100
|
+
(fn [js]
|
101
|
+
(net/transmit
|
102
|
+
repl-connection
|
103
|
+
:send-result
|
104
|
+
(evaluate-javascript repl-connection js))))
|
105
|
+
(net/connect repl-connection
|
106
|
+
(constantly nil)
|
107
|
+
(fn [iframe]
|
108
|
+
(set! iframe.style.display
|
109
|
+
"none")))))
|
@@ -0,0 +1,162 @@
|
|
1
|
+
; Copyright (c) Rich Hickey. All rights reserved.
|
2
|
+
; The use and distribution terms for this software are covered by the
|
3
|
+
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
4
|
+
; which can be found in the file epl-v10.html at the root of this distribution.
|
5
|
+
; By using this software in any fashion, you are agreeing to be bound by
|
6
|
+
; the terms of this license.
|
7
|
+
; You must not remove this notice, or any other, from this software.
|
8
|
+
|
9
|
+
(ns ^{:doc "Set operations such as union/intersection."
|
10
|
+
:author "Rich Hickey"}
|
11
|
+
clojure.set)
|
12
|
+
|
13
|
+
(defn- bubble-max-key [k coll]
|
14
|
+
"Move a maximal element of coll according to fn k (which returns a number)
|
15
|
+
to the front of coll."
|
16
|
+
(let [max (apply max-key k coll)]
|
17
|
+
(cons max (remove #(identical? max %) coll))))
|
18
|
+
|
19
|
+
(defn union
|
20
|
+
"Return a set that is the union of the input sets"
|
21
|
+
([] #{})
|
22
|
+
([s1] s1)
|
23
|
+
([s1 s2]
|
24
|
+
(if (< (count s1) (count s2))
|
25
|
+
(reduce conj s2 s1)
|
26
|
+
(reduce conj s1 s2)))
|
27
|
+
([s1 s2 & sets]
|
28
|
+
(let [bubbled-sets (bubble-max-key count (conj sets s2 s1))]
|
29
|
+
(reduce into (first bubbled-sets) (rest bubbled-sets)))))
|
30
|
+
|
31
|
+
(defn intersection
|
32
|
+
"Return a set that is the intersection of the input sets"
|
33
|
+
([s1] s1)
|
34
|
+
([s1 s2]
|
35
|
+
(if (< (count s2) (count s1))
|
36
|
+
(recur s2 s1)
|
37
|
+
(reduce (fn [result item]
|
38
|
+
(if (contains? s2 item)
|
39
|
+
result
|
40
|
+
(disj result item)))
|
41
|
+
s1 s1)))
|
42
|
+
([s1 s2 & sets]
|
43
|
+
(let [bubbled-sets (bubble-max-key #(- (count %)) (conj sets s2 s1))]
|
44
|
+
(reduce intersection (first bubbled-sets) (rest bubbled-sets)))))
|
45
|
+
|
46
|
+
(defn difference
|
47
|
+
"Return a set that is the first set without elements of the remaining sets"
|
48
|
+
([s1] s1)
|
49
|
+
([s1 s2]
|
50
|
+
(if (< (count s1) (count s2))
|
51
|
+
(reduce (fn [result item]
|
52
|
+
(if (contains? s2 item)
|
53
|
+
(disj result item)
|
54
|
+
result))
|
55
|
+
s1 s1)
|
56
|
+
(reduce disj s1 s2)))
|
57
|
+
([s1 s2 & sets]
|
58
|
+
(reduce difference s1 (conj sets s2))))
|
59
|
+
|
60
|
+
|
61
|
+
(defn select
|
62
|
+
"Returns a set of the elements for which pred is true"
|
63
|
+
[pred xset]
|
64
|
+
(reduce (fn [s k] (if (pred k) s (disj s k)))
|
65
|
+
xset xset))
|
66
|
+
|
67
|
+
(defn project
|
68
|
+
"Returns a rel of the elements of xrel with only the keys in ks"
|
69
|
+
[xrel ks]
|
70
|
+
(set (map #(select-keys % ks) xrel)))
|
71
|
+
|
72
|
+
(defn rename-keys
|
73
|
+
"Returns the map with the keys in kmap renamed to the vals in kmap"
|
74
|
+
[map kmap]
|
75
|
+
(reduce
|
76
|
+
(fn [m [old new]]
|
77
|
+
(if (and (not= old new)
|
78
|
+
(contains? m old))
|
79
|
+
(-> m (assoc new (get m old)) (dissoc old))
|
80
|
+
m))
|
81
|
+
map kmap))
|
82
|
+
|
83
|
+
(defn rename
|
84
|
+
"Returns a rel of the maps in xrel with the keys in kmap renamed to the vals in kmap"
|
85
|
+
[xrel kmap]
|
86
|
+
(set (map #(rename-keys % kmap) xrel)))
|
87
|
+
|
88
|
+
(defn index
|
89
|
+
"Returns a map of the distinct values of ks in the xrel mapped to a
|
90
|
+
set of the maps in xrel with the corresponding values of ks."
|
91
|
+
[xrel ks]
|
92
|
+
(reduce
|
93
|
+
(fn [m x]
|
94
|
+
(let [ik (select-keys x ks)]
|
95
|
+
(assoc m ik (conj (get m ik #{}) x))))
|
96
|
+
{} xrel))
|
97
|
+
|
98
|
+
(defn map-invert
|
99
|
+
"Returns the map with the vals mapped to the keys."
|
100
|
+
[m] (reduce (fn [m [k v]] (assoc m v k)) {} m))
|
101
|
+
|
102
|
+
(defn join
|
103
|
+
"When passed 2 rels, returns the rel corresponding to the natural
|
104
|
+
join. When passed an additional keymap, joins on the corresponding
|
105
|
+
keys."
|
106
|
+
([xrel yrel] ;natural join
|
107
|
+
(if (and (seq xrel) (seq yrel))
|
108
|
+
(let [ks (intersection (set (keys (first xrel))) (set (keys (first yrel))))
|
109
|
+
[r s] (if (<= (count xrel) (count yrel))
|
110
|
+
[xrel yrel]
|
111
|
+
[yrel xrel])
|
112
|
+
idx (index r ks)]
|
113
|
+
(reduce (fn [ret x]
|
114
|
+
(let [found (idx (select-keys x ks))]
|
115
|
+
(if found
|
116
|
+
(reduce #(conj %1 (merge %2 x)) ret found)
|
117
|
+
ret)))
|
118
|
+
#{} s))
|
119
|
+
#{}))
|
120
|
+
([xrel yrel km] ;arbitrary key mapping
|
121
|
+
(let [[r s k] (if (<= (count xrel) (count yrel))
|
122
|
+
[xrel yrel (map-invert km)]
|
123
|
+
[yrel xrel km])
|
124
|
+
idx (index r (vals k))]
|
125
|
+
(reduce (fn [ret x]
|
126
|
+
(let [found (idx (rename-keys (select-keys x (keys k)) k))]
|
127
|
+
(if found
|
128
|
+
(reduce #(conj %1 (merge %2 x)) ret found)
|
129
|
+
ret)))
|
130
|
+
#{} s))))
|
131
|
+
|
132
|
+
(defn subset?
|
133
|
+
"Is set1 a subset of set2?"
|
134
|
+
[set1 set2]
|
135
|
+
(and (<= (count set1) (count set2))
|
136
|
+
(every? #(contains? set2 %) set1)))
|
137
|
+
|
138
|
+
(defn superset?
|
139
|
+
"Is set1 a superset of set2?"
|
140
|
+
[set1 set2]
|
141
|
+
(and (>= (count set1) (count set2))
|
142
|
+
(every? #(contains? set1 %) set2)))
|
143
|
+
|
144
|
+
(comment
|
145
|
+
(refer 'set)
|
146
|
+
(def xs #{{:a 11 :b 1 :c 1 :d 4}
|
147
|
+
{:a 2 :b 12 :c 2 :d 6}
|
148
|
+
{:a 3 :b 3 :c 3 :d 8 :f 42}})
|
149
|
+
|
150
|
+
(def ys #{{:a 11 :b 11 :c 11 :e 5}
|
151
|
+
{:a 12 :b 11 :c 12 :e 3}
|
152
|
+
{:a 3 :b 3 :c 3 :e 7 }})
|
153
|
+
|
154
|
+
(join xs ys)
|
155
|
+
(join xs (rename ys {:b :yb :c :yc}) {:a :a})
|
156
|
+
|
157
|
+
(union #{:a :b :c} #{:c :d :e })
|
158
|
+
(difference #{:a :b :c} #{:c :d :e})
|
159
|
+
(intersection #{:a :b :c} #{:c :d :e})
|
160
|
+
|
161
|
+
(index ys [:b]))
|
162
|
+
|