clojure-russia

Работа и релокейт: #jobs-rus | #clojure-russia-offtop Телеграм-чат https://t.me/clojure_ru
kuzmin_m 2018-12-30T09:01:53.102600Z

@razum2um https://github.com/arohner/spectrum

👍 1
fmnoise 2018-12-30T19:11:52.104100Z

к обсуждению спеки - там есть мультиспека еще, можно попробовать ее и req-un если очень хочется извратиться

fmnoise 2018-12-30T19:11:59.104300Z

но я не уверен что стоит

kuzmin_m 2018-12-30T19:13:02.104900Z

я уже схему смотрю 😃 спасибо за ссылку на refined

kuzmin_m 2018-12-30T19:13:45.106Z

видимо стоило это сделать как только 1.9 альфа вышла 😃

fmnoise 2018-12-30T19:14:27.106600Z

сейчас добавили возможность удалять спеки из регистра

fmnoise 2018-12-30T19:14:41.107200Z

думаю как-то покрутить, попробовать схема-стайл сделать

kuzmin_m 2018-12-30T19:14:53.107700Z

а чем удаление поможет?

fmnoise 2018-12-30T19:15:40.108600Z

типа

{:user/name string?
 :user/email string?}

kuzmin_m 2018-12-30T19:16:24.110Z

так если ты из реестра удалил, как проверка будет работать?

kuzmin_m 2018-12-30T19:16:33.110500Z

или в какой-то контест заворачивать?

fmnoise 2018-12-30T19:16:43.110800Z

ну оно в ф-ии проверке будет регать, потом проверять, потом дерегать

fmnoise 2018-12-30T19:16:49.111Z

ну это так

fmnoise 2018-12-30T19:16:50.111300Z

идея

fmnoise 2018-12-30T19:17:00.112200Z

just for fun

kuzmin_m 2018-12-30T19:17:01.112300Z

а реестр это что?

kuzmin_m 2018-12-30T19:17:04.112700Z

var?

kuzmin_m 2018-12-30T19:17:08.113Z

atom?

kuzmin_m 2018-12-30T19:17:45.113200Z

(defonce ^:private registry-ref (atom {}))

kuzmin_m 2018-12-30T19:18:26.113700Z

а можно как-то приватную переменную сделать публичной?

kuzmin_m 2018-12-30T19:18:39.114100Z

если да, тогда переменную можно сделать динамической

kuzmin_m 2018-12-30T19:18:50.114500Z

и не иметь проблем с параллельным доступом

fmnoise 2018-12-30T19:20:19.114700Z

реестр спек

fmnoise 2018-12-30T19:20:25.115Z

глобальная штука

fmnoise 2018-12-30T19:21:54.116200Z

https://clojure.org/guides/spec#_registry

kuzmin_m 2018-12-30T19:26:59.117400Z

