Skip to content

Commit

Permalink
Merge pull request #10 from mbarbin/hash-and-segs
Browse files Browse the repository at this point in the history
Hash and segs
  • Loading branch information
mbarbin authored Oct 15, 2024
2 parents ad2740f + 30a1a2b commit 8975fa5
Show file tree
Hide file tree
Showing 22 changed files with 315 additions and 96 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"cSpell.words": [
"Fpath",
"Fsegment",
"janestreet"
]
}
15 changes: 15 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
## 0.2.2 (2024-10-15)

### Added

- Added `rem_empty_seg` to `Absolute_path` and `Relative_path`.
- In `fpath-sexp0` export hash keys interfaces compatible with stdlib hash functors.

### Changed

- Rename `Fpart` to `Fsegment` to fit `Fpath` terminology.

### Fixed

- Fix occurrence of hard coded dir separator.

## 0.2.1 (2024-09-22)

### Changed
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This repository defines 2 OCaml packages named `fpath-sexplib0` and `fpath-base`

## fpath-sexplib0

This package only depends on `fpath` and `sexplib0`. It defines a single module, `Fpath_sexplib0`, which is designed to be opened to shadow the `Fpath` module. This introduces three new modules to the scope: `Fpart`, `Absolute_path` and `Relative_path`.
This package only depends on `fpath` and `sexplib0`. It defines a single module, `Fpath_sexplib0`, which is designed to be opened to shadow the `Fpath` module. This introduces three new modules to the scope: `Fsegment`, `Absolute_path` and `Relative_path`.

**Fpath** is shadowed and retains all its original functionality, with the addition of a sexp serializer:

