rom-ldap 0.2.2

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 (104) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +251 -0
  3. data/CONTRIBUTING.md +18 -0
  4. data/README.md +172 -0
  5. data/TODO.md +33 -0
  6. data/config/responses.yml +328 -0
  7. data/lib/dry/monitor/ldap/colorizers/default.rb +17 -0
  8. data/lib/dry/monitor/ldap/colorizers/rouge.rb +31 -0
  9. data/lib/dry/monitor/ldap/logger.rb +58 -0
  10. data/lib/rom-ldap.rb +1 -0
  11. data/lib/rom/ldap.rb +22 -0
  12. data/lib/rom/ldap/alias.rb +30 -0
  13. data/lib/rom/ldap/associations.rb +6 -0
  14. data/lib/rom/ldap/associations/core.rb +23 -0
  15. data/lib/rom/ldap/associations/many_to_many.rb +18 -0
  16. data/lib/rom/ldap/associations/many_to_one.rb +22 -0
  17. data/lib/rom/ldap/associations/one_to_many.rb +32 -0
  18. data/lib/rom/ldap/associations/one_to_one.rb +19 -0
  19. data/lib/rom/ldap/associations/self_ref.rb +35 -0
  20. data/lib/rom/ldap/attribute.rb +327 -0
  21. data/lib/rom/ldap/client.rb +185 -0
  22. data/lib/rom/ldap/client/authentication.rb +118 -0
  23. data/lib/rom/ldap/client/operations.rb +233 -0
  24. data/lib/rom/ldap/commands.rb +6 -0
  25. data/lib/rom/ldap/commands/create.rb +41 -0
  26. data/lib/rom/ldap/commands/delete.rb +17 -0
  27. data/lib/rom/ldap/commands/update.rb +35 -0
  28. data/lib/rom/ldap/constants.rb +193 -0
  29. data/lib/rom/ldap/dataset.rb +286 -0
  30. data/lib/rom/ldap/dataset/conversion.rb +62 -0
  31. data/lib/rom/ldap/dataset/dsl.rb +299 -0
  32. data/lib/rom/ldap/dataset/persistence.rb +44 -0
  33. data/lib/rom/ldap/directory.rb +126 -0
  34. data/lib/rom/ldap/directory/capabilities.rb +71 -0
  35. data/lib/rom/ldap/directory/entry.rb +200 -0
  36. data/lib/rom/ldap/directory/env.rb +155 -0
  37. data/lib/rom/ldap/directory/operations.rb +282 -0
  38. data/lib/rom/ldap/directory/password.rb +122 -0
  39. data/lib/rom/ldap/directory/root.rb +187 -0
  40. data/lib/rom/ldap/directory/tokenization.rb +66 -0
  41. data/lib/rom/ldap/directory/transactions.rb +31 -0
  42. data/lib/rom/ldap/directory/vendors/active_directory.rb +129 -0
  43. data/lib/rom/ldap/directory/vendors/apache_ds.rb +27 -0
  44. data/lib/rom/ldap/directory/vendors/e_directory.rb +16 -0
  45. data/lib/rom/ldap/directory/vendors/open_directory.rb +12 -0
  46. data/lib/rom/ldap/directory/vendors/open_dj.rb +25 -0
  47. data/lib/rom/ldap/directory/vendors/open_ldap.rb +35 -0
  48. data/lib/rom/ldap/directory/vendors/three_eight_nine.rb +16 -0
  49. data/lib/rom/ldap/directory/vendors/unknown.rb +22 -0
  50. data/lib/rom/ldap/dsl.rb +76 -0
  51. data/lib/rom/ldap/errors.rb +47 -0
  52. data/lib/rom/ldap/expression.rb +77 -0
  53. data/lib/rom/ldap/expression_encoder.rb +174 -0
  54. data/lib/rom/ldap/extensions.rb +50 -0
  55. data/lib/rom/ldap/extensions/active_support_notifications.rb +26 -0
  56. data/lib/rom/ldap/extensions/compatibility.rb +11 -0
  57. data/lib/rom/ldap/extensions/dsml.rb +165 -0
  58. data/lib/rom/ldap/extensions/msgpack.rb +23 -0
  59. data/lib/rom/ldap/extensions/optimised_json.rb +25 -0
  60. data/lib/rom/ldap/extensions/rails_log_subscriber.rb +38 -0
  61. data/lib/rom/ldap/formatter.rb +26 -0
  62. data/lib/rom/ldap/functions.rb +207 -0
  63. data/lib/rom/ldap/gateway.rb +145 -0
  64. data/lib/rom/ldap/ldif.rb +74 -0
  65. data/lib/rom/ldap/ldif/exporter.rb +77 -0
  66. data/lib/rom/ldap/ldif/importer.rb +95 -0
  67. data/lib/rom/ldap/mapper_compiler.rb +19 -0
  68. data/lib/rom/ldap/matchers.rb +69 -0
  69. data/lib/rom/ldap/message_queue.rb +7 -0
  70. data/lib/rom/ldap/oid.rb +101 -0
  71. data/lib/rom/ldap/parsers/abstract_syntax.rb +91 -0
  72. data/lib/rom/ldap/parsers/attribute.rb +290 -0
  73. data/lib/rom/ldap/parsers/filter_syntax.rb +133 -0
  74. data/lib/rom/ldap/pdu.rb +285 -0
  75. data/lib/rom/ldap/plugin/pagination.rb +145 -0
  76. data/lib/rom/ldap/plugins.rb +7 -0
  77. data/lib/rom/ldap/projection_dsl.rb +38 -0
  78. data/lib/rom/ldap/relation.rb +135 -0
  79. data/lib/rom/ldap/relation/exporting.rb +72 -0
  80. data/lib/rom/ldap/relation/reading.rb +461 -0
  81. data/lib/rom/ldap/relation/writing.rb +64 -0
  82. data/lib/rom/ldap/responses.rb +17 -0
  83. data/lib/rom/ldap/restriction_dsl.rb +45 -0
  84. data/lib/rom/ldap/schema.rb +123 -0
  85. data/lib/rom/ldap/schema/attributes_inferrer.rb +59 -0
  86. data/lib/rom/ldap/schema/dsl.rb +13 -0
  87. data/lib/rom/ldap/schema/inferrer.rb +50 -0
  88. data/lib/rom/ldap/schema/type_builder.rb +133 -0
  89. data/lib/rom/ldap/scope.rb +19 -0
  90. data/lib/rom/ldap/search_request.rb +249 -0
  91. data/lib/rom/ldap/socket.rb +210 -0
  92. data/lib/rom/ldap/tasks/ldap.rake +103 -0
  93. data/lib/rom/ldap/tasks/ldif.rake +80 -0
  94. data/lib/rom/ldap/transaction.rb +29 -0
  95. data/lib/rom/ldap/type_map.rb +88 -0
  96. data/lib/rom/ldap/types.rb +158 -0
  97. data/lib/rom/ldap/version.rb +17 -0
  98. data/lib/rom/plugins/relation/ldap/active_directory.rb +182 -0
  99. data/lib/rom/plugins/relation/ldap/auto_restrictions.rb +69 -0
  100. data/lib/rom/plugins/relation/ldap/e_directory.rb +27 -0
  101. data/lib/rom/plugins/relation/ldap/instrumentation.rb +35 -0
  102. data/lib/rouge/lexers/ldap.rb +72 -0
  103. data/lib/rouge/themes/ldap.rb +49 -0
  104. metadata +231 -0
