changed README.md
 
@@ -10,7 +10,7 @@ by adding `panty` to your list of dependencies in `mix.exs`:
10
10
```elixir
11
11
def deps do
12
12
[
13
- {:panty, "~> 0.1.1"}
13
+ {:panty, "~> 0.1.3"}
14
14
]
15
15
end
16
16
```
changed hex_metadata.config
 
@@ -16,4 +16,4 @@
16
16
{<<"optional">>,false},
17
17
{<<"repository">>,<<"hexpm">>},
18
18
{<<"requirement">>,<<"~> 0.12.0">>}]]}.
19
- {<<"version">>,<<"0.1.2">>}.
19
+ {<<"version">>,<<"0.1.3">>}.
changed lib/collection.ex
 
@@ -3,26 +3,6 @@ defmodule Panty.Collection do
3
3
Collection utilities
4
4
"""
5
5
6
- @doc """
7
- Get index of a substring from a pattern.
8
-
9
- ## Examples
10
- iex> Collection.string_find_index("abcdef", "cde")
11
- 2
12
- iex> Collection.string_find_index("{% sections 'header' %}", "{% endschema %}")
13
- nil
14
-
15
- """
16
-
17
- @spec substring_index(String.t, String.t) :: integer() | nil
18
-
19
- def substring_index(pattern, substring) do
20
- case String.split(pattern, substring, parts: 2) do
21
- [left, _] -> String.length(left)
22
- [_] -> nil
23
- end
24
- end
25
-
26
6
@doc """
27
7
Get intersection from given lists.
28
8
 
@@ -34,7 +14,7 @@ defmodule Panty.Collection do
34
14
35
15
"""
36
16
37
- @spec intersection([any()], [any()]) :: [any()]
17
+ @spec intersection(list(), list()) :: list()
38
18
39
19
def intersection(first, second) do
40
20
first |> Enum.filter(&(Enum.member?(second, &1)))
 
@@ -49,7 +29,7 @@ defmodule Panty.Collection do
49
29
50
30
"""
51
31
52
- @spec initial([any(), ...]) :: [any()]
32
+ @spec initial(list()) :: list()
53
33
54
34
def initial(collection), do: _initial(collection)
55
35
 
