uuid-ncname 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6d0c55013befe4854c49979a826188f10feb869e24a589a0611ae1f97a2ea600
4
+ data.tar.gz: e78b411fa76e5cfe2c971a6904a0404e8f58ec3e5b64b9fa99620146c62d3b72
5
+ SHA512:
6
+ metadata.gz: 63c11981cbf9cc492fbdf1dbba02aca38c9afbefef4b839ce70019395d7a6cbca5c77060efe814f1e2b0a68388bd0ced59d3a1defabaa3bb4210b76fa59d45e3
7
+ data.tar.gz: c0c7c3d145c1245f2aa77184dba53b9cad9157689a2ee3d259c3ffc7d3b6175b990036a8058ebc1ebef97716f3cac27ce0b975685da0a4914e51775e1d864b86
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ syntax: glob
2
+ /.bundle/
3
+ /.yardoc
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
13
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.1
5
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in uuid-ncname.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # UUID::NCName: Turn UUIDs into NCNames (and back)
2
+
3
+ ```ruby
4
+ require 'uuid-ncname'
5
+ require 'uuidtools'
6
+
7
+ uu = UUIDTools::UUID.random_create
8
+ # => #<UUID:0x3fff0e597ef8 UUID:df521e0a-9d57-4f04-9a95-fc2888decc5a>
9
+
10
+ nc64 = UUID::NCName.to_ncname uu # => "E31IeCp1X8EmpX8KIjezFK"
11
+ nc32 = UUID::NCName.to_ncname_32 uu # => "E35jb4cu5k7yetkk7ykei33gfk"
12
+
13
+ orig = UUID::NCName.from_ncname nc64
14
+ # => "df521e0a-9d57-4f04-9a95-fc2888decc5a"
15
+
16
+ orig == UUID::NCName.from_ncname nc32 # => true
17
+ orig == uu.to_s # => true
18
+
19
+ # then you can turn it back into an object or whatever
20
+ uu == UUIDTools::UUID.parse(orig) # => true
21
+ ```
22
+
23
+ ## Description
24
+
25
+ The purpose of this module is to devise an alternative representation
26
+ of the [UUID](http://tools.ietf.org/html/rfc4122) which conforms to
27
+ the constraints of various other identifiers such as NCName, and create an
28
+ [isomorphic](http://en.wikipedia.org/wiki/Isomorphism) mapping between
29
+ them.
30
+
31
+ ## Rationale & Method
32
+
33
+ The UUID is a generic identifier which is large enough to be globally
34
+ unique. This makes it useful as a canonical name for data objects in
35
+ distributed systems, especially those that cross administrative
36
+ jurisdictions, such as the World-Wide Web. The
37
+ [representation](http://tools.ietf.org/html/rfc4122#section-3),
38
+ however, of the UUID, precludes it from being used in many places
39
+ where it would be useful to do so.
40
+
41
+ In particular, there are grammars for many types of identifiers which
42
+ must not begin with a digit. Others are case-insensitive, or
43
+ prohibited from containing hyphens (present in both the standard
44
+ notation and Base64URL), or indeed anything outside of
45
+ `^[A-Za-z_][0-9A-Za-z_]*$`.
46
+
47
+ The hexadecimal notation of the UUID has a 5/8 chance of beginning
48
+ with a digit, Base64 has a 5/32 chance, and Base32 has a 3/16
49
+ chance. As such, the identifier must be modified in such a way as to
50
+ guarantee beginning with an alphabetic letter (or underscore `_`, but
51
+ some grammars even prohibit that, so we omit it as well).
52
+
53
+ While it is conceivable to simply add a padding character, there are a
54
+ few considerations which make it more appealing to derive the initial
55
+ character from the content of the UUID itself:
56
+
57
+ * UUIDs are large (128-bit) identifiers as it is, and it is
58
+ undesirable to add meaningless syntax to them if we can avoid doing
59
+ so.
60
+
61
+ * 128 bits is an inconvenient number for aligning to both Base32 (130)
62
+ and Base64 (132), though 120 divides cleanly into 5, 6 and 8.
63
+
64
+ * The 13th quartet, or higher four bits of the
65
+ `time_hi_and_version_field` of the UUID is constant, as it indicates
66
+ the UUID's version. If we encode this value using the scheme common
67
+ to both Base64 and Base32, we get values between `A` and `P`, with
68
+ the valid subset between `B` and `F`.
69
+
70
+ **Therefore:** extract the UUID's version quartet, shift all
71
+ subsequent data 4 bits to the left, zero-pad to the octet, encode with
72
+ either _base64url_ or _base32_, truncate, and finally prepend the
73
+ encoded version character. Voilà, one token-safe UUID.
74
+
75
+ ## Applications
76
+
77
+ ### XML IDs
78
+
79
+ The `ID` production appears to have been constricted, inadvertently or
80
+ otherwise, from [Name](http://www.w3.org/TR/xml11/#NT-Name) in both
81
+ the XML 1.0 and 1.1 specifications,
82
+ to [NCName](http://www.w3.org/TR/xml-names/#NT-NCName)
83
+ by [XML Schema Part 2](http://www.w3.org/TR/xmlschema-2/#ID). This
84
+ removes the colon character `:` from the grammar. The net effect is
85
+ that
86
+
87
+ <foo id="urn:uuid:b07caf81-baae-449d-8a2e-48c0f5fa5538"/>
88
+
89
+ while being a _well-formed_ ID _and_ valid under DTD validation, is
90
+ _not_ valid per XML Schema Part 2 or anything that uses it (e.g. Relax
91
+ NG).
92
+
93
+ ### RDF blank node identifiers
94
+
95
+ Blank node identifiers in RDF are intended for serialization, to act
96
+ as a handle so that multiple RDF statements can refer to the same
97
+ blank
98
+ node. The
99
+ [RDF abstract syntax specifies](http://www.w3.org/TR/rdf-concepts/#section-URI-Vocabulary) that
100
+ the validity constraints of blank node identifiers be delegated to the
101
+ concrete syntax
102
+ specifications. The
103
+ [RDF/XML syntax specification](http://www.w3.org/TR/rdf-syntax-grammar/#rdf-id) lists
104
+ the blank node identifier as NCName. However, according
105
+ to [the Turtle spec](http://www.w3.org/TR/turtle/#BNodes), this is a
106
+ valid blank node identifier:
107
+
108
+ _:42df00ec-30a2-431f-be9e-e3a612b325db
109
+
110
+ despite
111
+ [an older version](http://www.w3.org/TeamSubmission/turtle/#nodeID)
112
+ listing a production equivalent to the more conservative
113
+ NCName. NTriples syntax is
114
+ [even more constrained](http://www.w3.org/TR/rdf-testcases/#ntriples),
115
+ given as `^[A-Za-z][0-9A-Za-z]*$`.
116
+
117
+ ### Generated symbols
118
+
119
+ > There are only two hard things in computer science: cache
120
+ > invalidation and naming things [and off-by-one errors].
121
+ >
122
+ > -- Phil Karlton [extension of unknown origin]
123
+
124
+ Suppose you wanted to create a [literate
125
+ programming](http://en.wikipedia.org/wiki/Literate_programming) system
126
+ (I do). One of your (my) stipulations is that the symbols get defined
127
+ in the *prose*, rather than the _code_. However, you (I) still want
128
+ to be able to validate the code's syntax, and potentially even run the
129
+ code, without having to commit to naming anything. You are (I am) also
130
+ interested in creating a global map of classes, datatypes and code
131
+ fragments, which can be operated on and tested in isolation, ported to
132
+ other languages, or transplanted into the more conventional packages
133
+ of programs, libraries and frameworks. The Base32 UUID NCName
134
+ representation should be adequate for placeholder symbols in just
135
+ about any programming language, save for those which do not permit
136
+ identifiers as long as 26 characters (which are extremely scarce).
137
+
138
+ ## Documentation
139
+
140
+ Generated and deposited
141
+ [in the usual place](http://www.rubydoc.info/gems/uuid-ncname/).
142
+
143
+ ## Installation
144
+
145
+ You know how to do this:
146
+
147
+ $ gem install uuid-ncname
148
+
149
+ Or, [download it off rubygems.org](https://rubygems.org/gems/uuid-ncname).
150
+
151
+ ## Contributing
152
+
153
+ Bug reports and pull requests are welcome at
154
+ [the GitHub repository](https://github.com/doriantaylor/rb-uuid-ncname).
155
+
156
+ ## License
157
+
158
+ This software is provided under
159
+ the [Apache License, 2.0](https://www.apache.org/licenses/LICENSE-2.0).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "uuid/ncname"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,218 @@
1
+ require "uuid/ncname/version"
2
+
3
+ require 'base64'
4
+ require 'base32'
5
+
6
+ module UUID::NCName
7
+
8
+ private
9
+
10
+ ENCODE = {
11
+ 32 => -> bin {
12
+ bin = bin.unpack 'C*'
13
+ bin[-1] >>= 1
14
+ out = ::Base32.encode bin.pack('C*')
15
+
16
+ out.downcase[0, 25]
17
+ },
18
+ 64 => -> bin {
19
+ bin = bin.unpack 'C*'
20
+ bin[-1] >>= 2
21
+ out = ::Base64.urlsafe_encode64 bin.pack('C*')
22
+
23
+ out[0, 21]
24
+ },
25
+ }
26
+
27
+ DECODE = {
28
+ 32 => -> str {
29
+ str = str.upcase[0, 25] + 'A======'
30
+ out = ::Base32.decode(str).unpack 'C*'
31
+ out[-1] <<= 1
32
+
33
+ out.pack 'C*'
34
+ },
35
+ 64 => -> str {
36
+ str = str[0, 21] + 'A=='
37
+ out = ::Base64.urlsafe_decode64(str).unpack 'C*'
38
+ out[-1] <<= 2
39
+
40
+ out.pack 'C*'
41
+ },
42
+ }
43
+
44
+ UUF = (['%02x' * 4] + ['%02x' * 2] * 3 + ['%02x' * 6]).join '-'
45
+
46
+ FORMAT = {
47
+ str: -> bin { UUF % bin.unpack('C*') },
48
+ hex: -> bin { bin.unpack 'H*' },
49
+ b64: -> bin { ::Base64.strict_encode64 bin },
50
+ bin: -> bin { bin },
51
+ }
52
+
53
+ def self.bin_uuid_to_pair data
54
+ list = data.unpack 'N4'
55
+ version = (list[1] & 0x0000f000) >> 12
56
+ list[1] = (list[1] & 0xffff0000) |
57
+ ((list[1] & 0x00000fff) << 4) | (list[2] >> 28)
58
+ list[2] = (list[2] & 0x0fffffff) << 4 | (list[3] >> 28)
59
+ list[3] <<= 4
60
+
61
+ return version, list.pack('N4')
62
+ end
63
+
64
+ def self.pair_to_bin_uuid version, data
65
+ version &= 0xf
66
+
67
+ list = data.unpack 'N4'
68
+ list[3] >>= 4
69
+ list[3] |= ((list[2] & 0xf) << 28)
70
+ list[2] >>= 4
71
+ list[2] |= ((list[1] & 0xf) << 28)
72
+ list[1] = (
73
+ list[1] & 0xffff0000) | (version << 12) | ((list[1] >> 4) & 0xfff)
74
+
75
+ list.pack 'N4'
76
+ end
77
+
78
+ def self.encode_version version
79
+ ((version & 15) + 65).chr
80
+ end
81
+
82
+ def self.decode_version version
83
+ (version.upcase.ord - 65) % 16
84
+ end
85
+
86
+ public
87
+
88
+ # Converts a UUID (or object that when converted to a string looks
89
+ # like a UUID) to an NCName. By default it produces the Base64
90
+ # variant.
91
+ #
92
+ # @param uuid [#to_s] whatever it is, it had better look like a
93
+ # UUID. This includes UUID objects, URNs, 32-character hex strings,
94
+ # 16-byte binary strings, etc.
95
+ #
96
+ # @param radix [32, 64] either the number 32 or the number 64.
97
+ #
98
+ # @return [String] The NCName-formatted UUID.
99
+
100
+ def self.to_ncname uuid, radix: 64
101
+ raise 'Radix must be either 32 or 64' unless [32, 64].any? radix
102
+ raise 'UUID must be something stringable' if uuid.nil? or
103
+ not uuid.respond_to? :to_s
104
+
105
+ uuid = uuid.to_s
106
+
107
+ bin = nil
108
+
109
+ if uuid.length == 16
110
+ bin = uuid
111
+ else
112
+ uuid.gsub!(/\s+/, '')
113
+ if (m = /^(?:urn:uuid:)?([0-9A-Fa-f-]{32,})$/.match(uuid))
114
+ bin = [m[1].tr('-', '')].pack 'H*'
115
+ elsif (m = /^([0-9A-Za-z+\/_-]+=*)$/.match(uuid))
116
+ match= m[1].tr('-_', '+/')
117
+ bin = ::Base64.decode64(match)
118
+ else
119
+ raise "Not sure what to do with #{uuid}"
120
+ end
121
+ end
122
+
123
+ raise 'Binary representation of UUID is shorter than 16 bytes' if
124
+ bin.length < 16
125
+
126
+ version, content = bin_uuid_to_pair bin[0, 16]
127
+
128
+ encode_version(version) + ENCODE[radix].call(content)
129
+ end
130
+
131
+ # Converts an NCName-encoded UUID back to its canonical
132
+ # representation. Will return nil if the input doesn't match the
133
+ # radix (if supplied) or is otherwise malformed. doesn't match
134
+ #
135
+ # @param ncname [#to_s] an NCName-encoded UUID, either a
136
+ # 22-character (Base64) variant, or a 26-character (Base32) variant.
137
+ #
138
+ # @param radix [nil, 32, 64] Optional radix; will use heuristic if omitted.
139
+ #
140
+ # @param format [:str, :hex, :b64, :bin] An optional formatting
141
+ # parameter; defaults to `:str`, the canonical string representation.
142
+ #
143
+ # @return [String, nil] The corresponding UUID or nil if the input
144
+ # is malformed.
145
+
146
+ def self.from_ncname ncname, radix: nil, format: :str
147
+ raise 'Format must be symbol-able' unless format.respond_to? :to_sym
148
+ raise "Invalid format #{format}" unless FORMAT[format]
149
+
150
+ return unless ncname and ncname.respond_to? :to_s
151
+
152
+ ncname = ncname.to_s.strip.gsub(/\s+/, '')
153
+ match = /^([A-Za-z])([0-9A-Za-z_-]{21,})$/.match(ncname) or return
154
+
155
+ if radix
156
+ raise "Radix must be 32 or 64, not #{radix}" unless [32, 64].any? radix
157
+ return unless { 32 => 26, 64 => 22 }[radix] == ncname.length
158
+ else
159
+ len = ncname.length
160
+
161
+ if ncname =~ /[_-]/
162
+ radix = 64
163
+ elsif len >= 26
164
+ radix = 32
165
+ elsif len >= 22
166
+ radix = 64
167
+ else
168
+ # uh will this ever get executed now that i put in that return?
169
+ raise "Not sure what to do with an identifier of length #{len}."
170
+ end
171
+ end
172
+
173
+ version, content = match.captures
174
+ version = decode_version version
175
+ content = DECODE[radix].call content
176
+
177
+ bin = pair_to_bin_uuid version, content
178
+
179
+ FORMAT[format].call bin
180
+ end
181
+
182
+ # Shorthand for conversion to the Base64 version
183
+ #
184
+ # @param uuid [#to_s] The UUID
185
+ # @return [String] The Base64-encoded NCName
186
+
187
+ def self.to_ncname_64 uuid
188
+ to_ncname uuid
189
+ end
190
+
191
+ # Shorthand for conversion from the Base64 version
192
+ #
193
+ # @param ncname [#to_s] The Base64 variant of the NCName-encoded UUID
194
+ # @param format [:str, :hex, :b64, :bin] The format
195
+
196
+ def self.from_ncname_64 ncname, format: :str
197
+ from_ncname ncname, radix: 64, format: format
198
+ end
199
+
200
+ # Shorthand for conversion to the Base32 version
201
+ #
202
+ # @param uuid [#to_s] The UUID
203
+ # @return [String] The Base32-encoded NCName
204
+
205
+ def self.to_ncname_32 uuid
206
+ to_ncname uuid, radix: 32
207
+ end
208
+
209
+ # Shorthand for conversion from the Base32 version
210
+ #
211
+ # @param ncname [#to_s] The Base32 variant of the NCName-encoded UUID
212
+ # @param format [:str, :hex, :b64, :bin] The format
213
+
214
+ def self.from_ncname_32 ncname, format: :str
215
+ from_ncname ncname, radix: 32, format: format
216
+ end
217
+
218
+ end
@@ -0,0 +1,5 @@
1
+ module UUID
2
+ module NCName
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,40 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "uuid/ncname/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "uuid-ncname"
8
+ spec.version = UUID::NCName::VERSION
9
+ spec.authors = ["Dorian Taylor"]
10
+ spec.email = ["code@doriantaylor.com"]
11
+
12
+ spec.homepage = "https://github.com/doriantaylor/rb-uuid-ncname"
13
+ spec.summary = %q{Format a UUID as a valid NCName.}
14
+ spec.description = <<DESC
15
+ This module creates an isomorphic representation of a UUID which is
16
+ guaranteed to fit into the grammar of the XML NCName construct, which
17
+ also happens to exhibit (modulo case and hyphens) the same constraints
18
+ as identifiers in nearly all programming languages. Provides case
19
+ sensitive (Base64) and case-insensitive (Base32) variants.
20
+ DESC
21
+
22
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
23
+ f.match(%r{^(test|spec|features)/})
24
+ end
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ # surprisingly do not need this
30
+ # spec.add_runtime_dependency 'uuidtools', '~> 2.1.5'
31
+ spec.add_runtime_dependency 'base32', '~> 0.3.2'
32
+
33
+ spec.add_development_dependency 'bundler', '~> 1.16'
34
+ spec.add_development_dependency 'rake', '~> 10.0'
35
+ spec.add_development_dependency 'rspec', '~> 3.0'
36
+
37
+ # only need it for testing, who knew
38
+ # spec.add_development_dependency 'uuidtools', '~> 2.1.5'
39
+ # actually don't even need it for that
40
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: uuid-ncname
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dorian Taylor
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-05-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base32
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.16'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: |
70
+ This module creates an isomorphic representation of a UUID which is
71
+ guaranteed to fit into the grammar of the XML NCName construct, which
72
+ also happens to exhibit (modulo case and hyphens) the same constraints
73
+ as identifiers in nearly all programming languages. Provides case
74
+ sensitive (Base64) and case-insensitive (Base32) variants.
75
+ email:
76
+ - code@doriantaylor.com
77
+ executables: []
78
+ extensions: []
79
+ extra_rdoc_files: []
80
+ files:
81
+ - ".gitignore"
82
+ - ".rspec"
83
+ - ".travis.yml"
84
+ - Gemfile
85
+ - README.md
86
+ - Rakefile
87
+ - bin/console
88
+ - bin/setup
89
+ - lib/uuid/ncname.rb
90
+ - lib/uuid/ncname/version.rb
91
+ - uuid-ncname.gemspec
92
+ homepage: https://github.com/doriantaylor/rb-uuid-ncname
93
+ licenses: []
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.7.6
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Format a UUID as a valid NCName.
115
+ test_files: []