diff --git a/proofs/psnj_toolbox/bin/dune b/proofs/psnj_toolbox/bin/dune index d1bcdc12be50c1dd3e076c2f6323124298167132..b401347dc45bb6899da03ae4d7d4fbe6fffe8d26 100644 --- a/proofs/psnj_toolbox/bin/dune +++ b/proofs/psnj_toolbox/bin/dune @@ -1,7 +1,7 @@ (executable (public_name psnj) (name main) - (modules main dopth chainprops appaxiom autosolve qfo split) + (modules main dopth chainprops appaxiom autosolve qfo split group) (libraries ezjsonm personoj diff --git a/proofs/psnj_toolbox/bin/group.ml b/proofs/psnj_toolbox/bin/group.ml new file mode 100644 index 0000000000000000000000000000000000000000..693d11fad4cf8e0df60fbe5f0e996d307fb4f0c2 --- /dev/null +++ b/proofs/psnj_toolbox/bin/group.ml @@ -0,0 +1,74 @@ +module StrMap = Map.Make (String) + +let add (k : string) (o : Ezjsonm.value) (m : Ezjsonm.value list StrMap.t) : + Ezjsonm.value list StrMap.t = + let objs = + match StrMap.find_opt k m with None -> [ o ] | Some objs -> o :: objs + in + StrMap.add k objs m + +let group minify group_by = + let groups = ref StrMap.empty in + (try + while true do + let line = input_line stdin in + let json : Ezjsonm.value = Ezjsonm.from_string line in + let name = Ezjsonm.(find json [ group_by ] |> get_string) in + groups := add name json !groups + done + with End_of_file -> ()); + let m = + StrMap.map List.rev !groups + |> StrMap.map (Ezjsonm.list Fun.id) + |> StrMap.map Ezjsonm.value + in + let obj = StrMap.to_seq m |> List.of_seq |> Ezjsonm.dict in + Ezjsonm.to_channel ~minify stdout obj + +open Cmdliner + +let minify = Arg.(value & flag & info [ "m" ]) + +let group_by = + let doc = "Group objects using field $(docv)" in + Arg.(value & opt string "name" & info [ "group-by"; "g" ] ~doc ~docv:"FIELD") + +let cmd = + let doc = "Group JSON objects in arrays depending on a field" in + let man = + [ + `S Manpage.s_description; + `P + "$(tname) is a filter that reads a list of JSON objects and group them \ + in a dictionary. Groups are determined by the value of a name (which \ + is-confusingly-$(b,name) by default). The values associated to this \ + name become the keys of the dictionary."; + `S Manpage.s_examples; + `P "Given JSON objects"; + `Pre + {|{ "name": "foo", "attr": "baz" } +{ "name": "bar", "attr": "frobz" } +{ "name": "foo", "attr": "nitz" }|}; + `P "The output of $(tname) -g name is"; + `Pre + {|{ + "bar": [ + { + "name": "bar", + "attr": "frobz" + } + ], + "foo": [ + { + "name": "foo", + "attr": "nitz" + }, + { + "name": "foo", + "attr": "baz" + } + ] + }|}; + ] + in + (Term.(const group $ minify $ group_by), Term.info "jgroup" ~doc ~man) diff --git a/proofs/psnj_toolbox/bin/main.ml b/proofs/psnj_toolbox/bin/main.ml index ee41eb416d726a7715161be13215d3dc4f92bdaa..53599e307b7f26b6d2b0a2d0cf821c813d335a1a 100644 --- a/proofs/psnj_toolbox/bin/main.ml +++ b/proofs/psnj_toolbox/bin/main.ml @@ -6,6 +6,14 @@ let default_cmd = (Term.(ret @@ const @@ `Help (`Pager, None)), Term.info "psnj" ~doc ~exits) let cmds = - [ Dopth.cmd; Chainprops.cmd; Appaxiom.cmd; Autosolve.cmd; Qfo.cmd; Split.cmd ] + [ + Dopth.cmd; + Chainprops.cmd; + Appaxiom.cmd; + Autosolve.cmd; + Qfo.cmd; + Split.cmd; + Group.cmd; + ] let () = Term.(exit @@ eval_choice default_cmd cmds) diff --git a/proofs/psnj_toolbox/bin/split.ml b/proofs/psnj_toolbox/bin/split.ml index 7db3920341f2870cb4385dc924cff10438f08d49..9f46eccfee446591be9201abd25a2c01feb158eb 100644 --- a/proofs/psnj_toolbox/bin/split.ml +++ b/proofs/psnj_toolbox/bin/split.ml @@ -1,16 +1,19 @@ let split prefix = + let fnames = ref [] in try while true do let line = input_line stdin in let json = Ezjsonm.from_string line in let name = Ezjsonm.(find json [ "name" ] |> get_string) in - let fname = String.concat "_" [ prefix; name ] in + let fname = String.concat "_" [ prefix; name ] ^ ".json" in + fnames := fname :: !fnames; let oc = open_out fname in at_exit (fun () -> close_out oc); output_string oc line; output_char oc '\n' done - with End_of_file -> () + with End_of_file -> + List.(iter (Format.printf "%s@\n") (sort_uniq String.compare !fnames)) open Cmdliner @@ -28,7 +31,8 @@ let cmd = "$(tname) reads a newline-seprated list of json objects on its \ standard input and copies each object to a file $(i,pr)_$(i,n).json \ where $(i,n) is the value associated to the (json) name $(b,name) and \ - $(i,pr) is a chosen prefix."; + $(i,pr) is a chosen prefix. The list of created files is returned on \ + standard output. Files appear at most once in the list."; `S Manpage.s_examples; `P "Faced with input"; `Pre diff --git a/proofs/psnj_toolbox/test/jgroup/dune b/proofs/psnj_toolbox/test/jgroup/dune new file mode 100644 index 0000000000000000000000000000000000000000..2284a0ba048942afd4ee986189dedf28cacb836e --- /dev/null +++ b/proofs/psnj_toolbox/test/jgroup/dune @@ -0,0 +1,2 @@ +(cram + (deps input.json)) diff --git a/proofs/psnj_toolbox/test/jgroup/input.json b/proofs/psnj_toolbox/test/jgroup/input.json new file mode 100644 index 0000000000000000000000000000000000000000..874e472de3108e4eb0aeeccf5245fe8bffa5d2dd --- /dev/null +++ b/proofs/psnj_toolbox/test/jgroup/input.json @@ -0,0 +1,3 @@ +{ "name": "foo", "attr": "baz" } +{ "name": "bar", "attr": "frobz" } +{ "name": "foo", "attr": "nitz" } diff --git a/proofs/psnj_toolbox/test/jgroup/jgroup.t b/proofs/psnj_toolbox/test/jgroup/jgroup.t new file mode 100644 index 0000000000000000000000000000000000000000..b8dea681cccde354ba2ffedc9ae15e2af0eceddc --- /dev/null +++ b/proofs/psnj_toolbox/test/jgroup/jgroup.t @@ -0,0 +1,19 @@ + $ psnj jgroup < input.json + { + "bar": [ + { + "name": "bar", + "attr": "frobz" + } + ], + "foo": [ + { + "name": "foo", + "attr": "baz" + }, + { + "name": "foo", + "attr": "nitz" + } + ] + } diff --git a/proofs/psnj_toolbox/test/jsplit/jsplit.t b/proofs/psnj_toolbox/test/jsplit/jsplit.t index 4650034f6ea1df594968744d1cc390df641bf566..c1d20b0fe20fe33597b6632ba62752aef1adca9d 100644 --- a/proofs/psnj_toolbox/test/jsplit/jsplit.t +++ b/proofs/psnj_toolbox/test/jsplit/jsplit.t @@ -1,7 +1,11 @@ - $ psnj jsplit -p ff < input.json; find . -type f -printf "\n%p\n" -exec cat {} \; + $ psnj jsplit -p ff < input.json + ff_bar.json + ff_foo.json + + $ find . -type f -printf "\n%p\n" -exec cat {} \; - ./ff_bar - { "name": "bar", "attr": "frobz" } - - ./ff_foo + ./ff_foo.json { "name": "foo", "attr": "baz" } + + ./ff_bar.json + { "name": "bar", "attr": "frobz" }