cmdx 0.1.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 +7 -0
- data/.DS_Store +0 -0
- data/.rspec +4 -0
- data/.rubocop.yml +64 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +76 -0
- data/Rakefile +12 -0
- data/docs/basics/call.md +31 -0
- data/docs/basics/context.md +67 -0
- data/docs/basics/run.md +34 -0
- data/docs/basics/setup.md +32 -0
- data/docs/batch.md +53 -0
- data/docs/configuration.md +57 -0
- data/docs/example.md +82 -0
- data/docs/getting_started.md +47 -0
- data/docs/hooks.md +59 -0
- data/docs/interruptions/exceptions.md +29 -0
- data/docs/interruptions/faults.md +89 -0
- data/docs/interruptions/halt.md +80 -0
- data/docs/logging.md +102 -0
- data/docs/outcomes/result.md +17 -0
- data/docs/outcomes/states.md +31 -0
- data/docs/outcomes/statuses.md +33 -0
- data/docs/parameters/coercions.md +52 -0
- data/docs/parameters/defaults.md +47 -0
- data/docs/parameters/definitions.md +123 -0
- data/docs/parameters/namespacing.md +57 -0
- data/docs/parameters/validations.md +312 -0
- data/docs/tips_and_tricks.md +79 -0
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/batch.rb +43 -0
- data/lib/cmdx/coercions/array.rb +15 -0
- data/lib/cmdx/coercions/big_decimal.rb +23 -0
- data/lib/cmdx/coercions/boolean.rb +27 -0
- data/lib/cmdx/coercions/complex.rb +21 -0
- data/lib/cmdx/coercions/date.rb +26 -0
- data/lib/cmdx/coercions/date_time.rb +26 -0
- data/lib/cmdx/coercions/float.rb +21 -0
- data/lib/cmdx/coercions/hash.rb +31 -0
- data/lib/cmdx/coercions/integer.rb +21 -0
- data/lib/cmdx/coercions/rational.rb +21 -0
- data/lib/cmdx/coercions/string.rb +15 -0
- data/lib/cmdx/coercions/time.rb +26 -0
- data/lib/cmdx/coercions/virtual.rb +15 -0
- data/lib/cmdx/configuration.rb +25 -0
- data/lib/cmdx/context.rb +15 -0
- data/lib/cmdx/core_ext/hash.rb +36 -0
- data/lib/cmdx/core_ext/module.rb +48 -0
- data/lib/cmdx/core_ext/object.rb +55 -0
- data/lib/cmdx/error.rb +23 -0
- data/lib/cmdx/errors.rb +92 -0
- data/lib/cmdx/fault.rb +47 -0
- data/lib/cmdx/faults.rb +11 -0
- data/lib/cmdx/immutator.rb +21 -0
- data/lib/cmdx/lazy_struct.rb +79 -0
- data/lib/cmdx/log_formatters/json.rb +13 -0
- data/lib/cmdx/log_formatters/key_value.rb +13 -0
- data/lib/cmdx/log_formatters/line.rb +14 -0
- data/lib/cmdx/log_formatters/logstash.rb +18 -0
- data/lib/cmdx/log_formatters/raw.rb +13 -0
- data/lib/cmdx/logger.rb +16 -0
- data/lib/cmdx/parameter.rb +101 -0
- data/lib/cmdx/parameter_inspector.rb +23 -0
- data/lib/cmdx/parameter_serializer.rb +20 -0
- data/lib/cmdx/parameter_validator.rb +19 -0
- data/lib/cmdx/parameter_value.rb +136 -0
- data/lib/cmdx/parameters.rb +34 -0
- data/lib/cmdx/parameters_inspector.rb +13 -0
- data/lib/cmdx/parameters_serializer.rb +13 -0
- data/lib/cmdx/railtie.rb +32 -0
- data/lib/cmdx/result.rb +170 -0
- data/lib/cmdx/result_inspector.rb +31 -0
- data/lib/cmdx/result_logger.rb +22 -0
- data/lib/cmdx/result_serializer.rb +38 -0
- data/lib/cmdx/run.rb +33 -0
- data/lib/cmdx/run_inspector.rb +21 -0
- data/lib/cmdx/run_serializer.rb +16 -0
- data/lib/cmdx/task.rb +151 -0
- data/lib/cmdx/task_hook.rb +18 -0
- data/lib/cmdx/utils/datetime_formatter.rb +17 -0
- data/lib/cmdx/utils/method_name.rb +24 -0
- data/lib/cmdx/utils/runtime.rb +19 -0
- data/lib/cmdx/validators/custom.rb +20 -0
- data/lib/cmdx/validators/exclusion.rb +51 -0
- data/lib/cmdx/validators/format.rb +27 -0
- data/lib/cmdx/validators/inclusion.rb +51 -0
- data/lib/cmdx/validators/length.rb +114 -0
- data/lib/cmdx/validators/numeric.rb +114 -0
- data/lib/cmdx/validators/presence.rb +27 -0
- data/lib/cmdx/version.rb +7 -0
- data/lib/cmdx.rb +80 -0
- data/lib/generators/cmdx/batch_generator.rb +30 -0
- data/lib/generators/cmdx/install_generator.rb +15 -0
- data/lib/generators/cmdx/task_generator.rb +30 -0
- data/lib/generators/cmdx/templates/batch.rb.tt +7 -0
- data/lib/generators/cmdx/templates/install.rb +23 -0
- data/lib/generators/cmdx/templates/task.rb.tt +9 -0
- data/lib/locales/en.yml +36 -0
- data/lib/locales/es.yml +36 -0
- metadata +288 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
module ResultSerializer
|
5
|
+
|
6
|
+
STRIP_FAILURE = proc do |h, r, k|
|
7
|
+
unless r.send(:"#{k}?")
|
8
|
+
# Strip caused/threw failures since its the same info as the log line
|
9
|
+
h[k] = r.send(k).to_h.except(:caused_failure, :threw_failure)
|
10
|
+
end
|
11
|
+
end.freeze
|
12
|
+
|
13
|
+
module_function
|
14
|
+
|
15
|
+
def call(result)
|
16
|
+
{
|
17
|
+
index: result.index,
|
18
|
+
run_id: result.run.id,
|
19
|
+
type: result.task.is_a?(Batch) ? "Batch" : "Task",
|
20
|
+
class: result.task.class.name,
|
21
|
+
id: result.task.id,
|
22
|
+
state: result.state,
|
23
|
+
status: result.status,
|
24
|
+
outcome: result.outcome,
|
25
|
+
metadata: result.metadata,
|
26
|
+
runtime: result.runtime,
|
27
|
+
tags: result.task.task_setting(:tags),
|
28
|
+
pid: Process.pid
|
29
|
+
}.tap do |hash|
|
30
|
+
if result.failed?
|
31
|
+
STRIP_FAILURE.call(hash, result, :caused_failure)
|
32
|
+
STRIP_FAILURE.call(hash, result, :threw_failure)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/cmdx/run.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
class Run
|
5
|
+
|
6
|
+
__cmdx_attr_delegator :index, to: :results
|
7
|
+
__cmdx_attr_delegator :state, :status, :outcome, :runtime, to: :first_result
|
8
|
+
|
9
|
+
attr_reader :id, :results
|
10
|
+
|
11
|
+
def initialize(attributes = {})
|
12
|
+
@id = attributes[:id] || SecureRandom.uuid
|
13
|
+
@results = Array(attributes[:results])
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_h
|
17
|
+
RunSerializer.call(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
RunInspector.call(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def first_result
|
27
|
+
return @first_result if defined?(@first_result)
|
28
|
+
|
29
|
+
@first_result = @results.first
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
module RunInspector
|
5
|
+
|
6
|
+
ORDERED_KEYS = %i[
|
7
|
+
state status outcome runtime
|
8
|
+
].freeze
|
9
|
+
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def call(run)
|
13
|
+
header = "Run: #{run.id}"
|
14
|
+
footer = ORDERED_KEYS.map { |key| "#{key}=#{run.send(key)}" }.join(" ")
|
15
|
+
spacer = "=" * [header.size, footer.size].max
|
16
|
+
|
17
|
+
run.results.map(&:to_s).unshift(header, spacer).push(spacer, footer).join("\n")
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/cmdx/task.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
class Task
|
5
|
+
|
6
|
+
HOOKS = [
|
7
|
+
:before_validation,
|
8
|
+
:after_validation,
|
9
|
+
:before_execution,
|
10
|
+
:after_execution,
|
11
|
+
*Result::STATUSES.map { |s| :"on_#{s}" },
|
12
|
+
*Result::STATES.map { |s| :"on_#{s}" }
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
__cmdx_attr_setting :task_settings, default: -> { CMDx.configuration.to_h.merge(tags: []) }
|
16
|
+
__cmdx_attr_setting :cmd_parameters, default: -> { Parameters.new }
|
17
|
+
__cmdx_attr_setting :cmd_hooks, default: {}
|
18
|
+
|
19
|
+
__cmdx_attr_delegator :task_setting, :task_setting?, to: :class
|
20
|
+
__cmdx_attr_delegator :skip!, :fail!, :throw!, to: :result
|
21
|
+
|
22
|
+
attr_reader :id, :errors, :context, :result, :run
|
23
|
+
alias ctx context
|
24
|
+
alias res result
|
25
|
+
|
26
|
+
private_class_method :new
|
27
|
+
|
28
|
+
def initialize(context = {})
|
29
|
+
@id = SecureRandom.uuid
|
30
|
+
@errors = Errors.new
|
31
|
+
@context = Context.build(context)
|
32
|
+
@run = @context.run || begin
|
33
|
+
run = Run.new(@context.delete!(:run).to_h)
|
34
|
+
@context.instance_variable_set(:@run, run)
|
35
|
+
end
|
36
|
+
@run.results << @result = Result.new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
|
41
|
+
HOOKS.each do |hook|
|
42
|
+
define_method(hook) do |*callables, **options, &block|
|
43
|
+
callables << block if block_given?
|
44
|
+
(cmd_hooks[hook] ||= []).push([callables, options]).uniq!
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def task_setting(key)
|
49
|
+
__cmdx_yield(task_settings[key])
|
50
|
+
end
|
51
|
+
|
52
|
+
def task_setting?(key)
|
53
|
+
task_settings.key?(key)
|
54
|
+
end
|
55
|
+
|
56
|
+
def task_settings!(**options)
|
57
|
+
task_settings.merge!(options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def optional(*attributes, **options, &)
|
61
|
+
parameters = Parameter.optional(*attributes, **options.merge(klass: self), &)
|
62
|
+
cmd_parameters.concat(parameters)
|
63
|
+
end
|
64
|
+
|
65
|
+
def required(*attributes, **options, &)
|
66
|
+
parameters = Parameter.required(*attributes, **options.merge(klass: self), &)
|
67
|
+
cmd_parameters.concat(parameters)
|
68
|
+
end
|
69
|
+
|
70
|
+
def call(...)
|
71
|
+
instance = send(:new, ...)
|
72
|
+
instance.send(:execute_call)
|
73
|
+
instance.result
|
74
|
+
end
|
75
|
+
|
76
|
+
def call!(...)
|
77
|
+
instance = send(:new, ...)
|
78
|
+
instance.send(:execute_call!)
|
79
|
+
instance.result
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
def call
|
85
|
+
raise UndefinedCallError, "call method not defined in #{self.class.name}"
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def logger
|
91
|
+
Logger.call(self)
|
92
|
+
end
|
93
|
+
|
94
|
+
def before_call
|
95
|
+
TaskHook.call(self, :before_execution)
|
96
|
+
|
97
|
+
result.executing!
|
98
|
+
TaskHook.call(self, :on_executing)
|
99
|
+
|
100
|
+
TaskHook.call(self, :before_validation)
|
101
|
+
ParameterValidator.call(self)
|
102
|
+
TaskHook.call(self, :after_validation)
|
103
|
+
end
|
104
|
+
|
105
|
+
def after_call
|
106
|
+
result.send(result.success? ? :complete! : :interrupt!)
|
107
|
+
TaskHook.call(self, :"on_#{result.status}")
|
108
|
+
TaskHook.call(self, :"on_#{result.state}")
|
109
|
+
|
110
|
+
TaskHook.call(self, :after_execution)
|
111
|
+
end
|
112
|
+
|
113
|
+
def terminate_call
|
114
|
+
Immutator.call(self)
|
115
|
+
ResultLogger.call(result)
|
116
|
+
end
|
117
|
+
|
118
|
+
def execute_call
|
119
|
+
result.runtime do
|
120
|
+
before_call
|
121
|
+
call
|
122
|
+
rescue UndefinedCallError => e
|
123
|
+
raise(e)
|
124
|
+
rescue StandardError => e
|
125
|
+
result.fail!(reason: "[#{e.class}] #{e.message}", original_exception: e) unless e.is_a?(Fault)
|
126
|
+
ensure
|
127
|
+
after_call
|
128
|
+
end
|
129
|
+
|
130
|
+
terminate_call
|
131
|
+
end
|
132
|
+
|
133
|
+
def execute_call!
|
134
|
+
result.runtime do
|
135
|
+
before_call
|
136
|
+
call
|
137
|
+
rescue UndefinedCallError => e
|
138
|
+
raise(e)
|
139
|
+
rescue Fault => e
|
140
|
+
raise(e) if Array(task_setting(:task_halt)).include?(e.result.status)
|
141
|
+
|
142
|
+
after_call # HACK: treat as NO-OP
|
143
|
+
else
|
144
|
+
after_call # ELSE: treat as success
|
145
|
+
end
|
146
|
+
|
147
|
+
terminate_call
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
module TaskHook
|
5
|
+
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def call(task, hook)
|
9
|
+
Array(task.class.cmd_hooks[hook]).each do |callables, options|
|
10
|
+
next unless task.__cmdx_eval(options)
|
11
|
+
|
12
|
+
hooks = Array(callables)
|
13
|
+
hooks.each { |h| task.__cmdx_try(h) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
module Utils
|
5
|
+
module MethodName
|
6
|
+
|
7
|
+
ROOTFIX = proc do |o, &block|
|
8
|
+
o == true ? block.call : o
|
9
|
+
end.freeze
|
10
|
+
|
11
|
+
module_function
|
12
|
+
|
13
|
+
def call(method_name, source, options = {})
|
14
|
+
options[:as] || begin
|
15
|
+
prefix = ROOTFIX.call(options[:prefix]) { "#{source}_" }
|
16
|
+
suffix = ROOTFIX.call(options[:suffix]) { "_#{source}" }
|
17
|
+
|
18
|
+
"#{prefix}#{method_name}#{suffix}".strip.to_sym
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
module Utils
|
5
|
+
module Runtime
|
6
|
+
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def call(&)
|
10
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
11
|
+
yield
|
12
|
+
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
13
|
+
|
14
|
+
finish - start
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
module Validators
|
5
|
+
module Custom
|
6
|
+
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def call(value, options = {})
|
10
|
+
return if options.dig(:custom, :validator).call(value, options)
|
11
|
+
|
12
|
+
raise ValidationError, options.dig(:custom, :message) || I18n.t(
|
13
|
+
"cmdx.validators.custom",
|
14
|
+
default: "is not valid"
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
module Validators
|
5
|
+
module Exclusion
|
6
|
+
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def call(value, options = {})
|
10
|
+
values = options.dig(:exclusion, :in) ||
|
11
|
+
options.dig(:exclusion, :within)
|
12
|
+
|
13
|
+
if values.is_a?(Range)
|
14
|
+
raise_within_validation_error!(values.begin, values.end, options) if values.cover?(value)
|
15
|
+
elsif Array(values).any? { |v| v === value } # rubocop:disable Style/CaseEquality
|
16
|
+
raise_of_validation_error!(values, options)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def raise_of_validation_error!(values, options)
|
23
|
+
values = values.map(&:inspect).join(", ")
|
24
|
+
message = options.dig(:exclusion, :of_message) ||
|
25
|
+
options.dig(:exclusion, :message)
|
26
|
+
message %= { values: } unless message.nil?
|
27
|
+
|
28
|
+
raise ValidationError, message || I18n.t(
|
29
|
+
"cmdx.validators.exclusion.of",
|
30
|
+
values:,
|
31
|
+
default: "must not be one of: #{values}"
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def raise_within_validation_error!(min, max, options)
|
36
|
+
message = options.dig(:exclusion, :in_message) ||
|
37
|
+
options.dig(:exclusion, :within_message) ||
|
38
|
+
options.dig(:exclusion, :message)
|
39
|
+
message %= { min:, max: } unless message.nil?
|
40
|
+
|
41
|
+
raise ValidationError, message || I18n.t(
|
42
|
+
"cmdx.validators.exclusion.within",
|
43
|
+
min:,
|
44
|
+
max:,
|
45
|
+
default: "must not be within #{min} and #{max}"
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
module Validators
|
5
|
+
module Format
|
6
|
+
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def call(value, options = {})
|
10
|
+
return if case options[:format]
|
11
|
+
in { with: with, without: without }
|
12
|
+
value.match?(with) && !value.match?(without)
|
13
|
+
in { with: with }
|
14
|
+
value.match?(with)
|
15
|
+
in { without: without }
|
16
|
+
!value.match?(without)
|
17
|
+
end
|
18
|
+
|
19
|
+
raise ValidationError, options.dig(:format, :message) || I18n.t(
|
20
|
+
"cmdx.validators.format",
|
21
|
+
default: "is an invalid format"
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
module Validators
|
5
|
+
module Inclusion
|
6
|
+
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def call(value, options = {})
|
10
|
+
values = options.dig(:inclusion, :in) ||
|
11
|
+
options.dig(:inclusion, :within)
|
12
|
+
|
13
|
+
if values.is_a?(Range)
|
14
|
+
raise_within_validation_error!(values.begin, values.end, options) unless values.cover?(value)
|
15
|
+
elsif Array(values).none? { |v| v === value } # rubocop:disable Style/CaseEquality
|
16
|
+
raise_of_validation_error!(values, options)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def raise_of_validation_error!(values, options)
|
23
|
+
values = values.map(&:inspect).join(", ")
|
24
|
+
message = options.dig(:inclusion, :of_message) ||
|
25
|
+
options.dig(:inclusion, :message)
|
26
|
+
message %= { values: } unless message.nil?
|
27
|
+
|
28
|
+
raise ValidationError, message || I18n.t(
|
29
|
+
"cmdx.validators.inclusion.of",
|
30
|
+
values:,
|
31
|
+
default: "must be one of: #{values}"
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def raise_within_validation_error!(min, max, options)
|
36
|
+
message = options.dig(:inclusion, :in_message) ||
|
37
|
+
options.dig(:inclusion, :within_message) ||
|
38
|
+
options.dig(:inclusion, :message)
|
39
|
+
message %= { min:, max: } unless message.nil?
|
40
|
+
|
41
|
+
raise ValidationError, message || I18n.t(
|
42
|
+
"cmdx.validators.inclusion.within",
|
43
|
+
min:,
|
44
|
+
max:,
|
45
|
+
default: "must be within #{min} and #{max}"
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
module Validators
|
5
|
+
module Length
|
6
|
+
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def call(value, options = {})
|
10
|
+
case options[:length]
|
11
|
+
in { within: within }
|
12
|
+
raise_within_validation_error!(within.begin, within.end, options) unless within.cover?(value.length)
|
13
|
+
in { not_within: not_within }
|
14
|
+
raise_not_within_validation_error!(not_within.begin, not_within.end, options) if not_within.cover?(value.length)
|
15
|
+
in { in: yn }
|
16
|
+
raise_within_validation_error!(yn.begin, yn.end, options) unless yn.cover?(value.length)
|
17
|
+
in { not_in: not_in }
|
18
|
+
raise_not_within_validation_error!(not_in.begin, not_in.end, options) if not_in.cover?(value.length)
|
19
|
+
in { min: min, max: max }
|
20
|
+
raise_within_validation_error!(min, max, options) unless value.length.between?(min, max)
|
21
|
+
in { min: min }
|
22
|
+
raise_min_validation_error!(min, options) unless min <= value.length
|
23
|
+
in { max: max }
|
24
|
+
raise_max_validation_error!(max, options) unless value.length <= max
|
25
|
+
in { is: is }
|
26
|
+
raise_is_validation_error!(is, options) unless value.length == is
|
27
|
+
in { is_not: is_not }
|
28
|
+
raise_is_not_validation_error!(is_not, options) if value.length == is_not
|
29
|
+
else
|
30
|
+
raise ArgumentError, "no known length validator options given"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def raise_within_validation_error!(min, max, options)
|
37
|
+
message = options.dig(:length, :within_message) ||
|
38
|
+
options.dig(:length, :in_message) ||
|
39
|
+
options.dig(:length, :message)
|
40
|
+
message %= { min:, max: } unless message.nil?
|
41
|
+
|
42
|
+
raise ValidationError, message || I18n.t(
|
43
|
+
"cmdx.validators.length.within",
|
44
|
+
min:,
|
45
|
+
max:,
|
46
|
+
default: "length must be within #{min} and #{max}"
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def raise_not_within_validation_error!(min, max, options)
|
51
|
+
message = options.dig(:length, :not_within_message) ||
|
52
|
+
options.dig(:length, :not_in_message) ||
|
53
|
+
options.dig(:length, :message)
|
54
|
+
message %= { min:, max: } unless message.nil?
|
55
|
+
|
56
|
+
raise ValidationError, message || I18n.t(
|
57
|
+
"cmdx.validators.length.not_within",
|
58
|
+
min:,
|
59
|
+
max:,
|
60
|
+
default: "length must not be within #{min} and #{max}"
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def raise_min_validation_error!(min, options)
|
65
|
+
message = options.dig(:length, :min_message) ||
|
66
|
+
options.dig(:length, :message)
|
67
|
+
message %= { min: } unless message.nil?
|
68
|
+
|
69
|
+
raise ValidationError, message || I18n.t(
|
70
|
+
"cmdx.validators.length.min",
|
71
|
+
min:,
|
72
|
+
default: "length must be at least #{min}"
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
def raise_max_validation_error!(max, options)
|
77
|
+
message = options.dig(:length, :max_message) ||
|
78
|
+
options.dig(:length, :message)
|
79
|
+
message %= { max: } unless message.nil?
|
80
|
+
|
81
|
+
raise ValidationError, message || I18n.t(
|
82
|
+
"cmdx.validators.length.max",
|
83
|
+
max:,
|
84
|
+
default: "length must be at most #{max}"
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
def raise_is_validation_error!(is, options)
|
89
|
+
message = options.dig(:length, :is_message) ||
|
90
|
+
options.dig(:length, :message)
|
91
|
+
message %= { is: } unless message.nil?
|
92
|
+
|
93
|
+
raise ValidationError, message || I18n.t(
|
94
|
+
"cmdx.validators.length.is",
|
95
|
+
is:,
|
96
|
+
default: "length must be #{is}"
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
100
|
+
def raise_is_not_validation_error!(is_not, options)
|
101
|
+
message = options.dig(:length, :is_not_message) ||
|
102
|
+
options.dig(:length, :message)
|
103
|
+
message %= { is_not: } unless message.nil?
|
104
|
+
|
105
|
+
raise ValidationError, message || I18n.t(
|
106
|
+
"cmdx.validators.length.is_not",
|
107
|
+
is_not:,
|
108
|
+
default: "length must not be #{is_not}"
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|