saphyr 0.4.2.beta → 0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d172fb9555ca86f1b02e7aebfd3fb9ff0de38c016e3ff70c04a362d6a919d479
4
- data.tar.gz: 838664f628c9ffa0fb948ce2812bf973664c4485b9322baf5fbe7f1f4894b2e4
3
+ metadata.gz: 9d491ec052216eb7db303fa4fb65b6a558ecbb2c39a24663a43ae85eb616da14
4
+ data.tar.gz: a07b8137c7e853c0e9625a18760139a220a1be4fdf5271365f81cd2459e288a5
5
5
  SHA512:
6
- metadata.gz: e2fb9ef59ea455da2490aee2a58f0a1af564ac71aa7ea246cf2e94bf1d7e5c934541aaffcd68b715d8622f257482b934ce74c947e6d8bc4911c28c83085075da
7
- data.tar.gz: f5112099c3cd3a1d5d034717a3f72b7abad3af7133d5a1081c289371d4e390b9fe88dc99ed07b329b703829780e5535dff0a2234d4a49030ea4a3fde91bce48d
6
+ metadata.gz: a816ea8a58c18ae02e599f077f40ce54081e84e8a12ea47e9e3734ce410e238c2562105bc4fd55cf9facfba94477d5856cf708877514eb369f5ffdd85413d7f1
7
+ data.tar.gz: bf4a796653f788a49f80bb2b1344d87a059e20a98c8fbd9ed8cd87d13062c228c153c62a8097204f252e69157611cd6d59b6b36b601fbd566b8a9bd0a8c24ff5
data/CHANGELOG CHANGED
@@ -1,13 +1,16 @@
1
- No changelog update during all the beta development phase.
1
+ -----------------------------------------------------------------
2
+ Version: 0.5.0 - 2025-05-21
3
+
4
+ - Refactor the way we validate field type
5
+ Adding EXPECTED_TYPES to field_base to automate the check
6
+ - Add :default option to field
2
7
 
3
8
  -----------------------------------------------------------------
4
9
  Version: 0.4.2.beta - 2025-05-06
5
- -----------------------------------------------------------------
6
10
 
7
11
  - Fix CVE-2024-47220 upgrade webrick to ~> 1.8.2
8
12
 
9
13
  -----------------------------------------------------------------
10
14
  Version: 0.1.0.beta - 2023-08-30
11
- -----------------------------------------------------------------
12
15
 
13
16
  - Initial release
@@ -6,7 +6,7 @@ module Saphyr
6
6
  value.is_a? TrueClass or value.is_a? FalseClass
7
7
  end
8
8
 
9
- def assert_class klass, value, errors, error_code=Fields::FieldBase::ERR_TYPE
9
+ def assert_class(klass, value, errors, error_code=Fields::FieldBase::ERR_TYPE)
10
10
  klass = [klass] unless klass.is_a? Array
11
11
  test = false
12
12
  klass.each do |k|
@@ -24,7 +24,7 @@ module Saphyr
24
24
  test
25
25
  end
26
26
 
27
- def assert_eq opt_value, value, errors, error_code=Fields::FieldBase::ERR_EQ
27
+ def assert_eq(opt_value, value, errors, error_code=Fields::FieldBase::ERR_EQ)
28
28
  return nil if opt_value.nil?
29
29
  unless value == opt_value
