deeplink 2.0.0 → 3.0.0
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 +4 -4
- data/CHANGELOG.md +64 -0
- data/README.md +69 -42
- data/lib/deeplink/link.rb +29 -23
- data/lib/deeplink/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5258494e8891ca8dcd0e05f5d19002c981d0d7ec213e96a2a9f446d08e9622e7
|
|
4
|
+
data.tar.gz: 6d80c29a397aa832ca8618d37b9c67dec410cf977072a1b50928aae9c5766bd1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 897d7c31b35d1614539545155dd0403ce703ea34574868ea1ff55a8882c4fa6f203683f77c045b9a013e002cb98278ef138899a27341875416c57b4c3cdc7ef2
|
|
7
|
+
data.tar.gz: 58a3790de63fd53b4535c4ef3bdecdf9e70d13cbf2d9fb8477ccb7f51bbf4fb4b23c09a7fd987279601ba09b763963a578a45de57885904f4762eedd15018dc8
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 3.0.0 (2026-10-20)
|
|
4
|
+
|
|
5
|
+
### Breaking changes
|
|
6
|
+
|
|
7
|
+
- `query` returns decoded values (`a b` instead of `a+b`). Values are encoded only by `to_s`, and
|
|
8
|
+
query keys are now encoded too.
|
|
9
|
+
- `add_query` with a `nil` value adds a parameter without a value (`?flag`) instead of `flag=`.
|
|
10
|
+
|
|
11
|
+
### Fixes
|
|
12
|
+
|
|
13
|
+
- Keep URL fragments (`deep://page#section`), available through `fragment`.
|
|
14
|
+
- Keep query parameters without a value (`?flag`), stored with a `nil` value.
|
|
15
|
+
- Encode query values that are not strings, such as symbols.
|
|
16
|
+
- Parse links without a double slash (`deep:foo`, `deep:/foo`) instead of returning `''`.
|
|
17
|
+
- Parse query values containing `{` or `}` in full.
|
|
18
|
+
|
|
19
|
+
### Development
|
|
20
|
+
|
|
21
|
+
- Add `changelog_uri` to the gem metadata and ship `CHANGELOG.md` with the gem.
|
|
22
|
+
|
|
23
|
+
## 2.0.0 (2026-10-20)
|
|
24
|
+
|
|
25
|
+
### Breaking changes
|
|
26
|
+
|
|
27
|
+
- Require Ruby >= 3.2 (was >= 2.5).
|
|
28
|
+
|
|
29
|
+
### Fixes
|
|
30
|
+
|
|
31
|
+
- Support Ruby 4.0, which removed the CGI library. Query values are encoded exactly as before.
|
|
32
|
+
- Already encoded query values are no longer double encoded (`?q=hello%20world` used to become
|
|
33
|
+
`q=hello%2520world`).
|
|
34
|
+
- `remove_query` without keys returns `nil` instead of raising `NoMethodError`.
|
|
35
|
+
|
|
36
|
+
### Development
|
|
37
|
+
|
|
38
|
+
- CI tests Ruby 3.2, 3.3, 3.4 and 4.0, and runs RuboCop in a separate job.
|
|
39
|
+
- Add Dependabot for GitHub Actions and Bundler.
|
|
40
|
+
- Update development dependencies (RuboCop 1.92, RSpec 3.13, `debug` and `irb` instead of
|
|
41
|
+
`pry-byebug`).
|
|
42
|
+
- `rake` runs the specs and RuboCop.
|
|
43
|
+
|
|
44
|
+
## 1.1.0 (2020-05-01)
|
|
45
|
+
|
|
46
|
+
- Drop support for Ruby 2.1.
|
|
47
|
+
|
|
48
|
+
## 1.0.1 (2018-02-13)
|
|
49
|
+
|
|
50
|
+
- Code style fixes.
|
|
51
|
+
|
|
52
|
+
## 1.0.0 (2016-05-06)
|
|
53
|
+
|
|
54
|
+
- First stable release.
|
|
55
|
+
|
|
56
|
+
## 0.1.4 (2016-04-06)
|
|
57
|
+
|
|
58
|
+
- Fix `NoMethodError` when parsing query parameters on Ruby < 2.1.
|
|
59
|
+
|
|
60
|
+
## 0.1.3 (2015-12-11)
|
|
61
|
+
|
|
62
|
+
- Fix parsing `nil` links.
|
|
63
|
+
- Parse query parameters with unusual characters.
|
|
64
|
+
- Allow removing a list of query parameters.
|
data/README.md
CHANGED
|
@@ -3,96 +3,123 @@
|
|
|
3
3
|
|
|
4
4
|
# Deeplink
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Parse, inspect and build mobile deep links (`myapp://products/42?ref=email`) in an easy way.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Ruby's `URI` treats the first part after `://` as a host, so deep links like `myapp://products/42`
|
|
9
|
+
end up with `products` as the host. This gem reads them the way apps do: a scheme, a path, a query
|
|
10
|
+
and a fragment.
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
This gem needs Ruby >= 3.2.
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
## Installation
|
|
13
15
|
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
+
```sh
|
|
17
|
+
bundle add deeplink
|
|
16
18
|
```
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
$ bundle
|
|
21
|
-
|
|
22
|
-
Or install it yourself as:
|
|
20
|
+
Or install it yourself:
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
```sh
|
|
23
|
+
gem install deeplink
|
|
24
|
+
```
|
|
25
25
|
|
|
26
26
|
## Usage
|
|
27
27
|
|
|
28
28
|
### Parsing a deep link
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Call `Deeplink.parse` with a deep link string to read its scheme and path.
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
deeplink = Deeplink.parse('myshop://products/42')
|
|
34
|
+
|
|
35
|
+
deeplink.scheme # => "myshop"
|
|
36
|
+
deeplink.path # => "/products/42"
|
|
37
|
+
deeplink.to_s # => "myshop://products/42"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Links without a double slash are supported too:
|
|
31
41
|
|
|
32
42
|
```ruby
|
|
33
|
-
deeplink = Deeplink.parse('
|
|
43
|
+
deeplink = Deeplink.parse('sms:+351910000000?body=hello')
|
|
34
44
|
|
|
35
|
-
deeplink.scheme # => "
|
|
36
|
-
deeplink.path # => "
|
|
37
|
-
deeplink.to_s # => "
|
|
45
|
+
deeplink.scheme # => "sms"
|
|
46
|
+
deeplink.path # => "+351910000000"
|
|
47
|
+
deeplink.to_s # => "sms:+351910000000?body=hello"
|
|
38
48
|
```
|
|
39
49
|
|
|
40
50
|
### Query string
|
|
41
51
|
|
|
42
|
-
|
|
52
|
+
Use `query` to read the query parameters, and `query?` to check whether there are any.
|
|
43
53
|
|
|
44
54
|
```ruby
|
|
45
|
-
deeplink = Deeplink.parse('
|
|
55
|
+
deeplink = Deeplink.parse('myshop://products/42?ref=email')
|
|
46
56
|
|
|
47
|
-
deeplink.query
|
|
57
|
+
deeplink.query # => { ref: "email" }
|
|
58
|
+
deeplink.query? # => true
|
|
48
59
|
```
|
|
49
60
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
You can add one or more query parameters sending a Hash to `add_query`.
|
|
61
|
+
Values are stored decoded and only encoded again by `to_s`. Parameters without a value get a `nil`
|
|
62
|
+
value.
|
|
53
63
|
|
|
54
64
|
```ruby
|
|
55
|
-
deeplink = Deeplink.parse('
|
|
65
|
+
deeplink = Deeplink.parse('myshop://search?q=running%20shoes&in_stock')
|
|
66
|
+
|
|
67
|
+
deeplink.query # => { q: "running shoes", in_stock: nil }
|
|
68
|
+
deeplink.to_s # => "myshop://search?q=running+shoes&in_stock"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### Adding query parameters
|
|
56
72
|
|
|
57
|
-
|
|
58
|
-
deeplink.to_s # => "foursquare://checkins/20982?foo=bar"
|
|
73
|
+
Send a Hash with one or more parameters to `add_query`. Values are converted to strings.
|
|
59
74
|
|
|
60
|
-
|
|
75
|
+
```ruby
|
|
76
|
+
deeplink = Deeplink.parse('myshop://cart')
|
|
61
77
|
|
|
62
|
-
deeplink.add_query(
|
|
63
|
-
deeplink.to_s
|
|
78
|
+
deeplink.add_query(coupon: 'SUMMER 10', items: 3) # => { coupon: "SUMMER 10", items: "3" }
|
|
79
|
+
deeplink.to_s # => "myshop://cart?coupon=SUMMER+10&items=3"
|
|
64
80
|
```
|
|
65
81
|
|
|
66
|
-
#### Removing
|
|
82
|
+
#### Removing query parameters
|
|
67
83
|
|
|
68
|
-
|
|
69
|
-
|
|
84
|
+
Call `remove_query` with the key (or list of keys) to remove. It returns the value of the deleted
|
|
85
|
+
key(s).
|
|
70
86
|
|
|
71
87
|
```ruby
|
|
72
|
-
deeplink = Deeplink.parse('
|
|
88
|
+
deeplink = Deeplink.parse('myshop://products/42?ref=email&utm_source=newsletter')
|
|
89
|
+
|
|
90
|
+
deeplink.remove_query(:utm_source) # => "newsletter"
|
|
91
|
+
deeplink.to_s # => "myshop://products/42?ref=email"
|
|
73
92
|
|
|
74
|
-
deeplink.remove_query(:
|
|
75
|
-
deeplink.to_s
|
|
93
|
+
deeplink.remove_query(:ref, :missing) # => ["email", nil]
|
|
94
|
+
deeplink.to_s # => "myshop://products/42"
|
|
76
95
|
```
|
|
77
96
|
|
|
97
|
+
### Fragment
|
|
98
|
+
|
|
99
|
+
The fragment is available through `fragment`, and is kept as given (percent-encoded).
|
|
100
|
+
|
|
78
101
|
```ruby
|
|
79
|
-
deeplink = Deeplink.parse('
|
|
102
|
+
deeplink = Deeplink.parse('myshop://products/42#reviews')
|
|
80
103
|
|
|
81
|
-
deeplink.
|
|
82
|
-
deeplink.to_s
|
|
104
|
+
deeplink.fragment # => "reviews"
|
|
105
|
+
deeplink.to_s # => "myshop://products/42#reviews"
|
|
83
106
|
```
|
|
84
107
|
|
|
85
108
|
## Development
|
|
86
109
|
|
|
87
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake`
|
|
110
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake`
|
|
111
|
+
to run the tests and RuboCop. You can also run `bin/console` for an interactive prompt that will
|
|
112
|
+
allow you to experiment.
|
|
88
113
|
|
|
89
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new
|
|
114
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new
|
|
115
|
+
version, update the version number in `version.rb` and `CHANGELOG.md`, and then run
|
|
116
|
+
`bundle exec rake release`, which will create a git tag for the version, push git commits and tags,
|
|
117
|
+
and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
90
118
|
|
|
91
119
|
## Contributing
|
|
92
120
|
|
|
93
121
|
Bug reports and pull requests are welcome on GitHub at https://github.com/rikas/deeplink.
|
|
94
122
|
|
|
95
|
-
|
|
96
123
|
## License
|
|
97
124
|
|
|
98
|
-
The gem is available as open source under the terms of the [MIT License](
|
|
125
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/lib/deeplink/link.rb
CHANGED
|
@@ -11,9 +11,11 @@ end
|
|
|
11
11
|
|
|
12
12
|
module Deeplink
|
|
13
13
|
class Link
|
|
14
|
-
|
|
14
|
+
# The fragment is kept as given, so it should already be percent-encoded.
|
|
15
|
+
attr_accessor :scheme, :path, :fragment
|
|
15
16
|
|
|
16
|
-
# To add and remove items to the
|
|
17
|
+
# Query values are stored decoded and only encoded by #to_s. To add and remove items to the
|
|
18
|
+
# query string use #add_query and #remove_query.
|
|
17
19
|
attr_reader :query
|
|
18
20
|
|
|
19
21
|
def initialize(uri)
|
|
@@ -22,9 +24,12 @@ module Deeplink
|
|
|
22
24
|
uri = parse(uri)
|
|
23
25
|
|
|
24
26
|
self.scheme = uri.scheme
|
|
25
|
-
self.
|
|
27
|
+
self.fragment = uri.fragment
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
# Links without "//" (e.g. "deep:foo?a=1") are opaque, and URI leaves the query in there.
|
|
30
|
+
self.path, query_string = uri.opaque ? uri.opaque.split('?', 2) : [uri.path, uri.query]
|
|
31
|
+
|
|
32
|
+
@query = parse_query(query_string) if query_string
|
|
28
33
|
end
|
|
29
34
|
|
|
30
35
|
# Add query parameters to the link. You can add one or more parameters since this method
|
|
@@ -37,6 +42,8 @@ module Deeplink
|
|
|
37
42
|
# deeplink.add_query(lat: 38.7179233, lon: -9.150129)
|
|
38
43
|
#
|
|
39
44
|
# deeplink.to_s # => "link://directions?lat=38.7179233&lon=-9.150129"
|
|
45
|
+
#
|
|
46
|
+
# Values are converted to strings. A nil value adds a parameter without a value ("?flag").
|
|
40
47
|
def add_query(hash)
|
|
41
48
|
@query ||= {}
|
|
42
49
|
|
|
@@ -84,13 +91,9 @@ module Deeplink
|
|
|
84
91
|
def to_s
|
|
85
92
|
return '' unless scheme && path
|
|
86
93
|
|
|
87
|
-
uri = "#{scheme}:/#{path}"
|
|
88
|
-
|
|
89
|
-
if
|
|
90
|
-
query_string = query.map { |key, value| "#{key}=#{value}" }.join('&')
|
|
91
|
-
|
|
92
|
-
uri += "?#{query_string}"
|
|
93
|
-
end
|
|
94
|
+
uri = @double_slash ? "#{scheme}:/#{path}" : "#{scheme}:#{path}"
|
|
95
|
+
uri += "?#{query_string}" if query?
|
|
96
|
+
uri += "##{fragment}" if fragment
|
|
94
97
|
|
|
95
98
|
uri
|
|
96
99
|
end
|
|
@@ -98,31 +101,34 @@ module Deeplink
|
|
|
98
101
|
private
|
|
99
102
|
|
|
100
103
|
def parse(original_uri)
|
|
104
|
+
@double_slash = original_uri.match?(%r{\A[^:/?#]+://})
|
|
105
|
+
|
|
101
106
|
# Because URI is dumb and thinks that every uri needs to have a host. Adding an extra slash
|
|
102
107
|
# we are basically tricking URI to think that host is nil (and avoid errors).
|
|
103
|
-
uri = original_uri.sub(
|
|
108
|
+
uri = @double_slash ? original_uri.sub('://', ':///') : original_uri
|
|
104
109
|
|
|
105
110
|
URI.parse(uri)
|
|
106
111
|
end
|
|
107
112
|
|
|
108
113
|
def sanitize(hash)
|
|
109
|
-
|
|
114
|
+
hash.to_h { |key, value| [key.to_sym, value&.to_s] }
|
|
115
|
+
end
|
|
110
116
|
|
|
111
|
-
|
|
112
|
-
|
|
117
|
+
def parse_query(query_str)
|
|
118
|
+
query_str.split('&').each_with_object({}) do |pair, params|
|
|
119
|
+
key, value = pair.split('=', 2)
|
|
120
|
+
next if key.nil? || key.empty?
|
|
113
121
|
|
|
114
|
-
|
|
122
|
+
params[CGI.unescape(key).to_sym] = value && CGI.unescape(value)
|
|
115
123
|
end
|
|
116
|
-
|
|
117
|
-
sanitized
|
|
118
124
|
end
|
|
119
125
|
|
|
120
|
-
def
|
|
121
|
-
|
|
126
|
+
def query_string
|
|
127
|
+
query.map do |key, value|
|
|
128
|
+
key = CGI.escape(key.to_s)
|
|
122
129
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
query_str.scan(/([^&=]+)=([^&{}#]*)/).to_h { |key, value| [key, CGI.unescape(value)] }
|
|
130
|
+
value.nil? ? key : "#{key}=#{CGI.escape(value)}"
|
|
131
|
+
end.join('&')
|
|
126
132
|
end
|
|
127
133
|
end
|
|
128
134
|
end
|
data/lib/deeplink/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: deeplink
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ricardo Otero
|
|
@@ -16,6 +16,7 @@ executables: []
|
|
|
16
16
|
extensions: []
|
|
17
17
|
extra_rdoc_files: []
|
|
18
18
|
files:
|
|
19
|
+
- CHANGELOG.md
|
|
19
20
|
- LICENSE.txt
|
|
20
21
|
- README.md
|
|
21
22
|
- lib/deeplink.rb
|
|
@@ -27,6 +28,7 @@ licenses:
|
|
|
27
28
|
metadata:
|
|
28
29
|
source_code_uri: https://github.com/rikas/deeplink
|
|
29
30
|
bug_tracker_uri: https://github.com/rikas/deeplink/issues
|
|
31
|
+
changelog_uri: https://github.com/rikas/deeplink/blob/main/CHANGELOG.md
|
|
30
32
|
rubygems_mfa_required: 'true'
|
|
31
33
|
rdoc_options: []
|
|
32
34
|
require_paths:
|