dev_suite 0.2.7 → 0.2.10
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/.codeclimate.yml +12 -0
- data/.github/workflows/ci.yml +1 -1
- data/.sonarcloud.properties +23 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +17 -33
- data/README.md +216 -0
- data/dev_suite.gemspec +1 -0
- data/examples/helpers/api_helper.rb +51 -0
- data/examples/helpers/data_helper.rb +72 -0
- data/examples/helpers/helpers.rb +4 -0
- data/examples/workflow/basic_workflow.rb +15 -0
- data/examples/workflow/composite_workflow.rb +21 -0
- data/examples/workflow/conditional_workflow.rb +17 -0
- data/examples/workflow/full_workflow.rb +79 -0
- data/examples/workflow/loop_workflow.rb +17 -0
- data/examples/workflow/order_processing_workflow.rb +163 -0
- data/examples/workflow/parallel_workflow.rb +17 -0
- data/lib/dev_suite/dev_suite.rb +3 -0
- data/lib/dev_suite/method_tracer/config/config.rb +11 -0
- data/lib/dev_suite/method_tracer/config/configuration.rb +16 -0
- data/lib/dev_suite/method_tracer/config.rb +9 -0
- data/lib/dev_suite/method_tracer/helpers.rb +41 -0
- data/lib/dev_suite/method_tracer/logger.rb +46 -0
- data/lib/dev_suite/method_tracer/method_tracer.rb +20 -0
- data/lib/dev_suite/method_tracer/tracer.rb +65 -0
- data/lib/dev_suite/method_tracer.rb +7 -0
- data/lib/dev_suite/request_builder/builder/base.rb +27 -0
- data/lib/dev_suite/request_builder/builder/builder.rb +10 -0
- data/lib/dev_suite/request_builder/builder/http.rb +32 -0
- data/lib/dev_suite/request_builder/builder.rb +9 -0
- data/lib/dev_suite/request_builder/config/config.rb +11 -0
- data/lib/dev_suite/request_builder/config/configuration.rb +24 -0
- data/lib/dev_suite/request_builder/config.rb +9 -0
- data/lib/dev_suite/request_builder/formatter/base.rb +13 -0
- data/lib/dev_suite/request_builder/formatter/formatter.rb +10 -0
- data/lib/dev_suite/request_builder/formatter/graphql.rb +19 -0
- data/lib/dev_suite/request_builder/formatter.rb +9 -0
- data/lib/dev_suite/request_builder/request_builder.rb +21 -0
- data/lib/dev_suite/request_builder/tool/base.rb +19 -0
- data/lib/dev_suite/request_builder/tool/curl.rb +91 -0
- data/lib/dev_suite/request_builder/tool/tool.rb +11 -0
- data/lib/dev_suite/request_builder/tool/validator/curl.rb +38 -0
- data/lib/dev_suite/request_builder/tool/validator/validator.rb +11 -0
- data/lib/dev_suite/request_builder/tool/validator.rb +11 -0
- data/lib/dev_suite/request_builder/tool.rb +9 -0
- data/lib/dev_suite/request_builder.rb +7 -0
- data/lib/dev_suite/request_logger/adapter/adapter.rb +11 -9
- data/lib/dev_suite/request_logger/adapter/faraday.rb +12 -1
- data/lib/dev_suite/request_logger/adapter/middleware/faraday.rb +3 -3
- data/lib/dev_suite/request_logger/adapter/net_http.rb +15 -6
- data/lib/dev_suite/request_logger/config/configuration.rb +1 -0
- data/lib/dev_suite/request_logger/extractor/base.rb +8 -2
- data/lib/dev_suite/request_logger/extractor/extractor.rb +5 -6
- data/lib/dev_suite/request_logger/extractor/faraday.rb +32 -14
- data/lib/dev_suite/request_logger/extractor/net_http.rb +53 -12
- data/lib/dev_suite/request_logger/logger.rb +9 -3
- data/lib/dev_suite/request_logger/request.rb +12 -0
- data/lib/dev_suite/request_logger/response.rb +34 -9
- data/lib/dev_suite/utils/construct/component/base.rb +13 -0
- data/lib/dev_suite/utils/construct/component/component.rb +1 -0
- data/lib/dev_suite/utils/construct/component/manager.rb +27 -10
- data/lib/dev_suite/utils/construct/component/validator/base.rb +25 -0
- data/lib/dev_suite/utils/construct/component/validator/validation_error.rb +21 -0
- data/lib/dev_suite/utils/construct/component/validator/validation_rule.rb +68 -0
- data/lib/dev_suite/utils/construct/component/validator/validator.rb +15 -0
- data/lib/dev_suite/utils/construct/component/validator.rb +13 -0
- data/lib/dev_suite/utils/construct/config/dependency_handler.rb +25 -34
- data/lib/dev_suite/utils/construct/config/settings/base.rb +43 -26
- data/lib/dev_suite/utils/data/base_operations.rb +61 -0
- data/lib/dev_suite/utils/data/data.rb +19 -0
- data/lib/dev_suite/utils/data/path_access.rb +172 -0
- data/lib/dev_suite/utils/data/search_filter.rb +60 -0
- data/lib/dev_suite/utils/data/serialization.rb +29 -0
- data/lib/dev_suite/utils/data/transformations.rb +45 -0
- data/lib/dev_suite/utils/data.rb +9 -0
- data/lib/dev_suite/utils/dependency_loader.rb +2 -2
- data/lib/dev_suite/utils/emoji.rb +19 -0
- data/lib/dev_suite/utils/file_loader/file_loader.rb +1 -5
- data/lib/dev_suite/utils/file_loader/loader/json.rb +4 -1
- data/lib/dev_suite/utils/file_loader/loader/loader.rb +23 -19
- data/lib/dev_suite/utils/file_loader/loader.rb +0 -2
- data/lib/dev_suite/utils/file_writer/atomic_writer.rb +53 -0
- data/lib/dev_suite/utils/file_writer/backup_manager.rb +21 -0
- data/lib/dev_suite/utils/file_writer/file_writer.rb +24 -0
- data/lib/dev_suite/utils/file_writer/writer/base.rb +43 -0
- data/lib/dev_suite/utils/file_writer/writer/json.rb +24 -0
- data/lib/dev_suite/utils/file_writer/writer/text.rb +27 -0
- data/lib/dev_suite/utils/file_writer/writer/writer.rb +14 -0
- data/lib/dev_suite/utils/file_writer/writer/yaml.rb +44 -0
- data/lib/dev_suite/utils/file_writer/writer.rb +11 -0
- data/lib/dev_suite/utils/file_writer/writer_manager.rb +32 -0
- data/lib/dev_suite/utils/file_writer.rb +9 -0
- data/lib/dev_suite/utils/logger.rb +7 -5
- data/lib/dev_suite/utils/store/config/config.rb +13 -0
- data/lib/dev_suite/utils/store/config/configuration.rb +30 -0
- data/lib/dev_suite/utils/store/config.rb +11 -0
- data/lib/dev_suite/utils/store/driver/base.rb +35 -0
- data/lib/dev_suite/utils/store/driver/driver.rb +18 -0
- data/lib/dev_suite/utils/store/driver/file.rb +61 -0
- data/lib/dev_suite/utils/store/driver/memory.rb +42 -0
- data/lib/dev_suite/utils/store/driver.rb +11 -0
- data/lib/dev_suite/utils/store/store.rb +69 -0
- data/lib/dev_suite/utils/store.rb +9 -0
- data/lib/dev_suite/utils/utils.rb +17 -5
- data/lib/dev_suite/utils/warning_handler.rb +25 -0
- data/lib/dev_suite/version.rb +1 -1
- data/lib/dev_suite/workflow/engine.rb +27 -0
- data/lib/dev_suite/workflow/step/base.rb +56 -0
- data/lib/dev_suite/workflow/step/composite.rb +27 -0
- data/lib/dev_suite/workflow/step/conditional.rb +23 -0
- data/lib/dev_suite/workflow/step/loop.rb +21 -0
- data/lib/dev_suite/workflow/step/parallel.rb +18 -0
- data/lib/dev_suite/workflow/step/step.rb +21 -0
- data/lib/dev_suite/workflow/step.rb +9 -0
- data/lib/dev_suite/workflow/step_context.rb +46 -0
- data/lib/dev_suite/workflow/workflow.rb +39 -0
- data/lib/dev_suite/workflow.rb +7 -0
- metadata +101 -3
- data/lib/dev_suite/utils/construct/component/initializer.rb +0 -28
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Utils
|
|
5
|
+
module Store
|
|
6
|
+
module Config
|
|
7
|
+
class Configuration < Utils::Construct::Config::Base
|
|
8
|
+
set_default_settings(
|
|
9
|
+
driver: {
|
|
10
|
+
file: {
|
|
11
|
+
path: "#{Dir.pwd}/tmp/store.json",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
config_attr :driver,
|
|
17
|
+
default_value: :memory,
|
|
18
|
+
type: :symbol,
|
|
19
|
+
resolver: :resolve_driver
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def resolve_driver(value)
|
|
24
|
+
Driver.build_component(value)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Utils
|
|
5
|
+
module Store
|
|
6
|
+
module Driver
|
|
7
|
+
class Base < Construct::Component::Base
|
|
8
|
+
def set(key, value)
|
|
9
|
+
raise NotImplementedError, "Subclasses must implement the `set` method"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def fetch(key)
|
|
13
|
+
raise NotImplementedError, "Subclasses must implement the `fetch` method"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def delete(key)
|
|
17
|
+
raise NotImplementedError, "Subclasses must implement the `delete` method"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def import(source)
|
|
21
|
+
raise NotImplementedError, "Subclasses must implement the `import` method"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def export(destination)
|
|
25
|
+
raise NotImplementedError, "Subclasses must implement the `export` method"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def clear
|
|
29
|
+
raise NotImplementedError, "Subclasses must implement the `clear` method"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Utils
|
|
5
|
+
module Store
|
|
6
|
+
module Driver
|
|
7
|
+
include Construct::Component::Manager
|
|
8
|
+
|
|
9
|
+
require_relative "base"
|
|
10
|
+
require_relative "file"
|
|
11
|
+
require_relative "memory"
|
|
12
|
+
|
|
13
|
+
register_component(File)
|
|
14
|
+
register_component(Memory)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Utils
|
|
5
|
+
module Store
|
|
6
|
+
module Driver
|
|
7
|
+
class File < Base
|
|
8
|
+
def initialize(**options)
|
|
9
|
+
super()
|
|
10
|
+
@path = options[:path] || fetch_setting(:path, default: "tmp/store.json")
|
|
11
|
+
@data = {}
|
|
12
|
+
load_data
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def set(key, value)
|
|
16
|
+
Data.set_value_by_path(@data, key, value)
|
|
17
|
+
save_data
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def fetch(key)
|
|
21
|
+
Data.get_value_by_path(@data, key)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def delete(key)
|
|
25
|
+
Data.delete_key_by_path(@data, key)
|
|
26
|
+
save_data
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def clear
|
|
30
|
+
@data = {}
|
|
31
|
+
save_data
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def import(source)
|
|
35
|
+
raise ArgumentError, "The file does not exist" unless ::File.exist?(source)
|
|
36
|
+
|
|
37
|
+
@data = FileLoader.load(source)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def export(destination)
|
|
41
|
+
FileWriter.write(destination, @data)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def load_data
|
|
47
|
+
@data = FileLoader.load(@path) if ::File.exist?(@path)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def save_data
|
|
51
|
+
FileWriter.write(@path, @data)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def fetch_setting(key, default: nil)
|
|
55
|
+
Config.configuration.settings.get(key, default: default)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Utils
|
|
5
|
+
module Store
|
|
6
|
+
module Driver
|
|
7
|
+
class Memory < Base
|
|
8
|
+
def initialize
|
|
9
|
+
super
|
|
10
|
+
@data = {}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def set(key, value)
|
|
14
|
+
Data.set_value_by_path(@data, key, value)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def fetch(key)
|
|
18
|
+
Data.get_value_by_path(@data, key)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def delete(key)
|
|
22
|
+
Data.delete_key_by_path(@data, key)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def clear
|
|
26
|
+
@data.clear
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def import(source)
|
|
30
|
+
raise ArgumentError, "The file does not exist" unless ::File.exist?(source)
|
|
31
|
+
|
|
32
|
+
@data = FileLoader.load(source)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def export(destination)
|
|
36
|
+
FileWriter.write(destination, @data)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Utils
|
|
5
|
+
module Store
|
|
6
|
+
require_relative "config"
|
|
7
|
+
require_relative "driver"
|
|
8
|
+
|
|
9
|
+
class Store
|
|
10
|
+
def initialize(**options)
|
|
11
|
+
@driver = initialize_driver(**options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def set(key, value)
|
|
15
|
+
@driver.set(key, value)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def fetch(key)
|
|
19
|
+
@driver.fetch(key)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def delete(key)
|
|
23
|
+
@driver.delete(key)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def import(source)
|
|
27
|
+
@driver.import(source)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def export(destination)
|
|
31
|
+
@driver.export(destination)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def clear
|
|
35
|
+
@driver.clear
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def initialize_driver(**options)
|
|
41
|
+
return Config.configuration.driver unless options.key?(:driver)
|
|
42
|
+
|
|
43
|
+
build_driver(options)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def build_driver(options)
|
|
47
|
+
Driver.build_component(options.fetch(:driver), **options.except(:driver))
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class << self
|
|
52
|
+
# Retrieve the singleton store instance
|
|
53
|
+
def instance
|
|
54
|
+
@store ||= Store.new
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Reset the singleton store instance
|
|
58
|
+
def reset!
|
|
59
|
+
@store = nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Create a new store instance (isolated from the singleton)
|
|
63
|
+
def create(**options)
|
|
64
|
+
Store.new(**options)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -2,14 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
module DevSuite
|
|
4
4
|
module Utils
|
|
5
|
+
PATH = "dev_suite/utils"
|
|
6
|
+
|
|
7
|
+
# Load essential modules immediately because they are critical for
|
|
8
|
+
# application startup and early functionality.
|
|
5
9
|
require_relative "emoji"
|
|
6
10
|
require_relative "logger"
|
|
11
|
+
require_relative "data"
|
|
7
12
|
require_relative "error_handler"
|
|
13
|
+
require_relative "warning_handler"
|
|
8
14
|
require_relative "dependency_loader"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
|
|
16
|
+
# Core utilities
|
|
17
|
+
autoload :Construct, "#{PATH}/construct"
|
|
18
|
+
|
|
19
|
+
# Functional utilities
|
|
20
|
+
autoload :Store, "#{PATH}/store"
|
|
21
|
+
autoload :Color, "#{PATH}/color"
|
|
22
|
+
autoload :Table, "#{PATH}/table"
|
|
23
|
+
autoload :FileLoader, "#{PATH}/file_loader"
|
|
24
|
+
autoload :FileWriter, "#{PATH}/file_writer"
|
|
25
|
+
autoload :PathMatcher, "#{PATH}/path_matcher"
|
|
14
26
|
end
|
|
15
27
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Utils
|
|
5
|
+
module WarningHandler
|
|
6
|
+
extend self
|
|
7
|
+
|
|
8
|
+
def warn_if_missing(attribute_name, value)
|
|
9
|
+
if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
|
10
|
+
log_warning("#{attribute_name} is missing or empty!")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def log_warning(message)
|
|
17
|
+
Utils::Logger.log(
|
|
18
|
+
message,
|
|
19
|
+
level: :warn,
|
|
20
|
+
emoji: :warning,
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/dev_suite/version.rb
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Workflow
|
|
5
|
+
class Engine
|
|
6
|
+
attr_reader :steps, :context
|
|
7
|
+
|
|
8
|
+
def initialize(initial_context = {}, **options)
|
|
9
|
+
@steps = []
|
|
10
|
+
@context = StepContext.new(initial_context, **options)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Add steps to the engine
|
|
14
|
+
def step(step)
|
|
15
|
+
@steps << step
|
|
16
|
+
self # Return the current engine instance to support chaining
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Execute the workflow
|
|
20
|
+
def execute
|
|
21
|
+
@steps.each do |step|
|
|
22
|
+
step.run(@context)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Workflow
|
|
5
|
+
module Step
|
|
6
|
+
class Base < Utils::Construct::Component::Base
|
|
7
|
+
attr_accessor :name, :next_step
|
|
8
|
+
|
|
9
|
+
def initialize(name:, &action)
|
|
10
|
+
super()
|
|
11
|
+
@name = name
|
|
12
|
+
@action = action
|
|
13
|
+
@next_step = nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Executes the step and moves to the next step
|
|
17
|
+
def run(context)
|
|
18
|
+
result = perform_action(context)
|
|
19
|
+
Utils::Logger.log("Step: #{@name} - Result: #{result}", level: :info)
|
|
20
|
+
|
|
21
|
+
# If the result is nil or false, stop execution chain
|
|
22
|
+
return unless result
|
|
23
|
+
|
|
24
|
+
update_context(context, result)
|
|
25
|
+
run_next_step(context)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Chain the next step
|
|
29
|
+
def next(step)
|
|
30
|
+
@next_step = step
|
|
31
|
+
step
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# Perform the action associated with this step
|
|
37
|
+
def perform_action(context)
|
|
38
|
+
@action.call(context)
|
|
39
|
+
rescue StandardError => e
|
|
40
|
+
Utils::Logger.log("Step: #{@name} - Error: #{e}", level: :error)
|
|
41
|
+
false
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Update the context with the result of the action (without clearing it)
|
|
45
|
+
def update_context(context, result)
|
|
46
|
+
context.update(result)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Execute the next step if it exists
|
|
50
|
+
def run_next_step(context)
|
|
51
|
+
@next_step&.run(context)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Workflow
|
|
5
|
+
module Step
|
|
6
|
+
class Composite < Base
|
|
7
|
+
def initialize(name:)
|
|
8
|
+
super
|
|
9
|
+
@steps = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Add steps to the composite
|
|
13
|
+
def step(step)
|
|
14
|
+
@steps << step
|
|
15
|
+
self
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Override execute to run all steps in sequence
|
|
19
|
+
def run(context)
|
|
20
|
+
@steps.each do |step|
|
|
21
|
+
step.run(context)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Workflow
|
|
5
|
+
module Step
|
|
6
|
+
class Conditional < Base
|
|
7
|
+
def initialize(name:, condition:, &action)
|
|
8
|
+
super(name: name, &action)
|
|
9
|
+
@condition = condition
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Only execute if the condition is met
|
|
13
|
+
def run(context)
|
|
14
|
+
if @condition.call(context)
|
|
15
|
+
super
|
|
16
|
+
else
|
|
17
|
+
Utils::Logger.log("Step: #{@name} - Skipped due to condition", level: :info)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Workflow
|
|
5
|
+
module Step
|
|
6
|
+
class Loop < Base
|
|
7
|
+
def initialize(name:, iterations:, &action)
|
|
8
|
+
super(name: name, &action)
|
|
9
|
+
@iterations = iterations
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def run(context)
|
|
13
|
+
@iterations.times do |i|
|
|
14
|
+
Utils::Logger.log("Step: #{@name} - Iteration: #{i + 1}", level: :info)
|
|
15
|
+
super(context)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Workflow
|
|
5
|
+
module Step
|
|
6
|
+
class Parallel < Base
|
|
7
|
+
# Executes multiple tasks in parallel using threads
|
|
8
|
+
def run(context)
|
|
9
|
+
tasks = @action.call(context)
|
|
10
|
+
threads = tasks.map do |task|
|
|
11
|
+
Thread.new { task.call(context) }
|
|
12
|
+
end
|
|
13
|
+
threads.each(&:join)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Workflow
|
|
5
|
+
module Step
|
|
6
|
+
include Utils::Construct::Component::Manager
|
|
7
|
+
|
|
8
|
+
require_relative "base"
|
|
9
|
+
require_relative "composite"
|
|
10
|
+
require_relative "conditional"
|
|
11
|
+
require_relative "loop"
|
|
12
|
+
require_relative "parallel"
|
|
13
|
+
|
|
14
|
+
register_component Base
|
|
15
|
+
register_component Composite
|
|
16
|
+
register_component Conditional
|
|
17
|
+
register_component Loop
|
|
18
|
+
register_component Parallel
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Workflow
|
|
5
|
+
class StepContext
|
|
6
|
+
attr_reader :data, :store
|
|
7
|
+
|
|
8
|
+
def initialize(data = {}, **options)
|
|
9
|
+
@data = data
|
|
10
|
+
@store = create_store(options)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Update the context with new data
|
|
14
|
+
def update(new_data)
|
|
15
|
+
unless new_data.is_a?(Hash) || new_data.is_a?(Array)
|
|
16
|
+
raise ArgumentError, "New data must be a Hash"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Utils::Data.deep_merge!(@data, new_data)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Set data by key
|
|
23
|
+
def set(key, value)
|
|
24
|
+
Utils::Data.set_value_by_path(@data, key, value)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Retrieve data by key
|
|
28
|
+
def get(key)
|
|
29
|
+
Utils::Data.get_value_by_path(@data, key)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Clear the context data
|
|
33
|
+
def clear
|
|
34
|
+
@data.clear # Reset the context data
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def create_store(options)
|
|
40
|
+
driver = options[:driver] || :file
|
|
41
|
+
path = options[:path]
|
|
42
|
+
Utils::Store.create(driver: driver, path: path)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DevSuite
|
|
4
|
+
module Workflow
|
|
5
|
+
require_relative "step_context"
|
|
6
|
+
require_relative "step"
|
|
7
|
+
require_relative "engine"
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def create_engine(context = {}, **options)
|
|
11
|
+
Engine.new(context, **options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def create_step(name, type: :base, **args, &block)
|
|
15
|
+
Step.build_component(type, name: name, **args, &block)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create_base_step(name, &block)
|
|
19
|
+
create_step(name, type: :base, &block)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def create_parallel_step(name, &block)
|
|
23
|
+
create_step(name, type: :parallel, &block)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def create_conditional_step(name, condition:, &block)
|
|
27
|
+
create_step(name, type: :conditional, condition: condition, &block)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def create_loop_step(name, iterations:, &block)
|
|
31
|
+
create_step(name, type: :loop, iterations: iterations, &block)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def create_composite_step(name)
|
|
35
|
+
create_step(name, type: :composite)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|