(require '[clojure.spec.alpha :as s])

(let [reg #'s/registry-ref]
  (.setDynamic reg true)
  (assert (.isDynamic reg))
  (with-bindings {reg (atom {})}
    (clojure.spec.alpha/registry)
    #_(clojure.spec.alpha/def :foo/:foo int?)
    #_(clojure.spec.alpha/valid? :foo/foo 1)))                      

kuzmin_m 2018-12-30T19:27:05.117700Z

только это не работает

kuzmin_m 2018-12-30T19:28:05.118300Z

видимо, потому что defonce

fmnoise 2018-12-30T19:28:24.118700Z

та не, добавлять спеку в глобальный реест с подхаченным ns и потом удалять

fmnoise 2018-12-30T19:29:37.119500Z

короче вряд ли будет работать

fmnoise 2018-12-30T19:29:44.119800Z

просто покрутить хочется от нечего делать

kuzmin_m 2018-12-30T20:33:56.120500Z

@fmnoise а как в схеме сделать and, т.е. проверить одну схему, а затем другую?

fmnoise 2018-12-30T21:16:12.120800Z

в смысле?

fmnoise 2018-12-30T21:16:24.121200Z

делаешь просто and и проверяешь обе схемы

fmnoise 2018-12-30T21:17:00.121700Z

эксперименты с реестром закончились манки-патчингом) https://gist.github.com/fmnoise/56fdd0951f593e668f4a5e40dc771577

kuzmin_m 2018-12-30T21:17:53.122Z

в смысле and?

kuzmin_m 2018-12-30T21:18:34.122900Z

(def a {:a s/Int}) (def b( {b s/Int}) (def z (and a b)) ???

fmnoise 2018-12-30T21:23:52.123300Z

так смерж просто

fmnoise 2018-12-30T21:24:05.123500Z

это ж мапки

kuzmin_m 2018-12-30T21:25:02.124200Z

а если они вложенные

kuzmin_m 2018-12-30T21:25:08.124500Z

а елси у них один ключ?

fmnoise 2018-12-30T21:25:15.124800Z

в смысле один ключ?)

kuzmin_m 2018-12-30T21:25:41.125700Z

(def a {:a s/Int}) (def a’ {:a (s/pred #{1 2 3}))

fmnoise 2018-12-30T21:26:56.126300Z

Int тогда избыточный

fmnoise 2018-12-30T21:27:12.126800Z

второй схемы хватит

fmnoise 2018-12-30T21:27:39.127200Z

там надо мозги перестроить от спеки

fmnoise 2018-12-30T21:27:42.127500Z

что подчас тяжело

fmnoise 2018-12-30T21:27:48.127800Z

другая философия совсем

kuzmin_m 2018-12-30T21:28:25.128500Z

допустим, у меня есть сущность

kuzmin_m 2018-12-30T21:28:34.128800Z

и у нее есть разные сосотяния

kuzmin_m 2018-12-30T21:28:45.129200Z

причем состояние не одно поле

fmnoise 2018-12-30T21:28:48.129500Z

ну вот там начинается веселое

kuzmin_m 2018-12-30T21:28:50.129700Z

а набор полей

fmnoise 2018-12-30T21:28:53.129800Z

constraint

kuzmin_m 2018-12-30T21:29:00.130Z

а толку?

kuzmin_m 2018-12-30T21:29:10.130400Z

если он ошибку не выдаст подробную

kuzmin_m 2018-12-30T21:29:21.131100Z

это просто предикат проверить

fmnoise 2018-12-30T21:29:26.131200Z

там с ошибками так себе

fmnoise 2018-12-30T21:30:00.131700Z

там можно добавить свой типа символ

fmnoise 2018-12-30T21:30:04.132Z

который будет означать ошибку

fmnoise 2018-12-30T21:30:16.132500Z

'does-not-looks-good

fmnoise 2018-12-30T21:30:18.132700Z

типа такого

kuzmin_m 2018-12-30T21:30:41.132900Z

это сама спека делает?

kuzmin_m 2018-12-30T21:30:44.133100Z

или расширение?

fmnoise 2018-12-30T21:32:15.133300Z

что именно?

kuzmin_m 2018-12-30T21:32:32.133700Z

символ добавить

fmnoise 2018-12-30T21:34:11.134200Z

вот как тут в примере

fmnoise 2018-12-30T21:35:25.135400Z

ты сам добавляешь

kuzmin_m 2018-12-30T21:35:28.135800Z

а, я думал это что-то вроде `{:a {^:name ’symbol} s/Int}

fmnoise 2018-12-30T21:35:43.136200Z

оно тебе его просто в валидации возвращает типа как код ошибки

fmnoise 2018-12-30T21:36:15.136700Z

типа осмысленное сообщение об ошибке можно сделать

fmnoise 2018-12-30T21:36:54.137300Z

ребята развили эту же идею и с guards в refined https://speakerdeck.com/kachayev/keep-your-data-safe-with-refined-types?slide=62

fmnoise 2018-12-30T21:37:46.138Z

вообще у самой схемы composability очень слабое место

kuzmin_m 2018-12-30T21:38:02.138200Z

у spec еще хуже 😃

fmnoise 2018-12-30T21:38:23.138400Z

нет, у spec лучше

fmnoise 2018-12-30T21:38:31.139100Z

и следующий слайд

kuzmin_m 2018-12-30T21:38:43.139400Z

так как из фукнции вернуть спеку?

kuzmin_m 2018-12-30T21:38:47.139700Z

верне вернуть то можно

kuzmin_m 2018-12-30T21:38:51.140Z

но толку

fmnoise 2018-12-30T21:38:54.140100Z

в смысле из функции

fmnoise 2018-12-30T21:39:12.140800Z

я про то, что схема которая сложнее чем просто мапка это вещь в себе

kuzmin_m 2018-12-30T21:39:15.141100Z

ну типа (fn [] (s/keys ....)

fmnoise 2018-12-30T21:39:27.141600Z

добавить\убрать что-то в нее не получится

kuzmin_m 2018-12-30T21:39:27.141700Z

оно вернет

fmnoise 2018-12-30T21:40:15.142500Z

например когда ты в constrained завернул что-то, потом ты не сможешь сделать assoc или dissoc

fmnoise 2018-12-30T21:40:35.143100Z

а без constrained она очень простая

fmnoise 2018-12-30T21:40:45.143300Z

и большинство задач не решает

fmnoise 2018-12-30T21:41:13.143900Z

кстати вот эта фишка и была довольной сильной мотивацией при создании schema-refined

fmnoise 2018-12-30T21:41:28.144300Z

мы намучились тогда со схемой прилично

kuzmin_m 2018-12-30T21:41:54.144700Z

что-то мне подсказывает, что я буду все руками делать 😃

fmnoise 2018-12-30T21:43:30.145400Z

короче идеального решения нет

fmnoise 2018-12-30T21:43:39.145800Z

все ждали что спека его принесет

fmnoise 2018-12-30T21:43:53.146300Z

но спека не о валидации вообще

kuzmin_m 2018-12-30T21:45:58.147100Z

а почему {(s/optional-key :foo) s/Keywordа не {:foo (s/optioinal-key ....}?

kuzmin_m 2018-12-30T21:46:30.147800Z

так вроде не нужно изобретать schema-tools, чтобы делать select, assoc и прочее

fmnoise 2018-12-30T21:53:29.148200Z

спроси авторов

fmnoise 2018-12-30T21:53:49.148500Z

которые уже давно забросили ее

kuzmin_m 2018-12-30T21:55:52.150100Z

Видимо, нужно разделять форму данных и валидацию данных под конретную бизнес операцию. Рыжиков в подкасте говорил, что в FHIR большинство полей опциональные

fmnoise 2018-12-30T21:57:18.150300Z

ну вот да

fmnoise 2018-12-30T21:57:27.150600Z

спека про форму

fmnoise 2018-12-30T21:57:32.150800Z

схема хз про что

kuzmin_m 2018-12-30T21:57:51.151200Z

но спеку я “сломал”

kuzmin_m 2018-12-30T21:57:57.151400Z

вчерашним примером

kuzmin_m 2018-12-30T21:58:12.151600Z

https://repl.it/@darkleaf/inheritance

kuzmin_m 2018-12-30T21:58:18.152Z

на java это можно сделать

kuzmin_m 2018-12-30T21:58:30.152400Z

на спеке - для ключей с неймспейсом - нет

kuzmin_m 2018-12-30T22:00:18.152900Z

{:publication/id 1
 :publication/translation {:publication.translation/title "article"
                           :article.translation/content "some content"}
 :article/image-url "http://..."}

kuzmin_m 2018-12-30T22:00:50.153600Z

пока это единственное непонятное место в спеке

fmnoise 2018-12-30T22:07:27.153900Z

так а еще раз, что у тебя не получилось?

kuzmin_m 2018-12-30T22:07:40.154200Z

посмотри java код

kuzmin_m 2018-12-30T22:07:51.154600Z

есть публикация и статья

kuzmin_m 2018-12-30T22:08:06.155Z

есть перевод публикации и перевод статьи

kuzmin_m 2018-12-30T22:08:19.155400Z

первые - родители для вторых

kuzmin_m 2018-12-30T22:09:07.156500Z

и у статьи может быть переопределенный метод, возвращающий перевод статьи вместо перевода публикации

kuzmin_m 2018-12-30T22:09:26.157100Z

т.е. в clojure это как-то так:

kuzmin_m 2018-12-30T22:09:47.157300Z

{:publication/id 1
 :publication/translation {:publication.translation/title "article"}}

kuzmin_m 2018-12-30T22:09:52.157600Z

это публикация

kuzmin_m 2018-12-30T22:10:06.158Z

и у нее есть “метод” :publication/translation

kuzmin_m 2018-12-30T22:10:16.158200Z

и я хочу его расширить

kuzmin_m 2018-12-30T22:10:24.158400Z

новыми ключами

kuzmin_m 2018-12-30T22:10:42.158800Z

и ключи должны быть с неймспейсом

kuzmin_m 2018-12-30T22:10:51.159Z

для req-un можно сделать

kuzmin_m 2018-12-30T22:11:00.159300Z

интересно именно для req

fmnoise 2018-12-30T22:11:40.159600Z

в смысле расширить*

kuzmin_m 2018-12-30T22:11:49.160100Z

s/merge

fmnoise 2018-12-30T22:11:50.160200Z

ты один раз определил и вот оно

kuzmin_m 2018-12-30T22:11:57.160400Z

смотри

kuzmin_m 2018-12-30T22:12:25.161100Z

есть (s/def :foo (s/keys :req [::a ::b]))

kuzmin_m 2018-12-30T22:12:56.161900Z

а есть его расширение (s/def ::foo' (s/merge ::foo (s/keys :req [::c}))

kuzmin_m 2018-12-30T22:13:30.162300Z

и это работает только на первом уровне

kuzmin_m 2018-12-30T22:13:47.162700Z

а для вложенных не работает

kuzmin_m 2018-12-30T22:14:01.163100Z

т.е. единсввенное что я могу сделать:

kuzmin_m 2018-12-30T22:14:34.163500Z

{:publication/id 1
 :article/translation {:publication.translation/title "article"
                       :article.translation/content "foo"}}

kuzmin_m 2018-12-30T22:14:50.163800Z

вместо

{:publication/id 1
 :publication/translation {:publication.translation/title "article"
                           :article.translation/content "foo"}}

kuzmin_m 2018-12-30T22:15:12.164300Z

т.е. есть фукнция, работающая с публикацией

kuzmin_m 2018-12-30T22:15:17.164500Z

и ее переводами

kuzmin_m 2018-12-30T22:15:24.164800Z

и я не могу ей передать статью

kuzmin_m 2018-12-30T22:15:34.165100Z

т.к. у нее переводы не в том ключе лежат

fmnoise 2018-12-30T22:18:18.166400Z

так статью не можешь или публикацию?

kuzmin_m 2018-12-30T22:18:37.167100Z

функция принимает публикацию

kuzmin_m 2018-12-30T22:18:47.167400Z

но статья - это расширение публикации

kuzmin_m 2018-12-30T22:18:59.167700Z

и фукнкция должна работать с ней

kuzmin_m 2018-12-30T22:19:51.169400Z

получается ключ :article/translation, а должен быть :publication/translation

fmnoise 2018-12-30T22:19:51.169500Z

ну сделай на первом уровне через :opt [:article/translation :publication/translation]

kuzmin_m 2018-12-30T22:20:10.170300Z

публикация не знает своих потомков

fmnoise 2018-12-30T22:20:10.170600Z

и отдельно проверяй что какой-то из них точно должен быть

kuzmin_m 2018-12-30T22:20:15.170700Z

потомки знают публикацию

kuzmin_m 2018-12-30T22:20:28.171100Z

потом появится галерея

kuzmin_m 2018-12-30T22:20:33.171300Z

и еще чего-нибудь

kuzmin_m 2018-12-30T22:20:45.171800Z

по факту это циклическая зависимость

fmnoise 2018-12-30T22:21:08.172100Z

не понял про потомков

fmnoise 2018-12-30T22:21:27.172600Z

у тебя мапка с id и translation

kuzmin_m 2018-12-30T22:21:40.172900Z

ага

kuzmin_m 2018-12-30T22:21:45.173200Z

только они с неймспейсами

fmnoise 2018-12-30T22:22:17.173900Z

ну в мапке у тебя или publication неймспейс или article

kuzmin_m 2018-12-30T22:22:24.174100Z

нет

kuzmin_m 2018-12-30T22:22:33.174400Z

должен быть только publication у всех

kuzmin_m 2018-12-30T22:23:17.174800Z

(defn title [publication]
  (-> publication :publication/transalation :publication/title))

kuzmin_m 2018-12-30T22:23:23.175100Z

скорми ей статью

fmnoise 2018-12-30T22:23:25.175300Z

так вообще тогда проблемы не вижу

fmnoise 2018-12-30T22:24:06.175700Z

а где начинается article?

fmnoise 2018-12-30T22:26:52.177Z

у тебя во внутренней мапке либо :article.translation/content либо :publication.translation/content?

fmnoise 2018-12-30T22:27:09.177300Z

или как?

kuzmin_m 2018-12-30T22:28:57.177500Z

(ns publication.translation)

(s/def ::title string?)
(s/def ::translation (s/keys :req [::title]))

(ns publication
  (:require [publication.translation :as translation]))

(s/def ::id int?)
(s/def ::publication (s/keys :req [::id ::translation/translation]))

(ns article.translation
  (:require [publication.translation :as base]))

(s/def ::content string?)
(s/def ::translation (s/merge ::base/translation (s/keys :req [::content])))

(ns article
  (:require
   [publication :as base]
   [publication.translation :as base.translation]
   [article.translation :as translation]))

(s/def ::image-url string?)
(s/def ::article (s/merge ::base/publication
                          (s/keys :req [::image-url])
                          ;;;;;
                          (s/keys :req [::translation/translation :as ::base/translation])))

kuzmin_m 2018-12-30T22:30:55.178Z

> у тебя во внутренней мапке либо :article.translation/content либо :publication.translation/content?

{:publication/id 1
 :publication/translation {:publication.translation/title "article"}}

{:publication/id 1
 :publication/translation {:publication.translation/title "article"
                           :article.translation/content "foo"}
 :article/image-url "http://"}

{:publication/id 1
 :publication/translation {:publication.translation/title "article"
                           :gallery.translation/author "foo"}
 :gallery/image-urls ["http://"]}

kuzmin_m 2018-12-30T22:31:12.178700Z

или не понятно?

fmnoise 2018-12-30T22:31:41.179300Z

ну тут надо просто определить все что только может быть под ключем :publication/translation

fmnoise 2018-12-30T22:32:08.180200Z

publication.translation/title я вижу req

kuzmin_m 2018-12-30T22:32:12.180500Z

на зависимости посмотри

fmnoise 2018-12-30T22:32:17.180700Z

остальноe opt

kuzmin_m 2018-12-30T22:32:33.181100Z

не может publication.translation зависеть от article.tranlation

kuzmin_m 2018-12-30T22:32:36.181300Z

будет цикл

kuzmin_m 2018-12-30T22:32:45.181600Z

и это не расширяемо

fmnoise 2018-12-30T22:33:01.182200Z

ну тут зависимостей не может быть

kuzmin_m 2018-12-30T22:33:02.182300Z

т.е. это невозможно в спеке сделать

fmnoise 2018-12-30T22:33:31.182900Z

тут напихал ключей, написал ф-ю которая проверяет их дополнительно

fmnoise 2018-12-30T22:34:26.183400Z

ну или добавлять тип и делать через мультиспеку

fmnoise 2018-12-30T22:35:35.184900Z

я б добавил в :publication/translation :publication.translation/type

kuzmin_m 2018-12-30T22:35:41.185Z

в общем, в спеке это не делается для этих данных тут нужен какой-то (s/merge-in)

fmnoise 2018-12-30T22:36:05.186Z

и зависимо от него уже через мультиметод решал

kuzmin_m 2018-12-30T22:36:26.186500Z

да, но этот тип должен быть в верхней мапе по логике

fmnoise 2018-12-30T22:36:32.186800Z

ну и что

kuzmin_m 2018-12-30T22:36:50.187200Z

т.е. данные под спеку подгонять? 😃

kuzmin_m 2018-12-30T22:37:00.187700Z

наверное наоборот должно быть

fmnoise 2018-12-30T22:37:34.188200Z

я не понял тип у публикации или у перевода?

kuzmin_m 2018-12-30T22:38:10.188500Z

{:publication/id 1
 :publication/translation {:publication.translation/title "article"
                           :article.translation/content "foo"}
 :article/image-url "http://"
 :publication/type :article}

fmnoise 2018-12-30T22:38:21.188800Z

о, тип у публикации и от него зависят ключи перевода

kuzmin_m 2018-12-30T22:38:33.189100Z

{:publication/id 1
 :publication/translation {:publication.translation/title "article"
                           :publication.translation/type :article
                           :article.translation/content "foo"}
 :article/image-url "http://"}

kuzmin_m 2018-12-30T22:38:39.189300Z

так не правильно

kuzmin_m 2018-12-30T22:38:54.189800Z

это простой случай, переводов может быть много

kuzmin_m 2018-12-30T22:39:06.190100Z

но это не рассматриваем

fmnoise 2018-12-30T22:40:43.191100Z

ну тогда да, придется в каждый перевод добавлять тип

fmnoise 2018-12-30T22:40:50.191300Z

чтобы спека работала

kuzmin_m 2018-12-30T22:41:25.191700Z

(s/def ::article (s/merge (s/merge-in ::base/publication
                                      [::base.translation/translation]
                                      (s/keys :req [::translation/content]))
                          (s/keys :req [::image-url])))
                          

kuzmin_m 2018-12-30T22:41:37.192Z

вот что-то такое нужно

kuzmin_m 2018-12-30T22:42:59.192600Z

попробую поподробнее расписать и в #clojure-spec вбросить

fmnoise 2018-12-30T22:43:11.192800Z

давай)

fmnoise 2018-12-30T22:43:27.193300Z

вагную тебе там скажут у тебя кривая схема данных)

kuzmin_m 2018-12-30T22:43:35.193600Z

кривые данные?

kuzmin_m 2018-12-30T22:43:38.193900Z

=D

fmnoise 2018-12-30T22:44:18.194200Z

короче да

fmnoise 2018-12-30T22:44:30.194600Z

тут можно порешать 2 ключами с типами

fmnoise 2018-12-30T22:45:52.195900Z

может можно как-то и без типа, а привязаться к наличию специального атрибута

fmnoise 2018-12-30T22:46:22.196300Z

например article.translation/content или gallery/image-url

fmnoise 2018-12-30T22:46:35.196700Z

типа если есть gallery/image-url значит это галерея

fmnoise 2018-12-30T22:46:44.197Z

если есть article.translation/content значит это артикл

fmnoise 2018-12-30T23:07:06.198900Z

но это опять же применение типа, просто базирующееся на том что некие ключи соответствуют одному типу, а некоторые другому

fmnoise 2018-12-30T23:08:46.199900Z

плюс в том что мультиспека позволяет диспатчить как угодно

fmnoise 2018-12-30T23:31:59.205100Z

вот пример похожий на твой

(s/def ::base (s/keys :req [:pub/title]))
(s/def ::image (s/merge ::base (s/keys :req [:img/url :img/alt])))
(s/def ::article (s/merge ::base (s/keys :req [:article/title :article/author])))

(def types {:img ::image
            :article ::article})

(defn trans-type [m]
  (types (some (-> types keys set) (->> m keys (mapv (comp keyword namespace))))))

(defmulti t identity)

(defmethod t :default [v] (trans-type v))

(s/def ::t (s/multi-spec t :translation.type))

fmnoise 2018-12-30T23:33:21.205300Z

@kuzmin_m ^^

👌 1