Skip to content

Commit 3df32ec

Browse files
authored
Add a from_payload method (#37)
1 parent 2f68d4e commit 3df32ec

File tree

7 files changed

+69
-106
lines changed

7 files changed

+69
-106
lines changed

lib/universalid/extensions/global_id/global_id_model.rb

+4-6
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,12 @@ def self.find(value)
1414
def initialize(universal_id)
1515
@uid = case universal_id
1616
when URI::UID then universal_id
17-
when String
18-
case universal_id
19-
when /\A#{URI::UID::SCHEME}/o then URI::UID.parse(universal_id)
20-
else URI::UID.parse(URI::UID.build_string(universal_id, self))
21-
end
17+
when String then URI::UID.match?(universal_id) ?
18+
URI::UID.parse(universal_id) :
19+
URI::UID.from_payload(universal_id)
2220
end
2321

24-
@id = @uid&.payload
22+
@id = uid&.payload
2523
end
2624
end
2725

lib/uri/uid.rb

+24-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class UID < ::URI::Generic
99
VERSION = UniversalID::VERSION
1010
SCHEME = "uid"
1111
HOST = "universalid"
12+
PATTERN = /\A#{SCHEME}:\/\/#{HOST}\/[-_0-9A-Z]+#[-_0-9A-Z]+\z/io
1213

1314
class << self
1415
def encoder
@@ -29,6 +30,11 @@ def parse(value)
2930
new(*::URI.split(value))
3031
end
3132

33+
def match?(uri)
34+
return true if uri.is_a?(self)
35+
uri.to_s.match? PATTERN
36+
end
37+
3238
def build_string(payload, object = nil)
3339
"#{SCHEME}://#{HOST}/#{payload}##{fingerprint(object)}"
3440
end
@@ -38,6 +44,17 @@ def build(object, options = {}, &block)
3844
parse "#{SCHEME}://#{HOST}#{path}##{fingerprint(object)}"
3945
end
4046

47+
def from_payload(payload, object = nil)
48+
parse(build_string(payload, object)).tap do |uid|
49+
# NOTE: fingerprint mismatch can happen when building from a UID payload
50+
# ensure the fingerprint is correct
51+
if uid&.valid? && URI::UID.fingerprint(uid.decode) != uid.fingerprint
52+
remove_instance_variable :@decoded_fingerprint if instance_variable_defined?(:@decoded_fingerprint)
53+
uid.instance_variable_set :@fragment, URI::UID.build(uid.decode).fingerprint
54+
end
55+
end
56+
end
57+
4158
def encode(object, options = {})
4259
return yield(object, options) if block_given?
4360
encoder.encode object, options
@@ -99,7 +116,7 @@ def payload
99116
end
100117

101118
def fingerprint(decode: false)
102-
return decode_fingerprint if decode
119+
return @decoded_fingerprint ||= decode_fingerprint if decode
103120
fragment
104121
end
105122

@@ -114,11 +131,14 @@ def invalid?
114131
!valid?
115132
end
116133

117-
def decode
134+
def decode(force: false)
118135
return nil unless valid?
119-
return yield(decode_payload, *decode_fingerprint) if block_given?
120136

121-
decode_payload
137+
remove_instance_variable :@decoded if force && instance_variable_defined?(:@decoded)
138+
return @decoded if defined?(@decoded)
139+
140+
@decoded ||= yield(decode_payload, *decode_fingerprint) if block_given?
141+
@decoded ||= decode_payload
122142
end
123143

124144
def deconstruct_keys(_keys)

test/test_extension.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def assert_record(expected, actual)
121121
end
122122

123123
def self.scalars
124-
{
124+
@scalars ||= {
125125
bigdecimal: BigDecimal("123.45"),
126126
complex: Complex(1, 2),
127127
date: Date.today,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# frozen_string_literal: true
2+
3+
class UniversalID::Packer::GlobalIDModelTest < Minitest::Test
4+
def test_new_from_uid
5+
uid = URI::UID.build(scalars)
6+
model = UniversalID::Extensions::GlobalIDModel.new(uid)
7+
8+
assert_instance_of UniversalID::Extensions::GlobalIDModel, model
9+
assert_equal uid, model.uid
10+
assert_equal scalars, model.uid.decode
11+
end
12+
13+
def test_new_from_uid_payload
14+
uid = URI::UID.build(scalars)
15+
model = UniversalID::Extensions::GlobalIDModel.new(uid.payload)
16+
17+
assert_instance_of UniversalID::Extensions::GlobalIDModel, model
18+
assert_equal uid, model.uid
19+
assert_equal scalars, model.uid.decode
20+
end
21+
22+
def test_new_from_uri
23+
uri = URI::UID.build(scalars).to_s
24+
model = UniversalID::Extensions::GlobalIDModel.new(uri)
25+
26+
assert_instance_of UniversalID::Extensions::GlobalIDModel, model
27+
assert_equal uri, model.uid.to_s
28+
assert_equal scalars, model.uid.decode
29+
end
30+
end

test/uri/uid/ruby_composites_test.rb

-48
This file was deleted.

test/uri/uid/ruby_scalars_test.rb

-47
This file was deleted.

test/uri/uid_test.rb

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# frozen_string_literal: true
2+
3+
class URI::UIDTest < Minitest::Test
4+
def test_from_payload
5+
expected = scalars
6+
payload = URI::UID.build(expected).payload
7+
actual = URI::UID.from_payload(payload).decode
8+
assert_equal expected, actual
9+
end
10+
end

0 commit comments

Comments
 (0)