tag_uri 1.0.1 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.travis.yml +1 -2
- data/CHANGES.md +49 -14
- data/Gemfile +3 -0
- data/README.md +96 -17
- data/certs/yb66.pem +26 -0
- data/lib/tag_uri.rb +269 -21
- data/lib/tag_uri/version.rb +4 -1
- data/spec/spec_helper.rb +18 -9
- data/spec/support/fixtures/urls.txt +82 -0
- data/spec/tag_uri_spec.rb +329 -17
- data/tag_uri.gemspec +4 -2
- metadata +37 -7
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f1f7613a274c36cb5de4cb1105e0af41db251bf2fa0f16bdd31c2eeb7d8a5bdb
|
4
|
+
data.tar.gz: 8cdd72e27fdd464ecbb36f65a3c6f5ee60e0a762ac73270058827cf2724d0eb0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af684a9e4ce533c01ed5600b730959551a4dfbca805c2e5e2f2f6d3da2462a9365b856cb03c3e358a54cde88339699f043f02ceb9f3379124bf9a00cd9a9f49e
|
7
|
+
data.tar.gz: f802572ff78c7a1e2d965370019cae2e046ae93f250e4ed9c23e10992236d2ce5a39f55f4c42ff86666d979f65b5f9f30f6f9c58f30b8ca8ce015e7c7d1fcba5
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
Binary file
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,27 +1,62 @@
|
|
1
1
|
# CH CH CH CHANGES #
|
2
2
|
|
3
|
-
##
|
3
|
+
## Otherwise known as the changelog
|
4
4
|
|
5
|
-
|
5
|
+
All notable changes to this project will be documented in this file.
|
6
6
|
|
7
|
-
|
7
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
8
|
+
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
8
9
|
|
9
|
-
----
|
10
10
|
|
11
|
-
|
11
|
+
## Unreleased
|
12
12
|
|
13
|
-
* Updated to use Ruby v2's keywords.
|
14
|
-
* Bumped to v1.0.0 as a semver release.
|
15
13
|
|
16
|
-
|
14
|
+
## [v2.0.1] - Tuesday the 15th of January, 2019
|
17
15
|
|
18
|
-
###
|
16
|
+
### Added
|
19
17
|
|
20
|
-
|
18
|
+
- Support for a more secure installation via MediumSecurity and HighSecurity options.
|
21
19
|
|
22
|
-
###
|
20
|
+
### Changed
|
23
21
|
|
24
|
-
|
25
|
-
* Changed the module name, it should all be uppercase so now it is.
|
22
|
+
- Updated the README to reflect the changes.
|
26
23
|
|
27
|
-
|
24
|
+
|
25
|
+
## [v2.0.0] - Tuesday the 15th of January, 2019
|
26
|
+
|
27
|
+
### Added
|
28
|
+
|
29
|
+
- Started using [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
|
30
|
+
|
31
|
+
### Changed
|
32
|
+
|
33
|
+
- Expanded the use of the library beyond just atom.
|
34
|
+
- Added lots more tests.
|
35
|
+
- The API now adheres more to the terms used in the RFC.
|
36
|
+
- Tried to keep the laziness factor available.
|
37
|
+
- Removed the old `TagURI.create` API (the major version change means it's a breaking change).
|
38
|
+
- Tried to get TagURI::URI closer to the Ruby stdlib's URI API. More could probably be done here.
|
39
|
+
- Improved the docs by adding specs that mirror the examples given.
|
40
|
+
- Git tags will now be signed by GPG too (look in my gists for Keybase or go to [http://keybase.io/iainb](http://keybase.io/iainb) to get the key).
|
41
|
+
|
42
|
+
|
43
|
+
## [v1.0.1] - Sunday the 14th of June, 2015
|
44
|
+
|
45
|
+
- Improved the docs.
|
46
|
+
|
47
|
+
|
48
|
+
## [v1.0.0] - Sunday the 14th of June, 2015
|
49
|
+
|
50
|
+
- Updated to use Ruby v2's keywords.
|
51
|
+
- Bumped to v1.0.0 as a semver release.
|
52
|
+
|
53
|
+
|
54
|
+
## [v0.0.3] - Wednesday the 27th of February, 2013
|
55
|
+
|
56
|
+
- Since the Github repo is called tag-uri (because a hypen is clearer in a URL) I've added tag-uri.rb and taguri.rb to the lib to require the library in case anyone uses the wrong name.
|
57
|
+
|
58
|
+
|
59
|
+
## [v0.0.2] - Wednesday the 27th of February, 2013
|
60
|
+
|
61
|
+
- Changed to be a class method, as if it's mixed in to a model then the model will likely want to use that name for the field.
|
62
|
+
- Changed the module name, it should all be uppercase so now it is.
|
data/Gemfile
CHANGED
@@ -11,11 +11,14 @@ group :development do
|
|
11
11
|
gem "maruku"
|
12
12
|
unless RUBY_ENGINE == 'jruby' || RUBY_ENGINE == "rbx"
|
13
13
|
gem "pry-byebug"
|
14
|
+
gem "rb-readline"
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
18
|
group :test do
|
18
19
|
gem "rspec"
|
19
20
|
gem "rspec-its"
|
21
|
+
gem "rspec-given"
|
20
22
|
gem "simplecov"
|
23
|
+
gem "timecop"
|
21
24
|
end
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# TagURI
|
2
2
|
|
3
|
-
An implementation of tag
|
3
|
+
An implementation of tag URIs.
|
4
4
|
See http://tools.ietf.org/html/rfc4151
|
5
5
|
|
6
6
|
### Build status ###
|
@@ -10,7 +10,7 @@ Master branch:
|
|
10
10
|
|
11
11
|
## Why? ##
|
12
12
|
|
13
|
-
|
13
|
+
I originally wrote this because every Atom entry must have a globally unique ID, in the `id` element, and I was writing an atom feed.
|
14
14
|
|
15
15
|
* The ID must be a valid URI, as defined by RFC 2396.
|
16
16
|
* The ID must be globally unique, across all Atom feeds, everywhere, for all time. This part is actually easier than it sounds.
|
@@ -27,23 +27,69 @@ You don't have to just use it with Atom, it's also useful anywhere that a non-ti
|
|
27
27
|
> Tag URIs finally let URIs do what they were meant to do: identify without implying any sort of location or behavior that they don't have. They're easy to create, they're human legible, they work with existing systems, they're an open standard, and they don't have any backward compatibility issues. What's not to like?
|
28
28
|
|
29
29
|
|
30
|
-
##
|
30
|
+
## Usage
|
31
31
|
|
32
|
-
|
32
|
+
require 'tag_uri'
|
33
33
|
|
34
|
-
|
34
|
+
### THE MOST BASIC WAY
|
35
35
|
|
36
|
-
|
36
|
+
tag_uri = TagURI::URI.new authority_name: "helpful-iain@theprintedbird.com",
|
37
|
+
date: "2019-01-09",
|
38
|
+
specific: "My slippers"
|
37
39
|
|
38
|
-
|
40
|
+
tag_uri.to_s
|
41
|
+
# => "tag:helpful-iain@theprintedbird.com,2019-01-09:My%20slippers"
|
42
|
+
tag.authority_name
|
43
|
+
# => "helpful-iain@theprintedbird.com"
|
44
|
+
tag.date
|
45
|
+
# => 2019-01-09 00:00:00 +0900 # You get a Time object back
|
46
|
+
tag.specific "My slippers"
|
39
47
|
|
40
|
-
|
48
|
+
### ANOTHER MOST BASIC WAY
|
41
49
|
|
42
|
-
|
50
|
+
TagURI::URI.new email: "helpful-iain@theprintedbird.com",
|
51
|
+
date: "2019-01-09",
|
52
|
+
specific: "My slippers"
|
43
53
|
|
44
|
-
|
54
|
+
tag_uri.to_s
|
55
|
+
# => "tag:helpful-iain@theprintedbird.com,2019-01-09:My%20slippers"
|
56
|
+
tag.authority_name
|
57
|
+
# => "helpful-iain@theprintedbird.com"
|
58
|
+
tag.date
|
59
|
+
# => 2019-01-09 00:00:00 +0900
|
60
|
+
tag.specific "My slippers"
|
45
61
|
|
46
|
-
|
62
|
+
### (NOT TO FLOG A DEAD HORSE BUT) ANOTHER MOST BASIC WAY
|
63
|
+
|
64
|
+
TagURI::URI.new domain: "theprintedbird.com",
|
65
|
+
date: "2019-01-09",
|
66
|
+
specific: "My slippers"
|
67
|
+
|
68
|
+
tag_uri.to_s
|
69
|
+
# => "tag:theprintedbird.com,2019-01-09:My%20slippers"
|
70
|
+
tag.authority_name
|
71
|
+
# => "theprintedbird.com"
|
72
|
+
tag.date
|
73
|
+
# => 2019-01-09 00:00:00 +0900
|
74
|
+
tag.specific "My slippers"
|
75
|
+
|
76
|
+
|
77
|
+
### YOU HAVE A WEB LINK TO AN ARTICLE ABOUT BEESWAX (WHY NOT?) AND YOU'RE FEELING LAZY
|
78
|
+
|
79
|
+
Don't be this lazy as you'll be letting a computer and my programming try to guess what you wanted. But…
|
80
|
+
|
81
|
+
# Imagine it's the 2018-03-11 today, because today is the day that'll be
|
82
|
+
# chosen for your tag date.
|
83
|
+
tag_uri = TagURI::URI.new uri: "http://www.example.com/posts/beeswax#bees"
|
84
|
+
|
85
|
+
tag_uri.to_s
|
86
|
+
# => "tag:www.example.com,2018-03-11:/posts/beeswax#bees"
|
87
|
+
tag_uri.authority_name
|
88
|
+
# => "www.example.com"
|
89
|
+
tag_uri.specific
|
90
|
+
# => "/posts/beeswax"
|
91
|
+
tag_uri.fragment # yes, you get fragments too!
|
92
|
+
# => "bees"
|
47
93
|
|
48
94
|
Given a model:
|
49
95
|
|
@@ -55,16 +101,49 @@ Given a model:
|
|
55
101
|
# => "howto-atom-linkblog"
|
56
102
|
post.created_at
|
57
103
|
# => 2004-05-27 00:00:00 0100
|
58
|
-
|
59
|
-
|
60
|
-
# => "tag:diveintomark.org,2013-02-26:/archives/2004/05/27/howto-atom-linkblog"
|
104
|
+
post.prefix
|
105
|
+
# => "/archives/2004/05/27/" # Why? It's up to you.
|
61
106
|
|
62
|
-
|
107
|
+
tag_uri = TagURI::URI.new authority_name: request.host,
|
108
|
+
date: post.created_at,
|
109
|
+
specific: "#{post.prefix}#{slug}"
|
63
110
|
|
64
|
-
|
111
|
+
tag_uri.to_s
|
112
|
+
# => "tag:diveintomark.org,2013-02-26:/archives/2004/05/27/howto-atom-linkblog"
|
65
113
|
|
66
114
|
or something like that.
|
67
115
|
|
116
|
+
|
117
|
+
## Installation
|
118
|
+
|
119
|
+
Add this line to your application's Gemfile:
|
120
|
+
|
121
|
+
gem 'tag_uri'
|
122
|
+
|
123
|
+
And then execute:
|
124
|
+
|
125
|
+
$ bundle
|
126
|
+
|
127
|
+
Or install it yourself as:
|
128
|
+
|
129
|
+
$ gem install tag_uri
|
130
|
+
|
131
|
+
## Even better installation
|
132
|
+
|
133
|
+
I'm trying to be a [responsible citizen regarding security](https://keybase.io/iainb) so I've followed the [instructions here](https://guides.rubygems.org/security/) and created a [public certicate](https://gist.github.com/yb66/0fb0e3007de4d4279aeaf162e0ced40a#file-yb66-pem) and signed the gem, so you can install it via:
|
134
|
+
|
135
|
+
gem cert --add <(curl -Ls https://gist.githubusercontent.com/yb66/0fb0e3007de4d4279aeaf162e0ced40a/raw/49466a801e1fd237fffe4658143a96c6cca6c961/yb66.pem)
|
136
|
+
|
137
|
+
gem install tag_uri -P MediumSecurity
|
138
|
+
|
139
|
+
The MediumSecurity trust profile will verify signed gems, but allow the installation of unsigned dependencies.
|
140
|
+
|
141
|
+
If all of TagURI’s dependencies are signed you can use HighSecurity.
|
142
|
+
|
143
|
+
gem install tag_uri -P HighSecurity
|
144
|
+
|
145
|
+
It's just one more [good reason](https://cfoc.org/rubygems-vulnerability-can-compel-installing-malware/) to get on to gem authors and ask them to sign their gems, and ask the Rubygems authors to be [proactive with security measures](https://github.com/rubygems/rubygems/issues/2496).
|
146
|
+
|
68
147
|
## Versioning ##
|
69
148
|
|
70
149
|
This library uses [semver](http://semver.org).
|
data/certs/yb66.pem
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIEbjCCAtagAwIBAgIBATANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDDCVoZWxw
|
3
|
+
ZnVsLWlhaW4vREM9dGhlcHJpbnRlZGJpcmQvREM9Y29tMB4XDTE5MDExNTA3MjAw
|
4
|
+
OVoXDTIwMDExNTA3MjAwOVowMDEuMCwGA1UEAwwlaGVscGZ1bC1pYWluL0RDPXRo
|
5
|
+
ZXByaW50ZWRiaXJkL0RDPWNvbTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoC
|
6
|
+
ggGBALhp1KlrdriWAuhXhM3I0oZblbOUAgk8UZSyI6vLQ4oK8uHWmdBkrzUublq4
|
7
|
+
7cU1T0IIFeKOzjN2aXS660q2Ev7Bpwt1oBjMVqLMZYJM4gixwzXW9labQhnjefEy
|
8
|
+
CTWRa/i4gL8NbwOg/UeX5rHiCy/xaqyxj//24E7m5e72JrpK11ZZ5/4TUvxDfOJr
|
9
|
+
w+16BAxH3ELBRjXoOXnlb7SzA2ohNnwuoom5gi9Ju6z0ooSa9cegqauHBbme8wgO
|
10
|
+
5bPwGi+MbiLKoMDcnakuUoKqWL6qA+/QofNnrmtgBmMe08dd9/ermztT/dBdNQiE
|
11
|
+
eOXDR+sM5ardxl+5TdAcGuheMgZBiBVqaMVowUp1VPV1f/sY8RsfYqFVBg/I+jcu
|
12
|
+
uulV50CkaLYmZVa0sWiCNg/pkKROpVktwfkRo3EKCllckMc29qPts64g0UkyBi1q
|
13
|
+
stO7Yk/0PmhHcWHHv8Lfuin0Cmpt01AuKi3ToOBJHAvLWkORlOw1mIC9mdOR3c9Y
|
14
|
+
jeBbawIDAQABo4GSMIGPMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
|
15
|
+
BBSyOPfHSTgay7iGZ94b0JDrrcaBDTAqBgNVHREEIzAhgR9oZWxwZnVsLWlhaW5A
|
16
|
+
dGhlcHJpbnRlZGJpcmQuY29tMCoGA1UdEgQjMCGBH2hlbHBmdWwtaWFpbkB0aGVw
|
17
|
+
cmludGVkYmlyZC5jb20wDQYJKoZIhvcNAQELBQADggGBAAoYHPvpy84kUzvM1tMF
|
18
|
+
AMUFH6V/hkBdcTRS3mE+8lpMHBiPluByk1/vfUTlo9kGFtEEXd1ginKqMozLKFrr
|
19
|
+
5yRAi08zsRA0pSDuOJsX95x4Rr5GnAUKeVOXJHry0Kae3btQdJ59ZqvFPyNiXKEB
|
20
|
+
SUIa4GUcWFaIl2yL7epcCNsyhEqvnRPq0zvfY0IGT3AcHxchCWbnurkci32eAiqW
|
21
|
+
TESqr8zDJzsH7HSyOHlNdvWQRrYfhh8p+JsbRqJ4rChBPYnZM6fnlFtvPUNbBaRr
|
22
|
+
cw7FROiP0G0E7GAd7loZ78WoQEM6regiCibP3LPehIl94P3K2+CCOI148rNlyXBE
|
23
|
+
ATDB99qMn3ZgZEE0i5jxxVOHbMQWcvN3oElPuVVq6gLhqnZn50DW2B6wf3s4MMMd
|
24
|
+
ILghhrKlF+3IGSo6pOtgZB3Y84IgtvmYyo3Unv8VkRqZ22ZSxz7GFy+X7SABSGxU
|
25
|
+
ewk/WBT8wib1dm745Y+U42Icj8FgHqKkq1mDIcMcyLqxLA==
|
26
|
+
-----END CERTIFICATE-----
|
data/lib/tag_uri.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
3
|
require 'addressable/uri'
|
4
|
+
require 'time'
|
4
5
|
|
5
6
|
# Implementation of tag URI's.
|
6
7
|
# @see http://tools.ietf.org/html/rfc4151
|
@@ -9,26 +10,273 @@ module TagURI
|
|
9
10
|
class Error < StandardError; end
|
10
11
|
class ArgumentError < Error; end
|
11
12
|
|
12
|
-
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
13
|
+
|
14
|
+
# From the RFC @see https://tools.ietf.org/html/rfc4151#section-2.1
|
15
|
+
# The general syntax of a tag URI, in ABNF [2], is:
|
16
|
+
#
|
17
|
+
# tagURI = "tag:" taggingEntity ":" specific [ "#" fragment ]
|
18
|
+
#
|
19
|
+
# Where:
|
20
|
+
#
|
21
|
+
# taggingEntity = authorityName "," date
|
22
|
+
# authorityName = DNSname / emailAddress
|
23
|
+
# date = year ["-" month ["-" day]]
|
24
|
+
# year = 4DIGIT
|
25
|
+
# month = 2DIGIT
|
26
|
+
# day = 2DIGIT
|
27
|
+
# DNSname = DNScomp *( "." DNScomp ) ; see RFC 1035 [3]
|
28
|
+
# DNScomp = alphaNum [*(alphaNum /"-") alphaNum]
|
29
|
+
# emailAddress = 1*(alphaNum /"-"/"."/"_") "@" DNSname
|
30
|
+
# alphaNum = DIGIT / ALPHA
|
31
|
+
# specific = *( pchar / "/" / "?" ) ; pchar from RFC 3986 [1]
|
32
|
+
# fragment = *( pchar / "/" / "?" ) ; same as RFC 3986 [1]
|
33
|
+
# pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
34
|
+
# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
35
|
+
# pct-encoded = "%" HEXDIG HEXDIG
|
36
|
+
# sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
|
37
|
+
class URI
|
38
|
+
# To match the terminology of the RFC I've put straightforward regex into
|
39
|
+
# constants.
|
40
|
+
|
41
|
+
# No underscores, only alphanums.
|
42
|
+
ALPHANUM = /[0-9a-zA-Z]/
|
43
|
+
# No percent encoding here for hexnums.
|
44
|
+
HEXDIG = /[0-9a-fA-F]/
|
45
|
+
# This is where the percent encodings are checked, e.g. %20.
|
46
|
+
PCT_ENCODED = /% #{HEXDIG} #{HEXDIG}/x
|
47
|
+
# Magic markers here.
|
48
|
+
SUB_DELIMS = /[\!\$\&'\(\)\*\+,\;\=]/x
|
49
|
+
# The uncarved block.
|
50
|
+
UNRESERVED = /[\w\-\.\~]/
|
51
|
+
# (Possibly percent-encoded) characters
|
52
|
+
PCHAR = /#{UNRESERVED} | #{PCT_ENCODED} | #{SUB_DELIMS} | \: | @/x
|
53
|
+
# The thing really being tagged.
|
54
|
+
SPECIFIC = %r< (?: #{PCHAR} | / | \? )+ >x
|
55
|
+
# fragment = *( pchar / "/" / "?" ) ; same as RFC 3986 [1]
|
56
|
+
# Even more specific.
|
57
|
+
FRAGMENT = /(?<=\#)#{SPECIFIC}/x
|
58
|
+
# DNScomp = alphaNum [*(alphaNum /"-") alphaNum]
|
59
|
+
|
60
|
+
# Don't get too hung up on validating it's a domain name,
|
61
|
+
# just do enough.
|
62
|
+
DNSNAME = /
|
63
|
+
\b
|
64
|
+
(?:
|
65
|
+
(?=[a-z0-9-]{1,63}\.)
|
66
|
+
(?: xn--)?
|
67
|
+
[a-z0-9]+
|
68
|
+
(?: -[a-z0-9]+)*
|
69
|
+
\.)+
|
70
|
+
[a-z]{2,63}
|
71
|
+
\b
|
72
|
+
/x
|
73
|
+
|
74
|
+
# It's not worth validating the email address beyond this either.
|
75
|
+
EMAIL = /(?<email_id>[^,]+)@(?<email_domain>[^,@]+)/ # yes, anything goes
|
76
|
+
|
77
|
+
# ISO8601 date
|
78
|
+
YYYY_MM_DD = /\d{4}-\d\d-\d\d/
|
79
|
+
OTHER_DATES = %r<\d{4}(?<separator>[\-\_/])\d\d[\-\_/]\d\d>
|
80
|
+
|
81
|
+
# One scheme to rule them all, at least in this module.
|
82
|
+
TAG_SCHEME = /(?<scheme>tag)\:/
|
83
|
+
|
84
|
+
# Be tolerant
|
85
|
+
ANY_SCHEME = /(?<scheme>#{ALPHANUM}+)\:/
|
86
|
+
|
87
|
+
# I have the authoritay!
|
88
|
+
AUTHORITY_NAME = /(?<authority_name>
|
89
|
+
(?: #{DNSNAME} )
|
90
|
+
|
|
91
|
+
(?: #{EMAIL} )
|
92
|
+
)/x
|
93
|
+
|
94
|
+
# The whole pattern to capture a tag uri.
|
95
|
+
TAG = /\A
|
96
|
+
#{ANY_SCHEME}
|
97
|
+
#{AUTHORITY_NAME}
|
98
|
+
,
|
99
|
+
(?<date>#{YYYY_MM_DD})
|
100
|
+
\:
|
101
|
+
(?<specific> #{SPECIFIC} )
|
102
|
+
(?<fragment> #{FRAGMENT} )?
|
103
|
+
\z/x
|
104
|
+
|
105
|
+
|
106
|
+
# Should be slightly faster than the other version.
|
107
|
+
VALIDATE_TAG = /\A
|
108
|
+
#{TAG_SCHEME}
|
109
|
+
#{AUTHORITY_NAME}
|
110
|
+
,
|
111
|
+
#{YYYY_MM_DD}
|
112
|
+
\:
|
113
|
+
#{SPECIFIC}
|
114
|
+
(?: #{FRAGMENT} )?
|
115
|
+
\z/x
|
116
|
+
|
117
|
+
TIME_FORMAT="%Y-%m-%d"
|
118
|
+
|
119
|
+
|
120
|
+
# @param uri [#to_s]
|
121
|
+
# @param authority_name [String]
|
122
|
+
# @param date [String,Time,#to_time]
|
123
|
+
# @param specific [String]
|
124
|
+
# @param fragment [String]
|
125
|
+
# @param email [String]
|
126
|
+
# @param domain [String]
|
127
|
+
def initialize( uri: nil,
|
128
|
+
authority_name: nil,
|
129
|
+
date: nil,
|
130
|
+
specific: nil,
|
131
|
+
fragment: nil,
|
132
|
+
email: nil,
|
133
|
+
domain: nil
|
134
|
+
)
|
135
|
+
@scheme = "tag"
|
136
|
+
if uri
|
137
|
+
# handle TagURI::URI object
|
138
|
+
if (uri.respond_to? :authority_name and
|
139
|
+
uri.respond_to? :date and
|
140
|
+
uri.respond_to? :specific)
|
141
|
+
@authority_name = uri.authority_name
|
142
|
+
@date = uri.date
|
143
|
+
@specific = uri.specific
|
144
|
+
return
|
145
|
+
else
|
146
|
+
uri = uri.to_s
|
147
|
+
# handle something that looks very like a TagURI::URI object
|
148
|
+
if ::URI.regexp.match uri and
|
149
|
+
(md = TAG.match uri) and
|
150
|
+
md[:scheme] == "tag"
|
151
|
+
@authority_name = md[:authority_name]
|
152
|
+
@date = Time.strptime md[:date], TIME_FORMAT
|
153
|
+
@specific = md[:specific]
|
154
|
+
self.fragment = md[:fragment]
|
155
|
+
return
|
156
|
+
else # see what we can salvage from the uri
|
157
|
+
extra_uri = Addressable::URI.parse uri
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
@date =
|
163
|
+
if date
|
164
|
+
if date.respond_to? :to_time
|
165
|
+
date
|
166
|
+
elsif date.to_s =~ /\A#{YYYY_MM_DD}$/
|
167
|
+
Time.strptime date.to_s, TIME_FORMAT
|
168
|
+
else
|
169
|
+
fail ArgumentError, "Date should be a valid time/date/string that conforms to YYYY-MM-DD"
|
170
|
+
end
|
171
|
+
elsif uri and (md = /\A[^,]+,(?<date>#{YYYY_MM_DD})/.match uri )
|
172
|
+
Time.strptime md[:date], TIME_FORMAT
|
173
|
+
elsif extra_uri and (md = OTHER_DATES.match extra_uri.path)
|
174
|
+
Time.strptime md[0], "%Y#{md[:separator]}%m#{md[:separator]}%d"
|
175
|
+
else
|
176
|
+
Time.now
|
177
|
+
end
|
178
|
+
|
179
|
+
@authority_name =
|
180
|
+
if authority_name
|
181
|
+
if (md = AUTHORITY_NAME.match authority_name)
|
182
|
+
md[0]
|
183
|
+
else
|
184
|
+
fail ArgumentError, "Authority name must be a domain name or email address"
|
185
|
+
end
|
186
|
+
elsif email
|
187
|
+
if (md = EMAIL.match email)
|
188
|
+
md[0]
|
189
|
+
else
|
190
|
+
fail ArgumentError, "email given was invalid"
|
191
|
+
end
|
192
|
+
elsif domain
|
193
|
+
if (md = DNSNAME.match domain)
|
194
|
+
md[0]
|
195
|
+
else
|
196
|
+
fail ArgumentError, "domain given was invalid"
|
197
|
+
end
|
198
|
+
elsif extra_uri and extra_uri.normalized_authority
|
199
|
+
extra_uri.normalized_authority
|
200
|
+
elsif extra_uri and extra_uri.normalized_path and (md = AUTHORITY_NAME.match(extra_uri.normalized_path))
|
201
|
+
md[:authority_name]
|
202
|
+
elsif uri and (md = AUTHORITY_NAME.match uri)
|
203
|
+
md[0]
|
204
|
+
# else what?
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
@specific =
|
209
|
+
if specific
|
210
|
+
specific
|
211
|
+
elsif extra_uri and (md = /,[\d\-]+\:(?<specific>#{SPECIFIC})/.match extra_uri.normalized_path )
|
212
|
+
md[:specific]
|
213
|
+
elsif uri and (md = /,[\d\-]+\:(?<specific>#{SPECIFIC})/.match uri )
|
214
|
+
md[:specific]
|
215
|
+
elsif extra_uri
|
216
|
+
extra_uri.normalized_path
|
217
|
+
end
|
218
|
+
|
219
|
+
self.fragment =
|
220
|
+
if fragment
|
221
|
+
fragment
|
222
|
+
elsif extra_uri and (md = /,[\d\-]+\:[^\#]+#(?<fragment>#{FRAGMENT})/.match extra_uri.normalized_path)
|
223
|
+
md[:fragment]
|
224
|
+
elsif uri and (md = /,[\d\-]+\:[^\#]+#(?<fragment>#{FRAGMENT})/.match uri )
|
225
|
+
md[:fragment]
|
226
|
+
elsif extra_uri
|
227
|
+
extra_uri.normalized_fragment
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
|
233
|
+
# @!attribute [r] scheme
|
234
|
+
# @return [String] Have a guess what it will be… (`"tag"`;)
|
235
|
+
attr_reader :scheme
|
236
|
+
|
237
|
+
# @!attribute [r] authority_name
|
238
|
+
# @return [String]
|
239
|
+
# @!attribute [r] date
|
240
|
+
# @return [String]
|
241
|
+
# @!attribute [r] specific
|
242
|
+
# @return [String]
|
243
|
+
attr_accessor :authority_name, :date, :specific
|
244
|
+
|
245
|
+
|
246
|
+
def fragment
|
247
|
+
@fragment || ""
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
def fragment=( frag )
|
252
|
+
@fragment = if frag
|
253
|
+
frag.start_with?("#") ?
|
254
|
+
frag.sub(/#/, "") :
|
255
|
+
frag
|
256
|
+
else
|
257
|
+
""
|
258
|
+
end
|
259
|
+
@fragment
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
def tagging_entity
|
264
|
+
%Q!#{@authority_name},#{@date.strftime "%F"}!
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
def to_s
|
269
|
+
s = %Q!#{self.scheme}:#{self.tagging_entity}:#{self.specific.gsub(/\s/, "%20")}!
|
270
|
+
unless @fragment.nil? or @fragment.empty?
|
271
|
+
s << "##{self.fragment}"
|
272
|
+
end
|
273
|
+
s
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
def valid?
|
278
|
+
!!(VALIDATE_TAG =~ self.to_s)
|
279
|
+
end
|
280
|
+
|
33
281
|
end
|
34
282
|
end
|
data/lib/tag_uri/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -2,14 +2,13 @@
|
|
2
2
|
|
3
3
|
require 'rspec'
|
4
4
|
require 'rspec/its'
|
5
|
-
|
5
|
+
require 'rspec/given'
|
6
|
+
require 'timecop'
|
7
|
+
Spec_dir = Pathname( __dir__ )
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
require File.join(File.dirname(caller[0]), path.to_str)
|
11
|
-
end
|
12
|
-
end
|
9
|
+
if ENV["DEBUG"]
|
10
|
+
require 'pry-byebug'
|
11
|
+
binding.pry
|
13
12
|
end
|
14
13
|
|
15
14
|
# code coverage
|
@@ -18,6 +17,7 @@ SimpleCov.start do
|
|
18
17
|
add_filter "/vendor.noindex/"
|
19
18
|
add_filter "/coverage/"
|
20
19
|
add_filter "/bin/"
|
20
|
+
add_filter "/spec/"
|
21
21
|
end
|
22
22
|
|
23
23
|
|
@@ -25,5 +25,14 @@ Dir[ File.join( Spec_dir, "/support/**/*.rb")].each do |f|
|
|
25
25
|
require f
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
TIME_NOW = Time.parse "2018-03-11T06:49:16+00:00"
|
29
|
+
RSpec.configure do |config|
|
30
|
+
|
31
|
+
config.before(:each, :time_sensitive => true) do
|
32
|
+
Timecop.freeze TIME_NOW
|
33
|
+
end
|
34
|
+
|
35
|
+
config.after(:each, :time_sensitive => true) do
|
36
|
+
Timecop.return
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
SHOULD MATCH:
|
2
|
+
|
3
|
+
j.mp
|
4
|
+
1337.net
|
5
|
+
a.b-c.de
|
6
|
+
xn--bcher-kva.tld
|
7
|
+
shouldfail.com
|
8
|
+
foo.com
|
9
|
+
|
10
|
+
END
|
11
|
+
|
12
|
+
SHOULD NOT MATCH:
|
13
|
+
|
14
|
+
223.255.255.254
|
15
|
+
0.0.0.0
|
16
|
+
10.1.1.0
|
17
|
+
10.1.1.255
|
18
|
+
224.1.1.1
|
19
|
+
10.1.1.1
|
20
|
+
1.1.1.1.1
|
21
|
+
123.123.123
|
22
|
+
a.b--c.de/
|
23
|
+
foo.bar/
|
24
|
+
142.42.1.1/
|
25
|
+
foo.bar/foo(bar)baz quux
|
26
|
+
foo.bar/baz
|
27
|
+
foo.bar/?q=Test%20URL-encoded%20stuff
|
28
|
+
foo.com/unicode_(✪)_in_parens
|
29
|
+
foo.bar?q=Spaces should be encoded
|
30
|
+
142.42.1.1:8080/
|
31
|
+
foo.com/blah_(wikipedia)#cite-1
|
32
|
+
foo.com/blah_(wikipedia)_blah#cite-1
|
33
|
+
foo.com/(something)?after=parens
|
34
|
+
code.google.com/events/#&product=browser
|
35
|
+
foo.com/blah_blah
|
36
|
+
foo.com/blah_blah/
|
37
|
+
foo.com/blah_blah_(wikipedia)
|
38
|
+
foo.com/blah_blah_(wikipedia)_(again)
|
39
|
+
www.example.com/wpstyle/?p=364
|
40
|
+
www.example.com/foo/?bar=baz&inga=42&quux
|
41
|
+
userid@example.com
|
42
|
+
userid@example.com/
|
43
|
+
userid@example.com:8080
|
44
|
+
userid@example.com:8080/
|
45
|
+
✪df.ws/123
|
46
|
+
bücher.tld
|
47
|
+
☺.damowmow.com/
|
48
|
+
userid:password@example.com
|
49
|
+
userid:password@example.com/
|
50
|
+
userid:password@example.com:8080
|
51
|
+
userid:password@example.com:8080/
|
52
|
+
مثال.إختبار
|
53
|
+
例子.测试
|
54
|
+
उदाहरण.परीक्षा
|
55
|
+
➡.ws/䨹
|
56
|
+
⌘.ws
|
57
|
+
⌘.ws/
|
58
|
+
-.~_!$&'()*+,;=:%40:80%2f::::::@example.com
|
59
|
+
.
|
60
|
+
..
|
61
|
+
../
|
62
|
+
?
|
63
|
+
??
|
64
|
+
??/
|
65
|
+
#
|
66
|
+
##
|
67
|
+
##/
|
68
|
+
//
|
69
|
+
//a
|
70
|
+
///a
|
71
|
+
///
|
72
|
+
/a
|
73
|
+
1234
|
74
|
+
h://test
|
75
|
+
should fail
|
76
|
+
-error-.invalid/
|
77
|
+
-a.b.co
|
78
|
+
a.b-.co
|
79
|
+
3628126748
|
80
|
+
.www.foo.bar/
|
81
|
+
www.foo.bar./
|
82
|
+
.www.foo.bar./
|
data/spec/tag_uri_spec.rb
CHANGED
@@ -2,27 +2,339 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
require 'time'
|
5
|
-
require 'ostruct'
|
6
5
|
require_relative "../lib/tag_uri.rb"
|
7
6
|
|
8
|
-
describe "Generating a tag uri" do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
7
|
+
describe "Generating a tag uri", :time_sensitive do
|
8
|
+
|
9
|
+
context "THE MOST BASIC WAY" do
|
10
|
+
When(:tag_uri) {
|
11
|
+
TagURI::URI.new authority_name: "helpful-iain@theprintedbird.com",
|
12
|
+
date: "2019-01-09",
|
13
|
+
specific: "My slippers"
|
14
|
+
}
|
15
|
+
Then { tag_uri.to_s == "tag:helpful-iain@theprintedbird.com,2019-01-09:My%20slippers"}
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
context "ANOTHER MOST BASIC WAY" do
|
20
|
+
When(:tag_uri) {
|
21
|
+
TagURI::URI.new email: "helpful-iain@theprintedbird.com",
|
22
|
+
date: "2019-01-09",
|
23
|
+
specific: "My slippers"
|
24
|
+
}
|
25
|
+
Then { tag_uri.to_s == "tag:helpful-iain@theprintedbird.com,2019-01-09:My%20slippers"}
|
26
|
+
end
|
27
|
+
|
28
|
+
context "(NOT TO FLOG A DEAD HORSE BUT) ANOTHER MOST BASIC WAY" do
|
29
|
+
When(:tag_uri) {
|
30
|
+
TagURI::URI.new domain: "theprintedbird.com",
|
31
|
+
date: "2019-01-09",
|
32
|
+
specific: "My slippers"
|
33
|
+
}
|
34
|
+
Then { tag_uri.to_s == "tag:theprintedbird.com,2019-01-09:My%20slippers"}
|
35
|
+
end
|
36
|
+
|
37
|
+
context "YOU HAVE A WEB LINK TO AN ARTICLE ABOUT BEESWAX (WHY NOT?) AND YOU'RE FEELING LAZY", :time_sensitive do
|
38
|
+
When(:tag_uri) {
|
39
|
+
TagURI::URI.new uri: "http://www.example.com/posts/beeswax#bees"
|
40
|
+
}
|
41
|
+
Then { tag_uri.to_s == "tag:www.example.com,2018-03-11:/posts/beeswax#bees"}
|
42
|
+
And { tag_uri.scheme == "tag" }
|
43
|
+
And { tag_uri.authority_name == "www.example.com" }
|
44
|
+
And { tag_uri.date == TIME_NOW }
|
45
|
+
And { tag_uri.specific == "/posts/beeswax" }
|
46
|
+
And { tag_uri.fragment == "bees" }
|
47
|
+
end
|
48
|
+
|
49
|
+
context "Some of the examples on the internet" do
|
50
|
+
context "diveintomark atom tag" do
|
51
|
+
Given(:url) { "http://diveintomark.org/archives/2004/05/27/howto-atom-linkblog" }
|
52
|
+
Given(:specific) { "/archives/2004/05/27/howto-atom-linkblog" }
|
53
|
+
Given(:date) { Time.strptime "2004/05/27", "%Y/%m/%d" }
|
54
|
+
Given(:authority_name) { "diveintomark.org" }
|
55
|
+
Given(:prefix) { "/archives/2004/05/27" }
|
56
|
+
Given(:expected) { "tag:diveintomark.org,2004-05-27:/archives/2004/05/27/howto-atom-linkblog" }
|
57
|
+
Given(:fragment) { "" }
|
58
|
+
context "identity" do
|
59
|
+
context "by string" do
|
60
|
+
When(:tag_uri) { TagURI::URI.new uri: expected }
|
61
|
+
Then { tag_uri.to_s == expected }
|
62
|
+
And { tag_uri.scheme == "tag" }
|
63
|
+
And { tag_uri.authority_name == authority_name }
|
64
|
+
And { tag_uri.date == date }
|
65
|
+
And { tag_uri.specific == specific }
|
66
|
+
And { tag_uri.fragment == fragment }
|
67
|
+
end
|
68
|
+
context "by uri" do
|
69
|
+
When(:tag_uri) { TagURI::URI.new uri: TagURI::URI.new(uri: expected) }
|
70
|
+
Then { tag_uri.to_s == expected }
|
71
|
+
And { tag_uri.scheme == "tag" }
|
72
|
+
And { tag_uri.authority_name == authority_name }
|
73
|
+
And { tag_uri.date == date }
|
74
|
+
And { tag_uri.specific == specific }
|
75
|
+
And { tag_uri.fragment == fragment }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
context "authority_name given" do
|
79
|
+
context "That is valid" do
|
80
|
+
When(:tag_uri) { TagURI::URI.new uri: url,
|
81
|
+
authority_name: authority_name }
|
82
|
+
Then { tag_uri.to_s == expected }
|
83
|
+
And { tag_uri.scheme == "tag" }
|
84
|
+
And { tag_uri.authority_name == authority_name }
|
85
|
+
And { tag_uri.date == date }
|
86
|
+
And { tag_uri.specific == specific }
|
87
|
+
And { tag_uri.fragment == fragment }
|
88
|
+
end
|
89
|
+
context "That is not valid" do
|
90
|
+
it "should fail, tagged by TagURI" do
|
91
|
+
expect { TagURI::URI.new uri: url,
|
92
|
+
authority_name: "NOT_A_DOMAIN_NAME"
|
93
|
+
}.to raise_error TagURI::ArgumentError
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
context "date given" do
|
98
|
+
context "That is valid" do
|
99
|
+
When(:tag_uri) { TagURI::URI.new uri: url,
|
100
|
+
date: date }
|
101
|
+
Then { tag_uri.to_s == expected }
|
102
|
+
And { tag_uri.scheme == "tag" }
|
103
|
+
And { tag_uri.authority_name == authority_name }
|
104
|
+
And { tag_uri.date == date }
|
105
|
+
And { tag_uri.specific == specific }
|
106
|
+
And { tag_uri.fragment == fragment }
|
107
|
+
end
|
108
|
+
|
109
|
+
context "That is not valid" do
|
110
|
+
date = "Not a date"
|
111
|
+
it "should throw an error (tagged by the library)" do
|
112
|
+
expect { TagURI::URI.new uri: url, date: date }.to raise_error TagURI::ArgumentError
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
context "specific given" do
|
117
|
+
When(:tag_uri) { TagURI::URI.new uri: url,
|
118
|
+
specific: specific }
|
119
|
+
Then { tag_uri.to_s == expected }
|
120
|
+
And { tag_uri.scheme == "tag" }
|
121
|
+
And { tag_uri.authority_name == authority_name }
|
122
|
+
And { tag_uri.date == date }
|
123
|
+
And { tag_uri.specific == specific }
|
124
|
+
And { tag_uri.fragment == fragment }
|
125
|
+
end
|
126
|
+
context "email given" do
|
127
|
+
context "That is valid" do
|
128
|
+
Given(:email) { "alice@example.org" }
|
129
|
+
When(:tag_uri) { TagURI::URI.new uri: url,
|
130
|
+
email: email }
|
131
|
+
Then { tag_uri.to_s == expected.sub(authority_name, email) }
|
132
|
+
And { tag_uri.scheme == "tag" }
|
133
|
+
And { tag_uri.authority_name == email }
|
134
|
+
And { tag_uri.date == date }
|
135
|
+
And { tag_uri.specific == specific }
|
136
|
+
And { tag_uri.fragment == fragment }
|
137
|
+
end
|
138
|
+
context "That is not valid" do
|
139
|
+
it "should fail, tagged by TagURI" do
|
140
|
+
expect { TagURI::URI.new uri: url,
|
141
|
+
email: "NOT_AN_EMAIL_ADDRESS"
|
142
|
+
}.to raise_error TagURI::ArgumentError
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "domain given" do
|
148
|
+
context "That is valid" do
|
149
|
+
Given(:domain) { "diveintomark.org" }
|
150
|
+
When(:tag_uri) { TagURI::URI.new uri: url,
|
151
|
+
domain: domain }
|
152
|
+
Then { tag_uri.to_s == expected }
|
153
|
+
And { tag_uri.scheme == "tag" }
|
154
|
+
And { tag_uri.authority_name == domain }
|
155
|
+
And { tag_uri.date == date }
|
156
|
+
And { tag_uri.specific == specific }
|
157
|
+
And { tag_uri.fragment == fragment }
|
158
|
+
end
|
159
|
+
context "That is not valid" do
|
160
|
+
it "should fail, tagged by TagURI" do
|
161
|
+
expect { TagURI::URI.new uri: url,
|
162
|
+
domain: "NOT_A_DOMAIN_NAME"
|
163
|
+
}.to raise_error TagURI::ArgumentError
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "No authority_name or domain or email given" do
|
169
|
+
context "But the URI has valid one of those" do
|
170
|
+
When(:tag_uri) { TagURI::URI.new uri: url }
|
171
|
+
Then { tag_uri.to_s == expected }
|
172
|
+
And { tag_uri.scheme == "tag" }
|
173
|
+
And { tag_uri.authority_name == authority_name }
|
174
|
+
And { tag_uri.date == date }
|
175
|
+
And { tag_uri.specific == specific }
|
176
|
+
And { tag_uri.fragment == fragment }
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
context "Sandro's dog tag" do
|
181
|
+
Given(:url) { "sandro@hawke.org" }
|
182
|
+
Given(:authority_name) { "sandro@hawke.org" }
|
183
|
+
Given(:specific) { "Taiko" }
|
184
|
+
Given(:date) { Time.parse "2001-06-05" }
|
185
|
+
Given(:expected) { "tag:sandro@hawke.org,2001-06-05:Taiko" }
|
186
|
+
Given(:fragment) { "" }
|
187
|
+
context "identity" do
|
188
|
+
When(:tag_uri) { TagURI::URI.new uri: expected }
|
189
|
+
Then { tag_uri.to_s == expected }
|
190
|
+
And { tag_uri.scheme == "tag" }
|
191
|
+
And { tag_uri.authority_name == authority_name }
|
192
|
+
And { tag_uri.date == date }
|
193
|
+
And { tag_uri.specific == specific }
|
194
|
+
And { tag_uri.fragment == fragment }
|
195
|
+
end
|
196
|
+
context "authority_name given" do
|
197
|
+
When(:tag_uri) { TagURI::URI.new uri: url,
|
198
|
+
authority_name: authority_name }
|
199
|
+
Given(:expected) { "tag:sandro@hawke.org,2018-03-11:sandro@hawke.org" }
|
200
|
+
Then { tag_uri.to_s == expected }
|
201
|
+
And { tag_uri.scheme == "tag" }
|
202
|
+
And { tag_uri.authority_name == authority_name }
|
203
|
+
And { tag_uri.date == TIME_NOW }
|
204
|
+
And { tag_uri.specific == authority_name }
|
205
|
+
And { tag_uri.fragment == fragment }
|
206
|
+
end
|
207
|
+
context "date given" do
|
208
|
+
When(:tag_uri) { TagURI::URI.new uri: url,
|
209
|
+
date: date }
|
210
|
+
Given(:expected) { "tag:sandro@hawke.org,2001-06-05:sandro@hawke.org" }
|
211
|
+
Then { tag_uri.to_s == expected }
|
212
|
+
And { tag_uri.scheme == "tag" }
|
213
|
+
And { tag_uri.authority_name == authority_name }
|
214
|
+
And { tag_uri.date == date }
|
215
|
+
And { tag_uri.specific == authority_name }
|
216
|
+
And { tag_uri.fragment == fragment }
|
217
|
+
end
|
218
|
+
context "specific given" do
|
219
|
+
When(:tag_uri) { TagURI::URI.new uri: url,
|
220
|
+
specific: specific }
|
221
|
+
Given(:expected) { "tag:sandro@hawke.org,2018-03-11:Taiko" }
|
222
|
+
Then { tag_uri.to_s == expected }
|
223
|
+
And { tag_uri.scheme == "tag" }
|
224
|
+
And { tag_uri.authority_name == authority_name }
|
225
|
+
And { tag_uri.date == TIME_NOW }
|
226
|
+
And { tag_uri.specific == specific }
|
227
|
+
And { tag_uri.fragment == fragment }
|
228
|
+
end
|
229
|
+
context "No authority_name or domain or email given" do
|
230
|
+
context "But the URI has valid one of those" do
|
231
|
+
When(:tag_uri) { TagURI::URI.new uri: url, specific: specific, date: date }
|
232
|
+
Then { tag_uri.to_s == expected }
|
233
|
+
And { tag_uri.scheme == "tag" }
|
234
|
+
And { tag_uri.authority_name == authority_name }
|
235
|
+
And { tag_uri.date == date }
|
236
|
+
And { tag_uri.specific == specific }
|
237
|
+
And { tag_uri.fragment == fragment }
|
238
|
+
end
|
239
|
+
end
|
21
240
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
241
|
+
end
|
242
|
+
context "And one I made up because I was listening to Beeswax by Nirvana at the time" do
|
243
|
+
context "Beeswax" do
|
244
|
+
Given(:url) { "http://example.com/2019-01-09/beeswax#bees" }
|
245
|
+
Given(:specific) { "beeswax" }
|
246
|
+
Given(:date) { Time.parse "2019-01-08" }
|
247
|
+
Given(:authority_name) { "example.com" }
|
248
|
+
Given(:expected) { "tag:example.com,2019-01-08:beeswax#bees" }
|
249
|
+
Given(:fragment) { "bees" }
|
250
|
+
context "identity" do
|
251
|
+
When(:tag_uri) { TagURI::URI.new uri: expected }
|
252
|
+
Then { tag_uri.to_s == expected }
|
253
|
+
And { tag_uri.scheme == "tag" }
|
254
|
+
And { tag_uri.authority_name == authority_name }
|
255
|
+
And { tag_uri.date == date }
|
256
|
+
And { tag_uri.specific == specific }
|
257
|
+
And { tag_uri.fragment == fragment }
|
258
|
+
end
|
259
|
+
context "authority_name given" do
|
260
|
+
When(:tag_uri) { TagURI::URI.new uri: url,
|
261
|
+
authority_name: authority_name }
|
262
|
+
Given(:expected) { "tag:example.com,2019-01-09:/2019-01-09/beeswax#bees" }
|
263
|
+
Then { tag_uri.to_s == expected }
|
264
|
+
And { tag_uri.scheme == "tag" }
|
265
|
+
And { tag_uri.authority_name == authority_name }
|
266
|
+
And { tag_uri.date == Time.parse("2019-01-09") }
|
267
|
+
And { tag_uri.specific == "/2019-01-09/beeswax" }
|
268
|
+
And { tag_uri.fragment == fragment }
|
269
|
+
end
|
270
|
+
context "date given" do
|
271
|
+
When(:tag_uri) { TagURI::URI.new uri: url,
|
272
|
+
date: date }
|
273
|
+
Given(:expected) { "tag:example.com,2019-01-08:/2019-01-09/beeswax#bees" }
|
274
|
+
Then { tag_uri.to_s == expected }
|
275
|
+
And { tag_uri.scheme == "tag" }
|
276
|
+
And { tag_uri.authority_name == authority_name }
|
277
|
+
And { tag_uri.date == date }
|
278
|
+
And { tag_uri.specific == "/2019-01-09/beeswax" }
|
279
|
+
And { tag_uri.fragment == fragment }
|
25
280
|
end
|
281
|
+
context "fragment given" do
|
282
|
+
When(:tag_uri) { TagURI::URI.new uri: url,
|
283
|
+
fragment: "bees" }
|
284
|
+
Given(:expected) { "tag:example.com,2019-01-09:/2019-01-09/beeswax#bees" }
|
285
|
+
Then { tag_uri.to_s == expected }
|
286
|
+
And { tag_uri.scheme == "tag" }
|
287
|
+
And { tag_uri.authority_name == authority_name }
|
288
|
+
And { tag_uri.date == Time.parse("2019-01-09") }
|
289
|
+
And { tag_uri.specific == "/2019-01-09/beeswax" }
|
290
|
+
And { tag_uri.fragment == fragment }
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe "Validating a tag" do
|
297
|
+
context "A valid tag" do
|
298
|
+
Given(:a_tag) { "tag:diveintomark.org,2004-05-27:/archives/2004/05/27/howto-atom-linkblog" }
|
299
|
+
When(:tag_uri) { TagURI::URI.new uri: a_tag }
|
300
|
+
Then { tag_uri.valid? }
|
301
|
+
end
|
302
|
+
context "An invalid tag" do
|
303
|
+
Given(:a_tag) { "tag:,2004-05-27:/archives/2004/05/27/howto-atom-linkblog" }
|
304
|
+
When(:tag_uri) { TagURI::URI.new uri: a_tag }
|
305
|
+
Then { !tag_uri.valid? }
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
|
310
|
+
SHOULD = []
|
311
|
+
SHOULD_NOT = []
|
312
|
+
pn = Spec_dir.join("support/fixtures/urls.txt")
|
313
|
+
|
314
|
+
pn.each_line do |line|
|
315
|
+
line.chomp!
|
316
|
+
next if line.nil? or line.empty?
|
317
|
+
if ~ /^SHOULD MATCH\:/ ... ~ /^END/ # flip flop be bop
|
318
|
+
SHOULD << line unless $~ or ~ /^SHOULD MATCH\:/
|
319
|
+
else
|
320
|
+
SHOULD_NOT << line unless ~ /^SHOULD NOT MATCH\:/
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
|
325
|
+
describe "TagURI::URI::DNSNAME" do
|
326
|
+
|
327
|
+
SHOULD.each do |uri|
|
328
|
+
context "#{uri}" do
|
329
|
+
When(:match) { /^#{TagURI::URI::DNSNAME}$/ =~ uri }
|
330
|
+
Then { match }
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
SHOULD_NOT.each do |uri|
|
335
|
+
context "#{uri}" do
|
336
|
+
When(:match) { /^#{TagURI::URI::DNSNAME}$/ =~ uri }
|
337
|
+
Then { !match }
|
26
338
|
end
|
27
339
|
end
|
28
340
|
end
|
data/tag_uri.gemspec
CHANGED
@@ -7,10 +7,10 @@ Gem::Specification.new do |gem|
|
|
7
7
|
gem.name = "tag_uri"
|
8
8
|
gem.version = TagURI::VERSION
|
9
9
|
gem.authors = ["Iain Barnett"]
|
10
|
-
gem.email = ["
|
10
|
+
gem.email = ["helpful-iain@theprintedbird.com"]
|
11
11
|
gem.description = %q{An implementation of tag URI's.
|
12
12
|
See http://tools.ietf.org/html/rfc4151}
|
13
|
-
gem.summary = %q{Instead of using a permalink as the id for an Atom feed entry, use a tag URI.}
|
13
|
+
gem.summary = %q{Instead of using a permalink as the id for an Atom feed entry (or anything else you'd use a permalink for), use a tag URI.}
|
14
14
|
gem.homepage = "https://github.com/yb66/tag-uri"
|
15
15
|
|
16
16
|
gem.files = `git ls-files`.split($/)
|
@@ -19,4 +19,6 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
gem.add_dependency("addressable")
|
21
21
|
gem.required_ruby_version = '~> 2.0'
|
22
|
+
gem.cert_chain = ['certs/yb66.pem']
|
23
|
+
gem.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/
|
22
24
|
end
|
metadata
CHANGED
@@ -1,14 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tag_uri
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Iain Barnett
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIEbjCCAtagAwIBAgIBATANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDDCVoZWxw
|
14
|
+
ZnVsLWlhaW4vREM9dGhlcHJpbnRlZGJpcmQvREM9Y29tMB4XDTE5MDExNTA3MjAw
|
15
|
+
OVoXDTIwMDExNTA3MjAwOVowMDEuMCwGA1UEAwwlaGVscGZ1bC1pYWluL0RDPXRo
|
16
|
+
ZXByaW50ZWRiaXJkL0RDPWNvbTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoC
|
17
|
+
ggGBALhp1KlrdriWAuhXhM3I0oZblbOUAgk8UZSyI6vLQ4oK8uHWmdBkrzUublq4
|
18
|
+
7cU1T0IIFeKOzjN2aXS660q2Ev7Bpwt1oBjMVqLMZYJM4gixwzXW9labQhnjefEy
|
19
|
+
CTWRa/i4gL8NbwOg/UeX5rHiCy/xaqyxj//24E7m5e72JrpK11ZZ5/4TUvxDfOJr
|
20
|
+
w+16BAxH3ELBRjXoOXnlb7SzA2ohNnwuoom5gi9Ju6z0ooSa9cegqauHBbme8wgO
|
21
|
+
5bPwGi+MbiLKoMDcnakuUoKqWL6qA+/QofNnrmtgBmMe08dd9/ermztT/dBdNQiE
|
22
|
+
eOXDR+sM5ardxl+5TdAcGuheMgZBiBVqaMVowUp1VPV1f/sY8RsfYqFVBg/I+jcu
|
23
|
+
uulV50CkaLYmZVa0sWiCNg/pkKROpVktwfkRo3EKCllckMc29qPts64g0UkyBi1q
|
24
|
+
stO7Yk/0PmhHcWHHv8Lfuin0Cmpt01AuKi3ToOBJHAvLWkORlOw1mIC9mdOR3c9Y
|
25
|
+
jeBbawIDAQABo4GSMIGPMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
|
26
|
+
BBSyOPfHSTgay7iGZ94b0JDrrcaBDTAqBgNVHREEIzAhgR9oZWxwZnVsLWlhaW5A
|
27
|
+
dGhlcHJpbnRlZGJpcmQuY29tMCoGA1UdEgQjMCGBH2hlbHBmdWwtaWFpbkB0aGVw
|
28
|
+
cmludGVkYmlyZC5jb20wDQYJKoZIhvcNAQELBQADggGBAAoYHPvpy84kUzvM1tMF
|
29
|
+
AMUFH6V/hkBdcTRS3mE+8lpMHBiPluByk1/vfUTlo9kGFtEEXd1ginKqMozLKFrr
|
30
|
+
5yRAi08zsRA0pSDuOJsX95x4Rr5GnAUKeVOXJHry0Kae3btQdJ59ZqvFPyNiXKEB
|
31
|
+
SUIa4GUcWFaIl2yL7epcCNsyhEqvnRPq0zvfY0IGT3AcHxchCWbnurkci32eAiqW
|
32
|
+
TESqr8zDJzsH7HSyOHlNdvWQRrYfhh8p+JsbRqJ4rChBPYnZM6fnlFtvPUNbBaRr
|
33
|
+
cw7FROiP0G0E7GAd7loZ78WoQEM6regiCibP3LPehIl94P3K2+CCOI148rNlyXBE
|
34
|
+
ATDB99qMn3ZgZEE0i5jxxVOHbMQWcvN3oElPuVVq6gLhqnZn50DW2B6wf3s4MMMd
|
35
|
+
ILghhrKlF+3IGSo6pOtgZB3Y84IgtvmYyo3Unv8VkRqZ22ZSxz7GFy+X7SABSGxU
|
36
|
+
ewk/WBT8wib1dm745Y+U42Icj8FgHqKkq1mDIcMcyLqxLA==
|
37
|
+
-----END CERTIFICATE-----
|
38
|
+
date: 2019-01-15 00:00:00.000000000 Z
|
12
39
|
dependencies:
|
13
40
|
- !ruby/object:Gem::Dependency
|
14
41
|
name: addressable
|
@@ -28,7 +55,7 @@ description: |-
|
|
28
55
|
An implementation of tag URI's.
|
29
56
|
See http://tools.ietf.org/html/rfc4151
|
30
57
|
email:
|
31
|
-
-
|
58
|
+
- helpful-iain@theprintedbird.com
|
32
59
|
executables: []
|
33
60
|
extensions: []
|
34
61
|
extra_rdoc_files: []
|
@@ -40,11 +67,13 @@ files:
|
|
40
67
|
- LICENCE.txt
|
41
68
|
- README.md
|
42
69
|
- Rakefile
|
70
|
+
- certs/yb66.pem
|
43
71
|
- lib/tag-uri.rb
|
44
72
|
- lib/tag_uri.rb
|
45
73
|
- lib/tag_uri/version.rb
|
46
74
|
- lib/taguri.rb
|
47
75
|
- spec/spec_helper.rb
|
76
|
+
- spec/support/fixtures/urls.txt
|
48
77
|
- spec/tag_uri_spec.rb
|
49
78
|
- tag_uri.gemspec
|
50
79
|
homepage: https://github.com/yb66/tag-uri
|
@@ -66,11 +95,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
95
|
version: '0'
|
67
96
|
requirements: []
|
68
97
|
rubyforge_project:
|
69
|
-
rubygems_version: 2.
|
98
|
+
rubygems_version: 2.7.3
|
70
99
|
signing_key:
|
71
100
|
specification_version: 4
|
72
|
-
summary: Instead of using a permalink as the id for an Atom feed entry
|
73
|
-
URI.
|
101
|
+
summary: Instead of using a permalink as the id for an Atom feed entry (or anything
|
102
|
+
else you'd use a permalink for), use a tag URI.
|
74
103
|
test_files:
|
75
104
|
- spec/spec_helper.rb
|
105
|
+
- spec/support/fixtures/urls.txt
|
76
106
|
- spec/tag_uri_spec.rb
|
metadata.gz.sig
ADDED
Binary file
|