Giter Club home page Giter Club logo

pathex's Issues

Pathex does not compile with elixir 1.14.0-rc0

== Compilation error in file lib/pathex/accessibility.ex ==
** (ArgumentError) cannot pipe value into function.()
|> case do
{:ok, value} -> value
:error -> throw(:path_not_found)
end, the :|> operator can only take two arguments
(elixir 1.14.0-rc.0) lib/macro.ex:323: Macro.pipe/3
(elixir 1.14.0-rc.0) expanding macro: Kernel.|>/2
lib/pathex/accessibility.ex:144: Pathex.Accessibility.from_list/2
(elixir 1.14.0-rc.0) expanding macro: Kernel.|>/2
lib/pathex/accessibility.ex:144: Pathex.Accessibility.from_list/2
expanding macro: Pathex.path/2
lib/pathex/accessibility.ex:144: Pathex.Accessibility.from_list/2

great library, this could be elixir issue

Is it possible to define collection type when using from_list?

Hi there, apologies if I missed this in the documentation, but is it possible to define the collection type when creating a path via from_list?

e.g. I want to create something similar to path :alpha / (0 :: :list), but dynamically.

I attempted to do something like from_list([:alpha, 0 :: :list]), however, I got an error saying that :: was not a defined function.

The use case for this is that I want to use the above path to force_set and create if it doesn't exist, but I want it to create a list rather than a map. From testing it seems that defining the collection type correctly results in a list being created for the 0 path.

Any assistance would be much appreciated!

Thanks!

All lens deletion bug

As @ffloyd mentioned in #20, I see some weird behavior with all/0 lens:

import Pathex

data = [
  %{ "a" => 1 },
  %{ "a" => 2 }
]

all_a = Pathex.Lenses.all() ~> path("a")

Pathex.get(data, all_a) |> IO.inspect(label: "get")
Pathex.delete!(data, all_a) |> IO.inspect(label: "delete!")

And as result get/2 works, but delete/2 fails:

** (Pathex.Error) 
  Couldn't find element

    Path:      all() ~> path("a")

    Structure: [%{"a" => 1}, %{"a" => 2}]

    (stdlib 3.17.2) erl_eval.erl:685: :erl_eval.do_apply/6
    (stdlib 3.17.2) erl_eval.erl:893: :erl_eval.expr_list/6
    (stdlib 3.17.2) erl_eval.erl:408: :erl_eval.expr/5
    (elixir 1.14.0) lib/module/parallel_checker.ex:100: Module.ParallelChecker.verify/1

How should I create a path from a list?

I want to create a dynamic path.

data = [{:a, []}, {:b, [{:c, []}]}]
assert {:ok, {:c, []}} = view(data, path 1 / 1 / 0)

This is good, but what if I don't know [1, 1, 0] at compile time. I couldn't see anything documented about passing a list as a path, so I tried the following:

def make_path(elems) do
  elems
  |> Enum.map(fn elem -> path elem end)
  |> Enum.reduce(fn p1, p2 -> p1 ~> p2 end)
end

assert {:ok, {:c, []}} = view(data, make_path([1, 1, 0]))
# fails with :error

Any idea what I am missing here?

Thanks.

Matt

Dialyzer complains about deletion functions

When using (some) functions which rely on the magic :delete_me atom, Dialyzer complains about a pattern that can never match the type (this error is for the most generic case where no types can be inferred at the place of use):

The pattern 
          'delete_me' can never match the type 
          'error' | {'ok', [any()] | tuple() | map()}

Affected functions (for me) are delete/2, delete!/2, and pop!/1. pop/1 Isn't affected, and I'm not sure why.

Reproduction:

Paste this module into any project which has pathex dependency installed, and run Dialyzer.

defmodule PathexTest do
  use Pathex

  def pop_key_from_my_map(%{} = my_map, key) do
    Pathex.delete(my_map, path(key)) # The pattern 'delete_me' can never match the type 'error' | {'ok',map()}
    Pathex.delete!(my_map, path(key)) # The pattern 'delete_me' can never match the type 'error' | {'ok',map()}
    Pathex.pop!(my_map, path(key)) # The pattern 'delete_me' can never match the type 'error' | {'ok',map()}
    Pathex.pop(my_map, path(key)) # No warning for some reason?
  end