30
30
  errors << {
@@ -39,7 +39,7 @@ module Saphyr
39
39
  true
40
40
  end
41
41
 
42
- def assert_in opt_values, value, errors, error_code=Fields::FieldBase::ERR_IN
42
+ def assert_in(opt_values, value, errors, error_code=Fields::FieldBase::ERR_IN)
43
43
  return nil if opt_values.nil?
44
44
  unless opt_values.include? value
45
45
  errors << {
@@ -53,6 +53,19 @@ module Saphyr
53
53
  end
54
54
  true
55
55
  end
56
+
57
+ def assert_not_empty(value, errors, error_code=Fields::FieldBase::ERR_NOT_EMPTY)
58
+ if value.empty?
59
+ errors << {
60
+ type: err(error_code),
61
+ data: {
62
+ _val: value,
63
+ }
64
+ }
65
+ return false
66
+ end
67
+ true
68
+ end
56
69
  end
57
70
  end
58
71
  end
@@ -5,6 +5,7 @@ module Saphyr
5
5
  # Base
6
6
  ERR_NOT_NULLABLE = 'not-nullable'
7
7
  ERR_BAD_FORMAT = 'bad-format'
8
+ ERR_NOT_EMPTY = 'not-empty'
8
9
  ERR_TYPE = 'type'
9
10
  ERR_IN = 'in'
10
11
  ERR_EQ = 'eq'
data/lib/saphyr/engine.rb CHANGED
@@ -41,7 +41,7 @@ module Saphyr
41
41
  # lookup into the global schemas.
42
42
  # @param name [Symbol] The name of the schema.
43
43
  # @return [Saphyr::Schema]
44
- # @rmaise [Saphyr::Error] if no schema was found.
44
+ # @raise [Saphyr::Error] if no schema was found.
45
45
  def find_schema(name)
46
46
  @validators.each do |validator|
47
47
  schema = validator.find_schema name
@@ -171,20 +171,25 @@ module Saphyr
171
171
  end
172
172
 
173
173
  unless data.key? name
174
- next unless @ctx.schema.strict?
175
- if field.required?
176
- @ctx.errors << {
177
- path: field_path,
178
- errors: [
179
- {
180
- type: 'strict_mode:missing_in_data',
181
- data: {
182
- field: name,
174
+ if field.default?
175
+ data[name] = field.opts[:default]
176
+ else
177
+ next unless @ctx.schema.strict?
178
+ if field.required?
179
+ @ctx.errors << {
180
+ path: field_path,
181
+ errors: [
182
+ {
183
+ type: 'strict_mode:missing_in_data',
184
+ data: {
185
+ field: name,
186
+ }
183
187
  }
184
- }
185
- ],
186
- }
188
+ ],
189
+ }
190
+ end
187
191
  end
192
+
188
193
  next
189
194
  end
190
195
 
@@ -3,7 +3,7 @@ module Saphyr
3
3
 
4
4
  class ArrayField < FieldBase
5
5
  PREFIX = 'array'
6
-
6
+ EXPECTED_TYPES = Array
7
7
  AUTHORIZED_OPTIONS = [:len, :min, :max, :of_type, :of_schema, :opts]
8
8
 
9
9
  REQUIRED_ONE_OF_OPTIONS = [:of_type, :of_schema]
@@ -34,7 +34,6 @@ module Saphyr
34
34
  private
35
35
 
36
36
  def do_validate(ctx, name, value, errors)
37
- return unless assert_class Array, value, errors
38
37
  assert_size_len @opts[:len], value, errors
39
38
  assert_size_min @opts[:min], value, errors
40
39
  assert_size_max @opts[:max], value, errors
@@ -0,0 +1,74 @@
1
+ require 'base64'
2
+
3
+ module Saphyr
4
+ module Fields
5
+
6
+ # The +B64+ field type
7
+ #
8
+ # Allowed options is: +:strict+ (boolean)
9
+ #
10
+ # When in strict mode (:strict == true):
11
+ # - Line breaks are not allowed
12
+ # - Padding must be correct
13
+ #
14
+ # Not in strict mode (:strict == false):
15
+ # - Line breaks are allowed
16
+ # - Padding is not required
17
+ class B64Field < FieldBase
18
+ PREFIX = 'b64'
19
+ EXPECTED_TYPES = String
20
+
21
+ AUTHORIZED_OPTIONS = [:strict] # :strict = true / false
22
+
23
+ FORMAT_REGEXP = /^(?:[A-Za-z0-9+\/]*[\r\n|\n]*)*(?:[=]{1,2})?$/
24
+
25
+ def initialize(opts={})
26
+ if opts[:strict].nil?
27
+ opts[:strict] = true
28
+ else
29
+ unless [true, false].include? opts[:strict]
30
+ raise Saphyr::Error.new "Bad B64 strict option must be a boolean"
31
+ end
32
+ end
33
+ super opts
34
+ end
35
+
36
+ private
37
+
38
+ def do_validate(ctx, name, value, errors)
39
+ return unless assert_not_empty value, errors
40
+ begin
41
+ if @opts[:strict]
42
+ # NOTE: When in strict mode
43
+ # - Line breaks are not allowed
44
+ # - Padding must be correct (length % 4 == 0)
45
+ # In this case, we use Base64.strict_decode64 because it's a way
46
+ # faster than using regexp. An invalid base64 string will raise an error.
47
+ Base64.strict_decode64 value
48
+ else
49
+ # NOTE: When not in strict mode
50
+ # - Line breaks are allowed (like in PEM or EMAIL)
51
+ # - Padding is not required
52
+ # But, we can't use Base64.decode64 because it will not raise an error
53
+ # for a string like this one : 'not-b54**str'.
54
+ # (and obviously it's not a valid base64 format)
55
+ unless FORMAT_REGEXP.match? value
56
+ add_error value, errors
57
+ end
58
+ end
59
+ rescue
60
+ add_error value, errors
61
+ end
62
+ end
63
+
64
+ def add_error(value, errors)
65
+ errors << {
66
+ type: err('invalid'),
67
+ data: {
68
+ _val: value
69
+ }
70
+ }
71
+ end
72
+ end
73
+ end
74
+ end
@@ -6,13 +6,12 @@ module Saphyr
6
6
  # Allowed options are: +:eq+.
7
7
  class BooleanField < FieldBase
8
8
  PREFIX = 'boolean'
9
-
9
+ EXPECTED_TYPES = [TrueClass, FalseClass]
10
10
  AUTHORIZED_OPTIONS = [:eq]
11
11
 
12
12
  private
13
13
 
14
14
  def do_validate(ctx, name, value, errors)
15
- return unless assert_class [TrueClass, FalseClass], value, errors
16
15
  assert_eq @opts[:eq], value, errors
17
16
  end
18
17
  end
@@ -0,0 +1,39 @@
1
+ require 'date'
2
+
3
+ module Saphyr
4
+ module Fields
5
+
6
+ # The +DateTime+ field type.
7
+ #
8
+ # Allowed options is: +:format+
9
+ class DateTimeField < FieldBase
10
+ PREFIX = 'datetime'
11
+ EXPECTED_TYPES = String
12
+ AUTHORIZED_OPTIONS = [:format]
13
+
14
+ private
15
+
16
+ def do_validate(ctx, name, value, errors)
17
+ return unless assert_not_empty value, errors
18
+ begin
19
+ if @opts[:format].nil?
20
+ DateTime.parse value
21
+ else
22
+ DateTime.strptime value, @opts[:format]
23
+ end
24
+ rescue
25
+ add_error value, errors
26
+ end
27
+ end
28
+
29
+ def add_error(value, errors)
30
+ errors << {
31
+ type: err('invalid'),
32
+ data: {
33
+ _val: value
34
+ }
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ require 'uri'
2
+
3
+ module Saphyr
4
+ module Fields
5
+
6
+ # The +email+ field type
7
+ #
8
+ # No options are allowed.
9
+ class EmailField < FieldBase
10
+ PREFIX = 'email'
11
+ EXPECTED_TYPES = String
12
+
13
+ private
14
+
15
+ def do_validate(ctx, name, value, errors)
16
+ return unless assert_not_empty value, errors
17
+ unless value =~ ::URI::MailTo::EMAIL_REGEXP
18
+ errors << {
19
+ type: err('invalid'),
20
+ data: {
21
+ _val: value
22
+ }
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -17,13 +17,18 @@ module Saphyr
17
17
 
18
18
  # Every field type has the +:required+ and +:nullable+ options.
19
19
  # @api private
20
- DEFAULT_OPT_VALUES = {required: true, nullable: false}.freeze
20
+ DEFAULT_OPT_VALUES = {required: true, nullable: false, default: :_none_}.freeze
21
21
  # @api private
22
22
  DEFAULT_OPTS = DEFAULT_OPT_VALUES.keys.freeze
23
23
 
24
24
  # NOTE:
25
25
  # Override following constants to manage options
26
26
 
27
+ # List of expected classes for the field. It can be an array of class names, or
28
+ # a single class name. EX: [TrueClass, FalseClass] or Integer.
29
+ # @note Overriding this class constant is mandatory.
30
+ EXPECTED_TYPES = nil
31
+
27
32
  # List of authorized options.
28
33
  # @note Override this class constant if you want to use this feature.
29
34
  AUTHORIZED_OPTIONS = []
@@ -55,8 +60,10 @@ module Saphyr
55
60
  # @note Override this class constant if you want to use this feature.
56
61
  NOT_SUP_OR_EQUALS_OPTIONS = []
57
62
 
58
-
59
63
  def initialize(opts={})
64
+ if expected_types.nil?
65
+ raise Saphyr::Error.new "The 'EXPECTED_TYPES' constant must be defined"
66
+ end
60
67
  if opts.key? :required
61
68
  unless assert_boolean opts[:required]
62
69
  raise Saphyr::Error.new "Option ':required' must be a Boolean"
@@ -67,10 +74,21 @@ module Saphyr
67
74
  raise Saphyr::Error.new "Option ':nullable' must be a Boolean"
68
75
  end
69
76
  end
77
+ if opts.key? :default
78
+ unless assert_class expected_types, opts[:default], []
79
+ raise Saphyr::Error.new "Option ':default' bad type. Expecting: '#{self.class::EXPECTED_TYPES.to_s}', got: '#{opts[:default].class.name}'"
80
+ end
81
+ end
70
82
 
71
- unless authorized_options.size == 0
83
+ if authorized_options.size == 0
72
84
  opts.keys.each do |opt|
73
- next if opt == :required or opt == :nullable
85
+ unless [:required, :nullable, :default].include? opt
86
+ raise Saphyr::Error.new "Options are not allowed for this field type: '#{opt}'"
87
+ end
88
+ end
89
+ else
90
+ opts.keys.each do |opt|
91
+ next if opt == :required or opt == :nullable or opt == :default
74
92
  unless authorized_options.include? opt
75
93
  raise Saphyr::Error.new "Unauthorized option: #{opt}"
76
94
  end
@@ -151,6 +169,12 @@ module Saphyr
151
169
 
152
170
  # -----
153
171
 
172
+ # Get the +EXPECTED_TYPES+ options
173
+ # @return [Array]
174
+ def expected_types
175
+ self.class::EXPECTED_TYPES
176
+ end
177
+
154
178
  # Get the +AUTHORIZED_OPTIONS+ options
155
179
  # @return [Array]
156
180
  def authorized_options
@@ -212,6 +236,10 @@ module Saphyr
212
236
  @opts[:nullable]
213
237
  end
214
238
 
239
+ def default?
240
+ @opts[:default] != :_none_
241
+ end
242
+
215
243
  # -----
216
244
 
217
245
  # Check if the field value is valid.
@@ -221,6 +249,7 @@ module Saphyr
221
249
  def validate(ctx, name, value)
222
250
  # NOTE: Nullable is handle by the engine.
223
251
  errors = []
252
+ return errors unless assert_class self.class::EXPECTED_TYPES, value, errors
224
253
  do_validate ctx, name, value, errors
225
254
  errors
226
255
  end
@@ -6,7 +6,7 @@ module Saphyr
6
6
  # Allowed options are: +:eq, :gt, :gte, :lt, :lte, :in+.
7
7
  class FloatField < FieldBase
8
8
  PREFIX = 'float'
9
-
9
+ EXPECTED_TYPES = Float
10
10
  AUTHORIZED_OPTIONS = [:eq, :gt, :gte, :lt, :lte, :in]
11
11
 
12
12
  EXCLUSIVE_OPTIONS = [
@@ -36,7 +36,6 @@ module Saphyr
36
36
  private
37
37
 
38
38
  def do_validate(ctx, name, value, errors)
39
- return unless assert_class Float, value, errors
40
39
  assert_eq @opts[:eq], value, errors
41
40
  assert_numeric_gt @opts[:gt], value, errors
42
41
  assert_numeric_gte @opts[:gte], value, errors
@@ -6,7 +6,7 @@ module Saphyr
6
6
  # Allowed options are: +:eq, :gt, :gte, :lt, :lte, :in+.
7
7
  class IntegerField < FieldBase
8
8
  PREFIX = 'integer'
9
-
9
+ EXPECTED_TYPES = Integer
10
10
  AUTHORIZED_OPTIONS = [:eq, :gt, :gte, :lt, :lte, :in]
11
11
 
12
12
  EXCLUSIVE_OPTIONS = [
@@ -36,7 +36,6 @@ module Saphyr
36
36
  private
37
37
 
38
38
  def do_validate(ctx, name, value, errors)
39
- return unless assert_class Integer, value, errors
40
39
  assert_eq @opts[:eq], value, errors
41
40
  assert_numeric_gt @opts[:gt], value, errors
42
41
  assert_numeric_gte @opts[:gte], value, errors
@@ -0,0 +1,53 @@
1
+ module Saphyr
2
+ module Fields
3
+
4
+ # The +IP+ field type
5
+ #
6
+ # Allowed options is: +:kind in (:any, :ipv4, :ipv6)+
7
+ #
8
+ # - +:any+ : can be an ipv4 or ipv6 (default)
9
+ # - +:ipv4+ : must be an ipv4
10
+ # - +:ipv6+ : must be an ipv6
11
+ class IpField < FieldBase
12
+ PREFIX = 'ip'
13
+ EXPECTED_TYPES = String
14
+ AUTHORIZED_OPTIONS = [:kind]
15
+
16
+ def initialize(opts={})
17
+ if opts[:kind].nil?
18
+ opts[:kind] = :any
19
+ else
20
+ unless [:any, :ipv4, :ipv6].include? opts[:kind]
21
+ raise Saphyr::Error.new 'Bad IP kind option must be one of :any, :ipv4, :ipv6'
22
+ end
23
+ end
24
+ super opts
25
+ end
26
+
27
+ private
28
+
29
+ def do_validate(ctx, name, value, errors)
30
+ return unless assert_not_empty value, errors
31
+ begin
32
+ ip = IPAddr.new value
33
+ if @opts[:kind] == :ipv4 and not ip.ipv4?
34
+ add_error value, errors
35
+ elsif @opts[:kind] == :ipv6 and not ip.ipv6?
36
+ add_error value, errors
37
+ end
38
+ rescue
39
+ add_error value, errors
40
+ end
41
+ end
42
+
43
+ def add_error(value, errors)
44
+ errors << {
45
+ type: err('invalid'),
46
+ data: {
47
+ _val: value
48
+ }
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,103 @@
1
+ module Saphyr
2
+ module Fields
3
+
4
+ # The +IsoCountry+ field type (ISO-3166-1 alpha 2/3).
5
+ #
6
+ # Allowed options is: +:alpha with possible values: 2 or 3+
7
+ #
8
+ # - +2+ : Mean ISO-3166-1 alpha-2 (defulat)
9
+ # - +3+ : Mean ISO-3166-1 alpha-3
10
+ class IsoCountryField < FieldBase
11
+ PREFIX = 'iso-country'
12
+ EXPECTED_TYPES = String
13
+ AUTHORIZED_OPTIONS = [:alpha]
14
+
15
+ ALPHA_2 = [
16
+ 'AF', 'AX', 'AL', 'DZ', 'AS', 'AD', 'AO', 'AI', 'AQ', 'AG',
17
+ 'AR', 'AM', 'AW', 'AU', 'AT', 'AZ', 'BS', 'BH', 'BD', 'BB',
18
+ 'BY', 'BE', 'BZ', 'BJ', 'BM', 'BT', 'BO', 'BQ', 'BA', 'BW',
19
+ 'BV', 'BR', 'IO', 'BN', 'BG', 'BF', 'BI', 'CV', 'KH', 'CM',
20
+ 'CA', 'KY', 'CF', 'TD', 'CL', 'CN', 'CX', 'CC', 'CO', 'KM',
21
+ 'CG', 'CD', 'CK', 'CR', 'CI', 'HR', 'CU', 'CW', 'CY', 'CZ',
22
+ 'DK', 'DJ', 'DM', 'DO', 'EC', 'EG', 'SV', 'GQ', 'ER', 'EE',
23
+ 'SZ', 'ET', 'FK', 'FO', 'FJ', 'FI', 'FR', 'GF', 'PF', 'TF',
24
+ 'GA', 'GM', 'GE', 'DE', 'GH', 'GI', 'GR', 'GL', 'GD', 'GP',
25
+ 'GU', 'GT', 'GG', 'GN', 'GW', 'GY', 'HT', 'HM', 'VA', 'HN',
26
+ 'HK', 'HU', 'IS', 'IN', 'ID', 'IR', 'IQ', 'IE', 'IM', 'IL',
27
+ 'IT', 'JM', 'JP', 'JE', 'JO', 'KZ', 'KE', 'KI', 'KP', 'KR',
28
+ 'KW', 'KG', 'LA', 'LV', 'LB', 'LS', 'LR', 'LY', 'LI', 'LT',
29
+ 'LU', 'MO', 'MG', 'MW', 'MY', 'MV', 'ML', 'MT', 'MH', 'MQ',
30
+ 'MR', 'MU', 'YT', 'MX', 'FM', 'MD', 'MC', 'MN', 'ME', 'MS',
31
+ 'MA', 'MZ', 'MM', 'NA', 'NR', 'NP', 'NL', 'NC', 'NZ', 'NI',
32
+ 'NE', 'NG', 'NU', 'NF', 'MK', 'MP', 'NO', 'OM', 'PK', 'PW',
33
+ 'PS', 'PA', 'PG', 'PY', 'PE', 'PH', 'PN', 'PL', 'PT', 'PR',
34
+ 'QA', 'RE', 'RO', 'RU', 'RW', 'BL', 'SH', 'KN', 'LC', 'MF',
35
+ 'PM', 'VC', 'WS', 'SM', 'ST', 'SA', 'SN', 'RS', 'SC', 'SL',
36
+ 'SG', 'SX', 'SK', 'SI', 'SB', 'SO', 'ZA', 'GS', 'SS', 'ES',
37
+ 'LK', 'SD', 'SR', 'SJ', 'SE', 'CH', 'SY', 'TW', 'TJ', 'TZ',
38
+ 'TH', 'TL', 'TG', 'TK', 'TO', 'TT', 'TN', 'TR', 'TM', 'TC',
39
+ 'TV', 'UG', 'UA', 'AE', 'GB', 'US', 'UM', 'UY', 'UZ', 'VU',
40
+ 'VE', 'VN', 'VG', 'VI', 'WF', 'EH', 'YE', 'ZM', 'ZW'
41
+ ]
42
+
43
+ ALPHA_3 = [
44
+ 'AFG', 'ALA', 'ALB', 'DZA', 'ASM', 'AND', 'AGO', 'AIA', 'ATA', 'ATG',
45
+ 'ARG', 'ARM', 'ABW', 'AUS', 'AUT', 'AZE', 'BHS', 'BHR', 'BGD', 'BRB',
46
+ 'BLR', 'BEL', 'BLZ', 'BEN', 'BMU', 'BTN', 'BOL', 'BES', 'BIH', 'BWA',
47
+ 'BVT', 'BRA', 'IOT', 'BRN', 'BGR', 'BFA', 'BDI', 'CPV', 'KHM', 'CMR',
48
+ 'CAN', 'CYM', 'CAF', 'TCD', 'CHL', 'CHN', 'CXR', 'CCK', 'COL', 'COM',
49
+ 'COG', 'COD', 'COK', 'CRI', 'CIV', 'HRV', 'CUB', 'CUW', 'CYP', 'CZE',
50
+ 'DNK', 'DJI', 'DMA', 'DOM', 'ECU', 'EGY', 'SLV', 'GNQ', 'ERI', 'EST',
51
+ 'SWZ', 'ETH', 'FLK', 'FRO', 'FJI', 'FIN', 'FRA', 'GUF', 'PYF', 'ATF',
52
+ 'GAB', 'GMB', 'GEO', 'DEU', 'GHA', 'GIB', 'GRC', 'GRL', 'GRD', 'GLP',
53
+ 'GUM', 'GTM', 'GGY', 'GIN', 'GNB', 'GUY', 'HTI', 'HMD', 'VAT', 'HND',
54
+ 'HKG', 'HUN', 'ISL', 'IND', 'IDN', 'IRN', 'IRQ', 'IRL', 'IMN', 'ISR',
55
+ 'ITA', 'JAM', 'JPN', 'JEY', 'JOR', 'KAZ', 'KEN', 'KIR', 'PRK', 'KOR',
56
+ 'KWT', 'KGZ', 'LAO', 'LVA', 'LBN', 'LSO', 'LBR', 'LBY', 'LIE', 'LTU',
57
+ 'LUX', 'MAC', 'MDG', 'MWI', 'MYS', 'MDV', 'MLI', 'MLT', 'MHL', 'MTQ',
58
+ 'MRT', 'MUS', 'MYT', 'MEX', 'FSM', 'MDA', 'MCO', 'MNG', 'MNE', 'MSR',
59
+ 'MAR', 'MOZ', 'MMR', 'NAM', 'NRU', 'NPL', 'NLD', 'NCL', 'NZL', 'NIC',
60
+ 'NER', 'NGA', 'NIU', 'NFK', 'MKD', 'MNP', 'NOR', 'OMN', 'PAK', 'PLW',
61
+ 'PSE', 'PAN', 'PNG', 'PRY', 'PER', 'PHL', 'PCN', 'POL', 'PRT', 'PRI',
62
+ 'QAT', 'REU', 'ROU', 'RUS', 'RWA', 'BLM', 'SHN', 'KNA', 'LCA', 'MAF',
63
+ 'SPM', 'VCT', 'WSM', 'SMR', 'STP', 'SAU', 'SEN', 'SRB', 'SYC', 'SLE',
64
+ 'SGP', 'SXM', 'SVK', 'SVN', 'SLB', 'SOM', 'ZAF', 'SGS', 'SSD', 'ESP',
65
+ 'LKA', 'SDN', 'SUR', 'SJM', 'SWE', 'CHE', 'SYR', 'TWN', 'TJK', 'TZA',
66
+ 'THA', 'TLS', 'TGO', 'TKL', 'TON', 'TTO', 'TUN', 'TUR', 'TKM', 'TCA',
67
+ 'TUV', 'UGA', 'UKR', 'ARE', 'GBR', 'USA', 'UMI', 'URY', 'UZB', 'VUT',
68
+ 'VEN', 'VNM', 'VGB', 'VIR', 'WLF', 'ESH', 'YEM', 'ZMB', 'ZWE'
69
+ ]
70
+
71
+ def initialize(opts={})
72
+ if opts[:alpha].nil?
73
+ opts[:alpha] = 2
74
+ else
75
+ if opts[:alpha] != 2 and opts[:alpha] != 3
76
+ raise Saphyr::Error.new 'Bad county alpha option must be : 2 or 3'
77
+ end
78
+ end
79
+ super opts
80
+ end
81
+
82
+ private
83
+
84
+ def do_validate(ctx, name, value, errors)
85
+ return unless assert_not_empty value, errors
86
+ if @opts[:alpha] == 2
87
+ add_error value, errors unless ALPHA_2.include? value
88
+ else
89
+ add_error value, errors unless ALPHA_3.include? value
90
+ end
91
+ end
92
+
93
+ def add_error(value, errors)
94
+ errors << {
95
+ type: err('invalid'),
96
+ data: {
97
+ _val: value
98
+ }
99
+ }
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,114 @@
1
+ module Saphyr
2
+ module Fields
3
+
4
+ # The +IsoLang+ field type (ISO-639-1/2).
5
+ #
6
+ # Allowed options is: +:version with possible values: 1 or 2+
7
+ #
8
+ # - +1+ : Mean ISO-639-1 (default)
9
+ # - +2+ : Mean ISO-639-2
10
+ class IsoLangField < FieldBase
11
+ PREFIX = 'iso-lang'
12
+ EXPECTED_TYPES = String
13
+ AUTHORIZED_OPTIONS = [:version]
14
+
15
+ VERSION_1 = [
16
+ 'aa', 'ab', 'ae', 'af', 'ak', 'am', 'an', 'ar', 'as', 'av', 'ay', 'az',
17
+ 'ba', 'be', 'bg', 'bh', 'bi', 'bm', 'bn', 'bo', 'br', 'bs', 'ca', 'ce',
18
+ 'ch', 'co', 'cr', 'cs', 'cu', 'cv', 'cy', 'da', 'de', 'dv', 'dz', 'ee',
19
+ 'el', 'en', 'eo', 'es', 'et', 'eu', 'fa', 'ff', 'fi', 'fj', 'fo', 'fr',
20
+ 'fy', 'ga', 'gd', 'gl', 'gn', 'gu', 'gv', 'ha', 'he', 'hi', 'ho', 'hr',
21
+ 'ht', 'hu', 'hy', 'hz', 'ia', 'id', 'ie', 'ig', 'ii', 'ik', 'io', 'is',
22
+ 'it', 'iu', 'ja', 'jv', 'ka', 'kg', 'ki', 'kj', 'kk', 'kl', 'km', 'kn',
23
+ 'ko', 'kr', 'ks', 'ku', 'kv', 'kw', 'ky', 'la', 'lb', 'lg', 'li', 'ln',
24
+ 'lo', 'lt', 'lu', 'lv', 'mg', 'mh', 'mi', 'mk', 'ml', 'mn', 'mr', 'ms',
25
+ 'mt', 'my', 'na', 'nb', 'nd', 'ne', 'ng', 'nl', 'nn', 'no', 'nr', 'nv',
26
+ 'ny', 'oc', 'oj', 'om', 'or', 'os', 'pa', 'pi', 'pl', 'ps', 'pt', 'qu',
27
+ 'rm', 'rn', 'ro', 'ru', 'rw', 'sa', 'sc', 'sd', 'se', 'sg', 'si', 'sk',
28
+ 'sl', 'sm', 'sn', 'so', 'sq', 'sr', 'ss', 'st', 'su', 'sv', 'sw', 'ta',
29
+ 'te', 'tg', 'th', 'ti', 'tk', 'tl', 'tn', 'to', 'tr', 'ts', 'tt', 'tw',
30
+ 'ty', 'ug', 'uk', 'ur', 'uz', 've', 'vi', 'vo', 'wa', 'wo', 'xh', 'yi',
31
+ 'yo', 'za', 'zh', 'zu'
32
+ ]
33
+
34
+ VERSION_2 = [
35
+ 'aar', 'abk', 'ace', 'ach', 'ada', 'ady', 'afa', 'afh', 'afr', 'ain', 'aka',
36
+ 'akk', 'alb', 'ale', 'alg', 'alt', 'amh', 'ang', 'anp', 'apa', 'ara', 'arc',
37
+ 'arg', 'arm', 'arn', 'arp', 'art', 'arw', 'asm', 'ast', 'ath', 'aus', 'ava',
38
+ 'ave', 'awa', 'aym', 'aze', 'bad', 'bai', 'bak', 'bal', 'bam', 'ban', 'baq',
39
+ 'bas', 'bat', 'bej', 'bel', 'bem', 'ben', 'ber', 'bho', 'bih', 'bik', 'bin',
40
+ 'bis', 'bla', 'bnt', 'bos', 'bra', 'bre', 'btk', 'bua', 'bug', 'bul', 'bur',
41
+ 'byn', 'cad', 'cai', 'car', 'cat', 'cau', 'ceb', 'cel', 'cha', 'chb', 'che',
42
+ 'chg', 'chi', 'chk', 'chm', 'chn', 'cho', 'chp', 'chr', 'chu', 'chv', 'chy',
43
+ 'cmc', 'cnr', 'cop', 'cor', 'cos', 'cpe', 'cpf', 'cpp', 'cre', 'crh', 'crp',
44
+ 'csb', 'cus', 'cze', 'dak', 'dan', 'dar', 'day', 'del', 'den', 'dgr', 'din',
45
+ 'div', 'doi', 'dra', 'dsb', 'dua', 'dum', 'dut', 'dyu', 'dzo', 'efi', 'egy',
46
+ 'eka', 'elx', 'eng', 'enm', 'epo', 'est', 'ewe', 'ewo', 'fan', 'fao', 'fat',
47
+ 'fij', 'fil', 'fin', 'fiu', 'fon', 'fre', 'frm', 'fro', 'frr', 'frs', 'fry',
48
+ 'ful', 'fur', 'gaa', 'gay', 'gba', 'gem', 'geo', 'ger', 'gez', 'gil', 'gla',
49
+ 'gle', 'glg', 'glv', 'gmh', 'goh', 'gon', 'gor', 'got', 'grb', 'grc', 'gre',
50
+ 'grn', 'gsw', 'guj', 'gwi', 'hai', 'hat', 'hau', 'haw', 'heb', 'her', 'hil',
51
+ 'him', 'hin', 'hit', 'hmn', 'hmo', 'hrv', 'hsb', 'hun', 'hup', 'iba', 'ibo',
52
+ 'ice', 'ido', 'iii', 'ijo', 'iku', 'ile', 'ilo', 'ina', 'inc', 'ind', 'ine',
53
+ 'inh', 'ipk', 'ira', 'iro', 'ita', 'jav', 'jbo', 'jpn', 'jpr', 'jrb', 'kaa',
54
+ 'kab', 'kac', 'kal', 'kam', 'kan', 'kar', 'kas', 'kau', 'kaw', 'kaz', 'kbd',
55
+ 'kha', 'khi', 'khm', 'kho', 'kik', 'kin', 'kir', 'kmb', 'kok', 'kom', 'kon',
56
+ 'kor', 'kos', 'kpe', 'krc', 'krl', 'kro', 'kru', 'kua', 'kum', 'kur', 'kut',
57
+ 'lad', 'lah', 'lam', 'lao', 'lat', 'lav', 'lez', 'lim', 'lin', 'lit', 'lol',
58
+ 'loz', 'ltz', 'lua', 'lub', 'lug', 'lui', 'lun', 'luo', 'lus', 'mac', 'mad',
59
+ 'mag', 'mah', 'mai', 'mak', 'mal', 'man', 'mao', 'map', 'mar', 'mas', 'may',
60
+ 'mdf', 'mdr', 'men', 'mga', 'mic', 'min', 'mis', 'mkh', 'mlg', 'mlt', 'mnc',
61
+ 'mni', 'mno', 'moh', 'mon', 'mos', 'mul', 'mun', 'mus', 'mwl', 'mwr', 'myn',
62
+ 'myv', 'nah', 'nai', 'nap', 'nau', 'nav', 'nbl', 'nde', 'ndo', 'nds', 'nep',
63
+ 'new', 'nia', 'nic', 'niu', 'nno', 'nob', 'nog', 'non', 'nor', 'nqo', 'nso',
64
+ 'nub', 'nwc', 'nya', 'nym', 'nyn', 'nyo', 'nzi', 'oci', 'oji', 'ori', 'orm',
65
+ 'osa', 'oss', 'ota', 'oto', 'paa', 'pag', 'pal', 'pam', 'pan', 'pap', 'pau',
66
+ 'peo', 'per', 'phi', 'phn', 'pli', 'pol', 'pon', 'por', 'pra', 'pro', 'pus',
67
+ 'qaa', 'que', 'raj', 'rap', 'rar', 'roa', 'roh', 'rom', 'rum', 'run', 'rup',
68
+ 'rus', 'sad', 'sag', 'sah', 'sai', 'sal', 'sam', 'san', 'sas', 'sat', 'scn',
69
+ 'sco', 'sel', 'sem', 'sga', 'sgn', 'shn', 'sid', 'sin', 'sio', 'sit', 'sla',
70
+ 'slo', 'slv', 'sma', 'sme', 'smi', 'smj', 'smn', 'smo', 'sms', 'sna', 'snd',
71
+ 'snk', 'sog', 'som', 'son', 'sot', 'spa', 'srd', 'srn', 'srp', 'srr', 'ssa',
72
+ 'ssw', 'suk', 'sun', 'sus', 'sux', 'swa', 'swe', 'syc', 'syr', 'tah', 'tai',
73
+ 'tam', 'tat', 'tel', 'tem', 'ter', 'tet', 'tgk', 'tgl', 'tha', 'tib', 'tig',
74
+ 'tir', 'tiv', 'tkl', 'tlh', 'tli', 'tmh', 'tog', 'ton', 'tpi', 'tsi', 'tsn',
75
+ 'tso', 'tuk', 'tum', 'tup', 'tur', 'tut', 'tvl', 'twi', 'tyv', 'udm', 'uga',
76
+ 'uig', 'ukr', 'umb', 'und', 'urd', 'uzb', 'vai', 'ven', 'vie', 'vol', 'vot',
77
+ 'wak', 'wal', 'war', 'was', 'wel', 'wen', 'wln', 'wol', 'xal', 'xho', 'yao',
78
+ 'yap', 'yid', 'yor', 'ypk', 'zap', 'zbl', 'zen', 'zgh', 'zha', 'znd', 'zul',
79
+ 'zun', 'zxx', 'zza'
80
+ ]
81
+
82
+ def initialize(opts={})
83
+ if opts[:version].nil?
84
+ opts[:version] = 1
85
+ else
86
+ if opts[:version] != 1 and opts[:version] != 2
87
+ raise Saphyr::Error.new 'Bad language akpha option must be : 2 or 3'
88
+ end
89
+ end
90
+ super opts
91
+ end
92
+
93
+ private
94
+
95
+ def do_validate(ctx, name, value, errors)
96
+ return unless assert_not_empty value, errors
97
+ if @opts[:version] == 1
98
+ add_error value, errors unless VERSION_1.include? value
99
+ else
100
+ add_error value, errors unless VERSION_2.include? value
101
+ end
102
+ end
103
+
104
+ def add_error(value, errors)
105
+ errors << {
106
+ type: err('invalid'),
107
+ data: {
108
+ _val: value
109
+ }
110
+ }
111
+ end
112
+ end
113
+ end
114
+ end
@@ -3,9 +3,8 @@ module Saphyr
3
3
 
4
4
  class SchemaField < FieldBase
5
5
  PREFIX = 'schema'
6
-
6
+ EXPECTED_TYPES = Hash
7
7
  AUTHORIZED_OPTIONS = [:name]
8
-
9
8
  REQUIRED_OPTIONS = [:name]
10
9
 
11
10
  private
@@ -6,7 +6,7 @@ module Saphyr
6
6
  # Allowed options are: +:eq, :len, :min, :max, :in, :regexp+.
7
7
  class StringField < FieldBase
8
8
  PREFIX = 'string'
9
-
9
+ EXPECTED_TYPES = String
10
10
  AUTHORIZED_OPTIONS = [:eq, :len, :min, :max, :in, :regexp]
11
11
 
12
12
  EXCLUSIVE_OPTIONS = [
@@ -28,7 +28,6 @@ module Saphyr
28
28
  private
29
29
 
30
30
  def do_validate(ctx, name, value, errors)
31
- return unless assert_class String, value, errors
32
31
  assert_eq @opts[:eq], value, errors
33
32
  assert_size_len @opts[:len], value, errors
34
33
  assert_size_min @opts[:min], value, errors
@@ -0,0 +1,29 @@
1
+ require 'uri'
2
+
3
+ module Saphyr
4
+ module Fields
5
+
6
+ # The +URI+ field type
7
+ #
8
+ # No options are allowed.
9
+ class UriField < FieldBase
10
+ PREFIX = 'uri'
11
+ EXPECTED_TYPES = String
12
+
13
+ private
14
+
15
+ def do_validate(ctx, name, value, errors)
16
+ begin
17
+ URI.parse value
18
+ rescue URI::InvalidURIError
19
+ errors << {
20
+ type: err('invalid'),
21
+ data: {
22
+ _val: value
23
+ }
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,36 @@
1
+ require 'uri'
2
+
3
+ module Saphyr
4
+ module Fields
5
+
6
+ # The +URL+ field type
7
+ #
8
+ # No options are allowed.
9
+ class UrlField < FieldBase
10
+ PREFIX = 'url'
11
+ EXPECTED_TYPES = String
12
+
13
+ private
14
+
15
+ def do_validate(ctx, name, value, errors)
16
+ begin
17
+ uri = URI.parse value
18
+ unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
19
+ add_error value, errors
20
+ end
21
+ rescue URI::InvalidURIError
22
+ add_error value, errors
23
+ end
24
+ end
25
+
26
+ def add_error(value, errors)
27
+ errors << {
28
+ type: err('invalid'),
29
+ data: {
30
+ _val: value
31
+ }
32
+ }
33
+ end
34
+ end
35
+ end
36
+ end
data/lib/saphyr/fields.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  module Saphyr
2
2
  module Fields
3
3
  require_relative './fields/field_base'
4
-
5
4
  require_relative './fields/array_field'
6
5
  require_relative './fields/schema_field'
7
6
 
@@ -9,5 +8,13 @@ module Saphyr
9
8
  require_relative './fields/integer_field'
10
9
  require_relative './fields/float_field'
11
10
  require_relative './fields/boolean_field'
11
+ require_relative './fields/email_field'
12
+ require_relative './fields/uri_field'
13
+ require_relative './fields/url_field'
14
+ require_relative './fields/b64_field'
15
+ require_relative './fields/ip_field'
16
+ require_relative './fields/iso_country_field'
17
+ require_relative './fields/iso_lang_field'
18
+ require_relative './fields/datetime_field'
12
19
  end
13
20
  end
@@ -98,6 +98,13 @@ module Saphyr
98
98
  return 'Conditional field not allowed'
99
99
  end
100
100
 
101
+ # ------------------------------------
102
+ # Not Empty
103
+ # ------------------------------------
104
+ if type.end_with? 'not-empty'
105
+ return 'Cannot be empty'
106
+ end
107
+
101
108
  # ------------------------------------
102
109
  # Not Nullable
103
110
  # ------------------------------------
@@ -105,6 +112,14 @@ module Saphyr
105
112
  return 'Not nullable'
106
113
  end
107
114
 
115
+ # ------------------------------------
116
+ # Common
117
+ # ------------------------------------
118
+ # invalid
119
+ if type.end_with? 'invalid'
120
+ return "Invalid format, got: '#{data[:_val]}'"
121
+ end
122
+
108
123
  'unknown'
109
124
  end
110
125
  end
@@ -95,7 +95,7 @@ module Saphyr
95
95
  # -----
96
96
 
97
97
  # Validate an already parsed JSON document.
98
- # @param [Hash | Array] The data to validate.
98
+ # @param data [Hash | Array] The data to validate.
99
99
  # @return [Boolean] Wheter the validation was successful or failed.
100
100
  def validate(data)
101
101
  @ctx = Saphyr::Engine::Context.new [self], get_config, data, nil, '//'
@@ -119,7 +119,7 @@ module Saphyr
119
119
  end
120
120
 
121
121
  # Get a field from the data to validate.
122
- # @param [String | Symbol] The field name
122
+ # @param field [String | Symbol] The field name
123
123
  # @return The field value
124
124
  def get(field)
125
125
  data = @ctx.data_to_validate
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Saphyr
4
- VERSION = "0.4.2.beta"
4
+ VERSION = '0.6.0'
5
5
  end
data/lib/saphyr.rb CHANGED
@@ -157,4 +157,12 @@ Saphyr.register do
157
157
  field_type :integer, Saphyr::Fields::IntegerField
158
158
  field_type :float, Saphyr::Fields::FloatField
159
159
  field_type :boolean, Saphyr::Fields::BooleanField
160
+ field_type :email, Saphyr::Fields::EmailField
161
+ field_type :uri, Saphyr::Fields::UriField
162
+ field_type :url, Saphyr::Fields::UrlField
163
+ field_type :b64, Saphyr::Fields::B64Field
164
+ field_type :ip, Saphyr::Fields::IpField
165
+ field_type :iso_country, Saphyr::Fields::IsoCountryField
166
+ field_type :iso_lang, Saphyr::Fields::IsoLangField
167
+ field_type :datetime, Saphyr::Fields::DateTimeField
160
168
  end
@@ -4,7 +4,7 @@ By default the `Saphyr` library is including many field types.
4
4
 
5
5
  ## Common options
6
6
 
7
- All field type have the common `:required`, `:nullable`.
7
+ All field type have the common `:required`, `:nullable` and `:default` options.
8
8
 
9
9
  ## String
10
10
 
@@ -15,16 +15,14 @@ Here is an example with all possible options for `:string` type:
15
15
  ```ruby
16
16
  class MyValidator < Saphyr::Validator
17
17
  field :name, :string
18
- field :name, :string, eq: 'v1.1'
19
- field :name, :string, min: 5, max: 50
20
- field :name, :string, max: 50
21
- field :name, :string, len: 15
22
- field :name, :string, len: 15, regexp: /^[a-f0-9]+$/
23
- field :name, :string, regexp: /^[A-Z0-9]{15}$/
24
- field :name, :string, in: ['jpg', 'png', 'gif']
25
-
26
-
27
- field :location, :string, required: false, min: 10
18
+ field :version, :string, eq: 'v1.1' # Field name can be a
19
+ field "fname", :string, min: 5, max: 50 # Symbol or a String
20
+ field "lname", :string, max: 50
21
+ field "info", :string, len: 15
22
+ field :hexa, :string, len: 15, regexp: /^[a-f0-9]+$/
23
+ field :nid, :string, regexp: /^[A-Z0-9]{15}$/
24
+ field :extension, :string, in: ['jpg', 'png', 'gif']
25
+ field :location, :string, required: false, min: 10, default: 'here'
28
26
  field :info, :string, nullable: true, max: 1024
29
27
  end
30
28
  ```
@@ -33,7 +31,6 @@ end
33
31
  - If you use `:len` option then you cannot use `:min` and `:max` options
34
32
  - If you use `:in` option then you cannot use any of the other options
35
33
 
36
-
37
34
  ## Integer
38
35
 
39
36
  Authorized options for the `:integer` type: `[:eq, :gt, :gte, :lt, :lte, :in]`
@@ -42,15 +39,14 @@ Here is an example with all possible options for `:integer` type:
42
39
 
43
40
  ```ruby
44
41
  class MyValidator < Saphyr::Validator
45
- field :count, :integer
46
- field :count, :integer, eq: 'v1.1'
47
- field :count, :integer, gt: 0
48
- field :count, :integer, lt: 50
49
- field :count, :integer, gte: 5, lte: 50
50
- field :count, :integer, in: ['jpg', 'png', 'gif']
51
-
52
- field :count, :integer, required: false, gte: 10
53
- field :count, :integer, nullable: true, lte: 1024
42
+ field :id, :integer, gt: 0
43
+ field :nb, :integer
44
+ field :version, :integer, eq: '101'
45
+ field :value, :integer, lt: 50
46
+ field :range, :integer, gte: 5, lte: 50
47
+ field :velocity, :integer, in: [10, 20, 30, 40]
48
+ field :count, :integer, required: false, gte: 10, default: 20
49
+ field :round, :integer, nullable: true, lte: 1024
54
50
  end
55
51
  ```
56
52
 
@@ -65,15 +61,14 @@ Here is an example with all possible options for `:float` type:
65
61
 
66
62
  ```ruby
67
63
  class MyValidator < Saphyr::Validator
68
- field :price, :float
69
- field :price, :float, eq: 15.1
70
- field :price, :float, gt: 0
71
- field :price, :float, lt: 50
72
- field :price, :float, gte: 5, lte: 50
73
- field :price, :float, in: ['jpg', 'png', 'gif']
74
-
75
- field :price, :float, required: false, gte: 10
76
- field :price, :float, nullable: true, lte: 1024
64
+ field :value, :float
65
+ field :velocity, :float, eq: 15.1
66
+ field :x_axis, :float, gt: 0.0
67
+ field :y_axis, :float, lt: 50
68
+ field :z_axis, :float, gte: 5, lte: 50
69
+ field :focale, :float, in: [3.14, 1.618, 6.35]
70
+ field :price, :float, required: false, gte: 10, default: 22.2
71
+ field :discount, :float, nullable: true, lte: 1024
77
72
  end
78
73
  ```
79
74
 
@@ -88,12 +83,120 @@ Here is an example with all possible options for `:boolean` type:
88
83
 
89
84
  ```ruby
90
85
  class MyValidator < Saphyr::Validator
91
- field :active, :boolean
92
- field :active, :boolean, eq: true
93
- field :active, :boolean, eq: false
86
+ field :payed, :boolean
87
+ field :valid, :boolean, eq: true
88
+ field :option, :boolean, eq: false
89
+ field :active, :boolean, required: false, default: true
90
+ field :processed, :boolean, nullable: true
91
+ end
92
+ ```
93
+
94
+ ## Email
95
+
96
+ No options allowed for the `:email` type.
97
+
98
+ ```ruby
99
+ class MyValidator < Saphyr::Validator
100
+ field :email, :email
101
+ end
102
+ ```
103
+
104
+ ## URI and URL
105
+
106
+ No options allowed for the `:uri` and `:url` types.
107
+
108
+ ```ruby
109
+ class MyValidator < Saphyr::Validator
110
+ field :email, :uri # valid@email.com
111
+ field :isbn, :uri # urn:isbn:0451450523
112
+ field :location, :uri # https://example.com/page.html
113
+
114
+ field :site, :url # http://www.test.com/
115
+ field :blog, :url # http://test.com/page.html
116
+ end
117
+ ```
118
+
119
+ ## Base64
120
+
121
+ Authorized options for the `:b64` type: `[:strict]`
122
+
123
+ Here is an example with all possible options for `:b64` type:
124
+
125
+ ```ruby
126
+ class MyValidator < Saphyr::Validator
127
+ field :content, :b64 # By default :strict == true
128
+ field :text, :b64, strict: false
129
+ end
130
+ ```
131
+
132
+ In strict mode `:strict == true`:
133
+
134
+ - Line breaks are not allowed
135
+ - Padding must be correct (length % 4 == 0)
136
+
137
+ Not in strict mode `:strict == false`:
94
138
 
95
- field :active, :boolean, required: false
96
- field :active, :boolean, nullable: true
139
+ - Line breaks are allowed
140
+ - Padding is not required
141
+
142
+ ## IP
143
+
144
+ Authorized options for the `:ip` type: `[:kind]`
145
+
146
+ Here is an example with all possible options for `:ip` type:
147
+
148
+ ```ruby
149
+ class MyValidator < Saphyr::Validator
150
+ field :web1, :ip # Can be ipv4 or ipv6
151
+ field :db, :ip, kind: :ipv4 # Must be an ipv4
152
+ field :cache, :ip, kind: :ipv6 # Must be an ipv6
153
+ end
154
+ ```
155
+
156
+ ## Country (ISO-3166-1 alpha 2/3)
157
+
158
+ Authorized options for the `:iso_country` type: `[:alpha]`
159
+
160
+ Here is an example with all possible options for `:iso_country` type:
161
+
162
+ ```ruby
163
+ class MyValidator < Saphyr::Validator
164
+ field :country1, :iso_country # Default : ISO-3166-1 alpha-2
165
+ field :country2, :iso_country, alpha: 2
166
+ field :country3, :iso_country, alpha: 3
167
+ end
168
+ ```
169
+
170
+ - `:alpha = 2` : Mean ISO-3166-1 alpha-2
171
+ - `:alpha = 3` : Mean ISO-3166-1 alpha-3
172
+
173
+ ## Language (ISO-639-1, ISO-639-2)
174
+
175
+ Authorized options for the `:iso_lang` type: `[:version]`
176
+
177
+ Here is an example with all possible options for `:iso_lang` type:
178
+
179
+ ```ruby
180
+ class MyValidator < Saphyr::Validator
181
+ field :lang1, :iso_lang # Default : ISO-639-1
182
+ field :lang2, :iso_lang, version: 1
183
+ field :lang3, :iso_lang, version: 2
184
+ end
185
+ ```
186
+
187
+ - `:version = 1` : Mean ISO-639-1
188
+ - `:version = 2` : Mean ISO-639-2
189
+
190
+ ## DateTime
191
+
192
+ Authorized options for the `:datetime` type: `[:format]`
193
+
194
+ Here is an example with all possible options for `:format` type:
195
+
196
+ ```ruby
197
+ class MyValidator < Saphyr::Validator
198
+ field :datetime1, :datetime # Any valid format
199
+ field :datetime2, :datetime, format: '%d/%m/%Y %H:%M:%S'
97
200
  end
98
201
  ```
99
202
 
@@ -127,7 +230,7 @@ class MyValidator < Saphyr::Validator
127
230
  # | |
128
231
  # Size of array must be: 1 >= s <= 10 |
129
232
  # |
130
- # This 'opts' are for the element of array, ie: 'string'
233
+ # This 'opts' are for the elements of the array, ie: 'string' type
131
234
  end
132
235
  ```
133
236
 
@@ -147,7 +250,7 @@ data = {
147
250
  class MyValidator < Saphyr::Validator
148
251
  schema :tag do
149
252
  field :id, :integer, gt: 0
150
- field :label, :string, min: 5, max: 30
253
+ field :label, :string, min: 2, max: 30
151
254
  end
152
255
 
153
256
  field :code, :string, min: 5, max: 10
@@ -0,0 +1,47 @@
1
+ # How To Define a Field Type
2
+
3
+ It's possible to define your own custom type.
4
+
5
+ You can take inspiration from `lib/saphyr/fields/*_field.rb`.
6
+
7
+ Here is an example:
8
+
9
+ ## Define custom B62 field
10
+
11
+ ```ruby
12
+ class B62Field < Saphyr::Fields::FieldBase
13
+ PREFIX = 'b62'
14
+ EXPECTED_TYPES = String
15
+ AUTHORIZED_OPTIONS = [:len, :min, :max]
16
+
17
+ EXCLUSIVE_OPTIONS = [
18
+ [ :len, [:min, :max] ], # It mean if you use 'len' then you
19
+ ] # you can't use 'min' or 'max' and vice versa
20
+
21
+ private
22
+
23
+ def do_validate(ctx, name, value, errors)
24
+ assert_size_len @opts[:len], value, errors
25
+ assert_size_min @opts[:min], value, errors
26
+ assert_size_max @opts[:max], value, errors
27
+ assert_string_regexp /^[a-zA-Z0-9]+$/, value, errors, ERR_BAD_FORMAT
28
+ end
29
+ end
30
+ ```
31
+
32
+ ## Register the custom type
33
+
34
+ ```ruby
35
+ Saphyr.register do
36
+ field_type :b62, B62Field
37
+ end
38
+ ```
39
+
40
+ ## Use the custom type in a validator
41
+
42
+ ```ruby
43
+ class ItemValidator < Saphyr::Validator
44
+ field :id, :integer, gte: 1
45
+ field :uuid, :b62, min: 10, max: 100
46
+ end
47
+ ```
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saphyr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2.beta
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - odelbos
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-06 00:00:00.000000000 Z
11
+ date: 2025-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -50,6 +50,7 @@ extra_rdoc_files:
50
50
  - rdoc/01_Define_Schema.md
51
51
  - rdoc/02_Field_Types.md
52
52
  - rdoc/03_Strict_Mode.md
53
+ - rdoc/04_Define_Custom_Field_Type.md
53
54
  files:
54
55
  - CHANGELOG
55
56
  - LICENSE
@@ -63,12 +64,20 @@ files:
63
64
  - lib/saphyr/engine.rb
64
65
  - lib/saphyr/fields.rb
65
66
  - lib/saphyr/fields/array_field.rb
67
+ - lib/saphyr/fields/b64_field.rb
66
68
  - lib/saphyr/fields/boolean_field.rb
69
+ - lib/saphyr/fields/datetime_field.rb
70
+ - lib/saphyr/fields/email_field.rb
67
71
  - lib/saphyr/fields/field_base.rb
68
72
  - lib/saphyr/fields/float_field.rb
69
73
  - lib/saphyr/fields/integer_field.rb
74
+ - lib/saphyr/fields/ip_field.rb
75
+ - lib/saphyr/fields/iso_country_field.rb
76
+ - lib/saphyr/fields/iso_lang_field.rb
70
77
  - lib/saphyr/fields/schema_field.rb
71
78
  - lib/saphyr/fields/string_field.rb
79
+ - lib/saphyr/fields/uri_field.rb
80
+ - lib/saphyr/fields/url_field.rb
72
81
  - lib/saphyr/helpers.rb
73
82
  - lib/saphyr/helpers/format.rb
74
83
  - lib/saphyr/schema.rb
@@ -77,6 +86,7 @@ files:
77
86
  - rdoc/01_Define_Schema.md
78
87
  - rdoc/02_Field_Types.md
79
88
  - rdoc/03_Strict_Mode.md
89
+ - rdoc/04_Define_Custom_Field_Type.md
80
90
  homepage: https://github.com/odelbos/saphyr
81
91
  licenses:
82
92
  - MIT
@@ -91,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
101
  requirements:
92
102
  - - ">="
93
103
  - !ruby/object:Gem::Version
94
- version: 2.6.0
104
+ version: 2.7.0
95
105
  required_rubygems_version: !ruby/object:Gem::Requirement
96
106
  requirements:
97
107
  - - ">="