json-schema-openc-fork 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.
Files changed (114) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE.md +19 -0
  3. data/README.textile +452 -0
  4. data/lib/json-schema.rb +19 -0
  5. data/lib/json-schema/attribute.rb +43 -0
  6. data/lib/json-schema/attributes/additionalitems.rb +28 -0
  7. data/lib/json-schema/attributes/additionalproperties.rb +58 -0
  8. data/lib/json-schema/attributes/allof.rb +39 -0
  9. data/lib/json-schema/attributes/anyof.rb +47 -0
  10. data/lib/json-schema/attributes/dependencies.rb +44 -0
  11. data/lib/json-schema/attributes/disallow.rb +12 -0
  12. data/lib/json-schema/attributes/divisibleby.rb +22 -0
  13. data/lib/json-schema/attributes/enum.rb +24 -0
  14. data/lib/json-schema/attributes/extends.rb +50 -0
  15. data/lib/json-schema/attributes/format.rb +14 -0
  16. data/lib/json-schema/attributes/formats/custom.rb +21 -0
  17. data/lib/json-schema/attributes/formats/date.rb +24 -0
  18. data/lib/json-schema/attributes/formats/date_time.rb +36 -0
  19. data/lib/json-schema/attributes/formats/date_time_v4.rb +15 -0
  20. data/lib/json-schema/attributes/formats/ip.rb +41 -0
  21. data/lib/json-schema/attributes/formats/time.rb +22 -0
  22. data/lib/json-schema/attributes/formats/uri.rb +20 -0
  23. data/lib/json-schema/attributes/items.rb +26 -0
  24. data/lib/json-schema/attributes/limit.rb +179 -0
  25. data/lib/json-schema/attributes/maxdecimal.rb +18 -0
  26. data/lib/json-schema/attributes/multipleof.rb +11 -0
  27. data/lib/json-schema/attributes/not.rb +30 -0
  28. data/lib/json-schema/attributes/oneof.rb +56 -0
  29. data/lib/json-schema/attributes/pattern.rb +18 -0
  30. data/lib/json-schema/attributes/patternproperties.rb +22 -0
  31. data/lib/json-schema/attributes/properties.rb +74 -0
  32. data/lib/json-schema/attributes/properties_optional.rb +26 -0
  33. data/lib/json-schema/attributes/ref.rb +74 -0
  34. data/lib/json-schema/attributes/required.rb +28 -0
  35. data/lib/json-schema/attributes/type.rb +83 -0
  36. data/lib/json-schema/attributes/type_v4.rb +29 -0
  37. data/lib/json-schema/attributes/uniqueitems.rb +16 -0
  38. data/lib/json-schema/errors/custom_format_error.rb +6 -0
  39. data/lib/json-schema/errors/json_parse_error.rb +6 -0
  40. data/lib/json-schema/errors/schema_error.rb +6 -0
  41. data/lib/json-schema/errors/validation_error.rb +46 -0
  42. data/lib/json-schema/schema.rb +63 -0
  43. data/lib/json-schema/schema/reader.rb +113 -0
  44. data/lib/json-schema/schema/validator.rb +36 -0
  45. data/lib/json-schema/util/array_set.rb +14 -0
  46. data/lib/json-schema/util/uri.rb +16 -0
  47. data/lib/json-schema/util/uuid.rb +285 -0
  48. data/lib/json-schema/validator.rb +592 -0
  49. data/lib/json-schema/validators/draft1.rb +45 -0
  50. data/lib/json-schema/validators/draft2.rb +46 -0
  51. data/lib/json-schema/validators/draft3.rb +50 -0
  52. data/lib/json-schema/validators/draft4.rb +56 -0
  53. data/lib/json-schema/validators/hyper-draft4.rb +14 -0
  54. data/resources/draft-01.json +155 -0
  55. data/resources/draft-02.json +166 -0
  56. data/resources/draft-03.json +174 -0
  57. data/resources/draft-04.json +150 -0
  58. data/test/data/all_of_ref_data.json +3 -0
  59. data/test/data/any_of_ref_data.json +7 -0
  60. data/test/data/bad_data_1.json +3 -0
  61. data/test/data/good_data_1.json +3 -0
  62. data/test/data/one_of_ref_links_data.json +5 -0
  63. data/test/schemas/address_microformat.json +18 -0
  64. data/test/schemas/all_of_ref_base_schema.json +6 -0
  65. data/test/schemas/all_of_ref_schema.json +7 -0
  66. data/test/schemas/any_of_ref_jane_schema.json +4 -0
  67. data/test/schemas/any_of_ref_jimmy_schema.json +4 -0
  68. data/test/schemas/any_of_ref_john_schema.json +4 -0
  69. data/test/schemas/any_of_ref_schema.json +15 -0
  70. data/test/schemas/definition_schema.json +15 -0
  71. data/test/schemas/extends_and_additionalProperties-1-filename.schema.json +34 -0
  72. data/test/schemas/extends_and_additionalProperties-1-ref.schema.json +34 -0
  73. data/test/schemas/extends_and_additionalProperties-2-filename.schema.json +33 -0
  74. data/test/schemas/extends_and_additionalProperties-2-ref.schema.json +33 -0
  75. data/test/schemas/good_schema_1.json +10 -0
  76. data/test/schemas/good_schema_2.json +10 -0
  77. data/test/schemas/good_schema_extends1.json +10 -0
  78. data/test/schemas/good_schema_extends2.json +13 -0
  79. data/test/schemas/inner.schema.json +21 -0
  80. data/test/schemas/one_of_ref_links_schema.json +16 -0
  81. data/test/schemas/ref john with spaces schema.json +11 -0
  82. data/test/schemas/relative_definition_schema.json +8 -0
  83. data/test/schemas/self_link_schema.json +17 -0
  84. data/test/schemas/up_link_schema.json +17 -0
  85. data/test/test_all_of_ref_schema.rb +35 -0
  86. data/test/test_any_of_ref_schema.rb +35 -0
  87. data/test/test_bad_schema_ref.rb +39 -0
  88. data/test/test_common_test_suite.rb +66 -0
  89. data/test/test_custom_format.rb +116 -0
  90. data/test/test_definition.rb +15 -0
  91. data/test/test_extended_schema.rb +62 -0
  92. data/test/test_extends_and_additionalProperties.rb +52 -0
  93. data/test/test_files_v3.rb +43 -0
  94. data/test/test_fragment_resolution.rb +30 -0
  95. data/test/test_fragment_validation_with_ref.rb +34 -0
  96. data/test/test_full_validation.rb +208 -0
  97. data/test/test_helper.rb +47 -0
  98. data/test/test_initialize_data.rb +118 -0
  99. data/test/test_jsonschema_draft1.rb +171 -0
  100. data/test/test_jsonschema_draft2.rb +142 -0
  101. data/test/test_jsonschema_draft3.rb +502 -0
  102. data/test/test_jsonschema_draft4.rb +704 -0
  103. data/test/test_list_option.rb +21 -0
  104. data/test/test_merge_missing_values.rb +45 -0
  105. data/test/test_minitems.rb +16 -0
  106. data/test/test_one_of.rb +85 -0
  107. data/test/test_ruby_schema.rb +59 -0
  108. data/test/test_schema_loader.rb +74 -0
  109. data/test/test_schema_type_attribute.rb +20 -0
  110. data/test/test_schema_validation.rb +185 -0
  111. data/test/test_stringify.rb +48 -0
  112. data/test/test_uri_related.rb +67 -0
  113. data/test/test_validator.rb +53 -0
  114. metadata +284 -0
