defprotocol "no single method" error seems like a bug in Leiningen - clojure

I'm learning protocols in Clojure and I came across this error for the following code:
CompilerException java.lang.IllegalArgumentException: No single method: valores_BANG_ of interface: gangnam.core.Legi found for function: valores! of protocol: Legi, compiling:(NO_SOURCE_PATH:1:1)
Everything was working wonderfully until I tried to add seven+ methods to the protocol (valores! below). So I copied valores into valores! to make absolutely sure I was using the same code, except for the ! at the end, and it doesn't work. I also tried swapping it out for a different name (dele).
Then I remembered that I recently ran lein install and when I run lein install again, that seems to fix the problem. Any idea why this might be happening?
(defprotocol Legi
(lege [self] [self key])
(carpe! [self] [self key] [self key val])
(muta!* [self key val])
(juga! [from label to])
(claves [self])
(valores [self])
(valores! [self]))
(extend-protocol Legi
Iterable
(lege
([self]
(for [elm self]
(lege elm)))
([self key]
(for [elm self]
(lege elm key))))
(carpe!
([self]
(for [elm self]
(carpe! elm)))
([self key]
(for [elm self]
(carpe! elm key)))
([self key val]
(for [elm self]
(carpe! elm key val))))
(muta!*
[self key val]
(doall (for [elm self]
(muta!* elm key val))))
(juga! [from label to]
(for [elm from]
(juga! elm label to)))
(claves [self]
(for [elm self]
(claves elm)))
(valores [self]
(for [elm self]
(valores elm)))
(valores! [self]
(for [elm self]
(valores elm)))
Element
(lege
([self]
(into {} (for [k (.getPropertyKeys self)]
[(keyword k) (lege self k)])))
([self key]
(-> self (.getProperty (name key)))))
(carpe!
([self]
(for [k (.getPropertyKeys self)]
(carpe! self k)))
([self key]
(let [prop (lege self key)]
(res
(-> self (.removeProperty (name key))))
prop))
([self key val]
(let [prop (lege self key)]
(if (= val prop)
(carpe! self key)))))
(muta!* [self key val]
(res
(let [key (name key)]
(.setProperty self key val)
self)))
(juga! [from label to]
(when (and from to)
(res
(.addEdge *g*
nil from to (name label)))))
(claves [self]
(-> self .getPropertyKeys))
(valores [self]
(-> self lege vals))
(valores! [self]
(-> self lege vals)))

lein clean should solve this for you.

Related

How to pass new props to state of acomponent in Reagent?