@@ -67,7 +47,7 @@ defmodule Panty.Collection do
67
47
68
48
"""
69
49
70
- @spec compact([any()]) :: [any()]
50
+ @spec compact(list()) :: list()
71
51
72
52
def compact(collection) do
73
53
Enum.reject(collection, fn
 
@@ -88,9 +68,143 @@ defmodule Panty.Collection do
88
68
89
69
"""
90
70
91
- @spec reject([any()], any()) :: [any()]
71
+ @spec reject(list(), any()) :: list()
92
72
93
73
def reject(collection, pattern) do
94
74
Enum.reject(collection, fn el -> el == pattern end)
95
75
end
76
+
77
+ @doc """
78
+ This method is like _.difference except that it accepts iteratee which is invoked for each element of array and values to generate the criterion by which they're compared.
79
+ The order and references of result values are determined by the first array. The iteratee is invoked with one argument
80
+
81
+ ## Examples
82
+ iex> Collection.difference_by([2.1, 1.2], [2.3, 3.4], &Kernel.round/1)
83
+ [1.2]
84
+ iex> Collection.difference_by([%{"x" => 2}, %{"x" => 1}], [%{"x" => 1}], &(&1["x"]))
85
+ [%{"x" => 2}]
86
+
87
+ Iteratee shorthand
88
+
89
+ iex> Collection.difference_by([%{"x" => 2}, %{"x" => 1}], [%{"x" => 1}], "x")
90
+ [%{"x" => 2}]
91
+ iex> Collection.difference_by([%{x: 2}, %{x: 1}], [%{x: 1}], :x)
92
+ [%{x: 2}]
93
+
94
+ """
95
+
96
+ @spec difference_by(list(), list(), (any() -> any())) :: list()
97
+
98
+ def difference_by(list, alist, key) when is_bitstring(key) or is_atom(key) do
99
+ new_alist = alist |> Enum.map(&(&1[key]))
100
+ list
101
+ |> Enum.filter(fn el -> !Enum.member?(new_alist, el[key]) end)
102
+ end
103
+ def difference_by(list, alist, func) when is_function(func) do
104
+ new_alist = alist |> Enum.map(&(func.(&1)))
105
+ list
106
+ |> Enum.filter(fn el -> !Enum.member?(new_alist, func.(el)) end)
107
+ end
108
+
109
+ @doc """
110
+ Return a slice of array excluding elements dropped from the end.
111
+
112
+ ## Examples
113
+ iex> Collection.drop_right_while([1, 2, 3, 4, 5], &(&1 == 4))
114
+ [1, 2, 3]
115
+ iex> Collection.drop_right_while([%{a: 1, b: 2}, %{a: 2, b: 2}], &(&1.a == 2))
116
+ [%{a: 1, b: 2}]
117
+
118
+ """
119
+
120
+ @spec drop_right_while(list(), (... -> boolean)) :: list()
121
+
122
+ def drop_right_while(list, func) when is_function(func) do
123
+ _drop_loop(list, [], func)
124
+ end
125
+ def _drop_loop([], acc, _func), do: acc
126
+ def _drop_loop([h|t], acc, func), do: if func.(h), do: acc, else: _drop_loop(t, acc ++ [h], func)
127
+
128
+ @doc """
129
+ Fills a number of elements of a list with initial value
130
+
131
+ ## Examples
132
+ iex> Collection.fill(5, nil)
133
+ [nil, nil, nil, nil, nil]
134
+ iex> Collection.fill(3, "hi")
135
+ ["hi", "hi", "hi"]
136
+ """
137
+
138
+ @spec fill(integer(), any()) :: [any()]
139
+
140
+ def fill(num, val) when is_number(num), do: for _ <- 1..num, do: val
141
+
142
+ @doc """
143
+ Return a map from a list of pairs
144
+
145
+ ## Examples
146
+ iex> Collection.from_pairs([[:a, 1], [:b, 2]])
147
+ %{a: 1, b: 2}
148
+ iex > Collection.from_pairs([["vn", "Xin chao"], ["us", "hello"]])
149
+ %{"us" => "hello", "vn" => "Xin chao"}
150
+
151
+ """
152
+
153
+ @spec from_pairs(list()) :: map()
154
+
155
+ def from_pairs(list) do
156
+ exc = fn
157
+ (acc, key, val) when is_bitstring(key) or is_atom(key) -> Map.put(acc, key, val)
158
+ (_, _, _) -> throw("Key must be a string or atom.")
159
+ end
160
+ Enum.reduce(list, %{}, fn ([key, val], acc) -> exc.(acc, key, val) end)
161
+ end
162
+
163
+ @doc """
164
+ Find index from right to left.
165
+
166
+ ## Examples
167
+ iex> Collection.last_index_of([1, 1, 3, 4, 2], 4)
168
+ 3
169
+ iex> Collection.last_index_of([1, 9, 3, 1, 2], 4)
170
+ nil
171
+
172
+ """
173
+
174
+ @spec last_index_of(list(), any()) :: integer()
175
+
176
+ def last_index_of(list, el) do
177
+ list
178
+ |> Enum.reverse()
179
+ |> Enum.find_index(&(&1 == el))
180
+ |> case do
181
+ nil -> nil
182
+ idx -> length(list) - idx - 1
183
+ end
184
+ end
185
+
186
+ @doc """
187
+ Same as `last_index_of/2` but search from the index.
188
+
189
+ ## Examples
190
+ iex> Collection.last_index_of([1, 1, 3, 4, 2], 4, 2)
191
+ 3
192
+ iex> Collection.last_index_of("abbcd" |> String.graphemes, "b", 3)
193
+ nil
194
+
195
+ """
196
+
197
+ @spec last_index_of(list(), any(), integer) :: integer()
198
+
199
+ def last_index_of(list, el, from) do
200
+ list = list |> Enum.drop(from)
201
+
202
+ list
203
+ |> Enum.reverse()
204
+ |> Enum.find_index(&(&1 == el))
205
+ |> case do
206
+ nil -> nil
207
+ idx -> length(list) - idx - 1 + from
208
+ end
209
+ end
96
210
end
\ No newline at end of file
changed lib/panty.ex
 
@@ -1,5 +1,5 @@
1
1
defmodule Panty do
2
2
@moduledoc """
3
- Documentation for Panty.
3
+ Documentation for Panty - an utility library for elixir.
4
4
"""
5
5
end
changed lib/string.ex
 
@@ -52,4 +52,25 @@ defmodule Panty.String do
52
52
|> Enum.join("-")
53
53
|> String.downcase
54
54
end
55
+
56
+
57
+ @doc """
58
+ Get index of a substring from a pattern.
59
+
60
+ ## Examples
61
+ iex> Collection.string_find_index("abcdef", "cde")
62
+ 2
63
+ iex> Collection.string_find_index("{% sections 'header' %}", "{% endschema %}")
64
+ nil
65
+
66
+ """
67
+
68
+ @spec substring_index(String.t, String.t) :: integer() | nil
69
+
70
+ def substring_index(pattern, substring) do
71
+ case String.split(pattern, substring, parts: 2) do
72
+ [left, _] -> String.length(left)
73
+ [_] -> nil
74
+ end
75
+ end
55
76
end
\ No newline at end of file
changed mix.exs
 
@@ -5,7 +5,7 @@ defmodule Panty.Mixfile do
5
5
[
6
6
app: :panty,
7
7
name: "Panty",
8
- version: "0.1.2",
8
+ version: "0.1.3",
9
9
elixir: "~> 1.2",
10
10
start_permanent: Mix.env == :prod,
11
11
description: description(),