end

For me this is reproducable on a mix new project with two dependencies, but also causes a warning in VSCode even without the dialyxir dependency:

[
  {:pathex, "~> 2.4.2"},
  {:dialyxir, "~> 1.0", only: [:dev], runtime: false}
]

My environment:

> elixir --version
Erlang/OTP 25 [erts-13.0.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]

Elixir 1.14.1 (compiled with Erlang/OTP 25)

Delete a key?

Is it possible to add a function to delete a key?

p = path "hey" / "you"

%{"hey" => %{"x" => 2}} ==  delete %{"hey" => %{"you" => 1, "x" => 2}}, p
p = path "hey" / 1

%{"hey" => [0, 2]} ==  delete %{"hey" => [0, 1, 2]}, p

path(y :: :list, :json)

iex> path(y :: :list, :json)
** (FunctionClauseError) no function clause matching in Pathex.Builder.ForceUpdater.reduce_into/2

    The following arguments were given to Pathex.Builder.ForceUpdater.reduce_into/2:

        # 1
        []

        # 2
        {{:|>, [context: Pathex.Builder.ForceUpdater, imports: [{2, Kernel}]],
          [
            {{:., [], [{:function, [], Elixir}]}, [], []},
            {:case, [],
             [
               [
                 do: [
                   {:->, [],
                    [
                      [ok: {:value, [], Pathex.Builder.ForceUpdater}],
                      {:value, [], Pathex.Builder.ForceUpdater}
                    ]},
                   {:->, [],
                    [
                      [:error],
                      {:throw,
                       [context: Pathex.Builder.ForceUpdater, imports: [{1, Kernel}]],
                       [:path_not_found]}
                    ]}
                 ]
               ]
             ]}
          ]}, {:default, [], Elixir}}

    Attempted function clauses (showing 1 out of 1):

        defp reduce_into([path_item | _] = path_items, {acc_code, acc_items})

    (pathex 2.5.1) lib/pathex/builder/updaters/force_updater.ex:26: Pathex.Builder.ForceUpdater.reduce_into/2
    (elixir 1.14.3) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
    (pathex 2.5.1) lib/pathex/builder/updaters/force_updater.ex:21: Pathex.Builder.ForceUpdater.build/1
    (pathex 2.5.1) lib/pathex/builder.ex:47: anonymous fn/2 in Pathex.Builder.build/2
    (elixir 1.14.3) lib/enum.ex:1662: anonymous fn/3 in Enum.map/2
    (stdlib 4.2) maps.erl:411: :maps.fold_1/3
    (elixir 1.14.3) lib/enum.ex:2480: Enum.map/2
    (pathex 2.5.1) lib/pathex/builder.ex:46: Pathex.Builder.build/2

Invalid behaviour of `Pathex.delete!` when using concatenation and/or `all` lense

Let's say I have the following data:

data = %{
  "key" => "value",
  "list" => [
    %{
      "a" => 1,
      "b" => 2
    },
    %{
      "a" => 3,
      "b" => 4
    }
  ]
}

and my goal is to delete all "a" keys from all maps in the inner list. So, I create a path for them:

all_a = path("list") ~> Pathex.Lenses.all() ~> path("a")

Pathex.get(data, all_a)
# result:
[1, 3]

But when I use delete! it just wipes all items in the list:

Pathex.delete!(data, all_a)
# result:
%{"key" => "value", "list" => []}

Then I tried to not use the lens, but still do concatenation:

first_a_concat = path("list") ~> path(0) ~> path("a")

Pathex.get(data, first_a_concat)
# result:
1

Pathex.delete!(data, first_a_concat)
# result:
%{"key" => "value", "list" => [%{"a" => 3, "b" => 4}]} # it removes first item from the list!

When I use path without concatenation it works as it should:

first_a_path = path("list" / 0 / "a")

