yoti 1.5.0 → 1.6.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 +5 -5
- data/Gemfile +0 -2
- data/README.md +1 -1
- data/Rakefile +8 -0
- data/lib/yoti.rb +16 -0
- data/lib/yoti/activity_details.rb +17 -2
- data/lib/yoti/client.rb +2 -1
- data/lib/yoti/data_type/age_verification.rb +54 -0
- data/lib/yoti/data_type/attribute.rb +3 -0
- data/lib/yoti/data_type/base_profile.rb +13 -0
- data/lib/yoti/data_type/document_details.rb +96 -0
- data/lib/yoti/data_type/profile.rb +76 -0
- data/lib/yoti/dynamic_share_service/dynamic_scenario.rb +67 -0
- data/lib/yoti/dynamic_share_service/extension/extension.rb +45 -0
- data/lib/yoti/dynamic_share_service/extension/location_constraint_extension.rb +88 -0
- data/lib/yoti/dynamic_share_service/extension/thirdparty_attribute_extension.rb +58 -0
- data/lib/yoti/dynamic_share_service/extension/transactional_flow_extension.rb +47 -0
- data/lib/yoti/dynamic_share_service/policy/dynamic_policy.rb +184 -0
- data/lib/yoti/dynamic_share_service/policy/source_constraint.rb +88 -0
- data/lib/yoti/dynamic_share_service/policy/wanted_anchor.rb +53 -0
- data/lib/yoti/dynamic_share_service/policy/wanted_attribute.rb +85 -0
- data/lib/yoti/dynamic_share_service/share_url.rb +80 -0
- data/lib/yoti/http/profile_request.rb +1 -0
- data/lib/yoti/http/request.rb +13 -0
- data/lib/yoti/http/signed_request.rb +0 -3
- data/lib/yoti/protobuf/main.rb +11 -0
- data/lib/yoti/protobuf/sharepubapi/DataEntry_pb.rb +29 -0
- data/lib/yoti/protobuf/sharepubapi/ExtraData_pb.rb +19 -0
- data/lib/yoti/protobuf/sharepubapi/IssuingAttributes_pb.rb +23 -0
- data/lib/yoti/protobuf/sharepubapi/ThirdPartyAttribute_pb.rb +20 -0
- data/lib/yoti/sandbox.rb +5 -0
- data/lib/yoti/sandbox/anchor.rb +49 -0
- data/lib/yoti/sandbox/attribute.rb +52 -0
- data/lib/yoti/sandbox/profile.rb +171 -0
- data/lib/yoti/sandbox/sandbox.rb +105 -0
- data/lib/yoti/sandbox/sandbox_client.rb +45 -0
- data/lib/yoti/share/attribute_issuance_details.rb +43 -0
- data/lib/yoti/share/extra_data.rb +25 -0
- data/lib/yoti/ssl.rb +7 -0
- data/lib/yoti/util/age_processor.rb +4 -0
- data/lib/yoti/version.rb +1 -1
- data/rubocop.yml +4 -0
- data/yoti.gemspec +4 -2
- metadata +61 -4
- data/.travis.yml +0 -17
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yoti
|
|
4
|
+
module DynamicSharingService
|
|
5
|
+
class Extension
|
|
6
|
+
attr_reader :type
|
|
7
|
+
attr_reader :content
|
|
8
|
+
|
|
9
|
+
def to_json(*_args)
|
|
10
|
+
as_json.to_json
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def as_json(*_args)
|
|
14
|
+
{
|
|
15
|
+
type: @type,
|
|
16
|
+
content: @content
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.builder
|
|
21
|
+
ExtensionBuilder.new
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class ExtensionBuilder
|
|
26
|
+
def initialize
|
|
27
|
+
@extension = Extension.new
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def with_type(type)
|
|
31
|
+
@extension.instance_variable_set(:@type, type)
|
|
32
|
+
self
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def with_content(content)
|
|
36
|
+
@extension.instance_variable_set(:@content, content)
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def build
|
|
41
|
+
Marshal.load Marshal.dump @extension
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yoti
|
|
4
|
+
module DynamicSharingService
|
|
5
|
+
# A Location Constraint
|
|
6
|
+
class LocationConstraintExtension
|
|
7
|
+
EXTENSION_TYPE = 'LOCATION_CONSTRAINT'
|
|
8
|
+
|
|
9
|
+
attr_reader :content
|
|
10
|
+
attr_reader :type
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@content = {}
|
|
14
|
+
@type = EXTENSION_TYPE
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def as_json(*_args)
|
|
18
|
+
{
|
|
19
|
+
type: @type,
|
|
20
|
+
content: @content
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_json(*_args)
|
|
25
|
+
as_json.to_json
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.builder
|
|
29
|
+
LocationConstraintExtensionBuilder.new
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Builder for LocationConstraintExtension
|
|
34
|
+
class LocationConstraintExtensionBuilder
|
|
35
|
+
def with_latitude(latitude)
|
|
36
|
+
raise ArgumentError, 'Latitude must be Integer or Float'\
|
|
37
|
+
unless latitude.is_a?(Integer) || latitude.is_a?(Float)
|
|
38
|
+
raise ArgumentError, 'Latitude must be between -90 and 90'\
|
|
39
|
+
unless latitude >= -90 && latitude <= 90
|
|
40
|
+
|
|
41
|
+
@latitude = latitude
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def with_longitude(longitude)
|
|
46
|
+
raise ArgumentError, 'Longitude must be Integer or Float'\
|
|
47
|
+
unless longitude.is_a?(Integer) || longitude.is_a?(Float)
|
|
48
|
+
raise ArgumentError, 'Longitude must be between -180 and 180'\
|
|
49
|
+
unless longitude >= -180 && longitude <= 180
|
|
50
|
+
|
|
51
|
+
@longitude = longitude
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def with_radius(radius)
|
|
56
|
+
raise ArgumentError, 'Radius must be Integer or Float'\
|
|
57
|
+
unless radius.is_a?(Integer) || radius.is_a?(Float)
|
|
58
|
+
raise ArgumentError, 'Radius must be >= 0' unless radius >= 0
|
|
59
|
+
|
|
60
|
+
@radius = radius
|
|
61
|
+
self
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def with_max_uncertainty(uncertainty)
|
|
65
|
+
raise ArgumentError, 'Uncertainty must be Integer or Float'\
|
|
66
|
+
unless uncertainty.is_a?(Integer) || uncertainty.is_a?(Float)
|
|
67
|
+
raise ArgumentError, 'Uncertainty must be >= 0' unless uncertainty >= 0
|
|
68
|
+
|
|
69
|
+
@uncertainty = uncertainty
|
|
70
|
+
self
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def build
|
|
74
|
+
@radius ||= 150 unless @radius
|
|
75
|
+
@uncertainty ||= 150 unless @uncertainty
|
|
76
|
+
|
|
77
|
+
extension = LocationConstraintExtension.new
|
|
78
|
+
extension.instance_variable_get(:@content)[:expected_device_location] = {
|
|
79
|
+
latitude: @latitude,
|
|
80
|
+
longitude: @longitude,
|
|
81
|
+
radius: @radius,
|
|
82
|
+
max_uncertainty_radius: @uncertainty
|
|
83
|
+
}
|
|
84
|
+
extension
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yoti
|
|
4
|
+
module DynamicSharingService
|
|
5
|
+
class ThirdPartyAttributeExtensionBuilder
|
|
6
|
+
def initialize
|
|
7
|
+
@expiry_date = nil
|
|
8
|
+
@definitions = []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def with_expiry_date(expiry_date)
|
|
12
|
+
@expiry_date = expiry_date
|
|
13
|
+
self
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def with_definitions(*names)
|
|
17
|
+
names.each do |s|
|
|
18
|
+
@definitions += [{ name: s }]
|
|
19
|
+
end
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def build
|
|
24
|
+
extension = ThirdPartyAttributeExtension.new
|
|
25
|
+
extension.instance_variable_get(:@content)[:expiry_date] = @expiry_date
|
|
26
|
+
extension.instance_variable_get(:@content)[:definitions] = @definitions
|
|
27
|
+
extension
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class ThirdPartyAttributeExtension
|
|
32
|
+
EXTENSION_TYPE = 'THIRD_PARTY_ATTRIBUTE'
|
|
33
|
+
|
|
34
|
+
attr_reader :content
|
|
35
|
+
attr_reader :type
|
|
36
|
+
|
|
37
|
+
def initialize
|
|
38
|
+
@content = {}
|
|
39
|
+
@type = EXTENSION_TYPE
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def as_json(*_args)
|
|
43
|
+
{
|
|
44
|
+
type: @type,
|
|
45
|
+
content: @content
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_json(*_args)
|
|
50
|
+
as_json.to_json
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.builder
|
|
54
|
+
ThirdPartyAttributeExtensionBuilder.new
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yoti
|
|
4
|
+
module DynamicSharingService
|
|
5
|
+
# Extension for transactional flows
|
|
6
|
+
class TransactionalFlowExtension
|
|
7
|
+
EXTENSION_TYPE = 'TRANSACTIONAL_FLOW'
|
|
8
|
+
attr_reader :content
|
|
9
|
+
attr_reader :type
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@type = EXTENSION_TYPE
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_json(*_args)
|
|
16
|
+
as_json.to_json
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def as_json(*_args)
|
|
20
|
+
{
|
|
21
|
+
content: @content,
|
|
22
|
+
type: @type
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.builder
|
|
27
|
+
TransactionalFlowExtensionBuilder.new
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Builder for TransactionalFlowExtension
|
|
32
|
+
class TransactionalFlowExtensionBuilder
|
|
33
|
+
def initialize
|
|
34
|
+
@extension = TransactionalFlowExtension.new
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def with_content(content)
|
|
38
|
+
@extension.instance_variable_set(:@content, content)
|
|
39
|
+
self
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def build
|
|
43
|
+
Marshal.load Marshal.dump @extension
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yoti
|
|
4
|
+
module DynamicSharingService
|
|
5
|
+
# Describes a policy for a dynamic share
|
|
6
|
+
class DynamicPolicy
|
|
7
|
+
SELFIE_AUTH_TYPE = 1
|
|
8
|
+
PIN_AUTH_TYPE = 2
|
|
9
|
+
|
|
10
|
+
attr_reader :wanted_auth_types
|
|
11
|
+
attr_reader :wanted
|
|
12
|
+
|
|
13
|
+
def wanted_remember_me
|
|
14
|
+
return true if @wanted_remember_me
|
|
15
|
+
|
|
16
|
+
false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_json(*args)
|
|
20
|
+
as_json.to_json(*args)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def as_json(*_args)
|
|
24
|
+
{
|
|
25
|
+
wanted_auth_types: @wanted_auth_types,
|
|
26
|
+
wanted: @wanted
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.builder
|
|
31
|
+
DynamicPolicyBuilder.new
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Builder for DynamicPolicy
|
|
36
|
+
class DynamicPolicyBuilder
|
|
37
|
+
def initialize
|
|
38
|
+
@policy = DynamicPolicy.new
|
|
39
|
+
@wanted_auth_types = {}
|
|
40
|
+
@wanted_attributes = {}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def build
|
|
44
|
+
@policy.instance_variable_set(
|
|
45
|
+
:@wanted_auth_types,
|
|
46
|
+
@wanted_auth_types
|
|
47
|
+
.select { |_, wanted| wanted }
|
|
48
|
+
.keys
|
|
49
|
+
)
|
|
50
|
+
@policy.instance_variable_set(:@wanted, @wanted_attributes.values)
|
|
51
|
+
Marshal.load Marshal.dump @policy
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
#
|
|
55
|
+
# @param [Bool] wanted
|
|
56
|
+
#
|
|
57
|
+
def with_wanted_remember_me(wanted = true)
|
|
58
|
+
@policy.instance_variable_set(:@wanted_remember_me, wanted)
|
|
59
|
+
self
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
#
|
|
63
|
+
# @param [Integer] auth
|
|
64
|
+
# @param [Bool] wanted
|
|
65
|
+
#
|
|
66
|
+
def with_wanted_auth_type(auth, wanted = true)
|
|
67
|
+
@wanted_auth_types[auth] = wanted
|
|
68
|
+
self
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#
|
|
72
|
+
# @param [Bool] wanted
|
|
73
|
+
#
|
|
74
|
+
def with_selfie_auth(wanted = true)
|
|
75
|
+
with_wanted_auth_type(DynamicPolicy::SELFIE_AUTH_TYPE, wanted)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# @param [Bool] wanted
|
|
80
|
+
#
|
|
81
|
+
def with_pin_auth(wanted = true)
|
|
82
|
+
with_wanted_auth_type(DynamicPolicy::PIN_AUTH_TYPE, wanted)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
#
|
|
86
|
+
# @param [Yoti::DynamicSharingService::WantedAttribute] attribute
|
|
87
|
+
#
|
|
88
|
+
def with_wanted_attribute(attribute)
|
|
89
|
+
key = attribute.derivation || attribute.name
|
|
90
|
+
@wanted_attributes[key] = attribute
|
|
91
|
+
self
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
#
|
|
95
|
+
# @param [String] name
|
|
96
|
+
# @param [Hash] constraints
|
|
97
|
+
#
|
|
98
|
+
def with_wanted_attribute_by_name(name, constraints: nil)
|
|
99
|
+
attribute_builder = WantedAttribute.builder.with_name(name)
|
|
100
|
+
constraints&.each do |constraint|
|
|
101
|
+
attribute_builder.with_constraint constraint
|
|
102
|
+
end
|
|
103
|
+
attribute = attribute_builder.build
|
|
104
|
+
with_wanted_attribute attribute
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def with_family_name(options = {})
|
|
108
|
+
with_wanted_attribute_by_name Attribute::FAMILY_NAME, options
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def with_given_names(options = {})
|
|
112
|
+
with_wanted_attribute_by_name Attribute::GIVEN_NAMES, options
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def with_full_name(options = {})
|
|
116
|
+
with_wanted_attribute_by_name Attribute::FULL_NAME, options
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def with_date_of_birth(options = {})
|
|
120
|
+
with_wanted_attribute_by_name Attribute::DATE_OF_BIRTH, options
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
#
|
|
124
|
+
# @param [String] derivation
|
|
125
|
+
# @param [Hash] constraints
|
|
126
|
+
#
|
|
127
|
+
def with_age_derived_attribute(derivation, constraints: nil)
|
|
128
|
+
attribute_builder = WantedAttribute.builder
|
|
129
|
+
attribute_builder.with_name(Attribute::DATE_OF_BIRTH)
|
|
130
|
+
attribute_builder.with_derivation(derivation)
|
|
131
|
+
constraints&.each do |constraint|
|
|
132
|
+
attribute_builder.with_constraint constraint
|
|
133
|
+
end
|
|
134
|
+
with_wanted_attribute(attribute_builder.build)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
#
|
|
138
|
+
# @param [Integer] derivation
|
|
139
|
+
#
|
|
140
|
+
def with_age_over(age, options = {})
|
|
141
|
+
with_age_derived_attribute(Attribute::AGE_OVER + age.to_s, options)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
#
|
|
145
|
+
# @param [Integer] derivation
|
|
146
|
+
#
|
|
147
|
+
def with_age_under(age, options = {})
|
|
148
|
+
with_age_derived_attribute(Attribute::AGE_UNDER + age.to_s, options)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def with_gender(options = {})
|
|
152
|
+
with_wanted_attribute_by_name Attribute::GENDER, options
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def with_postal_address(options = {})
|
|
156
|
+
with_wanted_attribute_by_name(Attribute::POSTAL_ADDRESS, options)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def with_structured_postal_address(options = {})
|
|
160
|
+
with_wanted_attribute_by_name(Attribute::STRUCTURED_POSTAL_ADDRESS, options)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def with_nationality(options = {})
|
|
164
|
+
with_wanted_attribute_by_name(Attribute::NATIONALITY, options)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def with_phone_number(options = {})
|
|
168
|
+
with_wanted_attribute_by_name(Attribute::PHONE_NUMBER, options)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def with_selfie(options = {})
|
|
172
|
+
with_wanted_attribute_by_name(Attribute::SELFIE, options)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def with_email(options = {})
|
|
176
|
+
with_wanted_attribute_by_name(Attribute::EMAIL_ADDRESS, options)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def with_document_details
|
|
180
|
+
with_wanted_attribute_by_name(Attribute::DOCUMENT_DETAILS)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yoti
|
|
4
|
+
module DynamicSharingService
|
|
5
|
+
# A list of anchors to require for a dynamic share
|
|
6
|
+
class SourceConstraint
|
|
7
|
+
DRIVING_LICENCE = 'DRIVING_LICENCE'
|
|
8
|
+
PASSPORT = 'PASSPORT'
|
|
9
|
+
NATIONAL_ID = 'NATIONAL_ID'
|
|
10
|
+
PASS_CARD = 'PASS_CARD'
|
|
11
|
+
|
|
12
|
+
SOURCE_CONSTRAINT = 'SOURCE'
|
|
13
|
+
|
|
14
|
+
attr_reader :anchors
|
|
15
|
+
|
|
16
|
+
def soft_preference
|
|
17
|
+
return @soft_preference if @soft_preference
|
|
18
|
+
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_json(*_args)
|
|
23
|
+
as_json.to_json
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def as_json(*_args)
|
|
27
|
+
obj = {
|
|
28
|
+
type: SOURCE_CONSTRAINT,
|
|
29
|
+
preferred_sources: {
|
|
30
|
+
anchors: @anchors.map(&:as_json)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
obj[:preferred_sources][:soft_preference] = @soft_preference unless @soft_preference.nil?
|
|
34
|
+
obj
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def initialize
|
|
38
|
+
@anchors = []
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.builder
|
|
42
|
+
SourceConstraintBuilder.new
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Builder for SourceConstraint
|
|
47
|
+
class SourceConstraintBuilder
|
|
48
|
+
def initialize
|
|
49
|
+
@constraint = SourceConstraint.new
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def with_anchor_by_value(value, sub_type)
|
|
53
|
+
anchor = WantedAnchor.builder.with_value(value).with_sub_type(sub_type).build
|
|
54
|
+
with_anchor(anchor)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def with_anchor(anchor)
|
|
58
|
+
@constraint.anchors.push(anchor)
|
|
59
|
+
self
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def with_passport(sub_type = nil)
|
|
63
|
+
with_anchor_by_value(SourceConstraint::PASSPORT, sub_type)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def with_driving_licence(sub_type = nil)
|
|
67
|
+
with_anchor_by_value(SourceConstraint::DRIVING_LICENCE, sub_type)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def with_national_id(sub_type = nil)
|
|
71
|
+
with_anchor_by_value(SourceConstraint::NATIONAL_ID, sub_type)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def with_passcard(sub_type = nil)
|
|
75
|
+
with_anchor_by_value(SourceConstraint::PASS_CARD, sub_type)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def with_soft_preference(preference = true)
|
|
79
|
+
@constraint.instance_variable_set(:@soft_preference, preference)
|
|
80
|
+
self
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def build
|
|
84
|
+
Marshal.load Marshal.dump @constraint
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|