Repository: invenia/NamedDims.jl (julia)

Issue:
More duck typing with `hasnames`?
AxisKeys currently defines `hasnames` for handling different types that can support named dims operations. It'd be nice if we could move that API into NamedDims.jl where I think it belongs.

https://github.com/mcabbott/AxisKeys.jl/blob/master/src/names.jl#L19

Might also help to provide a more general `NamedDims.dim` function that'll do this for you?

```
NamedDims.dim(A, d) = hasnames(A) ? NamedDims.dim(dimnames(A), d) : d
```

Pull request description:
This allows `numerical_dims = dim(A, dims)` to work for any array, by doing nothing when `A` doesn't have names. This closes #136.

It also allows `unname(A)` to accept anything, so that `map(unname, args)` can strip all dimension names without first checking which arguments are are arrays.

Patch:
diff --git a/Project.toml b/Project.toml
index 0610f2a..5c359df 100644
--- a/Project.toml
+++ b/Project.toml
@@ -1,7 +1,7 @@
 name = "NamedDims"
 uuid = "356022a1-0364-5f58-8944-0da4b18d706f"
 authors = ["Invenia Technical Computing Corporation"]
-version = "0.2.28"
+version = "0.2.29"
 
 [deps]
 LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
diff --git a/src/name_operations.jl b/src/name_operations.jl
index d864d48..a5283ee 100644
--- a/src/name_operations.jl
+++ b/src/name_operations.jl
@@ -35,22 +35,22 @@ end
 
 """
     unname(A::NamedDimsArray) -> AbstractArray
-    unname(A::AbstractArray) -> AbstractArray
+    unname(A) === A
 
 Return the input array `A` without any dimension names.
 
 For `NamedDimsArray`s this returns the parent array, equivalent to calling `parent`, but for
-any other `AbstractArray` simply returns the input.
+anything else it simply returns the input.
 """
 unname(x::NamedDimsArray) = parent(x)
-unname(x::AbstractArray) = x
+unname(x) = x
 
 """
     dimnames(A) -> Tuple
     dimnames(A, d) -> Symbol
 
-Return the names of all the dimensions of the array `A`, 
-or just the one for the `d`-th dimension. 
+Return the names of all the dimensions of the array `A`,
+or just the one for the `d`-th dimension.
 
 Gives wildcards `:_` if this is not a `NamedDimsArray`.
 Like `size(A, d)`, it allows `d > ndims(A)`, in this case all the trailing dimension are given the wildcard name (`:_`).
diff --git a/src/wrapper_array.jl b/src/wrapper_array.jl
index 95982ee..de060b1 100644
--- a/src/wrapper_array.jl
+++ b/src/wrapper_array.jl
@@ -57,6 +57,7 @@ parent_type(::Type{<:NamedDimsArray{L,T,N,A}}) where {L,T,N,A} = A
 Base.parent(x::NamedDimsArray) = getfield(x, :data)
 
 dim(a::NamedDimsArray{L}, name) where {L} = dim(L, name)
+dim(a::AbstractArray, d) = d
 
 NamedDimsVecOrMat{L,T} = Union{NamedDimsArray{L,T,1},NamedDimsArray{L,T,2}}
 NamedDimsVector{L,T} = NamedDimsArray{L,T,1}


Test patch:
diff --git a/test/name_operations.jl b/test/name_operations.jl
index 4c9d799..870901a 100644
--- a/test/name_operations.jl
+++ b/test/name_operations.jl
@@ -3,10 +3,11 @@
         @test unname(NamedDimsArray(orig, (:x, :y))) === orig
         @test unname(orig) === orig
     end
+    @test unname((1,2,3)) === (1,2,3)
 end
 
 
-@testset "dimnames" begin   
+@testset "dimnames" begin
     nda = NamedDimsArray([10 20; 30 40], (:x, :y))
 
     @test dimnames(nda) === (:x, :y)
@@ -16,7 +17,7 @@ end
     @test dimnames([10 20; 30 40]) === (:_, :_)
     @test dimnames([10 20; 30 40], 2) === :_
     @test dimnames([10 20; 30 40], 3) === :_
-    
+
     v = NamedDimsArray(1:2, :a)
     @test dimnames(v, 2) == dimnames(permutedims(v), 1) # That's why :_ for d > ndims
 
diff --git a/test/wrapper_array.jl b/test/wrapper_array.jl
index 56c4a60..41ce815 100644
--- a/test/wrapper_array.jl
+++ b/test/wrapper_array.jl
@@ -1,5 +1,4 @@
 using NamedDims
-using NamedDims: names
 using SparseArrays
 using Test
 
@@ -7,12 +6,19 @@ using Test
 @testset "get the parent array that was wrapped" begin
     for orig in ([1 2; 3 4], spzeros(2, 2))
         @test parent(NamedDimsArray(orig, (:x, :y))) === orig
-
         @test unname(NamedDimsArray(orig, (:x, :y))) === orig
         @test unname(orig) === orig
     end
 end
 
+@testset "function dim(array, dim)" begin
+    nda = NamedDimsArray([10 20; 30 40], (:x, :y))
+    @test dim(nda, :x) == 1
+    @test dim(nda, [:y, :x]) == [2, 1]
+    @test dim(nda, 2) == 2
+    @test dim(parent(nda), 2) == 2
+    @test_throws ArgumentError dim(nda, :nope)
+end
 
 @testset "get the named array that was wrapped" begin
     @test dimnames(NamedDimsArray([10 20; 30 40], (:x, :y))) === (:x, :y)