Pathex.get(data, first_a_path)
# result:
1

Pathex.delete!(data, first_a_path)
# result:
%{"key" => "value", "list" => [%{"b" => 2}, %{"a" => 3, "b" => 4}]}

Then I tried to check what will happen with some deeeep data:

deep_data = %{
  "list" => [
    %{
      "list" => [
        %{
          "list" => [
            %{
              "a" => 1,
              "b" => 2
            }
          ]
        }
      ]
    }
  ]
}

deep_dive_path =
  path("list")
  ~> Pathex.Lenses.all()
  ~> path("list")
  ~> Pathex.Lenses.all()
  ~> path("list")
  ~> Pathex.Lenses.all()
  ~> path("a")

Pathex.get(deep_data, deep_dive_path)
# result:
[[[1]]] # btw, shouldn't it be a flat list here?

Pathex.delete!(deep_data, deep_dive_path)
# result:
** (CaseClauseError) no case clause matching: :delete_me
    (pathex 2.4.0) lib/pathex/lenses/all.ex:111: anonymous fn/3 in Pathex.Lenses.All.all/0
    (elixir 1.14.0) lib/enum.ex:4751: Enumerable.List.reduce/3
    (elixir 1.14.0) lib/enum.ex:2514: Enum.reduce_while/3
    (pathex 2.4.0) lib/pathex/lenses/all.ex:110: anonymous fn/2 in Pathex.Lenses.All.all/0
    (stdlib 3.17.2) erl_eval.erl:672: :erl_eval.do_apply/5
    (stdlib 3.17.2) erl_eval.erl:270: :erl_eval.expr/5
    (pathex 2.4.0) lib/pathex/lenses/all.ex:111: anonymous fn/3 in Pathex.Lenses.All.all/0
    (elixir 1.14.0) lib/enum.ex:4751: Enumerable.List.reduce/3

So, it looks like delete!/2 has some real problems with lenses and concatenation. =)

Error when using tuple with variable in path creation

Great Library!

using a variable inside a tuple key fails, also I think the error message about the pin operator is now invalid.

iex > val = "xxx"
iex > path  :x / {:foo, val}
** (CompileError) cannot use variable val as map key inside a pattern. Map keys in patterns can only be literals (such as atoms, strings, tuples, and the like) or an existing variable matched with the pin operator (such as ^some_var)

but wrapping the tuple in a variable works just fine

iex > key = {:foo, val}
{:foo, "xxx"}
iex > path :x / key
#Function<43.65746770/2 in :erl_eval.expr/5>

exists?/2 bug

iex> s = [
  %{
    children: [
      %{
        children: [],
        id: "fcfb1066-6e16-4a84-81e0-7746f12b7e76",
        tag: "test1",
        type: "section"
      },
      %{
        id: "035ca737-2cc2-488b-83f5-fe7cc2becc5e",
        parent_id: "a9963499-f6a4-4a32-bafa-aa22a9b059bc"
      },
      %{
        children: [
          %{
            other: [
              %{
                id: "035ca737-2cc2-488b-83f5-fe7cc2becc5e",
                parent_id: "a9963499-f6a4-4a32-bafa-aa22a9b059bc"
              }
            ],
            tag: "test4"
          }
        ],
        id: "8a9f0126-33a0-4c03-8c4a-5507f0562c8a",
        index: 2,
        parent: "layout",
        parent_id: "a9963499-f6a4-4a32-bafa-aa22a9b059bc",
        tag: "test2",
        type: "section"
      }
    ],
    parent: "dragLocation",
    parent_id: "dragLocation",
    tag: "test3"
  }
]

iex> Pathex.view s, tag_lens ~> matching("test2")
{:ok, "test2"}

iex> Pathex.exists? s, tag_lens ~> matching("test2")
** (CaseClauseError) no case clause matching: true
    (pathex 2.5.0) lib/pathex/lenses/some.ex:186: Pathex.Lenses.Some.map_view/2
    iex:6: (file)
    iex:6: (file)
    iex:6: (file)
    iex:9: (file)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.