lite-command 2.1.3 → 3.0.1
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 +4 -4
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile.lock +20 -17
- data/README.md +191 -174
- data/lib/generators/lite/command/install_generator.rb +15 -0
- data/lib/generators/lite/command/templates/install.rb +5 -0
- data/lib/lite/command/base.rb +20 -17
- data/lib/lite/command/configuration.rb +35 -0
- data/lib/lite/command/fault.rb +21 -8
- data/lib/lite/command/internals/attributes.rb +64 -0
- data/lib/lite/command/internals/{call.rb → calls.rb} +8 -4
- data/lib/lite/command/internals/{execute.rb → executions.rb} +11 -10
- data/lib/lite/command/internals/{fault.rb → faults.rb} +12 -6
- data/lib/lite/command/internals/{result.rb → results.rb} +1 -1
- data/lib/lite/command/sequence.rb +1 -1
- data/lib/lite/command/step.rb +1 -7
- data/lib/lite/command/utils.rb +11 -5
- data/lib/lite/command/version.rb +1 -1
- data/lib/lite/command.rb +10 -8
- data/lite-command.gemspec +1 -0
- metadata +24 -9
- data/lib/lite/command/attribute.rb +0 -102
- data/lib/lite/command/attribute_validator.rb +0 -35
- data/lib/lite/command/internals/context.rb +0 -46
data/lib/lite/command/base.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_model" unless defined?(ActiveModel)
|
4
|
+
|
3
5
|
module Lite
|
4
6
|
module Command
|
5
7
|
class Base
|
@@ -7,22 +9,23 @@ module Lite
|
|
7
9
|
def self.inherited(base)
|
8
10
|
super
|
9
11
|
|
10
|
-
base.include
|
11
|
-
|
12
|
-
base.include Lite::Command::Internals::
|
13
|
-
base.include Lite::Command::Internals::
|
14
|
-
base.include Lite::Command::Internals::
|
15
|
-
|
16
|
-
base.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
12
|
+
base.include ActiveModel::Validations
|
13
|
+
|
14
|
+
base.include Lite::Command::Internals::Attributes
|
15
|
+
base.include Lite::Command::Internals::Calls
|
16
|
+
base.include Lite::Command::Internals::Executions
|
17
|
+
base.include Lite::Command::Internals::Faults
|
18
|
+
base.include Lite::Command::Internals::Results
|
19
|
+
|
20
|
+
if Lite::Command.configuration.raise_dynamic_faults # rubocop:disable Style/GuardClause
|
21
|
+
base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
22
|
+
#{base}::Fault = Class.new(Lite::Command::Fault)
|
23
|
+
#{base}::Noop = Class.new(#{base}::Fault)
|
24
|
+
#{base}::Invalid = Class.new(#{base}::Fault)
|
25
|
+
#{base}::Failure = Class.new(#{base}::Fault)
|
26
|
+
#{base}::Error = Class.new(#{base}::Fault)
|
27
|
+
RUBY
|
28
|
+
end
|
26
29
|
end
|
27
30
|
|
28
31
|
attr_reader :context
|
@@ -30,7 +33,7 @@ module Lite
|
|
30
33
|
|
31
34
|
def initialize(context = {})
|
32
35
|
@context = Lite::Command::Context.build(context)
|
33
|
-
Utils.
|
36
|
+
Utils.try(self, :on_pending)
|
34
37
|
end
|
35
38
|
|
36
39
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Command
|
5
|
+
|
6
|
+
class Configuration
|
7
|
+
|
8
|
+
attr_accessor :raise_dynamic_faults
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@raise_dynamic_faults = false
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
|
18
|
+
attr_writer :configuration
|
19
|
+
|
20
|
+
def configuration
|
21
|
+
@configuration ||= Configuration.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def configure
|
25
|
+
yield(configuration)
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset_configuration!
|
29
|
+
@configuration = Configuration.new
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
data/lib/lite/command/fault.rb
CHANGED
@@ -5,7 +5,7 @@ module Lite
|
|
5
5
|
|
6
6
|
class Fault < StandardError
|
7
7
|
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :reason, :metadata, :caused_by, :thrown_by
|
9
9
|
|
10
10
|
def initialize(**params)
|
11
11
|
@reason = params.fetch(:reason)
|
@@ -16,23 +16,36 @@ module Lite
|
|
16
16
|
super(reason)
|
17
17
|
end
|
18
18
|
|
19
|
-
def self.build(type,
|
20
|
-
klass = dynamic ?
|
19
|
+
def self.build(type, catcher, thrower, dynamic: false)
|
20
|
+
klass = dynamic ? catcher.class : Lite::Command
|
21
21
|
fault = klass.const_get(type.to_s)
|
22
22
|
fault = fault.new(
|
23
|
-
reason:
|
24
|
-
metadata:
|
25
|
-
caused_by:
|
26
|
-
thrown_by:
|
23
|
+
reason: catcher.reason,
|
24
|
+
metadata: catcher.metadata,
|
25
|
+
caused_by: catcher.caused_by,
|
26
|
+
thrown_by: catcher.thrown_by
|
27
27
|
)
|
28
|
-
fault.set_backtrace(
|
28
|
+
fault.set_backtrace(thrower.backtrace) if thrower.respond_to?(:backtrace)
|
29
29
|
fault
|
30
30
|
end
|
31
31
|
|
32
|
+
def self.===(item)
|
33
|
+
klass0 = respond_to?(:new) ? self : self.class
|
34
|
+
klass1 = item.respond_to?(:new) ? item : item.class
|
35
|
+
return true if klass0 == klass1
|
36
|
+
|
37
|
+
klass0.ancestors.include?(klass1) || klass1.ancestors.include?(klass0)
|
38
|
+
end
|
39
|
+
|
32
40
|
def type
|
33
41
|
@type ||= self.class.name.split("::").last.downcase
|
34
42
|
end
|
35
43
|
|
44
|
+
def ===(item)
|
45
|
+
klass = item.respond_to?(:new) ? item : item.class
|
46
|
+
is_a?(klass)
|
47
|
+
end
|
48
|
+
|
36
49
|
end
|
37
50
|
|
38
51
|
class Noop < Fault; end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lite
|
4
|
+
module Command
|
5
|
+
module Internals
|
6
|
+
module Attributes
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.extend ClassMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
|
14
|
+
def required(*attributes, from: :context, **options)
|
15
|
+
delegate(*attributes, from:)
|
16
|
+
|
17
|
+
validates_each(*attributes, **options) do |command, method_name, _attr_value|
|
18
|
+
next unless Utils.evaluate(command, options)
|
19
|
+
next if command.errors.added?(from, :undefined) || command.errors.added?(method_name, :required)
|
20
|
+
|
21
|
+
if !command.respond_to?(from, true)
|
22
|
+
command.errors.add(from, :undefined, message: "is an undefined argument")
|
23
|
+
elsif !command.send(from).respond_to?(method_name, true)
|
24
|
+
command.errors.add(method_name, :required, message: "is a required argument")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def optional(*attributes, from: :context, **_options)
|
30
|
+
delegate(*attributes, from:)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def delegate(*attributes, from: :context)
|
36
|
+
attributes.each do |method_name|
|
37
|
+
define_method(method_name) do
|
38
|
+
return unless respond_to?(from)
|
39
|
+
|
40
|
+
Utils.try(send(from), method_name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def read_attribute_for_validation(method_name)
|
48
|
+
Utils.try(self, method_name)
|
49
|
+
rescue NameError
|
50
|
+
# Do nothing, fallback to :undefined error
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def validate_context_attributes
|
56
|
+
return if errors.empty?
|
57
|
+
|
58
|
+
invalid!(errors.full_messages.join(". "), errors.messages)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -13,25 +13,25 @@ module Lite
|
|
13
13
|
FAULTS = (STATUSES - [SUCCESS]).freeze
|
14
14
|
|
15
15
|
module Internals
|
16
|
-
module
|
16
|
+
module Calls
|
17
17
|
|
18
18
|
def self.included(base)
|
19
19
|
base.extend ClassMethods
|
20
|
-
base.class_eval
|
21
|
-
attr_reader :reason, :metadata
|
22
|
-
end
|
20
|
+
base.class_eval { attr_reader :reason, :metadata }
|
23
21
|
end
|
24
22
|
|
25
23
|
module ClassMethods
|
26
24
|
|
27
25
|
def call(context = {})
|
28
26
|
instance = send(:new, context)
|
27
|
+
instance.validate
|
29
28
|
instance.send(:execute)
|
30
29
|
instance
|
31
30
|
end
|
32
31
|
|
33
32
|
def call!(context = {})
|
34
33
|
instance = send(:new, context)
|
34
|
+
instance.validate
|
35
35
|
instance.send(:execute!)
|
36
36
|
instance
|
37
37
|
end
|
@@ -58,6 +58,10 @@ module Lite
|
|
58
58
|
!success? && reason?(reason)
|
59
59
|
end
|
60
60
|
|
61
|
+
def bad?(reason = nil)
|
62
|
+
![SUCCESS, NOOP].include?(status) && reason?(reason)
|
63
|
+
end
|
64
|
+
|
61
65
|
FAULTS.each do |f|
|
62
66
|
# eg: noop? or failure?("idk")
|
63
67
|
define_method(:"#{f}?") do |reason = nil|
|
@@ -11,7 +11,7 @@ module Lite
|
|
11
11
|
].freeze
|
12
12
|
|
13
13
|
module Internals
|
14
|
-
module
|
14
|
+
module Executions
|
15
15
|
|
16
16
|
def state
|
17
17
|
@state || PENDING
|
@@ -35,15 +35,16 @@ module Lite
|
|
35
35
|
increment_execution_index
|
36
36
|
assign_execution_cmd_id
|
37
37
|
start_monotonic_time
|
38
|
-
Utils.
|
38
|
+
Utils.try(self, :on_before_validation)
|
39
39
|
validate_context_attributes
|
40
|
+
Utils.try(self, :on_before_execution)
|
40
41
|
executing!
|
41
|
-
Utils.
|
42
|
+
Utils.try(self, :on_executing)
|
42
43
|
end
|
43
44
|
|
44
45
|
def after_execution
|
45
46
|
send(:"#{success? ? COMPLETE : INTERRUPTED}!")
|
46
|
-
Utils.
|
47
|
+
Utils.try(self, :on_after_execution)
|
47
48
|
stop_monotonic_time
|
48
49
|
append_execution_result
|
49
50
|
freeze_execution_objects
|
@@ -57,25 +58,25 @@ module Lite
|
|
57
58
|
|
58
59
|
def execute
|
59
60
|
around_execution { call }
|
60
|
-
Utils.
|
61
|
+
Utils.try(self, :on_success)
|
61
62
|
rescue StandardError => e
|
62
63
|
fault(e, ERROR, metadata) unless e.is_a?(Lite::Command::Fault)
|
63
64
|
after_execution
|
64
|
-
Utils.
|
65
|
+
Utils.try(self, :"on_#{status}", e)
|
65
66
|
ensure
|
66
|
-
Utils.
|
67
|
+
Utils.try(self, :"on_#{state}")
|
67
68
|
end
|
68
69
|
|
69
70
|
def execute!
|
70
71
|
around_execution { call }
|
71
|
-
Utils.
|
72
|
+
Utils.try(self, :on_success)
|
72
73
|
rescue StandardError => e
|
73
74
|
fault(e, ERROR, metadata) unless e.is_a?(Lite::Command::Fault)
|
74
75
|
after_execution
|
75
|
-
Utils.
|
76
|
+
Utils.try(self, :"on_#{status}", e)
|
76
77
|
raise(e)
|
77
78
|
else
|
78
|
-
Utils.
|
79
|
+
Utils.try(self, :"on_#{state}")
|
79
80
|
end
|
80
81
|
|
81
82
|
end
|
@@ -3,18 +3,24 @@
|
|
3
3
|
module Lite
|
4
4
|
module Command
|
5
5
|
module Internals
|
6
|
-
module
|
6
|
+
module Faults
|
7
7
|
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
def caused_by
|
9
|
+
return if success?
|
10
|
+
|
11
|
+
@caused_by || self
|
12
12
|
end
|
13
13
|
|
14
14
|
def caused_fault?
|
15
15
|
caused_by == self
|
16
16
|
end
|
17
17
|
|
18
|
+
def thrown_by
|
19
|
+
return if success?
|
20
|
+
|
21
|
+
@thrown_by || self
|
22
|
+
end
|
23
|
+
|
18
24
|
def threw_fault?
|
19
25
|
thrown_by == self
|
20
26
|
end
|
@@ -32,7 +38,7 @@ module Lite
|
|
32
38
|
end
|
33
39
|
|
34
40
|
def raise_dynamic_faults?
|
35
|
-
|
41
|
+
Lite::Command.configuration.raise_dynamic_faults
|
36
42
|
end
|
37
43
|
|
38
44
|
end
|
data/lib/lite/command/step.rb
CHANGED
data/lib/lite/command/utils.rb
CHANGED
@@ -6,16 +6,12 @@ module Lite
|
|
6
6
|
|
7
7
|
module_function
|
8
8
|
|
9
|
-
def try(object, method_name, *args, include_private:
|
9
|
+
def try(object, method_name, *args, include_private: true)
|
10
10
|
return unless object.respond_to?(method_name, include_private)
|
11
11
|
|
12
12
|
object.send(method_name, *args)
|
13
13
|
end
|
14
14
|
|
15
|
-
def hook(object, method_name, *args)
|
16
|
-
try(object, method_name, *args, include_private: true)
|
17
|
-
end
|
18
|
-
|
19
15
|
def call(object, argument)
|
20
16
|
if argument.is_a?(Symbol) || argument.is_a?(String)
|
21
17
|
object.send(argument)
|
@@ -26,6 +22,16 @@ module Lite
|
|
26
22
|
end
|
27
23
|
end
|
28
24
|
|
25
|
+
def evaluate(object, options = {})
|
26
|
+
if options[:if]
|
27
|
+
call(object, options[:if])
|
28
|
+
elsif options[:unless]
|
29
|
+
!call(object, options[:unless])
|
30
|
+
else
|
31
|
+
options.fetch(:default, true)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
29
35
|
end
|
30
36
|
end
|
31
37
|
end
|
data/lib/lite/command/version.rb
CHANGED
data/lib/lite/command.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
if defined?(Rails::Generators)
|
4
|
+
require "generators/lite/command/install_generator"
|
5
|
+
require "generators/rails/command_generator"
|
6
|
+
end
|
4
7
|
|
5
8
|
require "lite/command/version"
|
9
|
+
require "lite/command/configuration"
|
6
10
|
require "lite/command/utils"
|
7
11
|
require "lite/command/context"
|
8
|
-
require "lite/command/attribute"
|
9
|
-
require "lite/command/attribute_validator"
|
10
12
|
require "lite/command/fault"
|
11
13
|
require "lite/command/fault_streamer"
|
12
|
-
require "lite/command/internals/
|
13
|
-
require "lite/command/internals/
|
14
|
-
require "lite/command/internals/
|
15
|
-
require "lite/command/internals/
|
16
|
-
require "lite/command/internals/
|
14
|
+
require "lite/command/internals/attributes"
|
15
|
+
require "lite/command/internals/calls"
|
16
|
+
require "lite/command/internals/executions"
|
17
|
+
require "lite/command/internals/faults"
|
18
|
+
require "lite/command/internals/results"
|
17
19
|
require "lite/command/base"
|
18
20
|
require "lite/command/step"
|
19
21
|
require "lite/command/sequence"
|
data/lite-command.gemspec
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lite-command
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Juan Gomez
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-10-
|
11
|
+
date: 2024-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activemodel
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: ostruct
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -172,21 +186,22 @@ files:
|
|
172
186
|
- _config.yml
|
173
187
|
- bin/console
|
174
188
|
- bin/setup
|
189
|
+
- lib/generators/lite/command/install_generator.rb
|
190
|
+
- lib/generators/lite/command/templates/install.rb
|
175
191
|
- lib/generators/rails/USAGE
|
176
192
|
- lib/generators/rails/command_generator.rb
|
177
193
|
- lib/generators/rails/templates/command.rb.tt
|
178
194
|
- lib/lite/command.rb
|
179
|
-
- lib/lite/command/attribute.rb
|
180
|
-
- lib/lite/command/attribute_validator.rb
|
181
195
|
- lib/lite/command/base.rb
|
196
|
+
- lib/lite/command/configuration.rb
|
182
197
|
- lib/lite/command/context.rb
|
183
198
|
- lib/lite/command/fault.rb
|
184
199
|
- lib/lite/command/fault_streamer.rb
|
185
|
-
- lib/lite/command/internals/
|
186
|
-
- lib/lite/command/internals/
|
187
|
-
- lib/lite/command/internals/
|
188
|
-
- lib/lite/command/internals/
|
189
|
-
- lib/lite/command/internals/
|
200
|
+
- lib/lite/command/internals/attributes.rb
|
201
|
+
- lib/lite/command/internals/calls.rb
|
202
|
+
- lib/lite/command/internals/executions.rb
|
203
|
+
- lib/lite/command/internals/faults.rb
|
204
|
+
- lib/lite/command/internals/results.rb
|
190
205
|
- lib/lite/command/sequence.rb
|
191
206
|
- lib/lite/command/step.rb
|
192
207
|
- lib/lite/command/utils.rb
|
@@ -1,102 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Lite
|
4
|
-
module Command
|
5
|
-
class Attribute
|
6
|
-
|
7
|
-
attr_accessor :command
|
8
|
-
attr_reader :method_name, :options, :errors
|
9
|
-
|
10
|
-
def initialize(method_name, options)
|
11
|
-
@method_name = method_name
|
12
|
-
@options = options
|
13
|
-
@errors = []
|
14
|
-
end
|
15
|
-
|
16
|
-
def from
|
17
|
-
options[:from] || :context
|
18
|
-
end
|
19
|
-
|
20
|
-
def filled?
|
21
|
-
Utils.call(command, options[:filled]) || false
|
22
|
-
end
|
23
|
-
|
24
|
-
def required?
|
25
|
-
Utils.call(command, options[:required]) || false
|
26
|
-
end
|
27
|
-
|
28
|
-
def typed?
|
29
|
-
options.key?(:types) && types.any?
|
30
|
-
end
|
31
|
-
|
32
|
-
def types
|
33
|
-
@types ||= begin
|
34
|
-
t = Array(Utils.call(command, options[:types]))
|
35
|
-
|
36
|
-
if filled?
|
37
|
-
t.uniq - [NilClass]
|
38
|
-
else
|
39
|
-
t | [NilClass]
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def validate!
|
45
|
-
validate_respond_attribute!
|
46
|
-
return unless errors.empty?
|
47
|
-
|
48
|
-
validate_required_attribute!
|
49
|
-
validate_attribute_type!
|
50
|
-
validate_attribute_filled!
|
51
|
-
end
|
52
|
-
|
53
|
-
def valid?
|
54
|
-
errors.empty?
|
55
|
-
end
|
56
|
-
|
57
|
-
def value
|
58
|
-
return @value if defined?(@value)
|
59
|
-
|
60
|
-
@value = command.send(from).public_send(method_name)
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def validate_respond_attribute!
|
66
|
-
return if command.respond_to?(from, true)
|
67
|
-
|
68
|
-
@errors << "is not defined or an attribute"
|
69
|
-
end
|
70
|
-
|
71
|
-
def validate_required_attribute!
|
72
|
-
return unless required?
|
73
|
-
return if command.send(from).respond_to?(method_name)
|
74
|
-
|
75
|
-
@errors << "#{method_name} is required"
|
76
|
-
end
|
77
|
-
|
78
|
-
def validate_attribute_type!
|
79
|
-
return unless typed?
|
80
|
-
return if types.include?(value.class)
|
81
|
-
|
82
|
-
@errors << "#{method_name} type invalid"
|
83
|
-
end
|
84
|
-
|
85
|
-
def empty?
|
86
|
-
r = Utils.try(options[:filled], :[], :empty)
|
87
|
-
return false if r.nil? || r == true
|
88
|
-
return false unless value.respond_to?(:empty?)
|
89
|
-
|
90
|
-
value.empty?
|
91
|
-
end
|
92
|
-
|
93
|
-
def validate_attribute_filled!
|
94
|
-
return unless filled?
|
95
|
-
return unless value.nil? || empty?
|
96
|
-
|
97
|
-
@errors << "#{method_name} must be filled"
|
98
|
-
end
|
99
|
-
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Lite
|
4
|
-
module Command
|
5
|
-
class AttributeValidator
|
6
|
-
|
7
|
-
attr_reader :command
|
8
|
-
|
9
|
-
def initialize(command)
|
10
|
-
@command = command
|
11
|
-
end
|
12
|
-
|
13
|
-
def attributes
|
14
|
-
@attributes ||=
|
15
|
-
command.class.attributes.map do |_method_name, attribute|
|
16
|
-
attribute.tap { |a| a.command = command }
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def errors
|
21
|
-
@errors ||= attributes.each_with_object({}) do |attribute, h|
|
22
|
-
next if attribute.tap(&:validate!).valid?
|
23
|
-
|
24
|
-
h[attribute.from] ||= []
|
25
|
-
h[attribute.from] = h[attribute.from] | attribute.errors
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def valid?
|
30
|
-
attributes.empty? || errors.empty?
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|