linkhum 0.0.1
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 +15 -0
- data/.dokaz +1 -0
- data/LICENSE.txt +22 -0
- data/README.md +191 -0
- data/lib/linkhum.rb +111 -0
- data/linkhum.gemspec +32 -0
- metadata +134 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NDZmOTk1OTg3ZjU2MzYxMTc2ZTA1ZDM1YjM4NmI2NWJlYzdkMWUyYQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MmFjMWJlOTk3YjM5MGEyOTkzNWE2Y2E5NzYwZTFmM2U1Yjc5MjQwNw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZGE1YTI2MzFmY2E3OGY4OTJkNTg2Mjk5YzI3ZTFjZDAzNmFkNmI0MTMyMzVh
|
10
|
+
MTJjMjgzZGU0MjYxMjZiNWRkYTZmYjYzOGVhY2U1ZmU0NWU4MzI3ZjQ5YzIx
|
11
|
+
MjI1MTU4ZTM4NTAyMjc1N2Y3MzU2NGE2NGQzZGFhNjdlOTZkYjI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NzcwZjRmNDcwYTc4OTVjNTY4OTY2NTQ5OTg3NWIwZjZhOGU5MWFkOTExNGVm
|
14
|
+
MThkNDAzYmFlMjRkYTkwNWNiMWE0MTk3NWY1NzBmM2U4NGQ5NjY0ODA2MmFi
|
15
|
+
NGRjMGFkNzM0ZjY2NjU3NzRhZDNkMjEwNzYyMWI5YmZkYWJiYjY=
|
data/.dokaz
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require ./spec/dokaz_helper
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014-15 Victor 'Zverok' Shepelev
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
# LinkHum
|
2
|
+
|
3
|
+
**LinkHum** (aka "Links Humana") is URL auto-linker for user-entered texts.
|
4
|
+
It tries hard to do the most reasonable thing even in complex cases.
|
5
|
+
|
6
|
+
It will be useful for sites with plain-text user input
|
7
|
+
|
8
|
+
Features:
|
9
|
+
* auto-links URL;
|
10
|
+
* very accurate detection of punctiations inside and outside of URL;
|
11
|
+
* excessive tests set for complex (yet real-life) texts with URLs;
|
12
|
+
* customizable behavior.
|
13
|
+
|
14
|
+
**NB**: the original algo was written by [squadette](https://github.com/squadette)
|
15
|
+
and the test cases provided by users of _some secret social network_.
|
16
|
+
Just gemifying this (on behalf of original author).
|
17
|
+
|
18
|
+
## Install
|
19
|
+
|
20
|
+
```
|
21
|
+
[sudo] gem install linkhum
|
22
|
+
```
|
23
|
+
|
24
|
+
Or in your Gemfile
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
gem 'linkhum'
|
28
|
+
```
|
29
|
+
|
30
|
+
And then
|
31
|
+
|
32
|
+
```
|
33
|
+
bundle install
|
34
|
+
```
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
As simple as:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
LinkHum.urlify("Please look at http://github.com/zverok/linkhum, it's awesome!")
|
42
|
+
# => 'Please look at <a href="http://github.com/zverok/linkhum">http://github.com/zverok/linkhum</a>, it's awesome!'
|
43
|
+
```
|
44
|
+
|
45
|
+
## Showcase
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
# Doesn't touch punctuations outside:
|
49
|
+
LinkHum.urlify('http://slashdot.org, or http://lwn.net? They say, "just http://google.com"')
|
50
|
+
# => "<a href='http://slashdot.org'>http://slashdot.org</a>, or <a href='http://lwn.net'>http://lwn.net</a>? They say, \"just <a href='http://google.com'>http://google.com</a>\""
|
51
|
+
|
52
|
+
# But processes it inside:
|
53
|
+
LinkHum.urlify('Watch this: https://www.youtube.com/watch?v=Q9Dv4Hmf_O8')
|
54
|
+
# => "Watch this: <a href='https://www.youtube.com/watch?v=Q9Dv4Hmf_O8'>https://www.youtube.com/watch?v=Q9Dv4Hmf_O8</a>"
|
55
|
+
|
56
|
+
# Understands parentheses:
|
57
|
+
LinkHum.urlify("It's a movie: https://en.wikipedia.org/wiki/Hours_(2013_film) It's just parens: (https://www.youtube.com/watch?v=Q9Dv4Hmf_O8)")
|
58
|
+
# => "It's a movie: <a href='https://en.wikipedia.org/wiki/Hours_(2013_film)'>https://en.wikipedia.org/wiki/Hours_(2013_film)</a> It's just parens: (<a href='https://www.youtube.com/watch?v=Q9Dv4Hmf_O8'>https://www.youtube.com/watch?v=Q9Dv4Hmf_O8</a>)"
|
59
|
+
|
60
|
+
# URL shortening:
|
61
|
+
LinkHum.urlify("It's too long: http://www.booking.com/searchresults.ru.html?sid=28c7356c8d0fb6d81de3a45eff97e0fe;dcid=4;bb_asr=2&class_interval=1&csflt=%7B%7D&dest_id=-2167973&dest_type=city&group_adults=2&group_children=0&idf=1&label_click=undef&no_rooms=1&offset=0&review_score_group=empty&score_min=0&si=ai%2Cco%2Cci%2Cre%2Cdi&src=index&ss=Lisbon%2C%20Lisbon%20Region%2C%20Portugal&ss_raw=Lisbon&ssb=empty")
|
62
|
+
# => "It's too long: <a href='http://www.booking.com/searchresults.ru.html?sid=28c7356c8d0fb6d81de3a45eff97e0fe;dcid=4;bb_asr=2&class_interval=1&csflt=%7B%7D&dest_id=-2167973&dest_type=city&group_adults=2&group_children=0&idf=1&label_click=undef&no_rooms=1&offset=0&review_score_group=empty&score_min=0&si=ai,co,ci,re,di&src=index&ss=Lisbon,%20Lisbon%20Region,%20Portugal&ss_raw=Lisbon&ssb=empty'>http://www.booking.com/searchresults.ru.html?sid=28c7356c8d0f...</a>"
|
63
|
+
|
64
|
+
# It's customizable:
|
65
|
+
LinkHum.urlify(
|
66
|
+
"It's too long: http://www.booking.com/searchresults.ru.html?sid=28c7356c8d0fb6d81de3a45eff97e0fe;dcid=4;bb_asr=2&class_interval=1&csflt=%7B%7D&dest_id=-2167973&dest_type=city&group_adults=2&group_children=0&idf=1&label_click=undef&no_rooms=1&offset=0&review_score_group=empty&score_min=0&si=ai%2Cco%2Cci%2Cre%2Cdi&src=index&ss=Lisbon%2C%20Lisbon%20Region%2C%20Portugal&ss_raw=Lisbon&ssb=empty",
|
67
|
+
max_length: 20)
|
68
|
+
# =>
|
69
|
+
|
70
|
+
# International domains and Non-ASCII paths:
|
71
|
+
LinkHum.urlify("Domain: http://www.詹姆斯.com/, and path: https://ru.wikipedia.org/wiki/Эффект_Даннинга_—_Крюгера")
|
72
|
+
# => "Domain: <a href='http://www.詹姆斯.com/'>http://www.詹姆斯.com/</a>, and path: <a href='https://ru.wikipedia.org/wiki/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82_%D0%94%D0%B0%D0%BD%D0%BD%D0%B8%D0%BD%D0%B3%D0%B0_%E2%80%94_%D0%9A%D1%80%D1%8E%D0%B3%D0%B5%D1%80%D0%B0'>https://ru.wikipedia.org/wiki/Эффект_Даннинга_—_Крюгера</a>"
|
73
|
+
|
74
|
+
# Look, ma, no XSS!
|
75
|
+
LinkHum.urlify('http://example.com/foo?">here.</a><script>window.alert("wow");</script>')
|
76
|
+
# => "<a href='http://example.com/foo?%22%3Ehere.%3C/a%3E%3Cscript%3Ewindow.alert(%22wow%22);%3C/script%3E'>http://example.com/foo?\">here.</a><script>window.alert(\"wow\")...</a>"
|
77
|
+
```
|
78
|
+
|
79
|
+
## Customization
|
80
|
+
|
81
|
+
### On the fly
|
82
|
+
|
83
|
+
Custom URL params:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
LinkHum.urlify("http://oursite.com/posts/12345 has been mentioned at http://cnn.com"){
|
87
|
+
|uri|
|
88
|
+
uri.host == 'oursite.com' ? {} : {target: '_blank'}
|
89
|
+
}
|
90
|
+
# => "<a href='http://oursite.com/posts/12345'>http://oursite.com/posts/12345</a> has been mentioned at <a href='http://cnn.com' target='_blank'>http://cnn.com</a>"
|
91
|
+
```
|
92
|
+
|
93
|
+
Provided block should receive an instance of `Addressable::URI` and
|
94
|
+
return hash of additional link attributes. You can use it for opening
|
95
|
+
foreign links in new tab, or for styling them different (Wikipedia-style),
|
96
|
+
or to provide special icons for links to Youtube, Wikipedia and Google...
|
97
|
+
Up to you
|
98
|
+
|
99
|
+
### Define your own LinkHum
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
class MyLinks < LinkHum
|
103
|
+
def link_attrs(uri)
|
104
|
+
{target: '_blank'} unless uri.host == 'oursite.com'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
MyLinks.urlify("http://oursite.com/posts/12345 has been mentioned at http://cnn.com")
|
109
|
+
# => "<a href='http://oursite.com/posts/12345'>http://oursite.com/posts/12345</a> has been mentioned at <a href='http://cnn.com' target='_blank'>http://cnn.com</a>"
|
110
|
+
```
|
111
|
+
|
112
|
+
You can also define special strings, which should also became URLs on your
|
113
|
+
site:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
class MyLinks < LinkHum
|
117
|
+
special /@(\S+)\b/ do |username|
|
118
|
+
"http://oursite/users/#{username}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
MyLinks.urlify("Hey, @jude!")
|
123
|
+
# => "Hey, <a href='http://oursite/users/jude'>@jude</a>!"
|
124
|
+
|
125
|
+
# nil or false means no replacements:
|
126
|
+
class MyLinks < LinkHum
|
127
|
+
special /@(\S+)\b/ do |username|
|
128
|
+
"http://oursite/users/#{username}" if User.where(name: username).exists?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
MyLinks.urlify("So, our @dude and @unknownguy walk into a bar...")
|
133
|
+
# => "So, our <a href='http://oursite/users/dude'>@dude</a> and @unknownguy walk into a bar..."
|
134
|
+
```
|
135
|
+
|
136
|
+
Some `special` gotchas:
|
137
|
+
* for now, only one `special` per class is supported (an attempt to define
|
138
|
+
additional one will show warningn);
|
139
|
+
* it passes to the block values by the same logic as `String#scan` does:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
class AllSymbols < LinkHum
|
143
|
+
special /@\S+\b/ do |username|
|
144
|
+
p username
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
end
|
148
|
+
AllSymbols.urlify('@dude')
|
149
|
+
# Receives "@dude"
|
150
|
+
|
151
|
+
class SelectedPart < LinkHum
|
152
|
+
special /@(\S+)\b/ do |username|
|
153
|
+
p username
|
154
|
+
nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
SelectedPart.urlify('@dude')
|
158
|
+
# Receives "dude"
|
159
|
+
|
160
|
+
class SeveralArgs < LinkHum
|
161
|
+
special(/@(\S+)_(\S+)\b/) do |first, second|
|
162
|
+
p first, second
|
163
|
+
nil
|
164
|
+
end
|
165
|
+
end
|
166
|
+
SeveralArgs.urlify('@cool_dude')
|
167
|
+
# Receives "cool", "dude"
|
168
|
+
```
|
169
|
+
|
170
|
+
## Credits
|
171
|
+
|
172
|
+
* [squadette](https://github.com/squadette) -- author of original code;
|
173
|
+
* users of _some secret social network_ -- testing and advicing;
|
174
|
+
* [zverok](https://github.com/zverok) -- gemifying, documenting and
|
175
|
+
writing specs.
|
176
|
+
|
177
|
+
## Contributing
|
178
|
+
|
179
|
+
Just usual fork-change-pull request process.
|
180
|
+
|
181
|
+
### Development
|
182
|
+
|
183
|
+
* Don't forget to use `rspec` after any changes made (and specify them,
|
184
|
+
of course!)
|
185
|
+
* It's preferred to use `bundle exec dokaz` to check if README written
|
186
|
+
correctly and `bundle exec dokaz -fshow` to check what exactly code
|
187
|
+
from README will output.
|
188
|
+
|
189
|
+
## License
|
190
|
+
|
191
|
+
MIT
|
data/lib/linkhum.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'addressable/uri'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
class LinkHum
|
6
|
+
class << self
|
7
|
+
NOOP = ->(*){}
|
8
|
+
|
9
|
+
def urlify(text, options = {}, &block)
|
10
|
+
new(text).urlify(options.merge(link_processor: block))
|
11
|
+
end
|
12
|
+
|
13
|
+
def special(pattern = nil, &block)
|
14
|
+
return @special unless pattern
|
15
|
+
|
16
|
+
@special and
|
17
|
+
puts("Warning: redefining #{self}.special from #{caller.first}")
|
18
|
+
|
19
|
+
@special = [pattern, block]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
PROTOCOLS = '(?:https?|ftp)'
|
24
|
+
SPLIT_PATTERN = %r{(#{PROTOCOLS}://\p{^Space}+)}i
|
25
|
+
|
26
|
+
MAX_DISPLAY_LENGTH = 64
|
27
|
+
|
28
|
+
def initialize(text)
|
29
|
+
@text = text
|
30
|
+
@components = @text.split(SPLIT_PATTERN)
|
31
|
+
end
|
32
|
+
|
33
|
+
def urlify(options = {})
|
34
|
+
@components.map{|str|
|
35
|
+
SPLIT_PATTERN =~ str ? process_url(str, options) : process_text(str)
|
36
|
+
}.join
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def process_url(str, options)
|
42
|
+
url, punct = str.scan(%r{\A(#{PROTOCOLS}://.+?)(\p{Punct}*)\Z}i).flatten
|
43
|
+
return str unless url
|
44
|
+
|
45
|
+
if punct[0] == '/' || (punct[0] == ')' && url.include?('('))
|
46
|
+
url << punct.slice!(0)
|
47
|
+
end
|
48
|
+
|
49
|
+
make_link(url, options) + punct
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_text(str)
|
53
|
+
str = CGI.escapeHTML(str)
|
54
|
+
|
55
|
+
pattern, block = self.class.special
|
56
|
+
|
57
|
+
if pattern
|
58
|
+
str.gsub(pattern){|s|
|
59
|
+
if (u = block.call(*arguments(pattern, s)))
|
60
|
+
"<a href='#{screen_feet(u)}'>#{s}</a>"
|
61
|
+
else
|
62
|
+
s
|
63
|
+
end
|
64
|
+
}
|
65
|
+
else
|
66
|
+
str
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def arguments(pattern, string)
|
71
|
+
m = pattern.match(string)
|
72
|
+
m.captures.empty? ? m[0] : m.captures
|
73
|
+
end
|
74
|
+
|
75
|
+
def make_link(url, options)
|
76
|
+
uri = Addressable::URI.parse(url) rescue nil
|
77
|
+
return url unless uri
|
78
|
+
|
79
|
+
canonical = Addressable::URI.normalized_encode(uri) rescue uri
|
80
|
+
|
81
|
+
display_length = options.fetch(:max_length, MAX_DISPLAY_LENGTH)
|
82
|
+
"<a href='#{screen_feet(canonical)}'#{make_attrs(uri, options)}>"\
|
83
|
+
"#{truncate(CGI.escapeHTML(url), display_length)}</a>"
|
84
|
+
end
|
85
|
+
|
86
|
+
def make_attrs(uri, options)
|
87
|
+
block = options[:link_processor] || method(:link_attrs)
|
88
|
+
attrs = block.call(uri) || {}
|
89
|
+
return '' if attrs.empty?
|
90
|
+
' ' + attrs.map{|n, v| "#{n}='#{v}'"}.join(' ')
|
91
|
+
end
|
92
|
+
|
93
|
+
def link_attrs(*)
|
94
|
+
end
|
95
|
+
|
96
|
+
# TIL that ' (single quote) is in fact "feet mark"
|
97
|
+
def screen_feet(url)
|
98
|
+
url.gsub("'", '%27')
|
99
|
+
end
|
100
|
+
|
101
|
+
# stolen from activesupport/lib/active_support/core_ext/string/filters.rb
|
102
|
+
# then simplified
|
103
|
+
def truncate(string, truncate_at)
|
104
|
+
return string.dup if !truncate_at || string.length <= truncate_at
|
105
|
+
|
106
|
+
omission = '...'
|
107
|
+
stop = truncate_at - omission.length
|
108
|
+
|
109
|
+
"#{string[0, stop]}#{omission}"
|
110
|
+
end
|
111
|
+
end
|
data/linkhum.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'linkhum'
|
3
|
+
s.version = '0.0.1'
|
4
|
+
s.authors = ['Alexey Makhotkin', 'Victor Shepelev']
|
5
|
+
s.email = 'zverok.offline@gmail.com'
|
6
|
+
s.homepage = 'https://github.com/zverok/linkhum'
|
7
|
+
|
8
|
+
s.summary = 'Humane link urlifier'
|
9
|
+
s.licenses = ['MIT']
|
10
|
+
|
11
|
+
s.files = `git ls-files`.split($RS).reject do |file|
|
12
|
+
file =~ /^(?:
|
13
|
+
spec\/.*
|
14
|
+
|Gemfile
|
15
|
+
|Rakefile
|
16
|
+
|\.rspec
|
17
|
+
|\.gitignore
|
18
|
+
|\.rubocop.yml
|
19
|
+
|\.travis.yml
|
20
|
+
)$/x
|
21
|
+
end
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
|
24
|
+
s.add_dependency 'addressable'
|
25
|
+
|
26
|
+
s.add_development_dependency 'rake'
|
27
|
+
s.add_development_dependency 'rspec', '~> 3'
|
28
|
+
s.add_development_dependency 'rspec-its', '~> 1'
|
29
|
+
s.add_development_dependency 'nokogiri'
|
30
|
+
s.add_development_dependency 'rubocop'
|
31
|
+
#s.add_development_dependency 'dokaz'
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: linkhum
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexey Makhotkin
|
8
|
+
- Victor Shepelev
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-06-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: addressable
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ! '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ! '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ! '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ~>
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '3'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '3'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rspec-its
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '1'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: nokogiri
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ! '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rubocop
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
description:
|
99
|
+
email: zverok.offline@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- .dokaz
|
105
|
+
- LICENSE.txt
|
106
|
+
- README.md
|
107
|
+
- lib/linkhum.rb
|
108
|
+
- linkhum.gemspec
|
109
|
+
homepage: https://github.com/zverok/linkhum
|
110
|
+
licenses:
|
111
|
+
- MIT
|
112
|
+
metadata: {}
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 2.4.6
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: Humane link urlifier
|
133
|
+
test_files: []
|
134
|
+
has_rdoc:
|