Skip to content

Commit 6715473

Browse files
author
José Valim
committed
Add Path.relative and Path.type
1 parent ba528f0 commit 6715473

File tree

5 files changed

+165
-15
lines changed

5 files changed

+165
-15
lines changed

lib/elixir/lib/code.ex

+1-3
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ defmodule Code do
267267
For compiling many files at once, check `Kernel.ParallelCompiler`.
268268
"""
269269
def compile_string(string, file // "nofile") when is_binary(file) do
270-
:elixir_compiler.string :unicode.characters_to_list(string), to_binary(file)
270+
:elixir_compiler.string :unicode.characters_to_list(string), file
271271
end
272272

273273
@doc """
@@ -363,8 +363,6 @@ defmodule Code do
363363
# Finds the file given the relative_to path.
364364
# If the file is found, returns its path in binary, fails otherwise.
365365
defp find_file(file, relative_to) do
366-
file = to_binary(file)
367-
368366
file = if relative_to do
369367
Path.expand(file, relative_to)
370368
else

lib/elixir/lib/path.ex

+89
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,95 @@ defmodule Path do
8888
normalize FN.absname(FN.absname(path, relative_to), get_cwd(path))
8989
end
9090

91+
@doc """
92+
Returns the path type.
93+
94+
## Unix examples
95+
96+
Path.type("/usr/local/bin") #=> :absolute
97+
Path.type("usr/local/bin") #=> :relative
98+
Path.type("../usr/local/bin") #=> :relative
99+
100+
## Windows examples
101+
102+
Path.type("D:/usr/local/bin") #=> :absolute
103+
Path.type("usr/local/bin") #=> :relative
104+
Path.type("D:bar.ex") #=> :volumerelative
105+
Path.type("/bar/foo.ex") #=> :volumerelative
106+
107+
"""
108+
def type(name) when is_list(name) or is_binary(name) do
109+
case :os.type() do
110+
{ :unix, _ } -> unix_pathtype(name)
111+
{ :win32, _ } -> win32_pathtype(name)
112+
end |> elem(0)
113+
end
114+
115+
@doc """
116+
Forces the path to be a relative path.
117+
118+
## Unix examples
119+
120+
Path.relative("/usr/local/bin") #=> "usr/local/bin"
121+
Path.relative("usr/local/bin") #=> "usr/local/bin"
122+
Path.relative("../usr/local/bin") #=> "../usr/local/bin"
123+
124+
## Windows examples
125+
126+
Path.relative("D:/usr/local/bin") #=> "usr/local/bin"
127+
Path.relative("usr/local/bin") #=> "usr/local/bin"
128+
Path.relative("D:bar.ex") #=> "bar.ex"
129+
Path.relative("/bar/foo.ex") #=> "bar/foo.ex"
130+
131+
"""
132+
def relative(name) do
133+
case :os.type() do
134+
{ :unix, _ } -> unix_pathtype(name)
135+
{ :win32, _ } -> win32_pathtype(name)
136+
end |> elem(1)
137+
end
138+
139+
defp unix_pathtype(<<?/, relative :: binary>>), do:
140+
{ :absolute, relative }
141+
defp unix_pathtype([?/|relative]), do:
142+
{ :absolute, relative }
143+
defp unix_pathtype([list|rest]) when is_list(list), do:
144+
unix_pathtype(list ++ rest)
145+
defp unix_pathtype([atom|rest]) when is_atom(atom), do:
146+
unix_pathtype(atom_to_list(atom) ++ rest)
147+
defp unix_pathtype(relative), do:
148+
{ :relative, relative }
149+
150+
@slash [?/, ?\\]
151+
152+
defp win32_pathtype([list|rest]) when is_list(list), do:
153+
win32_pathtype(list++rest)
154+
defp win32_pathtype([atom|rest]) when is_atom(atom), do:
155+
win32_pathtype(atom_to_list(atom)++rest)
156+
defp win32_pathtype([char, list|rest]) when is_list(list), do:
157+
win32_pathtype([char|list++rest])
158+
defp win32_pathtype(<<c1, c2, relative :: binary>>) when c1 in @slash and c2 in @slash, do:
159+
{ :absolute, relative }
160+
defp win32_pathtype(<<c, relative :: binary>>) when c in @slash, do:
161+
{ :volumerelative, relative }
162+
defp win32_pathtype(<<_letter, ?:, c, relative :: binary>>) when c in @slash, do:
163+
{ :absolute, relative }
164+
defp win32_pathtype(<<_letter, ?:, relative :: binary>>), do:
165+
{ :volumerelative, relative }
166+
167+
defp win32_pathtype([c1, c2 | relative]) when c1 in @slash and c2 in @slash, do:
168+
{ :absolute, relative }
169+
defp win32_pathtype([c | relative]) when c in @slash, do:
170+
{ :volumerelative, relative }
171+
defp win32_pathtype([c1, c2, list|rest]) when is_list(list), do:
172+
win32_pathtype([c1, c2|list++rest])
173+
defp win32_pathtype([_letter, ?:, c | relative]) when c in @slash, do:
174+
{ :absolute, relative }
175+
defp win32_pathtype([_letter, ?: | relative]), do:
176+
{ :volumerelative, relative }
177+
defp win32_pathtype(relative), do:
178+
{ :relative, relative }
179+
91180
@doc """
92181
Returns the given `path` relative to the given `from` path.
93182

lib/elixir/lib/uri.ex

+8-8
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ defmodule URI do
2828
2929
Use decoder/1 if you want to customize or iterate each value manually.
3030
"""
31-
def decode_query(q, dict // HashDict.new) do
31+
def decode_query(q, dict // HashDict.new) when is_binary(q) do
3232
Enum.reduce query_decoder(q), dict, fn({ k, v }, acc) -> Dict.put(acc, k, v) end
3333
end
3434

3535
@doc """
3636
Returns an iterator function over the query string that decodes
3737
the query string in steps.
3838
"""
39-
def query_decoder(q) do
40-
fn -> { do_decoder(&1), to_binary(q) } end
39+
def query_decoder(q) when is_binary(q) do
40+
fn -> { do_decoder(&1), q } end
4141
end
4242

4343
defp do_decoder("") do
@@ -123,10 +123,10 @@ defmodule URI do
123123
for that particular scheme. Take a look at URI.HTTPS for an
124124
example of one of these extension modules.
125125
"""
126-
def parse(s) do
126+
def parse(s) when is_binary(s) do
127127
# From http://tools.ietf.org/html/rfc3986#appendix-B
128128
regex = %r/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/
129-
parts = nillify(Regex.run(regex, to_binary(s)))
129+
parts = nillify(Regex.run(regex, s))
130130

131131
destructure [_, _, scheme, _, authority, path, _, query, _, fragment], parts
132132
{ userinfo, host, port } = split_authority(authority)
@@ -144,12 +144,12 @@ defmodule URI do
144144
if scheme do
145145
module =
146146
try do
147-
Module.safe_concat(URI, :string.to_upper(binary_to_list(scheme)))
147+
Module.safe_concat(URI, String.upcase(scheme))
148148
rescue
149149
ArgumentError -> nil
150150
end
151151

152-
if module && match?({:module,^module}, Code.ensure_loaded(module)) do
152+
if module && Code.ensure_loaded?(module) do
153153
module.parse(default_port(info, module))
154154
else
155155
info
@@ -168,7 +168,7 @@ defmodule URI do
168168
s = s || ""
169169
components = Regex.run %r/(^(.*)@)?([^:]*)(:(\d*))?/, s
170170
destructure [_, _, userinfo, host, _, port], nillify(components)
171-
port = if port, do: list_to_integer(binary_to_list(port))
171+
port = if port, do: binary_to_integer(port)
172172
{ userinfo, host, port }
173173
end
174174

lib/elixir/test/elixir/path_test.exs

+67
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,73 @@ defmodule PathTest do
1111
end
1212
end
1313

14+
case :os.type do
15+
{ :unix, _ } ->
16+
test :relative do
17+
assert Path.relative("/usr/local/bin") == "usr/local/bin"
18+
assert Path.relative("usr/local/bin") == "usr/local/bin"
19+
assert Path.relative("../usr/local/bin") == "../usr/local/bin"
20+
21+
assert Path.relative('/usr/local/bin') == 'usr/local/bin'
22+
assert Path.relative('usr/local/bin') == 'usr/local/bin'
23+
assert Path.relative('../usr/local/bin') == '../usr/local/bin'
24+
25+
assert List.flatten(Path.relative(['/usr/', 'local/bin'])) == 'usr/local/bin'
26+
assert List.flatten(Path.relative(['usr/', 'local/bin'])) == 'usr/local/bin'
27+
assert List.flatten(Path.relative(['../usr', '/local/bin'])) == '../usr/local/bin'
28+
end
29+
30+
test :type do
31+
assert Path.type("/usr/local/bin") == :absolute
32+
assert Path.type("usr/local/bin") == :relative
33+
assert Path.type("../usr/local/bin") == :relative
34+
35+
assert Path.type('/usr/local/bin') == :absolute
36+
assert Path.type('usr/local/bin') == :relative
37+
assert Path.type('../usr/local/bin') == :relative
38+
39+
assert Path.type(['/usr/', 'local/bin']) == :absolute
40+
assert Path.type(['usr/', 'local/bin']) == :relative
41+
assert Path.type(['../usr', '/local/bin']) == :relative
42+
end
43+
{ :win32, _ } ->
44+
test :relative do
45+
assert Path.relative("C:/usr/local/bin") == "usr/local/bin"
46+
assert Path.relative("C:\\usr\\local\\bin") == "usr\\local\\bin"
47+
assert Path.relative("C:usr\\local\\bin") == "usr\\local\\bin"
48+
49+
assert Path.relative("/usr/local/bin") == "usr/local/bin"
50+
assert Path.relative("usr/local/bin") == "usr/local/bin"
51+
assert Path.relative("../usr/local/bin") == "../usr/local/bin"
52+
53+
assert Path.relative('/usr/local/bin') == 'usr/local/bin'
54+
assert Path.relative('usr/local/bin') == 'usr/local/bin'
55+
assert Path.relative('../usr/local/bin') == '../usr/local/bin'
56+
57+
assert List.flatten(Path.relative(['/usr/', 'local/bin'])) == 'usr/local/bin'
58+
assert List.flatten(Path.relative(['usr/', 'local/bin'])) == 'usr/local/bin'
59+
assert List.flatten(Path.relative(['../usr', '/local/bin'])) == '../usr/local/bin'
60+
end
61+
62+
test :type do
63+
assert Path.type("C:/usr/local/bin") == :absolute
64+
assert Path.type("C:\\usr\\local\\bin") == :absolute
65+
assert Path.type("C:usr\\local\\bin") == :volumerelative
66+
67+
assert Path.type("/usr/local/bin") == :absolute
68+
assert Path.type("usr/local/bin") == :relative
69+
assert Path.type("../usr/local/bin") == :relative
70+
71+
assert Path.type('/usr/local/bin') == :absolute
72+
assert Path.type('usr/local/bin') == :relative
73+
assert Path.type('../usr/local/bin') == :relative
74+
75+
assert Path.type(['/usr/', 'local/bin']) == :absolute
76+
assert Path.type(['usr/', 'local/bin']) == :relative
77+
assert Path.type(['../usr', '/local/bin']) == :relative
78+
end
79+
end
80+
1481
test :absname_with_binary do
1582
assert Path.absname("/foo/bar") == "/foo/bar"
1683
assert Path.absname("/foo/bar/") == "/foo/bar"

lib/elixir/test/elixir/uri_test.exs

-4
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,6 @@ defmodule URITest do
117117
URI.parse("http://foo.com:4444")
118118
end
119119

120-
test :parse_char_list do
121-
assert "/" == URI.parse('/').path
122-
end
123-
124120
test :parse_bad_uris do
125121
assert URI.parse("https:??@?F?@#>F//23/")
126122
assert URI.parse("")

0 commit comments

Comments
 (0)