hyraft-rule 0.1.0.alpha1
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/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +239 -0
- data/exe/hyr-rule +4 -0
- data/exe/hyr-rule-db +4 -0
- data/exe/hyraft-rule +6 -0
- data/exe/hyraft-rule-db +404 -0
- data/hyraft-rule.gemspec +54 -0
- data/lib/hyraft/rule/adapter_exhaust/data_gateway_command.rb +132 -0
- data/lib/hyraft/rule/adapter_request/remove_adapter_command.rb +76 -0
- data/lib/hyraft/rule/adapter_request/web_adapter_command.rb +211 -0
- data/lib/hyraft/rule/assemble_command.rb +98 -0
- data/lib/hyraft/rule/command.rb +79 -0
- data/lib/hyraft/rule/disassemble_command.rb +127 -0
- data/lib/hyraft/rule/engine/circuit_command.rb +82 -0
- data/lib/hyraft/rule/engine/port_command.rb +60 -0
- data/lib/hyraft/rule/engine/source_command.rb +70 -0
- data/lib/hyraft/rule/template_command.rb +102 -0
- data/lib/hyraft/rule/version.rb +7 -0
- data/lib/hyraft/rule.rb +40 -0
- metadata +93 -0
data/hyraft-rule.gemspec
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/hyraft/rule/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "hyraft-rule"
|
|
7
|
+
spec.version = Hyraft::Rule::VERSION
|
|
8
|
+
spec.authors = ["Demjhon Silver"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
spec.summary = "Hyraft Rule - Command system for Hyraft applications"
|
|
12
|
+
spec.description = "A standalone command system with migrations for Hyraft applications"
|
|
13
|
+
spec.homepage = "https://github.com/demjhonsilver/hyraft-rule"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.required_ruby_version = ">= 3.4.0"
|
|
16
|
+
|
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
|
19
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
20
|
+
|
|
21
|
+
# Manual file listing without git dependency
|
|
22
|
+
# In hyraft-rule.gemspec - update the files section
|
|
23
|
+
spec.files = [
|
|
24
|
+
"exe/hyraft-rule",
|
|
25
|
+
"exe/hyraft-rule-db",
|
|
26
|
+
"exe/hyr-rule",
|
|
27
|
+
"exe/hyr-rule-db",
|
|
28
|
+
"lib/hyraft/rule.rb",
|
|
29
|
+
"lib/hyraft/rule/version.rb",
|
|
30
|
+
"lib/hyraft/rule/command.rb",
|
|
31
|
+
"lib/hyraft/rule/engine/source_command.rb",
|
|
32
|
+
"lib/hyraft/rule/engine/circuit_command.rb",
|
|
33
|
+
"lib/hyraft/rule/engine/port_command.rb",
|
|
34
|
+
"lib/hyraft/rule/adapter_request/web_adapter_command.rb",
|
|
35
|
+
"lib/hyraft/rule/adapter_request/remove_adapter_command.rb",
|
|
36
|
+
"lib/hyraft/rule/adapter_exhaust/data_gateway_command.rb",
|
|
37
|
+
"lib/hyraft/rule/assemble_command.rb",
|
|
38
|
+
"lib/hyraft/rule/disassemble_command.rb",
|
|
39
|
+
"lib/hyraft/rule/template_command.rb",
|
|
40
|
+
"LICENSE.txt",
|
|
41
|
+
"README.md",
|
|
42
|
+
"CHANGELOG.md",
|
|
43
|
+
"hyraft-rule.gemspec"
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
spec.bindir = "exe"
|
|
47
|
+
spec.executables = ["hyraft-rule", "hyraft-rule-db", "hyr-rule", "hyr-rule-db"]
|
|
48
|
+
spec.require_paths = ["lib"]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
53
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
54
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# lib/hyraft/rule/adapter_exhaust/data_gateway_command.rb
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
module Hyraft
|
|
7
|
+
module Rule
|
|
8
|
+
module AdapterExhaust
|
|
9
|
+
class DataGatewayCommand
|
|
10
|
+
def self.start(args)
|
|
11
|
+
new(args).execute
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def initialize(args)
|
|
15
|
+
@gateway_name = args[0]
|
|
16
|
+
@table_name = extract_table_name(@gateway_name)
|
|
17
|
+
@target_dir = args[1] || "."
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def execute
|
|
21
|
+
return show_usage unless @gateway_name
|
|
22
|
+
|
|
23
|
+
filename = "sequel_#{@table_name}_gateway.rb"
|
|
24
|
+
gateway_dir = File.join(@target_dir, "adapter-exhaust/data-gateway")
|
|
25
|
+
full_path = File.join(gateway_dir, filename)
|
|
26
|
+
|
|
27
|
+
FileUtils.mkdir_p(gateway_dir)
|
|
28
|
+
File.write(full_path, gateway_template)
|
|
29
|
+
|
|
30
|
+
puts "✓ Created gateway: #{full_path}"
|
|
31
|
+
puts "Table name: #{@table_name}"
|
|
32
|
+
puts "Port Adapter: #{port_class_name}"
|
|
33
|
+
puts "Resource: #{source_class_name}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def extract_table_name(gateway_name)
|
|
39
|
+
gateway_name.sub(/_(gateway)?$/, '')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def port_class_name
|
|
43
|
+
"#{@table_name.capitalize}GatewayPort"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def gateway_class_name
|
|
47
|
+
"Sequel#{@table_name.capitalize}Gateway"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def source_class_name
|
|
51
|
+
@table_name.end_with?('s') ? @table_name[0..-2].capitalize : @table_name.capitalize
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def source_variable_name
|
|
55
|
+
@table_name.end_with?('s') ? @table_name[0..-2] : @table_name
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def show_usage
|
|
59
|
+
puts "Usage: hyraft-rule data-gateway <gateway_name> [target_dir]"
|
|
60
|
+
puts ""
|
|
61
|
+
puts "Examples:"
|
|
62
|
+
puts " hyraft-rule data-gateway articles"
|
|
63
|
+
puts " hyraft-rule data-gateway users"
|
|
64
|
+
puts " hyraft-rule data-gateway products"
|
|
65
|
+
puts ""
|
|
66
|
+
puts "This creates: adapter-exhaust/data-gateway/sequel_<name>_gateway.rb"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def gateway_template
|
|
70
|
+
port_name = port_class_name
|
|
71
|
+
gateway_name = gateway_class_name
|
|
72
|
+
source_name = source_class_name
|
|
73
|
+
source_var = source_variable_name
|
|
74
|
+
|
|
75
|
+
<<~RUBY
|
|
76
|
+
require_root 'engine/port/#{@table_name}_gateway_port'
|
|
77
|
+
require_root 'engine/source/#{source_var}'
|
|
78
|
+
require_root 'infra/database/sequel_connection'
|
|
79
|
+
|
|
80
|
+
class #{gateway_name} < #{port_name}
|
|
81
|
+
def initialize
|
|
82
|
+
@db = SequelConnection.db
|
|
83
|
+
@#{@table_name} = @db[:#{@table_name}]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def save(#{source_var})
|
|
87
|
+
if #{source_var}.id && find(#{source_var}.id)
|
|
88
|
+
@#{@table_name}.where(id: #{source_var}.id.to_i).update(
|
|
89
|
+
# Add update fields here
|
|
90
|
+
updated_at: Time.now
|
|
91
|
+
)
|
|
92
|
+
else
|
|
93
|
+
id = @#{@table_name}.insert(
|
|
94
|
+
# Add insert fields here
|
|
95
|
+
created_at: Time.now,
|
|
96
|
+
updated_at: Time.now
|
|
97
|
+
)
|
|
98
|
+
#{source_var}.id = id.to_s
|
|
99
|
+
end
|
|
100
|
+
#{source_var}
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def all
|
|
104
|
+
@#{@table_name}.order(Sequel.desc(:created_at)).all.map { |row| map_row_to_#{source_var}(row) }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def find(id)
|
|
108
|
+
row = @#{@table_name}.where(id: id.to_i).first
|
|
109
|
+
row && map_row_to_#{source_var}(row)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def delete(id)
|
|
113
|
+
@#{@table_name}.where(id: id.to_i).delete
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
private
|
|
117
|
+
|
|
118
|
+
def map_row_to_#{source_var}(row)
|
|
119
|
+
#{source_name}.new(
|
|
120
|
+
id: row[:id].to_s,
|
|
121
|
+
# Add entity attributes here
|
|
122
|
+
created_at: row[:created_at],
|
|
123
|
+
updated_at: row[:updated_at]
|
|
124
|
+
)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
RUBY
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module Hyraft
|
|
6
|
+
module Rule
|
|
7
|
+
class RemoveAdapterCommand
|
|
8
|
+
def self.start(args)
|
|
9
|
+
new(args).execute
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(args)
|
|
13
|
+
@adapter_input = args[0] # "admin-app/users" or "api-app/products"
|
|
14
|
+
@target_dir = args[1] || "."
|
|
15
|
+
parse_adapter_input
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def execute
|
|
19
|
+
return show_manifest unless @adapter_name
|
|
20
|
+
|
|
21
|
+
puts "\e[33m🗑️ Removing adapter: '#{@app_folder}/#{@adapter_name}'\e[0m"
|
|
22
|
+
|
|
23
|
+
remove_adapter_only
|
|
24
|
+
|
|
25
|
+
puts "\e[32m✅ Adapter removed: '#{@app_folder}/#{@adapter_name}'\e[0m"
|
|
26
|
+
puts "\e[36mNote: Engine layer and other adapters preserved\e[0m"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def parse_adapter_input
|
|
32
|
+
return unless @adapter_input
|
|
33
|
+
|
|
34
|
+
if @adapter_input.include?('/')
|
|
35
|
+
@app_folder, @adapter_name = @adapter_input.split('/', 2)
|
|
36
|
+
else
|
|
37
|
+
puts "❌ Error: Please specify app folder (e.g., admin-app/users)"
|
|
38
|
+
exit 1
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def remove_adapter_only
|
|
43
|
+
# Only remove the specific web adapter
|
|
44
|
+
adapter_path = "adapter-intake/#{@app_folder}/request/#{@adapter_name.downcase}_web_adapter.rb"
|
|
45
|
+
delete_file(adapter_path)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def delete_file(relative_path)
|
|
49
|
+
full_path = File.join(@target_dir, relative_path)
|
|
50
|
+
if File.exist?(full_path)
|
|
51
|
+
File.delete(full_path)
|
|
52
|
+
puts " ✓ Deleted: #{relative_path}"
|
|
53
|
+
else
|
|
54
|
+
puts " ⚠️ Not found: #{relative_path}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def show_manifest
|
|
59
|
+
puts "Hyraft Remove Adapter"
|
|
60
|
+
puts "Usage: hyraft-rule remove-adapter <folder>/<adapter_name> [target_dir]"
|
|
61
|
+
puts ""
|
|
62
|
+
puts "Examples:"
|
|
63
|
+
puts " hyraft-rule remove-adapter admin-app/users"
|
|
64
|
+
puts " hyraft-rule remove-adapter api-app/products"
|
|
65
|
+
puts " hyraft-rule remove-adapter mobile-app/categories"
|
|
66
|
+
puts ""
|
|
67
|
+
puts "This command only removes the web adapter, preserving:"
|
|
68
|
+
puts " • Engine layer (sources, circuits, ports)"
|
|
69
|
+
puts " • Data gateway"
|
|
70
|
+
puts " • Other app adapters"
|
|
71
|
+
puts ""
|
|
72
|
+
puts "Use 'hyraft-rule disassemble' to remove entire resource"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# lib/hyraft/rule/adapter_request/web_adapter_command.rb
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module Hyraft
|
|
6
|
+
module Rule
|
|
7
|
+
module AdapterRequest
|
|
8
|
+
class WebAdapterCommand
|
|
9
|
+
def self.start(args)
|
|
10
|
+
input = args[0]
|
|
11
|
+
return show_usage unless input
|
|
12
|
+
|
|
13
|
+
if input.include?('/')
|
|
14
|
+
folder_name, adapter_name = input.split('/', 2)
|
|
15
|
+
else
|
|
16
|
+
folder_name = "web-app"
|
|
17
|
+
adapter_name = input
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
target_dir = args[1] || "."
|
|
21
|
+
adapters_dir = File.join(target_dir, "adapter-intake", folder_name, "request")
|
|
22
|
+
full_path = File.join(adapters_dir, "#{adapter_name.downcase}_web_adapter.rb")
|
|
23
|
+
|
|
24
|
+
FileUtils.mkdir_p(adapters_dir)
|
|
25
|
+
File.write(full_path, web_adapter_template(adapter_name, folder_name))
|
|
26
|
+
|
|
27
|
+
puts "\e[94m✓ Created web adapter: #{full_path}\e[0m"
|
|
28
|
+
puts "\e[38;5;214mApp folder name: #{folder_name}, Adapter: #{adapter_name}\e[0m"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def self.show_usage
|
|
34
|
+
puts "Usage: hyraft-rule web-adapter [folder_name/]<AdapterName> [target_dir]"
|
|
35
|
+
puts ""
|
|
36
|
+
puts "Examples:"
|
|
37
|
+
puts " hyraft-rule web-adapter Articles"
|
|
38
|
+
puts " hyraft-rule web-adapter admin/Users"
|
|
39
|
+
puts " hyraft-rule web-adapter api-app/Products"
|
|
40
|
+
puts " hyraft-rule web-adapter mobile/Categories"
|
|
41
|
+
puts ""
|
|
42
|
+
puts "Default folder: web-app"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.web_adapter_template(adapter_name, folder_name = "web-app")
|
|
46
|
+
singular_name = adapter_name.downcase.chomp('s')
|
|
47
|
+
adapter_class_name = adapter_name.split('_').map(&:capitalize).join # "articles" → "Articles"
|
|
48
|
+
plural_name = singular_name + 's'
|
|
49
|
+
circuit_name = "#{adapter_class_name}Circuit"
|
|
50
|
+
gateway_name = "Sequel#{adapter_class_name}Gateway"
|
|
51
|
+
|
|
52
|
+
<<~RUBY
|
|
53
|
+
require_root 'engine/circuit/#{plural_name}_circuit'
|
|
54
|
+
require_root 'adapter-exhaust/data-gateway/sequel_#{plural_name}_gateway'
|
|
55
|
+
|
|
56
|
+
class #{adapter_class_name}WebAdapter
|
|
57
|
+
def initialize
|
|
58
|
+
gateway = #{gateway_name}.new
|
|
59
|
+
@#{plural_name} = #{circuit_name}.new(gateway)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# GET /#{plural_name}
|
|
63
|
+
def index(request)
|
|
64
|
+
#{plural_name} = @#{plural_name}.list || []
|
|
65
|
+
|
|
66
|
+
{
|
|
67
|
+
status: 200,
|
|
68
|
+
locals: {
|
|
69
|
+
#{plural_name}: #{plural_name}
|
|
70
|
+
},
|
|
71
|
+
display: 'pages/#{plural_name}/index.hyr'
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# GET /#{plural_name}/:id
|
|
76
|
+
def show(request)
|
|
77
|
+
id = request.params['route_params'].first
|
|
78
|
+
#{singular_name} = @#{plural_name}.find(id)
|
|
79
|
+
|
|
80
|
+
if #{singular_name}
|
|
81
|
+
{
|
|
82
|
+
status: 200,
|
|
83
|
+
locals: {
|
|
84
|
+
#{singular_name}: #{singular_name}
|
|
85
|
+
},
|
|
86
|
+
display: 'pages/#{plural_name}/show.hyr'
|
|
87
|
+
}
|
|
88
|
+
else
|
|
89
|
+
not_found_response(request)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# GET /#{plural_name}/new - Show create form
|
|
94
|
+
def new(request)
|
|
95
|
+
{
|
|
96
|
+
status: 200,
|
|
97
|
+
locals: {},
|
|
98
|
+
display: 'pages/#{plural_name}/new.hyr'
|
|
99
|
+
}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# POST /#{plural_name} - Create #{singular_name}
|
|
103
|
+
def create(request)
|
|
104
|
+
data = request.params['data'] || {}
|
|
105
|
+
|
|
106
|
+
# TODO: Add validation for required fields
|
|
107
|
+
# Example:
|
|
108
|
+
# if data['title'] && data['content']
|
|
109
|
+
# article = @articles.create(
|
|
110
|
+
# title: data['title'],
|
|
111
|
+
# content: data['content']
|
|
112
|
+
# )
|
|
113
|
+
#
|
|
114
|
+
# {
|
|
115
|
+
# status: 303,
|
|
116
|
+
# headers: { 'Location' => "/articles" },
|
|
117
|
+
# locals: {}
|
|
118
|
+
# }
|
|
119
|
+
# else
|
|
120
|
+
# {
|
|
121
|
+
# status: 422,
|
|
122
|
+
# locals: {
|
|
123
|
+
# error: "Title and content are required"
|
|
124
|
+
# },
|
|
125
|
+
# display: 'pages/articles/new.hyr'
|
|
126
|
+
# }
|
|
127
|
+
# end
|
|
128
|
+
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# GET /#{plural_name}/:id/edit - Show edit form
|
|
132
|
+
def edit(request)
|
|
133
|
+
id = request.params['route_params'].first
|
|
134
|
+
#{singular_name} = @#{plural_name}.find(id)
|
|
135
|
+
|
|
136
|
+
if #{singular_name}
|
|
137
|
+
{
|
|
138
|
+
status: 200,
|
|
139
|
+
locals: {
|
|
140
|
+
#{singular_name}: #{singular_name}
|
|
141
|
+
},
|
|
142
|
+
display: 'pages/#{plural_name}/edit.hyr'
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
not_found_response(request)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# PUT /#{plural_name}/:id - Update #{singular_name}
|
|
150
|
+
def update(request)
|
|
151
|
+
id = request.params['route_params'].first
|
|
152
|
+
data = request.params['data'] || {}
|
|
153
|
+
|
|
154
|
+
# TODO: Implement update logic
|
|
155
|
+
# Example:
|
|
156
|
+
# updated_#{singular_name} = @#{plural_name}.update(
|
|
157
|
+
# id: id,
|
|
158
|
+
# title: data['title'],
|
|
159
|
+
# content: data['content']
|
|
160
|
+
# )
|
|
161
|
+
|
|
162
|
+
if updated_#{singular_name}
|
|
163
|
+
{
|
|
164
|
+
status: 303,
|
|
165
|
+
headers: { 'Location' => "/#{plural_name}" },
|
|
166
|
+
locals: {}
|
|
167
|
+
}
|
|
168
|
+
else
|
|
169
|
+
{
|
|
170
|
+
status: 422,
|
|
171
|
+
locals: {
|
|
172
|
+
#{singular_name}: @#{plural_name}.find(id),
|
|
173
|
+
error: "Failed to update #{singular_name}"
|
|
174
|
+
},
|
|
175
|
+
display: 'pages/#{plural_name}/edit.hyr'
|
|
176
|
+
}
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# DELETE /#{plural_name}/:id - Delete #{singular_name}
|
|
181
|
+
def delete(request)
|
|
182
|
+
id = request.params['route_params'].first
|
|
183
|
+
@#{plural_name}.delete(id)
|
|
184
|
+
|
|
185
|
+
{
|
|
186
|
+
status: 303,
|
|
187
|
+
headers: { 'Location' => "/#{plural_name}" },
|
|
188
|
+
locals: {}
|
|
189
|
+
}
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
private
|
|
193
|
+
|
|
194
|
+
def not_found_response(request)
|
|
195
|
+
{
|
|
196
|
+
status: 404,
|
|
197
|
+
locals: {
|
|
198
|
+
error: "#{singular_name.capitalize} not found",
|
|
199
|
+
back_url: '/#{plural_name}',
|
|
200
|
+
back_text: 'Back to #{adapter_name}'
|
|
201
|
+
},
|
|
202
|
+
display: 'pages/#{plural_name}/404.hyr'
|
|
203
|
+
}
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
RUBY
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module Hyraft
|
|
6
|
+
module Rule
|
|
7
|
+
class AssembleCommand
|
|
8
|
+
def self.start(args)
|
|
9
|
+
new(args).execute
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(args)
|
|
13
|
+
@resource_input = args[0] # Can be "users" or "admin-app/users"
|
|
14
|
+
@target_dir = args[1] || "."
|
|
15
|
+
parse_resource_input
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def execute
|
|
19
|
+
return show_manifest unless @resource_name
|
|
20
|
+
|
|
21
|
+
puts "\e[35m🔧 Hyraft Assembly: Assembling '#{@resource_name}' resource\e[0m"
|
|
22
|
+
puts "\e[36mApp Folder: #{@app_folder}\e[0m" if @app_folder != "web-app"
|
|
23
|
+
|
|
24
|
+
assemble_engine_layer
|
|
25
|
+
assemble_adapter_layer
|
|
26
|
+
|
|
27
|
+
puts "\e[32m✅ Assembly Complete: '#{@resource_name}' resource assembled\e[0m"
|
|
28
|
+
puts "\e[36mNext steps:\e[0m"
|
|
29
|
+
puts " ⚡ Implement business logic in circuits"
|
|
30
|
+
puts " 🌐 Connect web adapters to router"
|
|
31
|
+
puts " 📊 Create database table manually"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def parse_resource_input
|
|
37
|
+
return unless @resource_input
|
|
38
|
+
|
|
39
|
+
if @resource_input.include?('/')
|
|
40
|
+
@app_folder, @resource_name = @resource_input.split('/', 2)
|
|
41
|
+
else
|
|
42
|
+
@app_folder = "web-app"
|
|
43
|
+
@resource_name = @resource_input
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def assemble_engine_layer
|
|
48
|
+
puts "\e[34m⚡ Assembling Engine Layer...\e[0m"
|
|
49
|
+
|
|
50
|
+
# Check if engine files already exist
|
|
51
|
+
singular_name = @resource_name.end_with?('s') ? @resource_name[0..-2].capitalize : @resource_name.capitalize
|
|
52
|
+
source_path = File.join(@target_dir, "engine/source/#{singular_name.downcase}.rb")
|
|
53
|
+
circuit_path = File.join(@target_dir, "engine/circuit/#{@resource_name.downcase}_circuit.rb")
|
|
54
|
+
port_path = File.join(@target_dir, "engine/port/#{@resource_name.downcase}_gateway_port.rb")
|
|
55
|
+
|
|
56
|
+
if File.exist?(source_path) || File.exist?(circuit_path) || File.exist?(port_path)
|
|
57
|
+
puts " ⚠️ Engine files already exist - skipping engine layer"
|
|
58
|
+
return
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Pass singular name for source, plural for others
|
|
62
|
+
SourceCommand.start([singular_name, @target_dir])
|
|
63
|
+
CircuitCommand.start(["#{@resource_name.capitalize}Circuit", @target_dir])
|
|
64
|
+
PortCommand.start(["#{@resource_name.capitalize}GatewayPort", @target_dir])
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def assemble_adapter_layer
|
|
68
|
+
puts "\e[34m🔌 Assembling Adapter Layer...\e[0m"
|
|
69
|
+
# Pass folder/resource format to web adapter command
|
|
70
|
+
AdapterRequest::WebAdapterCommand.start(["#{@app_folder}/#{@resource_name}", @target_dir])
|
|
71
|
+
AdapterExhaust::DataGatewayCommand.start([@resource_name, @target_dir])
|
|
72
|
+
|
|
73
|
+
# Generate templates as well
|
|
74
|
+
puts "\e[34m📝 Generating Templates...\e[0m"
|
|
75
|
+
TemplateCommand.start(["#{@app_folder}/#{@resource_name}", @target_dir])
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def show_manifest
|
|
80
|
+
puts "Hyraft Assembly Manifest"
|
|
81
|
+
puts "Usage: hyraft-rule assemble [folder/]<resource_name> [target_dir]"
|
|
82
|
+
puts ""
|
|
83
|
+
puts "Examples:"
|
|
84
|
+
puts " hyraft-rule assemble articles # Default: web-app/articles"
|
|
85
|
+
puts " hyraft-rule assemble users # Default: web-app/users"
|
|
86
|
+
puts " hyraft-rule assemble admin-app/users # Creates: admin-app/users"
|
|
87
|
+
puts " hyraft-rule assemble api/products # Creates: api/products"
|
|
88
|
+
puts " hyraft-rule assemble mobile/categories # Creates: mobile/categories"
|
|
89
|
+
puts ""
|
|
90
|
+
puts "Assembly Components:"
|
|
91
|
+
puts " ⚡ Engine Layer → Sources + Circuits + Ports"
|
|
92
|
+
puts " 🔌 Adapter Layer → Web Adapters + Data Gateways"
|
|
93
|
+
puts ""
|
|
94
|
+
puts "Note: Database migrations must be created separately"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hyraft
|
|
4
|
+
module Rule
|
|
5
|
+
class Command
|
|
6
|
+
def self.start(argv)
|
|
7
|
+
new(argv).execute
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(argv)
|
|
11
|
+
@argv = argv
|
|
12
|
+
@command = argv[0]
|
|
13
|
+
@args = argv[1..-1]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def execute
|
|
17
|
+
case @command
|
|
18
|
+
when "migrate"
|
|
19
|
+
MigrationCommand.start(@args)
|
|
20
|
+
when "source"
|
|
21
|
+
SourceCommand.start(@args)
|
|
22
|
+
when "circuit"
|
|
23
|
+
CircuitCommand.start(@args)
|
|
24
|
+
when "port"
|
|
25
|
+
PortCommand.start(@args)
|
|
26
|
+
when "web-adapter"
|
|
27
|
+
AdapterRequest::WebAdapterCommand.start(@args)
|
|
28
|
+
when "data-gateway"
|
|
29
|
+
AdapterExhaust::DataGatewayCommand.start(@args)
|
|
30
|
+
when "assemble"
|
|
31
|
+
AssembleCommand.start(@args)
|
|
32
|
+
when "disassemble"
|
|
33
|
+
DisassembleCommand.start(@args)
|
|
34
|
+
when "template"
|
|
35
|
+
TemplateCommand.start(@args)
|
|
36
|
+
when "remove-adapter", "rm-adapter"
|
|
37
|
+
require 'hyraft/rule/adapter_request/remove_adapter_command'
|
|
38
|
+
RemoveAdapterCommand.start(@args)
|
|
39
|
+
when "version", "-v", "--version"
|
|
40
|
+
puts "Hyraft Rule version #{VERSION}"
|
|
41
|
+
when "help", "-h", "h", "--help", nil
|
|
42
|
+
show_help
|
|
43
|
+
else
|
|
44
|
+
puts "Unknown command: #{@command}"
|
|
45
|
+
show_help
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def show_help
|
|
52
|
+
puts "Hyraft Rule - Command System for Hyraft Applications"
|
|
53
|
+
puts ""
|
|
54
|
+
puts "Commands:"
|
|
55
|
+
puts " source Generate source files"
|
|
56
|
+
puts " circuit Generate circuit files"
|
|
57
|
+
puts " port Generate port files"
|
|
58
|
+
puts " web-adapter Generate web adapter files"
|
|
59
|
+
puts " data-gateway Generate data gateway files"
|
|
60
|
+
puts " template Generate .hyr template files"
|
|
61
|
+
puts " assemble Assemble Engine + Adapters for a resource"
|
|
62
|
+
puts " disassemble Remove assembled Engine + Adapters for a resource"
|
|
63
|
+
puts " remove-adapter Remove specific adapter only (preserves engine)"
|
|
64
|
+
puts " version Show version information"
|
|
65
|
+
puts " help Show this help message"
|
|
66
|
+
puts ""
|
|
67
|
+
puts "Run 'hyr-rule <command>"
|
|
68
|
+
puts "Run 'hyraft-rule <command>"
|
|
69
|
+
puts ""
|
|
70
|
+
puts ""
|
|
71
|
+
puts "Database Commands:"
|
|
72
|
+
puts "Run 'hyr-rule-db <command>"
|
|
73
|
+
puts "Run 'hyraft-rule-db <command>"
|
|
74
|
+
puts ""
|
|
75
|
+
puts ""
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|