@@ -0,0 +1,103 @@
1
+ #
2
+ # Leverage LDAP env variables or RC files.
3
+ #
4
+ # @note
5
+ # Any LDAPURI must be compatible with ldapmodify.
6
+ #
7
+ # @example
8
+ # load 'rom/ldap/tasks/ldap.rake'
9
+ #
10
+ require 'pathname'
11
+ require 'pry'
12
+
13
+ module ROM
14
+ module LDAP
15
+ #
16
+ # `$ ldapmodify -a -H ldap://127.0.0.1:3389 -D 'cn=Directory Manager'
17
+ # -w 'topsecret' -c -v -f spec/fixtures/ldif/examples/users.ldif`
18
+ #
19
+ module RakeSupport
20
+ module_function
21
+
22
+ def message
23
+ puts "Using #{root}, alternatively set LDAPDIR=/path/to/root"
24
+ puts
25
+ puts "=========================================="
26
+ end
27
+
28
+ # ldapsearch with simple authentication.
29
+ #
30
+ def search(attrs:, filter:)
31
+ puts 'ldapsearch is not installed!' if ldapsearch.empty?
32
+ system(ldapsearch, '-x', *auth, filter, *attrs.split('.'))
33
+ end
34
+
35
+ # ldapmodify with simple authentication and continuous operation.
36
+ #
37
+ def modify(dir: root)
38
+ puts 'ldapmodify is not installed!' if ldapmodify.empty?
39
+
40
+ Dir.glob("#{dir}/*.ldif") do |file|
41
+ system(ldapmodify, '-x', *auth, '-a', '-c', '-v', '-f', file)
42
+ end
43
+ end
44
+
45
+ private_instance_methods
46
+
47
+ def root
48
+ Pathname(ENV['LDAPDIR'] || Dir.pwd)
49
+ end
50
+
51
+ def auth
52
+ abort('LDAPBINDDN and LDAPBINDPW are not set') unless ENV['LDAPBINDDN'] && ENV['LDAPBINDPW']
53
+ ['-D', ENV['LDAPBINDDN'], '-w', ENV['LDAPBINDPW']]
54
+ end
55
+
56
+ def ldapsearch
57
+ `which ldapsearch`.strip
58
+ end
59
+
60
+ def ldapmodify
61
+ `which ldapmodify`.strip
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+
68
+ namespace :ldap do
69
+ task :env do
70
+ ROM::LDAP::RakeSupport.message
71
+ end
72
+
73
+ # Iterate through *.ldif files in a folder.
74
+ #
75
+ # @example
76
+ #
77
+ # $ LDAPURI=ldap://127.0.0.1:3389 \
78
+ # LDAPBINDDN='cn=Directory Manager' \
79
+ # LDAPBINDPW=topsecret \
80
+ # LDAPDIR=./spec/fixtures/ldif \
81
+ # rake ldap:modify
82
+ #
83
+ desc 'Use ldapmodify'
84
+ task :modify, [:dir] => :env do |_t, args|
85
+ ROM::LDAP::RakeSupport.modify(args)
86
+ end
87
+
88
+
89
+ # 'LDAPBASE=dc=foo ldap:search[cn=*foo,gn.sn]'
90
+ #
91
+ # @example
92
+ # $ rake ldap:search
93
+ # $ rake ldap:search[cn=*41,uid.mail.sn]
94
+ # $ rake ldap:search[gn=adele]
95
+ # $ rake ldap:search[userid=adele*]
96
+ #
97
+ desc 'Use ldapsearch'
98
+ task :search, [:filter, :attrs] => :env do |_t, args|
99
+ args.with_defaults(attrs: "+ \\*", filter: '(objectClass=*)')
100
+ ROM::LDAP::RakeSupport.search(args)
101
+ end
102
+
103
+ end
@@ -0,0 +1,80 @@
1
+ # @example
2
+ # load 'rom/ldap/tasks/ldif.rake'
3
+
4
+ require 'rom/ldap'
5
+
6
+ module ROM
7
+ module LDAP
8
+ module RakeSupport
9
+ module_function
10
+
11
+ def directory
12
+ @directory ||= config.gateways[:default].directory
13
+ end
14
+
15
+ private_instance_methods
16
+
17
+ def config
18
+ @config ||= ROM::Configuration.new(:ldap)
19
+ end
20
+
21
+ def container
22
+ @container ||= ROM.container(config)
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+
29
+
30
+ namespace :ldif do
31
+ task :env do
32
+ # ENV['DEBUG'] = 'y'
33
+ end
34
+
35
+
36
+ #
37
+ # Parse and import LDIF file
38
+ # rake 'ldif:import[examples/users.ldif]'
39
+ #
40
+ desc 'import'
41
+ task :import, [:file] => :env do |_t, args|
42
+ abort 'file is required' unless args[:file]
43
+
44
+ timer = Time.now.utc
45
+ counter = 0
46
+
47
+ ROM::LDAP::LDIF(File.read(args[:file])) do |entry|
48
+ counter += 1
49
+ ROM::LDAP::RakeSupport.directory.add(entry)
50
+ end
51
+
52
+ duration = Time.now.utc - timer
53
+
54
+ puts "========================================="
55
+ puts "#{counter} entries in #{duration} seconds"
56
+ end
57
+
58
+
59
+
60
+ #
61
+ # Print LDIF
62
+ # rake 'ldif:export[(cn=*)]'
63
+ #
64
+ desc 'export'
65
+ task :export, [:filter] => :env do |_t, args|
66
+ args.with_defaults(filter: '(objectClass=*)')
67
+
68
+ using ROM::LDAP::LDIF
69
+
70
+ directory = ROM::LDAP::RakeSupport.directory
71
+ dataset = ROM::LDAP::Dataset.new(directory: directory, name: args[:filter])
72
+
73
+ puts "#"
74
+ puts "# #{Time.now}"
75
+ puts "# ========================================="
76
+ puts ""
77
+ puts dataset.export.to_ldif
78
+ end
79
+
80
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ module LDAP
5
+ # Work in progress
6
+ #
7
+ # @see https://tools.ietf.org/html/rfc5805
8
+ #
9
+ # @api private
10
+ class Transaction < ::ROM::Transaction
11
+
12
+ attr_reader :directory
13
+ private :directory
14
+
15
+ def initialize(directory)
16
+ @directory = directory
17
+ end
18
+
19
+ # rubocop:disable Lint/SuppressedException
20
+ def run(opts = EMPTY_OPTS)
21
+ directory.transaction(opts) { yield(self) }
22
+ rescue ::ROM::Transaction::Rollback
23
+ # noop
24
+ end
25
+ # rubocop:enable Lint/SuppressedException
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Layout/HashAlignment
4
+ module ROM
5
+ module LDAP
6
+ # LDAPv3 Syntaxes
7
+ #
8
+ # @see https://ldapwiki.com/wiki/LDAPSyntaxes
9
+ #
10
+ OID_TYPE_MAP = {
11
+ '1.3.6.1.1.16.1' => 'String', # UUID
12
+ '1.3.6.1.4.1.1466.115.121.1.1' => 'String', # ACI Item
13
+ '1.3.6.1.4.1.1466.115.121.1.2' => 'String', # Access Point
14
+ '1.3.6.1.4.1.1466.115.121.1.3' => 'String', # Attribute Type Description
15
+ '1.3.6.1.4.1.1466.115.121.1.4' => 'Binary', # Audio
16
+ '1.3.6.1.4.1.1466.115.121.1.5' => 'Binary', # Binary
17
+ '1.3.6.1.4.1.1466.115.121.1.6' => 'String', # Bit String
18
+ '1.3.6.1.4.1.1466.115.121.1.7' => 'Bool', # Boolean
19
+ '1.3.6.1.4.1.1466.115.121.1.8' => 'String', # Certificate
20
+ '1.3.6.1.4.1.1466.115.121.1.9' => 'String', # Certificate List
21
+ '1.3.6.1.4.1.1466.115.121.1.10' => 'String', # Certificate Pair
22
+ '1.3.6.1.4.1.1466.115.121.1.11' => 'String', # Country String - IA5 ISO-646 (ASCII). Limited to exactly two characters describing the ISO 3166 country code.
23
+ '1.3.6.1.4.1.1466.115.121.1.12' => 'String', # DN
24
+ '1.3.6.1.4.1.1466.115.121.1.13' => 'String', # Data Quality Syntax
25
+ '1.3.6.1.4.1.1466.115.121.1.14' => 'String', # Delivery Method
26
+ '1.3.6.1.4.1.1466.115.121.1.15' => 'String', # Directory String
27
+ '1.3.6.1.4.1.1466.115.121.1.19' => 'String', # DSA Quality Syntax
28
+ '1.3.6.1.4.1.1466.115.121.1.20' => 'String', # DSE Type
29
+ '1.3.6.1.4.1.1466.115.121.1.21' => 'String', # Enhanced Guide
30
+ '1.3.6.1.4.1.1466.115.121.1.22' => 'String', # Facsimile Telephone Number
31
+ '1.3.6.1.4.1.1466.115.121.1.23' => 'String', # Fax
32
+ '1.3.6.1.4.1.1466.115.121.1.24' => 'Time', # Generalized Time
33
+ '1.3.6.1.4.1.1466.115.121.1.25' => 'String', # Guide
34
+ '1.3.6.1.4.1.1466.115.121.1.26' => 'String', # IA5String - IA5 ISO-646 (ASCII).
35
+ '1.3.6.1.4.1.1466.115.121.1.27' => 'Integer', # INTEGER - IntegerMatch / integerOrderingMatch
36
+ '1.3.6.1.4.1.1466.115.121.1.28' => 'Binary', # JPEG - RFC2798: Joint Photographic Experts Group (JPEG) image syntax from inetOrgPerson object class schema.
37
+ '1.3.6.1.4.1.1466.115.121.1.32' => 'String', # Mail Preference
38
+ '1.3.6.1.4.1.1466.115.121.1.34' => 'String', # Name And Optional UID
39
+ '1.3.6.1.4.1.1466.115.121.1.35' => 'String', # Name Form Description
40
+ '1.3.6.1.4.1.1466.115.121.1.36' => 'Integer', # Numeric String - IA5 ISO-646 (ASCII).
41
+ '1.3.6.1.4.1.1466.115.121.1.37' => 'String', # Object Class Description
42
+ '1.3.6.1.4.1.1466.115.121.1.38' => 'String', # OID
43
+ '1.3.6.1.4.1.1466.115.121.1.39' => 'String', # Other Mailbox
44
+ '1.3.6.1.4.1.1466.115.121.1.40' => 'String', # Octet String - Treated as transparent 8-bit bytes. (passwords)
45
+ '1.3.6.1.4.1.1466.115.121.1.41' => 'String', # Postal Address - UTF-8 ISO-10646 (Unicode). Split by dollar sign "$".
46
+ '1.3.6.1.4.1.1466.115.121.1.42' => 'String', # Protocol Information
47
+ '1.3.6.1.4.1.1466.115.121.1.43' => 'String', # Presentation Address
48
+ '1.3.6.1.4.1.1466.115.121.1.44' => 'String', # Printable String
49
+ '1.3.6.1.4.1.1466.115.121.1.50' => 'String', # Telephone Number
50
+ '1.3.6.1.4.1.1466.115.121.1.51' => 'String', # Teletex Terminal Identifier
51
+ '1.3.6.1.4.1.1466.115.121.1.52' => 'String', # Telex Number
52
+ '1.3.6.1.4.1.1466.115.121.1.53' => 'Time', # UTC Time
53
+ '1.3.6.1.4.1.1466.115.121.1.54' => 'String', # LDAP Syntax Description
54
+ '1.3.6.1.4.1.1466.115.121.1.56' => 'String', # LDAP Schema Definition
55
+ '1.3.6.1.4.1.1466.115.121.1.57' => 'String', # LDAP Schema Description
56
+
57
+ # Microsoft Active Directory
58
+ #
59
+ # @see https://ldapwiki.com/wiki/Microsoft%20Active%20Directory%20Syntax
60
+ # @see https://docs.microsoft.com/en-gb/windows/desktop/ADSchema/attributes-all
61
+ # @see https://docs.microsoft.com/en-us/windows/desktop/ADSI/data-type-mapping-between-active-directory-and-ldap
62
+ #
63
+ '1.2.840.113556.1.2.19' => 'Time', # uSNCreated
64
+ '1.2.840.113556.1.2.120' => 'Time', # uSNChanged
65
+
66
+ '1.2.840.113556.1.4.49' => 'Time', # badPasswordTime
67
+ '1.2.840.113556.1.4.52' => 'Time', # lastLogon
68
+ '1.2.840.113556.1.4.53' => 'Time', # lastSetTime
69
+ '1.2.840.113556.1.4.60' => 'Time', # lockoutDuration
70
+ '1.2.840.113556.1.4.74' => 'Time', # maxPwdAge
71
+ '1.2.840.113556.1.4.76' => 'Integer', # maxStorage
72
+ '1.2.840.113556.1.4.78' => 'Time', # minPwdAge
73
+ '1.2.840.113556.1.4.96' => 'Time', # pwdLastSet
74
+ '1.2.840.113556.1.4.159' => 'Time', # accountExpires
75
+ '1.2.840.113556.1.4.371' => 'Integer', # rIDAllocationPool
76
+ '1.2.840.113556.1.4.662' => 'Time', # lockoutTime
77
+ '1.2.840.113556.1.4.903' => 'String', # DNWithOctetString
78
+ '1.2.840.113556.1.4.904' => 'String', # DNWithString
79
+ '1.2.840.113556.1.4.905' => 'String', # Telex
80
+ '1.2.840.113556.1.4.906' => 'Integer', # INTEGER8
81
+ '1.2.840.113556.1.4.907' => 'String', # ObjectSecurityDescriptor
82
+ '1.2.840.113556.1.4.1221' => 'String', # CaseIgnoreString' / ORName
83
+ '1.2.840.113556.1.4.1362' => 'String', # CaseExactString
84
+ '1.2.840.113556.1.4.1696' => 'Time' # lastLogonTimeStamp
85
+ }.freeze
86
+ end
87
+ end
88
+ # rubocop:enable Layout/HashAlignment
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/types'
4
+ require 'rom/ldap/functions'
5
+
6
+ module ROM
7
+ module LDAP
8
+ module Types
9
+ include ROM::Types
10
+
11
+ # Protocol ldap(s) only
12
+ #
13
+ # @return [Dry::Types::Constrained]
14
+ #
15
+ # @api public
16
+ URI = Strict::String.constrained(format: LDAPURI_REGEX)
17
+
18
+ # Something in parentheses
19
+ #
20
+ # @return [Dry::Types::Constrained]
21
+ #
22
+ # @api public
23
+ Filter = Strict::String.constrained(format: FILTER_REGEX)
24
+
25
+ #
26
+ # @return [Dry::Types::Constrained]
27
+ #
28
+ # @api public
29
+ DN = Strict::String.constrained(format: DN_REGEX)
30
+
31
+ # @return [Dry::Types::Constrained]
32
+ #
33
+ # @api public
34
+ Direction = Strict::Symbol.constrained(included_in: %i[asc desc])
35
+
36
+ # @return [Dry::Types::Constrained]
37
+ #
38
+ # @api public
39
+ Scope = Strict::Integer.constrained(included_in: SCOPES)
40
+
41
+ # @return [Dry::Types::Constrained]
42
+ #
43
+ # @api public
44
+ Deref = Strict::Integer.constrained(included_in: DEREF_ALL)
45
+
46
+ # Abstraction of LDAP constructors and operators
47
+ #
48
+ # @return [Dry::Types::Constrained]
49
+ #
50
+ # @api public
51
+ Abstract = Strict::Symbol.constrained(included_in: ABSTRACTS)
52
+
53
+ # Compatible filter fields (formatters may symbolise)
54
+ #
55
+ # @return [Dry::Types::Sum::Constrained]
56
+ #
57
+ # @api public
58
+ Field = Strict::String | Strict::Symbol
59
+
60
+ # Compatible filter values (including wildcard abstraction)
61
+ #
62
+ # @return [Dry::Types::Sum::Constrained]
63
+ #
64
+ # @api public
65
+ Value = Strict::String | Strict::Integer | Strict::Float | Strict::Symbol.constrained(included_in: %i[wildcard])
66
+
67
+ # @example => "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD...."
68
+ #
69
+ # @return [String]
70
+ #
71
+ # @api public
72
+ Media = Constructor(String, ->(v) { Functions[:mime_type].call(v[0]) })
73
+
74
+ # 1.3.6.1.4.1.1466.115.121.1.41
75
+ #
76
+ # A special format which uses UTF-8 encoding of ISO-10646 (Unicode)
77
+ # separated by '$' used for generating printable labels or other output.
78
+ # DOES allow extended characters e.g. é, Ø, å etc.
79
+ # Allows matchingRules of `caseIgnoreListMatch` and `caseIgnoreListSubstringsMatch`.
80
+ #
81
+ # @return [Array<String>]
82
+ #
83
+ # @api public
84
+ Address = Constructor(Array, ->(v) { v.split('$').map(&:strip) })
85
+
86
+ #
87
+ # Single Values --------
88
+ #
89
+ # @see Schema::Attribute read types
90
+
91
+ # @return [String]
92
+ #
93
+ # @api public
94
+ String = Constructor(String, ->(v) { Functions[:stringify].call(v[0]) })
95
+
96
+ # @return [Integer]
97
+ #
98
+ # @api public
99
+ Integer = Constructor(Integer, ->(v) { Functions[:map_to_integers][v][0] })
100
+
101
+ # @return [Symbol]
102
+ #
103
+ # @api public
104
+ Symbol = Constructor(Symbol, ->(v) { Functions[:map_to_symbols][v][0] })
105
+
106
+ # @return [Time]
107
+ #
108
+ # @api public
109
+ Time = Constructor(Time, ->(v) { Functions[:map_to_times][v][0] })
110
+
111
+ # @overload [ROM::Types::Bool]
112
+ #
113
+ # @return [Boolean]
114
+ #
115
+ # @api public
116
+ Bool = Constructor(Bool, ->(v) { Functions[:map_to_booleans][v][0] })
117
+
118
+ # @return [String]
119
+ #
120
+ # @api public
121
+ Binary = Constructor(String, ->(v) { Functions[:map_to_base64][v][0] }).meta(binary: true)
122
+
123
+ #
124
+ # Multiple Values --------
125
+ #
126
+
127
+ # @return [Array<String>]
128
+ #
129
+ # @api public
130
+ Strings = Constructor(Array, Functions[:stringify])
131
+
132
+ # @return [Array<Integer>]
133
+ #
134
+ # @api public
135
+ Integers = Constructor(Array, Functions[:map_to_integers])
136
+
137
+ # @return [Array<Symbol>]
138
+ #
139
+ # @api public
140
+ Symbols = Constructor(Array, Functions[:map_to_symbols])
141
+
142
+ # @return [Array<Time>]
143
+ #
144
+ # @api public
145
+ Times = Constructor(Array, Functions[:map_to_times])
146
+
147
+ # @return [Array<TrueClass, FalseClass>]
148
+ #
149
+ # @api public
150
+ Bools = Constructor(Array, Functions[:map_to_booleans])
151
+
152
+ # @return [Array<String>]
153
+ #
154
+ # @api public
155
+ Binaries = Constructor(Array, Functions[:map_to_base64]).meta(binary: true)
156
+ end
157
+ end
158
+ end