@@ -0,0 +1,63 @@
1
+ require 'pathname'
2
+
3
+ module JSON
4
+ class Schema
5
+
6
+ attr_accessor :schema, :uri, :validator
7
+
8
+ def initialize(schema,uri,parent_validator=nil)
9
+ @schema = schema
10
+ @uri = uri
11
+
12
+ # If there is an ID on this schema, use it to generate the URI
13
+ if @schema['id'] && @schema['id'].kind_of?(String)
14
+ temp_uri = Addressable::URI.parse(@schema['id'])
15
+ if temp_uri.relative?
16
+ temp_uri = uri.join(temp_uri)
17
+ end
18
+ @uri = temp_uri
19
+ end
20
+ @uri.fragment = ''
21
+
22
+ # If there is a $schema on this schema, use it to determine which validator to use
23
+ if @schema['$schema']
24
+ @validator = JSON::Validator.validator_for(@schema['$schema'])
25
+ elsif parent_validator
26
+ @validator = parent_validator
27
+ else
28
+ @validator = JSON::Validator.default_validator
29
+ end
30
+ end
31
+
32
+ def validate(data, fragments, processor, options = {})
33
+ @validator.validate(self, data, fragments, processor, options)
34
+ end
35
+
36
+ def self.stringify(schema)
37
+ case schema
38
+ when Hash then
39
+ Hash[schema.map { |key, value| [key.to_s, stringify(schema[key])] }]
40
+ when Array then
41
+ schema.map do |schema_item|
42
+ stringify(schema_item)
43
+ end
44
+ when Symbol then
45
+ schema.to_s
46
+ else
47
+ schema
48
+ end
49
+ end
50
+
51
+ # @return [JSON::Schema] a new schema matching an array whose items all match this schema.
52
+ def to_array_schema
53
+ array_schema = { 'type' => 'array', 'items' => schema }
54
+ array_schema['$schema'] = schema['$schema'] unless schema['$schema'].nil?
55
+ JSON::Schema.new(array_schema, uri, validator)
56
+ end
57
+
58
+ def to_s
59
+ @schema.to_json
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,113 @@
1
+ require 'open-uri'
2
+ require 'addressable/uri'
3
+ require 'pathname'
4
+
5
+ module JSON
6
+ class Schema
7
+ # Raised by {JSON::Schema::Reader} when one of its settings indicate
8
+ # a schema should not be readed.
9
+ class ReadRefused < StandardError
10
+ # @return [String] the requested schema location which was refused
11
+ attr_reader :location
12
+
13
+ # @return [Symbol] either +:uri+ or +:file+
14
+ attr_reader :type
15
+
16
+ def initialize(location, type)
17
+ @location = location
18
+ @type = type
19
+ super("Read of #{type == :uri ? 'URI' : type} at #{location} refused!")
20
+ end
21
+ end
22
+
23
+ # When an unregistered schema is encountered, the {JSON::Schema::Reader} is
24
+ # used to fetch its contents and register it with the {JSON::Validator}.
25
+ #
26
+ # This default reader will read schemas from the filesystem or from a URI.
27
+ class Reader
28
+ # The behavior of the schema reader can be controlled by providing
29
+ # callbacks to determine whether to permit reading referenced schemas.
30
+ # The options +accept_uri+ and +accept_file+ should be procs which
31
+ # accept a +URI+ or +Pathname+ object, and return a boolean value
32
+ # indicating whether to read the referenced schema.
33
+ #
34
+ # URIs using the +file+ scheme will be normalized into +Pathname+ objects
35
+ # and passed to the +accept_file+ callback.
36
+ #
37
+ # @param options [Hash]
38
+ # @option options [Boolean, #call] accept_uri (true)
39
+ # @option options [Boolean, #call] accept_file (true)
40
+ #
41
+ # @example Reject all unregistered schemas
42
+ # JSON::Validator.schema_reader = JSON::Schema::Reader.new(
43
+ # :accept_uri => false,
44
+ # :accept_file => false
45
+ # )
46
+ #
47
+ # @example Only permit URIs from certain hosts
48
+ # JSON::Validator.schema_reader = JSON::Schema::Reader.new(
49
+ # :accept_file => false,
50
+ # :accept_uri => proc { |uri| ['mycompany.com', 'json-schema.org'].include?(uri.host) }
51
+ # )
52
+ def initialize(options = {})
53
+ @accept_uri = options.fetch(:accept_uri, true)
54
+ @accept_file = options.fetch(:accept_file, true)
55
+ end
56
+
57
+ # @param location [#to_s] The location from which to read the schema
58
+ # @return [JSON::Schema]
59
+ # @raise [JSON::Schema::ReadRefused] if +accept_uri+ or +accept_file+
60
+ # indicated the schema should not be readed
61
+ # @raise [JSON::ParserError] if the schema was not a valid JSON object
62
+ def read(location)
63
+ uri = Addressable::URI.parse(location.to_s)
64
+ body = if uri.scheme.nil? || uri.scheme == 'file'
65
+ uri = Addressable::URI.convert_path(uri.path)
66
+ read_file(Pathname.new(uri.path).expand_path)
67
+ else
68
+ read_uri(uri)
69
+ end
70
+
71
+ JSON::Schema.new(JSON::Validator.parse(body), uri)
72
+ end
73
+
74
+ # @param uri [Addressable::URI]
75
+ # @return [Boolean]
76
+ def accept_uri?(uri)
77
+ if @accept_uri.respond_to?(:call)
78
+ @accept_uri.call(uri)
79
+ else
80
+ @accept_uri
81
+ end
82
+ end
83
+
84
+ # @param pathname [Pathname]
85
+ # @return [Boolean]
86
+ def accept_file?(pathname)
87
+ if @accept_file.respond_to?(:call)
88
+ @accept_file.call(pathname)
89
+ else
90
+ @accept_file
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def read_uri(uri)
97
+ if accept_uri?(uri)
98
+ open(uri.to_s).read
99
+ else
100
+ raise JSON::Schema::ReadRefused.new(uri.to_s, :uri)
101
+ end
102
+ end
103
+
104
+ def read_file(pathname)
105
+ if accept_file?(pathname)
106
+ File.read(Addressable::URI.unescape(pathname.to_s))
107
+ else
108
+ raise JSON::Schema::ReadRefused.new(pathname.to_s, :file)
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,36 @@
1
+ module JSON
2
+ class Schema
3
+ class Validator
4
+ attr_accessor :attributes, :formats, :uri, :names
5
+ attr_reader :default_formats
6
+
7
+ def initialize()
8
+ @attributes = {}
9
+ @formats = {}
10
+ @default_formats = {}
11
+ @uri = nil
12
+ @names = []
13
+ @metaschema_name = ''
14
+ end
15
+
16
+ def extend_schema_definition(schema_uri)
17
+ validator = JSON::Validator.validator_for(schema_uri)
18
+ @attributes.merge!(validator.attributes)
19
+ end
20
+
21
+ def validate(current_schema, data, fragments, processor, options = {})
22
+ current_schema.schema.each do |attr_name,attribute|
23
+ if @attributes.has_key?(attr_name.to_s)
24
+ @attributes[attr_name.to_s].validate(current_schema, data, fragments, processor, self, options)
25
+ end
26
+ end
27
+ data
28
+ end
29
+
30
+ def metaschema
31
+ resources = File.expand_path('../../../../resources', __FILE__)
32
+ File.join(resources, @metaschema_name)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ # This is a hack that I don't want to ever use anywhere else or repeat EVER, but we need enums to be
2
+ # an Array to pass schema validation. But we also want fast lookup! And we can't use sets because of
3
+ # backport support... so...
4
+
5
+ class ArraySet < Array
6
+ def include?(obj)
7
+ # On first invocation create a HASH (yeah, yeah) to act as our set given the array values
8
+ if !defined? @array_values
9
+ @array_values = {}
10
+ self.each {|x| @array_values[x] = 1}
11
+ end
12
+ @array_values.has_key? obj
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ module JSON
2
+ module Util
3
+ module URI
4
+ def self.normalized_uri(uri)
5
+ uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI)
6
+ # Check for absolute path
7
+ if uri.relative?
8
+ data = uri.to_s
9
+ data = "#{Dir.pwd}/#{data}" if data[0,1] != '/'
10
+ uri = Addressable::URI.convert_path(data)
11
+ end
12
+ uri
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,285 @@
1
+ #!/usr/bin/env ruby
2
+ ### http://mput.dip.jp/mput/uuid.txt
3
+
4
+ # Copyright(c) 2005 URABE, Shyouhei.
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this code, to deal in the code without restriction, including without
8
+ # limitation the rights to use, copy, modify, merge, publish, distribute,
9
+ # sublicense, and/or sell copies of the code, and to permit persons to whom the
10
+ # code is furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the code.
14
+ #
15
+ # THE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE CODE OR THE USE OR OTHER DEALINGS IN THE
21
+ # CODE.
22
+ #
23
+ # 2009-02-20: Modified by Pablo Lorenzoni <pablo@propus.com.br> to correctly
24
+ # include the version in the raw_bytes.
25
+
26
+
27
+ require 'digest/md5'
28
+ require 'digest/sha1'
29
+ require 'tmpdir'
30
+
31
+ module JSON
32
+ module Util
33
+
34
+ # Pure ruby UUID generator, which is compatible with RFC4122
35
+ UUID = Struct.new :raw_bytes
36
+
37
+ class UUID
38
+ private_class_method :new
39
+
40
+ class << self
41
+ def mask19 v, str # :nodoc
42
+ nstr = str.bytes.to_a
43
+ version = [0, 16, 32, 48, 64, 80][v]
44
+ nstr[6] &= 0b00001111
45
+ nstr[6] |= version
46
+ # nstr[7] &= 0b00001111
47
+ # nstr[7] |= 0b01010000
48
+ nstr[8] &= 0b00111111
49
+ nstr[8] |= 0b10000000
50
+ str = ''
51
+ nstr.each { |s| str << s.chr }
52
+ str
53
+ end
54
+
55
+ def mask18 v, str # :nodoc
56
+ version = [0, 16, 32, 48, 64, 80][v]
57
+ str[6] &= 0b00001111
58
+ str[6] |= version
59
+ # str[7] &= 0b00001111
60
+ # str[7] |= 0b01010000
61
+ str[8] &= 0b00111111
62
+ str[8] |= 0b10000000
63
+ str
64
+ end
65
+
66
+ def mask v, str
67
+ if RUBY_VERSION >= "1.9.0"
68
+ return mask19 v, str
69
+ else
70
+ return mask18 v, str
71
+ end
72
+ end
73
+ private :mask, :mask18, :mask19
74
+
75
+ # UUID generation using SHA1. Recommended over create_md5.
76
+ # Namespace object is another UUID, some of them are pre-defined below.
77
+ def create_sha1 str, namespace
78
+ sha1 = Digest::SHA1.new
79
+ sha1.update namespace.raw_bytes
80
+ sha1.update str
81
+ sum = sha1.digest
82
+ raw = mask 5, sum[0..15]
83
+ ret = new raw
84
+ ret.freeze
85
+ ret
86
+ end
87
+ alias :create_v5 :create_sha1
88
+
89
+ # UUID generation using MD5 (for backward compat.)
90
+ def create_md5 str, namespace
91
+ md5 = Digest::MD5.new
92
+ md5.update namespace.raw_bytes
93
+ md5.update str
94
+ sum = md5.digest
95
+ raw = mask 3, sum[0..16]
96
+ ret = new raw
97
+ ret.freeze
98
+ ret
99
+ end
100
+ alias :create_v3 :create_md5
101
+
102
+ # UUID generation using random-number generator. From it's random
103
+ # nature, there's no warranty that the created ID is really universaly
104
+ # unique.
105
+ def create_random
106
+ rnd = [
107
+ rand(0x100000000),
108
+ rand(0x100000000),
109
+ rand(0x100000000),
110
+ rand(0x100000000),
111
+ ].pack "N4"
112
+ raw = mask 4, rnd
113
+ ret = new raw
114
+ ret.freeze
115
+ ret
116
+ end
117
+ alias :create_v4 :create_random
118
+
119
+ def read_state fp # :nodoc:
120
+ fp.rewind
121
+ Marshal.load fp.read
122
+ end
123
+
124
+ def write_state fp, c, m # :nodoc:
125
+ fp.rewind
126
+ str = Marshal.dump [c, m]
127
+ fp.write str
128
+ end
129
+
130
+ private :read_state, :write_state
131
+ STATE_FILE = 'ruby-uuid'
132
+
133
+ # create the "version 1" UUID with current system clock, current UTC
134
+ # timestamp, and the IEEE 802 address (so-called MAC address).
135
+ #
136
+ # Speed notice: it's slow. It writes some data into hard drive on every
137
+ # invokation. If you want to speed this up, try remounting tmpdir with a
138
+ # memory based filesystem (such as tmpfs). STILL slow? then no way but
139
+ # rewrite it with c :)
140
+ def create clock=nil, time=nil, mac_addr=nil
141
+ c = t = m = nil
142
+ Dir.chdir Dir.tmpdir do
143
+ unless FileTest.exist? STATE_FILE then
144
+ # Generate a pseudo MAC address because we have no pure-ruby way
145
+ # to know the MAC address of the NIC this system uses. Note
146
+ # that cheating with pseudo arresses here is completely legal:
147
+ # see Section 4.5 of RFC4122 for details.
148
+ sha1 = Digest::SHA1.new
149
+ 256.times do
150
+ r = [rand(0x100000000)].pack "N"
151
+ sha1.update r
152
+ end
153
+ str = sha1.digest
154
+ r = rand 14 # 20-6
155
+ node = str[r, 6] || str
156
+ if RUBY_VERSION >= "1.9.0"
157
+ nnode = node.bytes.to_a
158
+ nnode[0] |= 0x01
159
+ node = ''
160
+ nnode.each { |s| node << s.chr }
161
+ else
162
+ node[0] |= 0x01 # multicast bit
163
+ end
164
+ k = rand 0x40000
165
+ open STATE_FILE, 'w' do |fp|
166
+ fp.flock IO::LOCK_EX
167
+ write_state fp, k, node
168
+ fp.chmod 0o777 # must be world writable
169
+ end
170
+ end
171
+ open STATE_FILE, 'r+' do |fp|
172
+ fp.flock IO::LOCK_EX
173
+ c, m = read_state fp
174
+ c = clock % 0x4000 if clock
175
+ m = mac_addr if mac_addr
176
+ t = time
177
+ if t.nil? then
178
+ # UUID epoch is 1582/Oct/15
179
+ tt = Time.now
180
+ t = tt.to_i*10000000 + tt.tv_usec*10 + 0x01B21DD213814000
181
+ end
182
+ c = c.succ # important; increment here
183
+ write_state fp, c, m
184
+ end
185
+ end
186
+
187
+ tl = t & 0xFFFF_FFFF
188
+ tm = t >> 32
189
+ tm = tm & 0xFFFF
190
+ th = t >> 48
191
+ th = th & 0x0FFF
192
+ th = th | 0x1000
193
+ cl = c & 0xFF
194
+ ch = c & 0x3F00
195
+ ch = ch >> 8
196
+ ch = ch | 0x80
197
+ pack tl, tm, th, cl, ch, m
198
+ end
199
+ alias :create_v1 :create
200
+
201
+ # A simple GUID parser: just ignores unknown characters and convert
202
+ # hexadecimal dump into 16-octet object.
203
+ def parse obj
204
+ str = obj.to_s.sub %r/\Aurn:uuid:/, ''
205
+ str.gsub! %r/[^0-9A-Fa-f]/, ''
206
+ raw = str[0..31].lines.to_a.pack 'H*'
207
+ ret = new raw
208
+ ret.freeze
209
+ ret
210
+ end
211
+
212
+ # The 'primitive constructor' of this class
213
+ # Note UUID.pack(uuid.unpack) == uuid
214
+ def pack tl, tm, th, ch, cl, n
215
+ raw = [tl, tm, th, ch, cl, n].pack "NnnCCa6"
216
+ ret = new raw
217
+ ret.freeze
218
+ ret
219
+ end
220
+ end
221
+
222
+ # The 'primitive deconstructor', or the dual to pack.
223
+ # Note UUID.pack(uuid.unpack) == uuid
224
+ def unpack
225
+ raw_bytes.unpack "NnnCCa6"
226
+ end
227
+
228
+ # Generate the string representation (a.k.a GUID) of this UUID
229
+ def to_s
230
+ a = unpack
231
+ tmp = a[-1].unpack 'C*'
232
+ a[-1] = sprintf '%02x%02x%02x%02x%02x%02x', *tmp
233
+ "%08x-%04x-%04x-%02x%02x-%s" % a
234
+ end
235
+ alias guid to_s
236
+
237
+ # Convert into a RFC4122-comforming URN representation
238
+ def to_uri
239
+ "urn:uuid:" + self.to_s
240
+ end
241
+ alias urn to_uri
242
+
243
+ # Convert into 128-bit unsigned integer
244
+ # Typically a Bignum instance, but can be a Fixnum.
245
+ def to_int
246
+ tmp = self.raw_bytes.unpack "C*"
247
+ tmp.inject do |r, i|
248
+ r * 256 | i
249
+ end
250
+ end
251
+ alias to_i to_int
252
+
253
+ # Gets the version of this UUID
254
+ # returns nil if bad version
255
+ def version
256
+ a = unpack
257
+ v = (a[2] & 0xF000).to_s(16)[0].chr.to_i
258
+ return v if (1..5).include? v
259
+ return nil
260
+ end
261
+
262
+ # Two UUIDs are said to be equal if and only if their (byte-order
263
+ # canonicalized) integer representations are equivallent. Refer RFC4122 for
264
+ # details.
265
+ def == other
266
+ to_i == other.to_i
267
+ end
268
+
269
+ include Comparable
270
+ # UUIDs are comparable (don't know what benefits are there, though).
271
+ def <=> other
272
+ to_s <=> other.to_s
273
+ end
274
+
275
+ # Pre-defined UUID Namespaces described in RFC4122 Appendix C.
276
+ NameSpace_DNS = parse "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
277
+ NameSpace_URL = parse "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
278
+ NameSpace_OID = parse "6ba7b812-9dad-11d1-80b4-00c04fd430c8"
279
+ NameSpace_X500 = parse "6ba7b814-9dad-11d1-80b4-00c04fd430c8"
280
+
281
+ # The Nil UUID in RFC4122 Section 4.1.7
282
+ Nil = parse "00000000-0000-0000-0000-000000000000"
283
+ end
284
+ end
285
+ end