furi 0.0.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +19 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +7 -0
- data/README.md +115 -8
- data/Rakefile +6 -0
- data/furi.gemspec +13 -14
- data/lib/furi.rb +166 -292
- data/lib/furi/query_token.rb +57 -0
- data/lib/furi/uri.rb +595 -0
- data/lib/furi/utils.rb +16 -0
- data/lib/furi/version.rb +1 -1
- metadata +20 -73
- data/spec/furi_spec.rb +0 -310
- data/spec/spec_helper.rb +0 -75
data/lib/furi/utils.rb
ADDED
data/lib/furi/version.rb
CHANGED
metadata
CHANGED
@@ -1,72 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: furi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bogdan Gusiev
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.7'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.7'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '10.0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '10.0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rspec
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: byebug
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
description: The phylosophy of this gem is to make any URI modification or parsing
|
11
|
+
date: 2021-04-05 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: The philosophy of this gem is to make any URI modification or parsing
|
70
14
|
operation to take only one line of code and never more
|
71
15
|
email:
|
72
16
|
- agresso@gmail.com
|
@@ -74,22 +18,28 @@ executables: []
|
|
74
18
|
extensions: []
|
75
19
|
extra_rdoc_files: []
|
76
20
|
files:
|
21
|
+
- ".github/workflows/ci.yml"
|
77
22
|
- ".gitignore"
|
78
23
|
- ".rspec"
|
24
|
+
- CHANGELOG.md
|
79
25
|
- Gemfile
|
80
26
|
- LICENSE.txt
|
81
27
|
- README.md
|
82
28
|
- Rakefile
|
83
29
|
- furi.gemspec
|
84
30
|
- lib/furi.rb
|
31
|
+
- lib/furi/query_token.rb
|
32
|
+
- lib/furi/uri.rb
|
33
|
+
- lib/furi/utils.rb
|
85
34
|
- lib/furi/version.rb
|
86
|
-
|
87
|
-
- spec/spec_helper.rb
|
88
|
-
homepage: ''
|
35
|
+
homepage: https://github.com/bogdan/furi
|
89
36
|
licenses:
|
90
37
|
- MIT
|
91
|
-
metadata:
|
92
|
-
|
38
|
+
metadata:
|
39
|
+
allowed_push_host: https://rubygems.org
|
40
|
+
homepage_uri: https://github.com/bogdan/furi
|
41
|
+
source_code_uri: https://github.com/bogdan/furi
|
42
|
+
post_install_message:
|
93
43
|
rdoc_options: []
|
94
44
|
require_paths:
|
95
45
|
- lib
|
@@ -97,18 +47,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
97
47
|
requirements:
|
98
48
|
- - ">="
|
99
49
|
- !ruby/object:Gem::Version
|
100
|
-
version:
|
50
|
+
version: 2.4.0
|
101
51
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
52
|
requirements:
|
103
53
|
- - ">="
|
104
54
|
- !ruby/object:Gem::Version
|
105
55
|
version: '0'
|
106
56
|
requirements: []
|
107
|
-
|
108
|
-
|
109
|
-
signing_key:
|
57
|
+
rubygems_version: 3.2.0
|
58
|
+
signing_key:
|
110
59
|
specification_version: 4
|
111
60
|
summary: Make URI processing as easy as it should be
|
112
|
-
test_files:
|
113
|
-
- spec/furi_spec.rb
|
114
|
-
- spec/spec_helper.rb
|
61
|
+
test_files: []
|
data/spec/furi_spec.rb
DELETED
@@ -1,310 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Furi do
|
4
|
-
|
5
|
-
class PartsMatcher
|
6
|
-
|
7
|
-
def initialize(expectation)
|
8
|
-
@expectation = expectation
|
9
|
-
end
|
10
|
-
|
11
|
-
def matches?(text)
|
12
|
-
@uri = Furi.parse(text)
|
13
|
-
@expectation.each do |part, value|
|
14
|
-
if @uri.send(part) != value
|
15
|
-
@unmatched_part = part
|
16
|
-
return false
|
17
|
-
end
|
18
|
-
end
|
19
|
-
return true
|
20
|
-
end
|
21
|
-
|
22
|
-
def failure_message
|
23
|
-
"Expected #{@unmatched_part.inspect} to equal #{@expectation[@unmatched_part].inspect}, but it was #{@uri.send(@unmatched_part).inspect}"
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
class SerializeAs
|
29
|
-
def initialize(expectation)
|
30
|
-
@expectation = expectation
|
31
|
-
if @expectation.is_a?(Array)
|
32
|
-
@expectation = @expectation.map do |item|
|
33
|
-
item.split("=").map {|z| CGI.escape(z.to_s)}.join("=")
|
34
|
-
end.join("&")
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def matches?(hash)
|
39
|
-
@hash = hash
|
40
|
-
Furi.serialize(hash) == @expectation
|
41
|
-
end
|
42
|
-
|
43
|
-
def failure_message
|
44
|
-
"Expected #{@hash.inspect} to serialize as #{@expectation.inspect}, but was serialized as #{Furi.serialize(@hash)}.\n" +
|
45
|
-
"Debug: #{unserialize(@expectation)}, but was serialized as #{unserialize(Furi.serialize(@hash))}"
|
46
|
-
end
|
47
|
-
|
48
|
-
def unserialize(string)
|
49
|
-
string.split("&").map do |z|
|
50
|
-
z.split("=").map do |q|
|
51
|
-
CGI.unescape(q)
|
52
|
-
end
|
53
|
-
end.inspect
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def have_parts(parts)
|
58
|
-
PartsMatcher.new(parts)
|
59
|
-
end
|
60
|
-
|
61
|
-
def serialize_as(value)
|
62
|
-
SerializeAs.new(value)
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
describe "#parse" do
|
68
|
-
it "parses URL without path" do
|
69
|
-
expect("http://gusiev.com").to have_parts(
|
70
|
-
protocol: 'http',
|
71
|
-
hostname: 'gusiev.com',
|
72
|
-
query_string: nil,
|
73
|
-
query: {},
|
74
|
-
path: nil,
|
75
|
-
port: nil,
|
76
|
-
)
|
77
|
-
end
|
78
|
-
|
79
|
-
it "extracts anchor" do
|
80
|
-
expect("http://gusiev.com/posts/index.html?a=b#zz").to have_parts(
|
81
|
-
anchor: 'zz',
|
82
|
-
query_string: 'a=b',
|
83
|
-
path: '/posts/index.html',
|
84
|
-
port: nil,
|
85
|
-
protocol: 'http',
|
86
|
-
)
|
87
|
-
end
|
88
|
-
|
89
|
-
it "works with path without URL" do
|
90
|
-
expect("/posts/index.html").to have_parts(
|
91
|
-
path: '/posts/index.html',
|
92
|
-
hostname: nil,
|
93
|
-
port: nil,
|
94
|
-
protocol: nil,
|
95
|
-
)
|
96
|
-
end
|
97
|
-
|
98
|
-
it "parses uri with user and password" do
|
99
|
-
expect("http://user:pass@gusiev.com").to have_parts(
|
100
|
-
username: 'user',
|
101
|
-
password: 'pass',
|
102
|
-
hostname: 'gusiev.com',
|
103
|
-
query_string: nil,
|
104
|
-
anchor: nil,
|
105
|
-
)
|
106
|
-
end
|
107
|
-
|
108
|
-
it "parses uri with user and without password" do
|
109
|
-
expect("http://user@gusiev.com").to have_parts(
|
110
|
-
username: 'user',
|
111
|
-
password: nil,
|
112
|
-
hostname: 'gusiev.com',
|
113
|
-
query_string: nil,
|
114
|
-
anchor: nil,
|
115
|
-
)
|
116
|
-
end
|
117
|
-
|
118
|
-
|
119
|
-
it "supports aliases" do
|
120
|
-
expect("http://gusiev.com#zz").to have_parts(
|
121
|
-
schema: 'http',
|
122
|
-
fragment: 'zz',
|
123
|
-
)
|
124
|
-
end
|
125
|
-
|
126
|
-
it "parses uri with explicit port and auth data" do
|
127
|
-
expect("http://user:pass@gusiev.com:80").to have_parts(
|
128
|
-
username: 'user',
|
129
|
-
password: 'pass',
|
130
|
-
userinfo: 'user:pass',
|
131
|
-
protocol: 'http',
|
132
|
-
port: 80,
|
133
|
-
query_string: nil,
|
134
|
-
)
|
135
|
-
end
|
136
|
-
it "parses url with query" do
|
137
|
-
expect("/index.html?a=b&c=d").to have_parts(
|
138
|
-
host: nil,
|
139
|
-
query_string: 'a=b&c=d',
|
140
|
-
query: {'a' => 'b', 'c' => 'd'}
|
141
|
-
)
|
142
|
-
end
|
143
|
-
|
144
|
-
it "finds out port if not explicitly defined`" do
|
145
|
-
expect("http://gusiev.com").to have_parts(
|
146
|
-
protocol: 'http',
|
147
|
-
port: nil,
|
148
|
-
"port!" => 80
|
149
|
-
)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
describe ".update" do
|
153
|
-
|
154
|
-
it "support update for query" do
|
155
|
-
expect(Furi.update("/index.html?a=b", query: {c: 'd'})).to eq('/index.html?c=d')
|
156
|
-
end
|
157
|
-
|
158
|
-
it "updates hostname" do
|
159
|
-
expect(Furi.update("www.gusiev.com/index.html", hostname: 'gusiev.com')).to eq('gusiev.com/index.html')
|
160
|
-
expect(Furi.update("/index.html", hostname: 'gusiev.com')).to eq('gusiev.com/index.html')
|
161
|
-
expect(Furi.update("http://www.gusiev.com/index.html", hostname: 'gusiev.com')).to eq('http://gusiev.com/index.html')
|
162
|
-
expect(Furi.update("/index.html", hostname: 'gusiev.com')).to eq('gusiev.com/index.html')
|
163
|
-
end
|
164
|
-
|
165
|
-
it "updates port" do
|
166
|
-
expect(Furi.update("gusiev.com", port: 33)).to eq('gusiev.com:33')
|
167
|
-
expect(Furi.update("gusiev.com/index.html", port: 33)).to eq('gusiev.com:33/index.html')
|
168
|
-
expect(Furi.update("gusiev.com:33/index.html", port: 80)).to eq('gusiev.com:80/index.html')
|
169
|
-
expect(Furi.update("http://gusiev.com:33/index.html", port: 80)).to eq('http://gusiev.com/index.html')
|
170
|
-
end
|
171
|
-
it "updates protocol" do
|
172
|
-
expect(Furi.update("http://gusiev.com", protocol: '')).to eq('//gusiev.com')
|
173
|
-
expect(Furi.update("http://gusiev.com", protocol: nil)).to eq('gusiev.com')
|
174
|
-
expect(Furi.update("http://gusiev.com", protocol: 'https')).to eq('https://gusiev.com')
|
175
|
-
expect(Furi.update("gusiev.com", protocol: 'http')).to eq('http://gusiev.com')
|
176
|
-
expect(Furi.update("gusiev.com", protocol: 'http:')).to eq('http://gusiev.com')
|
177
|
-
expect(Furi.update("gusiev.com", protocol: 'http:/')).to eq('http://gusiev.com')
|
178
|
-
expect(Furi.update("gusiev.com", protocol: 'http://')).to eq('http://gusiev.com')
|
179
|
-
end
|
180
|
-
|
181
|
-
end
|
182
|
-
|
183
|
-
describe ".build" do
|
184
|
-
it "should work correctly" do
|
185
|
-
expect(Furi.build(hostname: 'hello.com')).to eq('hello.com')
|
186
|
-
expect(Furi.build(hostname: 'hello.com', port: 88)).to eq('hello.com:88')
|
187
|
-
expect(Furi.build(hostname: 'hello.com', port: 88)).to eq('hello.com:88')
|
188
|
-
expect(Furi.build(schema: 'https', hostname: 'hello.com', port: 88)).to eq('https://hello.com:88')
|
189
|
-
expect(Furi.build(schema: 'http', hostname: 'hello.com', port: 80)).to eq('http://hello.com')
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
|
194
|
-
describe "serialize" do
|
195
|
-
it "should work" do
|
196
|
-
expect({a: 'b'}).to serialize_as("a=b")
|
197
|
-
expect(a: nil).to serialize_as("a=")
|
198
|
-
expect(nil).to serialize_as("")
|
199
|
-
expect(b: 2, a: 1).to serialize_as("b=2&a=1")
|
200
|
-
expect(a: {b: {c: []}}).to serialize_as("")
|
201
|
-
expect({:a => {:b => 'c'}}).to serialize_as("a%5Bb%5D=c")
|
202
|
-
expect(q: [1,2]).to serialize_as("q%5B%5D=1&q%5B%5D=2")
|
203
|
-
expect(a: {b: [1,2]}).to serialize_as("a%5Bb%5D%5B%5D=1&a%5Bb%5D%5B%5D=2")
|
204
|
-
expect(q: "cowboy hat?").to serialize_as("q=cowboy+hat%3F")
|
205
|
-
expect(a: true).to serialize_as("a=true")
|
206
|
-
expect(a: false).to serialize_as("a=false")
|
207
|
-
expect(a: [nil, 0]).to serialize_as("a%5B%5D=&a%5B%5D=0")
|
208
|
-
expect({f: ["b", 42, "your base"] }).to serialize_as("f%5B%5D=b&f%5B%5D=42&f%5B%5D=your+base")
|
209
|
-
expect({"a[]" => 1 }).to serialize_as("a%5B%5D=1")
|
210
|
-
expect({"a[b]" => [1] }).to serialize_as(["a[b][]=1"])
|
211
|
-
expect("a" => [1, 2], "b" => "blah" ).to serialize_as("a%5B%5D=1&a%5B%5D=2&b=blah")
|
212
|
-
|
213
|
-
expect(a: [1,{c: 2, b: 3}, 4]).to serialize_as(["a[]=1", "a[][c]=2", "a[][b]=3", "a[]=4"])
|
214
|
-
expect(->{
|
215
|
-
Furi.serialize([1,2])
|
216
|
-
}).to raise_error(ArgumentError)
|
217
|
-
expect(->{
|
218
|
-
Furi.serialize(a: [1,[2]])
|
219
|
-
}).to raise_error(ArgumentError)
|
220
|
-
|
221
|
-
|
222
|
-
params = { b:{ c:3, d:[4,5], e:{ x:[6], y:7, z:[8,9] }}};
|
223
|
-
expect(CGI.unescape(Furi.serialize(params))).to eq("b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9")
|
224
|
-
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
describe "parse_nested_query" do
|
229
|
-
it "should work" do
|
230
|
-
Furi.parse_nested_query("foo").
|
231
|
-
should eq "foo" => nil
|
232
|
-
Furi.parse_nested_query("foo=").
|
233
|
-
should eq "foo" => ""
|
234
|
-
Furi.parse_nested_query("foo=bar").
|
235
|
-
should eq "foo" => "bar"
|
236
|
-
Furi.parse_nested_query("foo=\"bar\"").
|
237
|
-
should eq "foo" => "\"bar\""
|
238
|
-
|
239
|
-
Furi.parse_nested_query("foo=bar&foo=quux").
|
240
|
-
should eq "foo" => "quux"
|
241
|
-
Furi.parse_nested_query("foo&foo=").
|
242
|
-
should eq "foo" => ""
|
243
|
-
Furi.parse_nested_query("foo=1&bar=2").
|
244
|
-
should eq "foo" => "1", "bar" => "2"
|
245
|
-
Furi.parse_nested_query("&foo=1&&bar=2").
|
246
|
-
should eq "foo" => "1", "bar" => "2"
|
247
|
-
Furi.parse_nested_query("foo&bar=").
|
248
|
-
should eq "foo" => nil, "bar" => ""
|
249
|
-
Furi.parse_nested_query("foo=bar&baz=").
|
250
|
-
should eq "foo" => "bar", "baz" => ""
|
251
|
-
Furi.parse_nested_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
|
252
|
-
should eq "my weird field" => "q1!2\"'w$5&7/z8)?"
|
253
|
-
|
254
|
-
Furi.parse_nested_query("a=b&pid%3D1234=1023").
|
255
|
-
should eq "pid=1234" => "1023", "a" => "b"
|
256
|
-
|
257
|
-
Furi.parse_nested_query("foo[]").
|
258
|
-
should eq "foo" => [nil]
|
259
|
-
Furi.parse_nested_query("foo[]=").
|
260
|
-
should eq "foo" => [""]
|
261
|
-
Furi.parse_nested_query("foo[]=bar").
|
262
|
-
should eq "foo" => ["bar"]
|
263
|
-
|
264
|
-
Furi.parse_nested_query("foo[]=1&foo[]=2").
|
265
|
-
should eq "foo" => ["1", "2"]
|
266
|
-
Furi.parse_nested_query("foo=bar&baz[]=1&baz[]=2&baz[]=3").
|
267
|
-
should eq "foo" => "bar", "baz" => ["1", "2", "3"]
|
268
|
-
Furi.parse_nested_query("foo[]=bar&baz[]=1&baz[]=2&baz[]=3").
|
269
|
-
should eq "foo" => ["bar"], "baz" => ["1", "2", "3"]
|
270
|
-
|
271
|
-
Furi.parse_nested_query("x[y][z]=1").
|
272
|
-
should eq "x" => {"y" => {"z" => "1"}}
|
273
|
-
Furi.parse_nested_query("x[y][z][]=1").
|
274
|
-
should eq "x" => {"y" => {"z" => ["1"]}}
|
275
|
-
Furi.parse_nested_query("x[y][z]=1&x[y][z]=2").
|
276
|
-
should eq "x" => {"y" => {"z" => "2"}}
|
277
|
-
Furi.parse_nested_query("x[y][z][]=1&x[y][z][]=2").
|
278
|
-
should eq "x" => {"y" => {"z" => ["1", "2"]}}
|
279
|
-
|
280
|
-
Furi.parse_nested_query("x[y][][z]=1").
|
281
|
-
should eq "x" => {"y" => [{"z" => "1"}]}
|
282
|
-
Furi.parse_nested_query("x[y][][z][]=1").
|
283
|
-
should eq "x" => {"y" => [{"z" => ["1"]}]}
|
284
|
-
Furi.parse_nested_query("x[y][][z]=1&x[y][][w]=2").
|
285
|
-
should eq "x" => {"y" => [{"z" => "1", "w" => "2"}]}
|
286
|
-
|
287
|
-
Furi.parse_nested_query("x[y][][v][w]=1").
|
288
|
-
should eq "x" => {"y" => [{"v" => {"w" => "1"}}]}
|
289
|
-
Furi.parse_nested_query("x[y][][z]=1&x[y][][v][w]=2").
|
290
|
-
should eq "x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}
|
291
|
-
|
292
|
-
Furi.parse_nested_query("x[y][][z]=1&x[y][][z]=2").
|
293
|
-
should eq "x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}
|
294
|
-
Furi.parse_nested_query("x[y][][z]=1&x[y][][w]=a&x[y][][z]=2&x[y][][w]=3").
|
295
|
-
should eq "x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}
|
296
|
-
|
297
|
-
lambda { Furi.parse_nested_query("x[y]=1&x[y]z=2") }.
|
298
|
-
should raise_error(TypeError, "expected Hash (got String) for param `y'")
|
299
|
-
|
300
|
-
lambda { Furi.parse_nested_query("x[y]=1&x[]=1") }.
|
301
|
-
should raise_error(TypeError, /expected Array \(got [^)]*\) for param `x'/)
|
302
|
-
|
303
|
-
lambda { Furi.parse_nested_query("x[y]=1&x[y][][w]=2") }.
|
304
|
-
should raise_error(TypeError, "expected Array (got String) for param `y'")
|
305
|
-
|
306
|
-
end
|
307
|
-
|
308
|
-
end
|
309
|
-
|
310
|
-
end
|