I have a component:
(defn inner-input [cljs_element activeEl title]
(let [form (atom title)]
(fn [cljs_element activeEl title]
[:input {:type "text"
:onChange #(reset! form (.. % -target -value))
:on-blur #(change-title cljs_element (.. % -target -value))
:style {:display (if (:active (:node cljs_element)) "block" "none")
:width (* (+ 1 (count #form)) 8)
:max-width 730
:min-width 170}
:value #form}])))
It is nested in other component:
(defn card-input [cljs_element activeEl]
(fn [cljs_element activeEl]
(let [title (:title (:node cljs_element))]
[:div
[inner-input cljs_element activeEl title]])))
When i type data to the input in the inner-input component, i need update the local state form. And when the outer component card-input updates i want to reset my form to new title prop from argument. How can i achieve that?
I tried put (reset! form title) between let and fn in the inner-input component but it will not help
You can use reagent/track! to listen to changes to title, and reagent/dispose to stop listening. You can alternatively use add-watch and remove-watch, but track is a more convenient syntax.
(defn inner-input [title]
(reagent/with-let
[form (reagent/atom #title)
watch (reagent/track! (fn [] (reset! form #title)))]
[:label
"Inner input"
[:input {:on-change (fn [e]
(reset! form (.. e -target -value)))
:on-blur (fn [e]
(reset! title (.. e -target -value)))
:value #form}]]
(finally
(reagent/dispose! watch))))
(defn card-input []
(reagent/with-let
[title (reagent/atom "hello")]
[:div
[:label "Title"
[:input {:on-change (fn [e]
(reset! title (.. e -target -value)))
:value #title}]]
[inner-input title]]))
Now if you type in the inner input it will only update the outer when you exit the input box, but changing the outer title will immediately change the inner one. Is that what you wanted?
But if you don't want to pass title as a ratom and have to pass it as a value, then instead you can compare it to the previous value to determine if it changed, and reset form only when it changes.
(when (not= #previous-title title)
(do (reset! previous-title title)
(reset! form title)))
This code can go in render seeing as it is safe to call when form changes... nothing will happen.

reagent forms multi-select not working for list

I was following the sample code from http://yogthos.github.io/reagent-forms-example.html and was attempting the use the multi-select option for a list.
(defn select-item [item]
(go
(reset! current-selection item)
(let [response (<! (check-for-response))]
(reset! current-response response)
(reset! past-response response))))
;;batch
(defn item-list []
[:div#items-list
[items-list-header]
[:ul.list-group.items {:field :multi-select :id :pick-a-few}
(if (pos? (count #items))
(doall (for [item #items]
^{:key (item "upc")}
[:li.list-group-item [:a {:class (set-item-class item) :on-click #(select-item item) :href "#"}
(item "description")]]))
[:li [:a "No Items For This Department"]])]])
(defn product-component []
[:div
[item-list]
[product-response]
;[bind-fields item-list items]
;[bind-fields item-list product-response]
])
Does anyone know why I am unable to multi-select? The logic in select-item will change, but I can't seem to see the multi-select in the UI
I've been messing around with bind-fields in my product component with no success.

Render resource when PUT

I am using liberator to build a API using Clojure. Given the follow code:
(defresource single-customer [id]
:allowed-methods [:get, :put]
:exists? (fn [_]
(let [e (get #cust/customers (keyword id))]
(if-not (nil? e)
{::entry e})))
:existed? (fn [_] (nil? (get #cust/customers (keyword id) ::sentinel)))
:available-media-types ["application/json"]
:can-put-to-missing? false
:put! (fn [q] (cust/set-as-fraudulent id))
:handle-ok ::entry)
Someone when can tell me if is possible, like the GET request, when I send a PUT request it be redirected to the resource ? "/customer/1" (for example) ?
Looking at the liberator decision graph, :put! can lead to either:
:handle-created (if :new?)
:handle-no-content (if not :new? and not :respond-with-entity?)
:handle-ok (if not :new, but :respond-with-entity?)
Try implementing :put! so it stores the entity as ::entry, and :handle-created similar to your current :handle-ok.

how to avoid nesting in clojure

when my write a function to check a user can delete a post by clojure,I get this
(defn delete!
{:arglists}
[^String id]
(if (valid-number? id)
(let [result {:code 200 :status "error" :messag "delete success"}]
(if-let [user (session/get :userid)]
(if-let [post (pdb/id id)]
(if (= user (post :user_id))
(do
(pdb/delete! (Long/valueOf id))
(assoc result :status "ok"))
(assoc result :message (emsg :not-own)))
(assoc result :message (emsg :post-id-error))))
(assoc result :message (emsg :not-login)))))
so i want to fix it,i get this
https://github.com/4clojure/4clojure/blob/develop/src/foreclojure/register.clj#L27
https://github.com/4clojure/4clojure/blob/develop/src/foreclojure/utils.clj#L32
but it is line,but not a nest.
the delete! function is nest ugly and it is very hard to understand it,how to write a macro to avoid the nesting a lot.or other way to avoid it.
This doesn't need a macro. I guess cond is a macro, but it is the only one we need to make this code readable.
(defn delete!
;; {:arglists} ; this line will not compile
[^String id]
(let [result {:code 200 :status "error" :message "delete success"}
user (session/get :userid)
post (and user (valid-number? id) (pbd/id id))]
(cond
(not user)
(assoc result :message (emsg :not-login))
(not post)
(assoc result :message (emsg :post-id-error))
(not= user (:user_id post))
(assoc result :message (emsg :not-own))
:else
(do
(pdb/delete! (Long/valueOf id))
(assoc result :status "ok")))))
This is something a lot of people run into, so don't feel bad.
Check out this blog by Christophe Grand, which I think is a pretty nice (and concise!) solution.
Edit: you only need something fancy like this (or alternatively the version using delay in this other post) if you need to short-circuit execution like the original - otherwise noisesmith's answer is the way to go.
Here's how you could do this sort of thing with the Either monad -- I'm sure there are libraries for it already but I'll implement it here for completeness. (Note: this code hasn't been validated.)
(defn success? [v]
(contains? v :success))
(defn inject [v]
{:success v})
(defn bind [v f]
(if (success? v)
(apply f (:success v))
v))
(defmacro >>= [v & body]
(let [binds (map #(list 'bind %) body)]
`(-> ~v ~#binds)))
(defn delete!
{:arglists}
[^String id]
(if (valid-number? id)
(let [result {:code 200 :status "error" :message "delete success"}
check
(>>= (inject {:id id})
#(if-let [user (session/get :userid)]
{:success (assoc % :user user)}
(:failure (assoc result :message (emsg :not-login))))
#(if-let [post (pdb/id (:id %))]
{:success (assoc % :post post)}
{:failure (assoc result :message (emsg :post-id-error))})
#(if (= (:user %) ((:post %) :user_id))
{:success %}
{:failure (assoc result :message (emsg :not-own))}))]
(if (success? check)
(do
(pdb/delete! (Long/valueOf id))
(assoc result :status "ok"))
(:failure check)))))
The >>= macro works like the -> macro (obviously, since it uses it), but if any of the functions return a {:failure ...} then the chain short-circuits (thanks to bind) and the failure value of the function that failed becomes the value returned by >>=.
Edit
I should note that the function I have named inject is actually called return, but I decided to name it inject here since that's more along the lines of what it does in this monad.

How to write this clojure enlive program so it can parse multiple urls?

This is a program to parse some sites. The first site is site1. All the logic to parse that perticular site is located to (-> config :site1)
(ns program.core
(require [net.cgrand.enlive-html :as html]))
(def config
{:site1
{:site-url
["http://www.site1.com/page/1"
"http://www.site1.com/page/2"
"http://www.site1.com/page/3"
"http://www.site1.com/page/4"]
:url-encoding "iso-8859-1"
:parsing-index
{:date
{:selector
[[:td.PadMed (html/nth-of-type 1)] :table [:tr (html/nth-of-type 2)]
[:td (html/nth-of-type 3)] [:span]]
:trimming-fn
(comp first :content) ; (first) to remove extra parenthese
}
:title
{:selector
[[:td.PadMed (html/nth-of-type 1)] :table :tr [:td (html/nth-of-type 2)] [:a]]
:trimming-fn
(comp first :content first :content)
}
:url
{:selector
[[:td.PadMed (html/nth-of-type 1)] :table :tr [:td (html/nth-of-type 2)] [:a]]
:trimming-fn
#(str "http://www.site.com" (:href (:attrs %)))
}
}
}})
;=== Fetch fn ===;
(defn fetch-encoded-url
([url] (fetch-encoded-url url "utf-8"))
([url encoding] (-> url java.net.URL.
.getContent
(java.io.InputStreamReader. encoding)
html/html-resource)))
Now I want to parse the pages contained in (-> config :site1 :site-url) In this example I use only the first url, but how can i design this to actually do kind of a master for for all the URLs?
(defn parse-element [element]
(into [] (map (-> config :site1 :parsing-index element :trimming-fn)
(html/select
(fetch-encoded-url
(-> config :site1 :site-url first)
(-> config :site1 :url-encoding))
(-> config :site1 :parsing-index element :selector)))))
(def element-lists
(apply map vector
(map parse-element (-> config :site1 :parsing-index keys))))
(def tagged-lists
(into [] (for [element-list element-lists]
(zipmap [:date :title :url] element-list))))
;==== Fn call ====
(println tagged-lists)
Pass :site1 as an argument to parse-element and elements-list.
(defn parse-element [site element]
(into [] (map (-> config site :parsing-index element :trimming-fn)
(html/select
(fetch-encoded-url
(-> config site :site-url first)
(-> config site :url-encoding))
(-> config site :parsing-index element :selector)))))
(def element-lists [site]
(apply map vector
(map (partial parse-element site) (-> config site :parsing-index keys))))
And then map over :site1 :site2… keys.
Addendum in answer to the further question in the comments.
You could wrap the html/select in a map over the :site-urls. Something like:
(defn parse-element [site element]
(let [site-urls (-> config site :site-url)]
(into [] (map (-> config site :parsing-index element :trimming-fn)
map
#(html/select
(fetch-encoded-url
%
(-> config site :url-encoding))
(-> config site :parsing-index element :selector)))
site-urls)))
(I hope I got the parens right.)
Then you'll probably need to check the :trimming-fn, in order for it to handle the nesting. An apply should suffice.