Expand All @@ -27,15 +27,15 @@ val classify
-> [ `Absolute of Absolute_path.t | `Relative of Relative_path.t ]
```

**Fpart** is a helper module for representing and manipulating the elements that constitute the '/' separated segments of a path.
**Fsegment** is a helper module for representing and manipulating the elements that constitute the '/' separated segments of a path.

**Absolute_path** and **Relative_path** are helper modules that distinguish between classes of paths in the type system, enhancing type safety for applications manipulating paths. Both types are defined as `private Fpath.t`, making it easy to cast and convert paths.

## fpath-base

This package further extends `fpath-sexplib0` and adds a dependency on `base`. It is designed to be compatible with `Base`-style containers such as `Map`, `Set`, `Hashtbl`, `Hash_set`.

This package defines a single module, `Fpath_base`, which is designed to be opened to shadow and further extend the four modules from `fpath-sexplib0`: `Fpath`, `Fpart`, `Absolute_path` and `Relative_path`. It exports `hashable` and `comparable` interfaces.
This package defines a single module, `Fpath_base`, which is designed to be opened to shadow and further extend the four modules from `fpath-sexplib0`: `Fpath`, `Fsegment`, `Absolute_path` and `Relative_path`. It exports `hashable` and `comparable` interfaces.

```ocaml
module Fpath : sig
Expand Down
2 changes: 1 addition & 1 deletion dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
(package
(name fpath-sexp0)
(synopsis
"Adds Fpath.sexp_of_t and defines 3 new modules: Fpart, Absolute_path and Relative_path")
"Adds Fpath.sexp_of_t and defines 3 new modules: Fsegment, Absolute_path and Relative_path")
(depends
(ocaml
(>= 5.2))
Expand Down
2 changes: 1 addition & 1 deletion fpath-sexp0.opam
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
synopsis:
"Adds Fpath.sexp_of_t and defines 3 new modules: Fpart, Absolute_path and Relative_path"
"Adds Fpath.sexp_of_t and defines 3 new modules: Fsegment, Absolute_path and Relative_path"
maintainer: ["Mathieu Barbin <opensource@mbarbin.org>"]
authors: ["Mathieu Barbin"]
license: "MIT"
Expand Down
10 changes: 4 additions & 6 deletions lib/fpath_base/src/fpath_base.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ module Fpath = struct
include T
include Comparable.Make (T)

let hash t = String.hash (T.to_string t)
let hash_fold_t state t = String.hash_fold_t state (T.to_string t)
end

Expand All @@ -12,7 +11,6 @@ module Absolute_path = struct
include T
include Comparable.Make (T)

let hash t = String.hash (T.to_string t)
let hash_fold_t state t = String.hash_fold_t state (T.to_string t)
end

Expand All @@ -21,15 +19,15 @@ module Relative_path = struct
include T
include Comparable.Make (T)

let hash t = String.hash (T.to_string t)
let hash_fold_t state t = String.hash_fold_t state (T.to_string t)
end

module Fpart = struct
module T = Fpath_sexp0.Fpart
module Fsegment = struct
module T = Fpath_sexp0.Fsegment
include T
include Comparable.Make (T)

let hash t = String.hash (T.to_string t)
let hash_fold_t state t = String.hash_fold_t state (T.to_string t)
end

module Fpart = Fsegment
10 changes: 7 additions & 3 deletions lib/fpath_base/src/fpath_base.mli
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ module Relative_path : sig
val hash_fold_t : Hash.state -> t -> Hash.state
end

module Fpart : sig
type t = Fpath_sexp0.Fpart.t
module Fsegment : sig
type t = Fpath_sexp0.Fsegment.t

include module type of Fpath_sexp0.Fpart with type t := t
include module type of Fpath_sexp0.Fsegment with type t := t
include Comparable.S with type t := t

val hash : t -> int
val hash_fold_t : Hash.state -> t -> Hash.state
end

(** This alias is kept for backward compatibility for now but will soon be
deprecated. Please upgrade code to [Fsegment]. *)
module Fpart = Fsegment
33 changes: 29 additions & 4 deletions lib/fpath_base/test/test__absolute_path.ml
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ let%expect_test "append" =

let%expect_test "extend" =
let abs = Absolute_path.v in
let file str = str |> Fpart.v in
let file str = str |> Fsegment.v in
let test a b = print_s [%sexp (Absolute_path.extend a b : Absolute_path.t)] in
require_does_raise [%here] (fun () : Fpart.t -> file "a/b");
[%expect {| (Invalid_argument "a/b: invalid file part") |}];
require_does_not_raise [%here] (fun () -> ignore (file ".." : Fpart.t));
require_does_raise [%here] (fun () : Fsegment.t -> file "a/b");
[%expect {| (Invalid_argument "a/b: invalid file segment") |}];
require_does_not_raise [%here] (fun () -> ignore (file ".." : Fsegment.t));
[%expect {||}];
test (abs "/") (file "a");
[%expect {| /a |}];
Expand Down Expand Up @@ -272,6 +272,31 @@ let%expect_test "to_dir_path" =
()
;;

let%expect_test "rem_empty_seg" =
let test path =
let is_dir_path = Absolute_path.is_dir_path path in
let path2 = Absolute_path.rem_empty_seg path in
let is_dir_path2 = Absolute_path.is_dir_path path2 in
print_s
[%sexp
{ path : Absolute_path.t; is_dir_path : bool }
, { path2 : Absolute_path.t; is_dir_path2 : bool }]
in
test (Absolute_path.v "/tmp/my-dir/");
[%expect
{|
(((path /tmp/my-dir/) (is_dir_path true))
((path2 /tmp/my-dir) (is_dir_path2 false)))
|}];
test (Absolute_path.v "/tmp/my-file");
[%expect
{|
(((path /tmp/my-file) (is_dir_path false))
((path2 /tmp/my-file) (is_dir_path2 false)))
|}];
()
;;

let%expect_test "relativize" =
let v str = str |> Fpath.v in
let abs = Absolute_path.v in
Expand Down
61 changes: 0 additions & 61 deletions lib/fpath_base/test/test__fpart.ml

This file was deleted.

62 changes: 62 additions & 0 deletions lib/fpath_base/test/test__fsegment.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
let%expect_test "of_string" =
let test str =
print_s [%sexp (Fsegment.of_string str : (Fsegment.t, [ `Msg of string ]) Result.t)]
in
test "";
[%expect {| (Error (Msg ": invalid file segment")) |}];
test "a";
[%expect {| (Ok a) |}];
test ".a";
[%expect {| (Ok .a) |}];
test "..";
[%expect {| (Ok ..) |}];
test "/";
[%expect {| (Error (Msg "/: invalid file segment")) |}];
test "a/b";
[%expect {| (Error (Msg "a/b: invalid file segment")) |}];
test "a\000b";
[%expect {| (Error (Msg "a\000b: invalid file segment")) |}];
()
;;

let%expect_test "hard coded" =
List.iter
~f:(fun (name, t) ->
print_endline (Printf.sprintf "%10s: " name ^ Fsegment.to_string t))
Fsegment.[ "dot", dot; "dot_dot", dot_dot; "dot_git", dot_git; "dot_hg", dot_hg ];
[%expect {|
dot: .
dot_dot: ..
dot_git: .git
dot_hg: .hg |}];
()
;;

let%expect_test "hashtbl" =
let t = Hashtbl.create (module Fsegment) in
Hashtbl.set t ~key:(Fsegment.v "my-file") ~data:42;
print_s [%sexp (t : int Hashtbl.M(Fsegment).t)];
[%expect {| ((my-file 42)) |}]
;;

module Pair = struct
[@@@coverage off]

type t =
{ a : Fsegment.t
; b : Fsegment.t
}
[@@deriving compare, hash, sexp_of]
end

let%expect_test "hash-fold-t" =
let t = Hashtbl.create (module Pair) in
Hashtbl.set t ~key:{ a = Fsegment.v "a"; b = Fsegment.v "b" } ~data:42;
print_s [%sexp (t : int Hashtbl.M(Pair).t)];
[%expect {|
((
((a a)
(b b))
42))
|}]
;;
File renamed without changes.
Loading

0 comments on commit 8975fa5

Please sign in to comment.