GlobEx - A library for glob expressions

GlobEx provides GlobEx.ls/1, GlobEx.match?/2 and the sigil ~g. GlobEx.ls/1 has the same functionality like Path.wildcard/2 and is just as fast. The motivation for GlobEx was match/2 to check if a path matches a glob expression.

Example:

iex(1)> import GlobEx.Sigils
GlobEx.Sigils
iex(2)> GlobEx.match?(~g|{lib,test}/**/*.{ex,exs}|, "test/test_helper.exs")
true
iex(3)> GlobEx.match?(~g|{lib,test}/**/*.{ex,exs}|, "test/unknown.foo")
false
iex(4)> GlobEx.ls(~g|{lib,test}/**/*.{ex,exs}|)
["lib/glob_ex.ex", "lib/glob_ex/compiler.ex", "lib/glob_ex/compiler_error.ex",
 "lib/glob_ex/sigils.ex", "test/glob_ex/compiler_test.exs",
 "test/glob_ex_test.exs", "test/test_helper.exs"]
iex(5)> GlobEx.ls(~g|*.exs|) # ignores files with a starting dot
["mix.exs"]
iex(6)> GlobEx.ls(~g|*.exs|d) # files starting with a dot will not be treated specially
[".credo.exs", ".formatter.exs", "mix.exs"]
4 Likes

Looks nice. Just curious what does a sigil give, compared to just using a string for expressions?

The functions ls/1 and match?/2 are expecting a precompiled blog in a GlobEx struct.

%GlobEx{
  source: "f*/?ar", 
  match_dot: false, 
  compiled:  [seq: [102, :star], seq: [:question, 97, 114]]
} = ~g|f*/?ar|

So GlobEx.ls(~g|?oo/?ar|) is the short version of "?oo/?ar" |> GlobEx.compile!() |> GlobEx.ls(). And GlobEx.compile/2 can be used to catch invalid blogs.

iex> GlobEx.compile("foo{bar")
{:error, %GlobEx.CompileError{reason: {:missing_delimiter, 4}}}
1 Like

Can you call those internally and accept a bare string to ls and match?

1 Like

Theoretically, I could do that. The idea is that match? and ls are just work with %GlobEx{} and compile/2 and compile!/2 with strings. This way I don’t have to return a tuple for ls/1 and match? doesn’t have to throw an exception. Furthermore ls/1 would have to become ls/2 so that the option :match_dot can be specified and the function ls!2 would be added.

So the API as it is, is simple and composable. In the other case, it is not so simple and only maybe a little more convenient :wink:.

The API was inspired by Regex, but I am not aware if the reasons for the API there are the same as mine.